极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 19503|回复: 15

做一个低端的、高价智能浇花

[复制链接]
发表于 2014-8-24 15:51:27 | 显示全部楼层 |阅读模式
本帖最后由 hi55234 于 2014-8-24 16:10 编辑




低端在于,暂时来说不过用了2个数字端口,一个接流量计、一个通过继电器控制电磁阀,而基础程序只能定时(其实通过时间定量)、定量浇花

高价在于:
1、这玩意用太阳能板+太阳能控制器+蓄电池+DC-DC降压构成了独立的供电系统
2、这玩意用DS1307记录时间,并丧心病狂的配上了GPS用于时间校队
3、为了赶时髦(传说中精度高一点),DHT11取湿度、DS18B20取温度

为了后续扩展的需要,预留gp2y1010的接口,而如果想手机上看数据,蓝牙模块也得上

先放一个基础程序,高价的部分还没有融合呢:
  1. int liuliangji=12;
  2. int diancifa=13;
  3. unsigned long time0=millis();
  4. unsigned long time1=millis();
  5. boolean chongfupanduan=0;
  6. boolean test1=1;

  7. int jsqLLx=0;
  8. float shishiliuliang=0;
  9. float leijiliuliang=0;
  10. int avrsudu=0;

  11. //////////////////////////////////////////////////////////////////////////////////////////////
  12. //1602
  13. //////////////////////////////////////////////////////////////////////////////////////////////

  14. #include <LiquidCrystal.h>

  15. // initialize the library with the numbers of the interface pins
  16. LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

  17. byte quan0[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};


  18. //////////////////////////////////////////////////////////////////////////////////////////////


  19. void setup() {
  20.   Serial.begin(9600);
  21.   pinMode(liuliangji,INPUT); //流量计接12
  22.   pinMode(diancifa, OUTPUT); //电磁阀接13
  23.   digitalWrite(diancifa, LOW); //开(电磁阀)闸放水

  24.     //1602
  25.   lcd.createChar(1, quan0); //全0
  26.   lcd.begin(16, 2);

  27.   }


  28. void loop() {


  29.   if(millis()-time0>1000) {

  30.   time0=millis();//每一秒还原一次
  31.   shishiliuliang=jsqLLx/7.5;//计算实时流量(公式:频率=7.5*流量(L/min))
  32.   leijiliuliang=leijiliuliang+(shishiliuliang/60);//(每秒积分)计数累计流量

  33.   lcd1602out();//每秒钟刷新显示类容
  34.   jsqLLx=0;//清空每秒流量

  35. }else{
  36.    int liuliangjidianping =digitalRead(liuliangji);//读取流量计的电平
  37.    
  38.    if(liuliangjidianping == HIGH && !chongfupanduan){ //高电平 且 本次没计数,就计数
  39. jsqLLx++;
  40.     chongfupanduan=!chongfupanduan;//本次已计数,则标记已计数
  41.    }
  42.    
  43.     if(liuliangjidianping == LOW && chongfupanduan)chongfupanduan=!chongfupanduan;//低电平,且 计数标记为1,则重置计数标记
  44. }



  45. if(millis()-time1>5000 && test1) { //时间控制,到时间就关了
  46. test1=0;
  47. digitalWrite(diancifa, HIGH);//关闭电磁阀,外加个判断,只关一次就好
  48. }


  49. int leijiliuliang2=leijiliuliang;
  50. if(leijiliuliang2 >100 && test1) { //流量控制,流量超了就关了
  51. test1=0;
  52. digitalWrite(diancifa, HIGH);//关闭电磁阀,外加个判断,只关一次就好
  53. }



  54. }













  55. void lcd1602out(){

  56. //清空第一排的所有内容
  57.   lcd.setCursor(0, 0);
  58.   for(int col=0;col<16;col++){
  59.   lcd.write(1);
  60.   }

  61.   lcd.setCursor(0, 0);//回归第一排,第一点

  62.    lcd.print("T ");
  63.    lcd.print(shishiliuliang);
  64.    lcd.print(" L/min");

  65.   //清空第2排的所有内容
  66.   lcd.setCursor(0, 1);
  67.   for(int col=0;col<16;col++){
  68.   lcd.write(1);
  69.   }

  70.   lcd.setCursor(0, 1);//回归第2排,第一点

  71.    lcd.print("Total:");
  72.    lcd.print(leijiliuliang);
  73.    lcd.print(" L");



  74.   }




复制代码



剩下的问题:

1、 LM339 电压比较器怎么用?有了这玩意,就能实现阳光好的时候太阳能板给蓄电池充电,而阳光不好的时候,蓄电池和充电控制器相断开,保证充电效果http://www.geek-workshop.com/thread-10793-1-1.html

2、研究一下DS1307模块自带的存储器,争取做到掉电不掉数据

3、目前程序还是内定量,日后接手机了,浇多少水,还是弄个变量比较实在

4、所谓自能浇水,那自然是天热多浇,天冷少浇,雨下够了就不浇了,那么,如果蒸发率整么测量比较合适呢?拿个量杯放着看自然是不错的,称重自然也是可行的,但尼玛时间久了,水脏了又怎么解决呢,天天换水也不是人感的活啊?


接下来的补充:
1、时间判断?只在规定时段内浇花
2、温度判断?天气太热,不浇花,温度下来了再慢慢浇
3、水压传感器?要是停水了,那就不用浇花了,电磁阀一直开着也会坏吧这个不用了,停水了,流量计自然就动不了了
  1. 水平水管中 水压与进水流量和出水流量之间的关系 最好是数学公式

  2. 根据伯努利方程,对于水平水管有:u2/2+p/ρ=C,其中u是液体的流速,p为静压力,ρ为流体密度,C为一常数。。
复制代码

4、蒸发率计算

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复

使用道具 举报

发表于 2014-8-24 17:52:01 | 显示全部楼层
呵呵,好奇下,水压传感器传感器什么样子??
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-24 18:46:29 | 显示全部楼层
Paderboy 发表于 2014-8-24 17:52
呵呵,好奇下,水压传感器传感器什么样子??

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

发表于 2014-8-24 19:00:33 | 显示全部楼层
真的是高价浇花机啊。。。。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-24 20:35:27 | 显示全部楼层
Paderboy 发表于 2014-8-24 19:00
真的是高价浇花机啊。。。。

整体成本,目测有望上1000

现在已经700了~~~T_T


屋顶浇水        709.26       
               
1        167        电池板+控制器
2        56.6        12V7AH
3        175.4        电线100m+空开
4        18        小太阳能板
5        32.67        万用表
6        56.4        电磁阀、流量计、接头
7        12.99        扎带
8        21.3        快接、通水
9        127.9        乱七八糟的零件
10        41        几个空开
回复 支持 反对

使用道具 举报

发表于 2014-8-25 12:05:02 | 显示全部楼层
楼主的这个流量代码想参考,可没有完全理解。
因为自己的流量代码占用了一个中断,参考了坛子里的计数代码
[pre lang="arduino" line="1" file="Flow"]double count = 0.00;//参数定义
double q =0.00;//参数定义
void setup()//主程序
{
  pinMode(2,INPUT);//定义针脚2为输入
  attachInterrupt(0,encoder,FALLING);//定义encoder子程序中断条件
  Serial.begin(9600);//定义波特率
}
void loop()
{
    Serial.println(q);//串口输出流量值
}
void encoder()//子程序
{
     count++;//自增
     q = count /488;//流量换算
}
[/code]
回复 支持 反对

使用道具 举报

发表于 2014-8-25 21:41:16 | 显示全部楼层
楼主这个同时浇几盆花?我曾经做过一个(当然比你的低端啦),可能是那时候材料不够吧,分支流时总是有的大有的小,甚至有的还不出水,发张头上的照片呗。
回复 支持 反对

使用道具 举报

发表于 2014-8-27 14:30:14 | 显示全部楼层
土壤湿度计模块,4钱一个。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-27 15:22:21 | 显示全部楼层
zwltanf 发表于 2014-8-25 12:05
楼主的这个流量代码想参考,可没有完全理解。
因为自己的流量代码占用了一个中断,参考了坛子里的计数代码 ...

这代码目测有2个小问题:

1、loop 是无限循环的,也就意味着在无中断的情况下,串口无限打印
2、缺乏周期的概念,也就是看不出实时流量速度

回复 支持 反对

使用道具 举报

发表于 2014-8-28 10:17:45 | 显示全部楼层
hi55234 发表于 2014-8-27 15:22
这代码目测有2个小问题:

1、loop 是无限循环的,也就意味着在无中断的情况下,串口无限打印

是累积流量,现在想做成累积流量达到10的时候整个系统程序停止
回复 支持 反对

使用道具 举报

发表于 2014-8-28 12:42:36 | 显示全部楼层
楼主现在水费太贵了,还是不要搞这种系统为妙。
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-30 14:15:10 | 显示全部楼层
暂时增加一个流量调节的

  1. int liuliangji=12;
  2. int diancifa=13;
  3. unsigned long meimiaoyilunhui=millis();//每秒一轮回

  4. boolean chongfupanduanA=0;//重复判定A
  5. boolean chongfupanduanB=1;//重复判定B

  6. int jsqLLx=0;
  7. float shishiliuliang=0;//实时流量
  8. float leijiliuliang=0;//累计流量
  9. float shedingjiaoguanliang=0;//设定浇灌量
  10. int shedingjiaoguanliangup=16;//设定浇灌量+  A2
  11. int shedingjiaoguanliangdown=17;//设定浇灌量-  A3

  12. unsigned long guzhangjianceA=millis();//故障检测
  13. int guzhangjiancejsq;//故障检测计数器

  14. int upok;//设定浇灌量增加
  15. int downok;//设定浇灌量减少
  16. boolean anjianzuse = 0;  //按键阻塞
  17. int tiaojieliang=5;//每次增减的 调节量 5L

  18. //////////////////////////////////////////////////////////////////////////////////////////////
  19. //1602
  20. //////////////////////////////////////////////////////////////////////////////////////////////

  21. #include <LiquidCrystal.h>

  22. // initialize the library with the numbers of the interface pins
  23. LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

  24. byte quan0[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};


  25. //////////////////////////////////////////////////////////////////////////////////////////////


  26. void setup() {
  27.   Serial.begin(9600);
  28.   pinMode(liuliangji,INPUT); //流量计接12
  29.   pinMode(diancifa, OUTPUT); //电磁阀接13
  30.   pinMode(shedingjiaoguanliangup,INPUT); //设定浇灌量,增加
  31.   pinMode(shedingjiaoguanliangdown,INPUT); //设定浇灌量,减少
  32.   digitalWrite(diancifa, LOW); //开(电磁阀)闸放水

  33.     //1602
  34.   lcd.createChar(1, quan0); //全0
  35.   lcd.begin(16, 2);

  36.   }


  37. void loop() {

  38. jiaohuaA();//每秒频率测定,实时流量计算,累计流量叠加,1602显示

  39. jiaohuaB();//通过3秒的频率次数的累加,来判断是否停水了(防止电池阀在没水的时候长期运行)

  40. jiaohuaC();

  41. if(leijiliuliang < shedingjiaoguanliang) { //流量控制,流量超了就关了
  42. digitalWrite(diancifa, LOW);//累计流量小于设定流量,打开电磁阀

  43. }else{
  44. digitalWrite(diancifa, HIGH);//关闭电磁阀
  45. shedingjiaoguanliang=0;//清空设定浇灌量
  46. leijiliuliang=0;//清空累计流量

  47. }



  48.   
  49. }




  50. void jiaohuaA(){

  51.   if(millis()-meimiaoyilunhui>1000) {

  52.   meimiaoyilunhui=millis();//每一秒还原一次
  53.   shishiliuliang=jsqLLx/7.5;//计算实时流量(公式:频率=7.5*流量(L/min))
  54.   leijiliuliang=leijiliuliang+(shishiliuliang/60);//(每秒积分)计数累计流量

  55.   lcd1602out();//每秒钟刷新显示类容
  56.   
  57.   guzhangjiancejsq=guzhangjiancejsq+jsqLLx;//累加频率的数量,来确定是否故障(停水了)
  58.   jsqLLx=0;//清空每秒频率

  59. }else{
  60.    int liuliangjidianping =digitalRead(liuliangji);//读取流量计的电平
  61.    
  62.    if(liuliangjidianping == HIGH && !chongfupanduanA){ //高电平 且 本次没计数,就计数
  63. jsqLLx++;
  64.     chongfupanduanA=!chongfupanduanA;//本次已计数,则标记已计数
  65.    }
  66.    
  67.     if(liuliangjidianping == LOW && chongfupanduanA)chongfupanduanA=!chongfupanduanA;//低电平,且 计数标记为1,则重置计数标记
  68. }

  69. }

  70. void jiaohuaB(){

  71. //停水状态的应急处理
  72. if(millis()-guzhangjianceA>3000) {
  73. guzhangjianceA=millis();//每3秒还原一次

  74. if(guzhangjiancejsq<21){//3秒累计频率小于21,则说明流量小于1L/min,这个时候认定为停水了
  75. digitalWrite(diancifa, HIGH);//关闭电磁阀
  76. delay(30000);//保持电池阀关闭状态30秒,散热,以免无水状态,电池阀长期工作
  77. }

  78. guzhangjiancejsq=0;//累计频率置0

  79. }

  80. }

  81. void jiaohuaC(){
  82.   
  83.   upok=digitalRead(shedingjiaoguanliangup);    //读取up按钮数值
  84.   downok=digitalRead(shedingjiaoguanliangdown);  //读取down按钮数值

  85.   if(!anjianzuse&&upok==HIGH){    //对设定流量进行修改(anjianzuse是为了防止按住按钮产生连续按动)
  86.   shedingjiaoguanliang=shedingjiaoguanliang+tiaojieliang;
  87.   anjianzuse = 1;                     //把现在的状态设置成已经按下状态
  88.   }
  89.   
  90.   if(!anjianzuse&&downok==HIGH){   
  91.   shedingjiaoguanliang=shedingjiaoguanliang-tiaojieliang;
  92.   if(shedingjiaoguanliang<0)shedingjiaoguanliang=0;
  93.   anjianzuse = 1;
  94.   }

  95.   if(upok==LOW && downok==LOW){        //如果都是低相当于没有按钮按下
  96.     anjianzuse=0;                      //置anjianzuse为假
  97.   }

  98. }

  99. void lcd1602out(){

  100. //清空第一排的所有内容
  101.   lcd.setCursor(0, 0);
  102.   for(int col=0;col<16;col++){
  103.   lcd.write(1);
  104.   }

  105.   lcd.setCursor(0, 0);//回归第一排,第一点

  106.    lcd.print("T ");
  107.    lcd.print(shishiliuliang);
  108.    lcd.print(" L/min");

  109.   //清空第2排的所有内容
  110.   lcd.setCursor(0, 1);
  111.   for(int col=0;col<16;col++){
  112.   lcd.write(1);
  113.   }

  114.   lcd.setCursor(0, 1);//回归第2排,第一点

  115.    lcd.print("Total:");
  116.    lcd.print(leijiliuliang);
  117.    lcd.print(" L");



  118.   }




复制代码
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-31 11:00:48 | 显示全部楼层
来个按钮玩玩



  1. int liuliangji=12;
  2. int diancifa=13;
  3. unsigned long meimiaoyilunhui=millis();//每秒一轮回

  4. boolean chongfupanduanA=0;//重复判定A
  5. boolean chongfupanduanB=1;//重复判定B

  6. int jsqLLx=0;
  7. float shishiliuliang=0;//实时流量
  8. float leijiliuliang=0;//累计流量
  9. int shedingjiaoguanliang=0;//设定浇灌量
  10. int shedingjiaoguanliangup=16;//设定浇灌量+  A2
  11. int shedingjiaoguanliangdown=17;//设定浇灌量-  A3

  12. unsigned long guzhangjianceA=millis();//故障检测
  13. int guzhangjiancejsq;//故障检测计数器

  14. int upok;//设定浇灌量增加
  15. int downok;//设定浇灌量减少
  16. boolean anjianzuse = 0;  //按键阻塞
  17. int tiaojieliang=5;//每次增减的 调节量 5L

  18. char temp3[27];
  19. unsigned long x;
  20. //////////////////////////////////////////////////////////////////////////////////////////////
  21. //1602
  22. //////////////////////////////////////////////////////////////////////////////////////////////

  23. #include <LiquidCrystal.h>

  24. // initialize the library with the numbers of the interface pins
  25. LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

  26. byte quan0[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};


  27. //////////////////////////////////////////////////////////////////////////////////////////////


  28. void setup() {
  29.   Serial.begin(9600);
  30.   pinMode(liuliangji,INPUT); //流量计接12
  31.   pinMode(diancifa, OUTPUT); //电磁阀接13
  32.   pinMode(shedingjiaoguanliangup,INPUT); //设定浇灌量,增加
  33.   pinMode(shedingjiaoguanliangdown,INPUT); //设定浇灌量,减少
  34.   digitalWrite(diancifa, LOW); //开(电磁阀)闸放水

  35.     //1602
  36.   lcd.createChar(1, quan0); //全0
  37.   lcd.begin(16, 2);

  38.   }


  39. void loop() {

  40. jiaohuaA();//每秒频率测定,实时流量计算,累计流量叠加,1602显示

  41. jiaohuaB();//通过3秒的频率次数的累加,来判断是否停水了(防止电池阀在没水的时候长期运行)

  42. jiaohuaC();

  43. if(leijiliuliang < shedingjiaoguanliang) { //流量控制,流量超了就关了
  44. digitalWrite(diancifa, LOW);//累计流量小于设定流量,打开电磁阀

  45. }else{
  46. digitalWrite(diancifa, HIGH);//关闭电磁阀
  47. shedingjiaoguanliang=0;//清空设定浇灌量
  48. leijiliuliang=0;//清空累计流量

  49. }



  50.   
  51. }




  52. void jiaohuaA(){

  53.   if(millis()-meimiaoyilunhui>1000) {

  54.   meimiaoyilunhui=millis();//每一秒还原一次
  55.   shishiliuliang=jsqLLx/7.5;//计算实时流量(公式:频率=7.5*流量(L/min))
  56.   leijiliuliang=leijiliuliang+(shishiliuliang/60);//(每秒积分)计数累计流量

  57.   lcd1602out();//每秒钟刷新显示类容
  58.   
  59.   guzhangjiancejsq=guzhangjiancejsq+jsqLLx;//累加频率的数量,来确定是否故障(停水了)
  60.   jsqLLx=0;//清空每秒频率

  61. }else{
  62.    int liuliangjidianping =digitalRead(liuliangji);//读取流量计的电平
  63.    
  64.    if(liuliangjidianping == HIGH && !chongfupanduanA){ //高电平 且 本次没计数,就计数
  65. jsqLLx++;
  66.     chongfupanduanA=!chongfupanduanA;//本次已计数,则标记已计数
  67.    }
  68.    
  69.     if(liuliangjidianping == LOW && chongfupanduanA)chongfupanduanA=!chongfupanduanA;//低电平,且 计数标记为1,则重置计数标记
  70. }

  71. }

  72. void jiaohuaB(){

  73. //停水状态的应急处理
  74. if(millis()-guzhangjianceA>3000) {
  75. guzhangjianceA=millis();//每3秒还原一次

  76. if(guzhangjiancejsq<21){//3秒累计频率小于21,则说明流量小于1L/min,这个时候认定为停水了
  77. digitalWrite(diancifa, HIGH);//关闭电磁阀
  78. delay(30000);//保持电池阀关闭状态30秒,散热,以免无水状态,电池阀长期工作
  79. }

  80. guzhangjiancejsq=0;//累计频率置0

  81. }

  82. }

  83. void jiaohuaC(){
  84.   
  85.   upok=digitalRead(shedingjiaoguanliangup);    //读取up按钮数值
  86.   downok=digitalRead(shedingjiaoguanliangdown);  //读取down按钮数值

  87.   if(!anjianzuse&&upok==HIGH){    //对设定流量进行修改(anjianzuse是为了防止按住按钮产生连续按动)
  88.   shedingjiaoguanliang=shedingjiaoguanliang+tiaojieliang;
  89.   if(shedingjiaoguanliang>99)shedingjiaoguanliang=99;//最多设定浇灌99L
  90.   anjianzuse = 1;                     //把现在的状态设置成已经按下状态
  91.   }
  92.   
  93.   if(!anjianzuse&&downok==HIGH){   
  94.   shedingjiaoguanliang=shedingjiaoguanliang-tiaojieliang;
  95.   if(shedingjiaoguanliang<0)shedingjiaoguanliang=0;//最少设定浇灌0L
  96.   anjianzuse = 1;
  97.   }

  98.   if(upok==LOW && downok==LOW){        //如果都是低相当于没有按钮按下
  99.     anjianzuse=0;                      //置anjianzuse为假
  100.   }

  101. }

  102. void lcd1602out(){

  103. //清空第一排的所有内容
  104.   lcd.setCursor(0, 0);
  105.   for(int col=0;col<16;col++){
  106.   lcd.write(1);
  107.   }

  108.   lcd.setCursor(0, 0);//回归第一排,第一点
  109.   for(int col=0;col<27;col++)temp3[col]=0;//清空1602打印数组,备用


  110. x=shishiliuliang*0.1; //实时流量的十位
  111. if(x==0) temp3[0]=32;
  112. else temp3[0]=x+48, DEC;

  113. x=shishiliuliang;
  114. x=x%10; //实时流量的个位
  115. temp3[1]=x+48, DEC;

  116. temp3[2]='.';//小数点

  117. x=(shishiliuliang*10); //实时流量的十分位
  118. x=x%10;
  119. temp3[3]=x+48, DEC;

  120. temp3[4]='L';
  121. temp3[5]='/';
  122. temp3[6]='m';
  123. temp3[7]='i';
  124. temp3[8]='n';
  125. temp3[9]=32;

  126. temp3[10]='S';
  127. temp3[11]='D';
  128. temp3[12]=':';

  129.   x=shedingjiaoguanliang*0.1; //设定浇灌量的十位
  130. if(x==0) temp3[13]=32;
  131. else temp3[13]=x+48, DEC;

  132. x=shedingjiaoguanliang%10; //设定浇灌量的个位
  133. temp3[14]=x+48, DEC;


  134. temp3[15]='L';

  135.    lcd.print(temp3);


  136.   //清空第2排的所有内容
  137.   lcd.setCursor(0, 1);
  138.   for(int col=0;col<16;col++){
  139.   lcd.write(1);
  140.   }

  141.   lcd.setCursor(0, 1);//回归第2排,第一点

  142.   for(int col=0;col<27;col++)temp3[col]=0;//清空1602打印数组,备用


  143. temp3[0]='T';
  144. temp3[1]='o';
  145. temp3[2]='t';
  146. temp3[3]='a';
  147.   temp3[4]='l';
  148. temp3[5]=':';

  149.   x=leijiliuliang*0.1; //累计流量的十位
  150. if(x==0) temp3[6]=32;
  151. else temp3[6]=x+48, DEC;

  152. x=leijiliuliang; //累计流量的个位
  153. x=x%10; //累计流量的个位
  154. temp3[7]=x+48, DEC;

  155. temp3[8]='.';

  156. x=leijiliuliang*10; //累计流量的十分位
  157.   x=x%10; //累计流量的十分位
  158. temp3[9]=x+48, DEC;


  159. x=leijiliuliang*100; //累计流量的百分位
  160.    x=x%10;
  161. temp3[10]=x+48, DEC;

  162. temp3[11]=32;
  163. temp3[12]='L';
  164.   
  165.    lcd.print(temp3);


  166.   }




复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-31 20:57:04 | 显示全部楼层



  1. /*
  2. 此程序最大特点为依赖gps的信号周期,已信号周期的发送完毕作为是否执行后续程序的唯一标准
  3. 换言之,就是离了gps这程序就不会动了,显然这不够科学,需要改进

  4. 2014-08-27 针对SRIF2, SRIF3 时间上的差异(2是秒百分位、3是千分位)导致纬度取不全,进行兼容性修正

  5. 剩余问题:在可用卫星数的表示上,SRIF3 为恒定2位,不足则补0,SRIF2 则只显示了一位,这个暂不修改

  6. 2014-08-31
  7. 关于浇花部分,对Pin 16 Pin 17进行了复用,而模式切换按键Pin 14 同时也复用做了浇花的停止按钮

  8. 主要问题在于故障检测子程序,jiaohuaB,遇到故障时用的是delay() 延迟30秒,这丫毫无疑问是死机的样子,根本无法操作

  9. 后续要改进

  10. */
  11. #include <MemoryFree.h>//剩余内存查询
  12. //////////////////////////////////////////////////////////////////////////////////////////////
  13. //GPS
  14. //////////////////////////////////////////////////////////////////////////////////////////////

  15. #include <SoftwareSerial.h>
  16. SoftwareSerial gps(8, 9); // RX, TX
  17. char temp1[450];//临时数组1,放gps数据的
  18. char temp2[135]="Time:2000/00/00 00:00:00#/latitude:00 00.0000 N#/longitude:000 00.0000 E#/weixingshu:00#/altitude: 000.0 M#/gp2y1010:0000 mV 77% 24C";
  19. char temp3[27];//1602显示(特定一行)输出的类容(因为 u8g.print没有换行符,所以用一个小的临时数组来搞定问题)
  20. //temp4为地面速率 + 地面航向
  21. char temp4[34]="speed:999.90 Knot#/course:359.90";
  22. char temp5[10];//接受蓝牙命令(没蓝牙的情况下,就通过串口助手直接发送命令)

  23. unsigned long x;//超级泛用酱油帝,X,主要就是1602显示时作为中间暂存值来用

  24. String jianyan="";//GPS数据包的ASCII异或校验
  25. int jsq1,jsq2,jsq3;//jsq3记录的是GPRMC中9第个逗号的前一个位置
  26. int jsq4,jsq5;//jsq4记录的是GPRMC中8第个逗号的前2个位置,jsq5记录的是GPRMC中7第个逗号的前2个位置,找出“地面速率”和“航向”
  27. int jsq6=0;//1602进行循环显示[暂时与蓝牙沟通]
  28. int jsq7=0;//gp2y1010利用gps每秒一次的数据做循环
  29. boolean jsq8=1;//这个布尔量决定蓝牙输出的gps nema-1803信息(作为蓝牙gps模块使用),还是输出检测信息(作为检测模块)
  30. int number1A,number2A,number3A,number4A;//$号的位置
  31. int number1B,number2B,number3B,number4B;//*号的位置
  32. int number5A,number6A,number7A,number8A;//$号的位置
  33. int number5B,number6B,number7B,number8B;//*号的位置
  34. int number9A,number10A,number11A,number12A;//$号的位置
  35. int number9B,number10B,number11B,number12B;//*号的位置
  36. int wanzhengdezushu;//完整的$-*组数
  37. int zifuweizhiA,zifuweizhiB;//字符位置,异或运算的时候用,A是$号的位置,B是*号的位置
  38. //布尔量0-24,最多表示12组完整的$--*字符串的存在
  39. boolean change0,change1,change2,change3,change4,change5,change6,change7,change8;
  40. boolean change9,change10,change11,change12,change13,change14,change15,change16,change17,change18;
  41. boolean change19,change20,change21,change22,change23,change24;
  42. boolean jiaoyanjieguo=0;//校验结果
  43. int yihuoyunsuan;//异或运算——校验结果
  44. int altitudeA,altitudeB;//海拔前逗号、海拔后逗号
  45. boolean altitudeC;
  46. boolean dingweiok;
  47. int weidubiaoji,jingdubiaoji;//经度标记、纬度标记
  48. //UTC +8(北京时间)时、分、秒、年、月、日
  49. int utc8s,utc8f,utc8m,utc8n,utc8y,utc8r;
  50. //小月的数组
  51. int xiaoyue[5]={4,6,9,11};
  52. //日进位,月进位,年进位,大小月判断值
  53. boolean rijinwei,yuejinwei,nianjinwei,xiaoyueok;
  54. unsigned long gpstimes;//gps计时器,如果超过一定时间10ms,则证明gps数据已经发送完毕
  55. //unsigned long quanjujishu;//全局计数,计算1秒之内,循环了多少次,这个次数在一定程度上表示了剩余性能
  56. boolean konghangpanduan;//空行判断,因为在读取串口数据后并没有延迟,完全依赖全局循环,那么,特定程序是否执行,就全靠布尔量来标记了
  57. //////////////////////////////////////////////////////////////////////////////////////////////
  58. //1602
  59. //////////////////////////////////////////////////////////////////////////////////////////////

  60. #include <LiquidCrystal.h>

  61. // initialize the library with the numbers of the interface pins
  62. LiquidCrystal lcd(2, 3, 4, 5, 6, 7);

  63. byte quan0[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  64. //////////////////////////////////////////////////////////////////////////////////////////////
  65. //DS18B20 温度
  66. //////////////////////////////////////////////////////////////////////////////////////////////
  67. #include <OneWire.h>
  68. #include <DallasTemperature.h>
  69. OneWire oneWire(10);// 数字接口10
  70. DallasTemperature sensors(&oneWire);
  71. //////////////////////////////////////////////////////////////////////////////////////////////
  72. //DHT11 湿度
  73. //////////////////////////////////////////////////////////////////////////////////////////////
  74. #include <dht11.h>
  75. dht11 DHT11;
  76. #define DHT11PIN 11 //DHT11 PIN 11
  77. //////////////////////////////////////////////////////////////////////////////////////////////
  78. //ds1307
  79. //////////////////////////////////////////////////////////////////////////////////////////////
  80. #include <Wire.h>
  81. #include <RTClib.h>
  82. void printDateTime(DateTime dateTime);
  83. RTC_DS1307 RTC;//创建实例
  84. int nian,yue,ri,shi,fen,miao;
  85. boolean shoushiqidong;//布尔量,授时启动
  86. //////////////////////////////////////////////////////////////////////////////////////////////
  87. //MQ-2
  88. //////////////////////////////////////////////////////////////////////////////////////////////
  89. int MQ2Pin=1;//A1——粉尘电压
  90. int dustVal=0;

  91. //////////////////////////////////////////////////////////////////////////////////////////////
  92. //浇花的一些定义
  93. //////////////////////////////////////////////////////////////////////////////////////////////
  94. int liuliangji=12;
  95. int diancifa=13;
  96. unsigned long meimiaoyilunhui=millis();//每秒一轮回

  97. boolean chongfupanduanA=0;//重复判定A

  98. int jsqLLx=0;
  99. float shishiliuliang=0;//实时流量
  100. float leijiliuliang=0;//累计流量
  101. int shedingjiaoguanliang=0;//设定浇灌量

  102. unsigned long guzhangjianceA=millis();//故障检测
  103. int guzhangjiancejsq;//故障检测计数器
  104. int tiaojieliang=5;//每次增减的 调节量 5L



  105. //////////////////////////////////////////////////////////////////////////////////////////////
  106. //切换GPS(浇花模式),以及切换GPS显示画面(浇花设定流量)
  107. //////////////////////////////////////////////////////////////////////////////////////////////
  108. boolean anjianzuseA=0;
  109. boolean anjianzuseB=0;
  110. unsigned long time1=millis();
  111. unsigned long time2=millis();

  112. unsigned long timeX=millis();//timeX实际记录的是luanqizaoba()所用的时间,大概300ms,总体上gps 450ms ,空闲250ms
  113. //////////////////////////////////////////////////////////////////////////////////////////////
  114. /*-------------------------------------------------------------------------------------------*/
  115. //////////////////////////////////////////////////////////////////////////////////////////////
  116. void setup() {
  117.   Serial.begin(9600);
  118.   gps.begin(9600);
  119.   //1602
  120.   lcd.createChar(1, quan0); //全0
  121.   lcd.begin(16, 2);

  122.   pinMode(14,INPUT);//切换浇花与其他模式的控制角
  123.   pinMode(16,INPUT); //切换jsq6++,注意复用
  124.   pinMode(17,INPUT); //切换jsq6--,注意复用
  125.   
  126.   pinMode(liuliangji,INPUT); //流量计接12
  127.   pinMode(diancifa, OUTPUT); //电磁阀接13
  128.   digitalWrite(diancifa, HIGH); //控制继电器关(开)电磁阀,这个主要是由继电器的有效电频决定,电磁阀接继电器常开(本例中继电器LOW有效)

  129.   //DS1307
  130.   Wire.begin(); //初始化总线
  131.   RTC.begin(); //初始化实时时钟

  132.   //对temp2进行处理,把“#/”替换成 换行+回车
  133.   for(int col=2;col<135;col++){

  134.   if(temp2[col-1]=='#' && temp2[col]=='/'){
  135.   temp2[col-1]=10;
  136.   temp2[col]=13;
  137. }
  138. }
  139. //对temp4进行处理,把“#/”替换成 换行+回车
  140.   for(int col=2;col<34;col++){
  141.   if(temp4[col-1]=='#' && temp4[col]=='/'){
  142.   temp4[col-1]=10;
  143.   temp4[col]=13;
  144. }
  145. }
  146. }

  147. void loop() {

  148. if(jsq8){

  149. //无条件接受串口的字符,全都给临时数组temp1
  150. while (gps.available() > 0) {
  151. gpstimes=millis();//重置gpstimes为millis()
  152. konghangpanduan=0;//因为串口有数据,所以空行判断为0,即不空行
  153. temp1[jsq1] = gps.read();//软串口读取GPS数据,并保存在临时数组temp1中
  154. if(jsq6<3)Serial.write(temp1[jsq1]);//用硬件串口,把收到的GPS数据同步转发出去

  155. //做一个保险,保证数组不会溢出,同时也限制了最大字符串的长度(450)
  156. if(jsq1<449) jsq1++;
  157. else jsq1=449;
  158. }


  159. //如果连续10ms串口都没有收到新的数据,则说明一个周期内(1秒)的GPS数据发送已完毕
  160. //这个空行一个周期只做一次,所以同时加入布尔量konghangpanduan的判断
  161. if(millis()-gpstimes>10 && !konghangpanduan){
  162. timeX=millis();
  163. //此处millis()-gpstimes延迟550ms可过,证明数据转发后,余下的时间大于550ms
  164. konghangpanduan=1;
  165. Serial.println();
  166. Serial.println();
  167. //////////////////////////////////////////////////////////////
  168. //luanqizaoba系列其实就是主程序
  169. /////////////////////////////////////////////////////////////
  170. luanqizaobaA();//部分定义、赋值,目的是计算出究竟有多少组完整的$----*0C
  171. luanqizaobaB();//DS1307时间的取得,以及通过GPS对DS1307校时
  172. luanqizaobaC();//这玩意实际上是主程序
  173. jsq1=0;
  174. ///////////////////////////////////////////////1602输出部分
  175. lcd1602out();
  176. /////////////////////////////////////////////
  177. timeX=millis()-timeX;
  178. Serial.print("timeX=");
  179. Serial.println(timeX);
  180. }

  181. }else{

  182. //浇花主程序///////////////////////////////////////////////////////////

  183. jiaohuaA();//每秒频率测定,实时流量计算,累计流量叠加,1602显示

  184. jiaohuaB();//通过3秒的频率次数的累加,来判断是否停水了(防止电池阀在没水的时候长期运行)


  185. if(leijiliuliang < shedingjiaoguanliang) { //流量控制,流量超了就关了
  186. digitalWrite(diancifa, LOW);//累计流量小于设定流量,打开电磁阀

  187. }else{
  188. digitalWrite(diancifa, HIGH);//关闭电磁阀
  189. shedingjiaoguanliang=0;//清空设定浇灌量
  190. leijiliuliang=0;//清空累计流量

  191. }

  192. /*-------------------------end------------------------------*/

  193. }


  194. while (Serial.available() > 0) {

  195. temp5[0] = Serial.read();
  196. delayMicroseconds(1150);

  197. //做一个保险,保证数组不会溢出,同时也限制了最大字符串的长度(10)
  198. //if(jsq2<10) jsq2++;
  199. //else jsq2=10;
  200. if(temp5[0]=='A')jsq6++;
  201. if(temp5[0]=='B'){
  202. if(jsq6>0)jsq6--;
  203. else jsq6=3;
  204. }
  205. if(temp5[0]=='G')jsq8=!jsq8;
  206. }

  207. //浇花程序的切换写在此处,主要由蓝牙的字符识别(退步)为按键的高低电平识别

  208. int qiehuandianpingA =digitalRead(14);//切换(GPS 与浇花之间)
  209. if(!anjianzuseA&&qiehuandianpingA == HIGH){ //高电平 就切换
  210. jsq8=!jsq8;
  211. anjianzuseA=!anjianzuseA;

  212. //切换模式之后,对浇花部分进行操作(即停止浇花)
  213. digitalWrite(diancifa, HIGH);//关闭电磁阀
  214. shedingjiaoguanliang=0;//清空设定浇灌量
  215. leijiliuliang=0;//清空累计流量
  216. guzhangjianceA=millis();//同时清空故障检测的时间,否则一开始就是故障状态

  217. time1=millis();
  218.    }
  219.    
  220. if(anjianzuseA && millis()-time1>1000)anjianzuseA=!anjianzuseA;//切换(GPS 与浇花之间)频率最大每秒一次


  221. //Pin16 Pin17 公用一套anjianzuseB(按键阻塞B)、时间间隔time2,以保证同一时刻只有一个键按下有效

  222. int qiehuandianpingB =digitalRead(17);//读取切换jsq6 OR 设定流量
  223. if(!anjianzuseB&&qiehuandianpingB == HIGH){ //高电平 就切换
  224. if(jsq8)jsq6++;
  225. else {
  226. shedingjiaoguanliang=shedingjiaoguanliang+tiaojieliang;
  227. if(shedingjiaoguanliang>99)shedingjiaoguanliang=99;//最多设定浇灌99L
  228. }
  229. anjianzuseB=!anjianzuseB;
  230. time2=millis();
  231.    }
  232.    

  233. int qiehuandianpingC =digitalRead(16);//读取切换jsq6 OR 设定流量
  234. if(!anjianzuseB&&qiehuandianpingC == HIGH){ //高电平 就切换
  235. if(jsq8){

  236. if(jsq6>0)jsq6--;
  237. else jsq6=3;

  238. }else {
  239. shedingjiaoguanliang=shedingjiaoguanliang-tiaojieliang;
  240. if(shedingjiaoguanliang<0)shedingjiaoguanliang=0;//最少设定浇灌0L
  241. }
  242. anjianzuseB=!anjianzuseB;
  243. time2=millis();
  244.    }
  245.    
  246. if(anjianzuseB && millis()-time2>1000)anjianzuseB=!anjianzuseB;//切换 jsq6 OR 设定流量 频率最大每秒一次




  247. }



  248. void luanqizaobaA()
  249. {
  250. //布尔量,授时启动
  251.   shoushiqidong=0;

  252.   //日进位,月进位
  253. rijinwei=0;
  254. yuejinwei=0;
  255. nianjinwei=0;

  256. //布尔量 1-24,2个一组,可以判断出12组$```*
  257. change0=1;//最开始的一个,必须置1
  258. change1=0;
  259. change2=0;
  260. change3=0;
  261. change4=0;
  262. change5=0;
  263. change6=0;
  264. change7=0;
  265. change8=0;
  266. change9=0;
  267. change10=0;
  268. change11=0;
  269. change12=0;
  270. change13=0;
  271. change14=0;
  272. change15=0;
  273. change16=0;
  274. change17=0;
  275. change18=0;
  276. change19=0;
  277. change20=0;
  278. change21=0;
  279. change22=0;
  280. change23=0;
  281. change24=0;
  282. //number 1-12,记录$号的位置,以便找出特定语句的开始
  283. number1A=0;
  284. number2A=0;
  285. number3A=0;
  286. number4A=0;
  287. number5A=0;
  288. number6A=0;
  289. number7A=0;
  290. number8A=0;
  291. number9A=0;
  292. number10A=0;
  293. number11A=0;
  294. number12A=0;
  295. //number 1-12,记录*号的位置,以便找出“校验码”,从而确定串口传输的完整性
  296. number1B=0;
  297. number2B=0;
  298. number3B=0;
  299. number4B=0;
  300. number5B=0;
  301. number6B=0;
  302. number7B=0;
  303. number8B=0;
  304. number9B=0;
  305. number10B=0;
  306. number11B=0;
  307. number12B=0;
  308. //海拔用的,起点位置,结束位置,布尔量充当开关
  309. altitudeA=0;
  310. altitudeB=0;
  311. altitudeC=0;
  312. weidubiaoji=0;//纬度标记
  313. jingdubiaoji=0;//经度标记
  314. //子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
  315. shujuchuli1();
  316. //根据不同个数的完整组,分别进行"校验码计算与对比",以确保有效性
  317. if(wanzhengdezushu>0){ //1
  318. zifuweizhiA=number1A;
  319. zifuweizhiB=number1B;
  320. shujuchuli2();
  321. shujuchuli3();
  322. }
  323. if(wanzhengdezushu>1){ //2
  324. zifuweizhiA=number2A;
  325. zifuweizhiB=number2B;
  326. shujuchuli2();
  327. shujuchuli3();
  328. }
  329. if(wanzhengdezushu>2){ //3
  330. zifuweizhiA=number3A;
  331. zifuweizhiB=number3B;
  332. shujuchuli2();
  333. shujuchuli3();
  334. }
  335. if(wanzhengdezushu>3){ //4
  336. zifuweizhiA=number4A;
  337. zifuweizhiB=number4B;
  338. shujuchuli2();
  339. shujuchuli3();
  340. }
  341. if(wanzhengdezushu>4){ //5
  342. zifuweizhiA=number5A;
  343. zifuweizhiB=number5B;
  344. shujuchuli2();
  345. shujuchuli3();
  346. }
  347. if(wanzhengdezushu>5){ //6
  348. zifuweizhiA=number6A;
  349. zifuweizhiB=number6B;
  350. shujuchuli2();
  351. shujuchuli3();
  352. }
  353. if(wanzhengdezushu>6){ //7
  354. zifuweizhiA=number7A;
  355. zifuweizhiB=number7B;
  356. shujuchuli2();
  357. shujuchuli3();
  358. }
  359. if(wanzhengdezushu>7){ //8
  360. zifuweizhiA=number8A;
  361. zifuweizhiB=number8B;
  362. shujuchuli2();
  363. shujuchuli3();
  364. }
  365. if(wanzhengdezushu>8){ //9
  366. zifuweizhiA=number9A;
  367. zifuweizhiB=number9B;
  368. shujuchuli2();
  369. shujuchuli3();
  370. }
  371. if(wanzhengdezushu>9){ //10
  372. zifuweizhiA=number10A;
  373. zifuweizhiB=number10B;
  374. shujuchuli2();
  375. shujuchuli3();
  376. }
  377. if(wanzhengdezushu>10){ //11
  378. zifuweizhiA=number11A;
  379. zifuweizhiB=number11B;
  380. shujuchuli2();
  381. shujuchuli3();
  382. }
  383. if(wanzhengdezushu>11){ //12
  384. zifuweizhiA=number12A;
  385. zifuweizhiB=number12B;
  386. shujuchuli2();
  387. shujuchuli3();
  388. }
  389. }
  390. void luanqizaobaB()
  391. {
  392.   ////////////////////////////////////////////////////////////////////////////////////////////////////////
  393. //////////////////////////////////////////时间部分

  394.   //获取当前日期和时间
  395.     DateTime now = RTC.now();
  396.       //通过串口传送当前的日期和时间
  397.       printDateTime(now);
  398. //尚缺一个部分,即授时的条件 授时启动(时间有偏差) + gps已经定位(gps时间本身可用),
  399. //////////////////////////////////////////////
  400. if(dingweiok){
  401. if(yue != utc8y) shoushiqidong=1;
  402. if(ri != utc8r) shoushiqidong=1;
  403. if(shi != utc8s) shoushiqidong=1;
  404. if(fen != utc8f) shoushiqidong=1;
  405. if(miao-utc8m>2 || utc8m-miao>2) shoushiqidong=1; //秒允许差3秒
  406. if(shoushiqidong){ //ds1307 重置时间
  407. shoushiqidong=0;
  408. //年
  409.    RTC.set(RTC_YEAR, utc8n);
  410.    //月
  411.    RTC.set(RTC_MONTH, utc8y);
  412.    //日
  413.    RTC.set(RTC_DAY, utc8r);
  414.    //时
  415.    RTC.set(RTC_HOUR, utc8s);
  416.    //分
  417. RTC.set(RTC_MINUTE, utc8f);
  418.    //秒
  419.    RTC.set(RTC_SECOND, utc8m);
  420. }
  421. }

  422. x=nian*0.1;
  423.   x=x%10;
  424.   temp2[7] = x+48, DEC;
  425.   x=nian%10;
  426.   temp2[8] = x+48, DEC;

  427.    
  428.   x=yue*0.1;
  429.   temp2[10] = x+48, DEC;
  430.   x=yue%10;
  431.   temp2[11] = x+48, DEC;


  432.     x=ri*0.1;
  433.   temp2[13] = x+48, DEC;
  434.   x=ri%10;
  435.   temp2[14] = x+48, DEC;
  436.    
  437.   x=shi*0.1;
  438.   temp2[16] = x+48, DEC;
  439.   x=shi%10;
  440.   temp2[17] = x+48, DEC;

  441.   x=fen*0.1;
  442.   temp2[19] = x+48, DEC;
  443.   x=fen%10;
  444.   temp2[20] = x+48, DEC;


  445.   x=miao*0.1;
  446.   temp2[22] = x+48, DEC;
  447.   x=miao%10;
  448.   temp2[23] = x+48, DEC;
  449. }
  450. void luanqizaobaC()
  451. {

  452. //////////////////////////////////////////// 温度、湿度部分
  453.    //DS18B20 取温度
  454.    sensors.requestTemperatures();
  455.    int wendu=sensors.getTempCByIndex(0);
  456.    //DHT11取湿度
  457.       DHT11.read(DHT11PIN);
  458.    int shidu=DHT11.humidity;

  459. x=shidu*0.1;
  460.   temp2[125] = x+48;//湿度十位
  461.   x=shidu%10;
  462.   temp2[126] = x+48;//湿度个位

  463.   x=wendu*0.1;
  464.   temp2[129] = x+48;//温度十位
  465.   x=wendu%10;
  466.   temp2[130] = x+48;//温度个位
  467. //打印整个临时数组temp2
  468. if(jsq6==3){
  469. Serial.println(temp2);
  470. Serial.println(temp4);
  471. //Serial.println(temp1);
  472.     Serial.print("freeMemory()=");
  473.     Serial.println(freeMemory());
  474. }

  475.    

  476.    
  477.    
  478. //清空临时数组temp1
  479. for(int col=0;col<450;col++)temp1[col]=0;



  480. }
  481. void fenchentou()
  482. {

  483. ////////////////////////

  484. dustVal=analogRead(MQ2Pin);

  485.   x=dustVal*4.882*0.001;
  486.   if(x==0) temp2[117] = 32;//空格
  487.   else temp2[117] = x+48, DEC;//千

  488.    x=dustVal*4.882*0.01;
  489.    x=x%10;
  490.    if(x==0 && temp2[117] == 32) temp2[118] = 32;//空格 ,在空气质量极好的地反,小于100mv的情况
  491.    else temp2[118] = x+48, DEC;//百
  492.      x=dustVal*4.882*0.1;
  493.   x=x%10;
  494.   temp2[119] = x+48, DEC;//十

  495.       x=dustVal*4.882;
  496.    x=x%10;
  497.   temp2[120] = x+48, DEC;//个



  498. }
  499. //////////////////////////////////////////////////////////////////////////////////////
  500. //子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
  501. void shujuchuli1()
  502. {
  503. //这个是典型的先接受,后处理的程序,因为需要逐个检查,所以接收多少字符就要循环多少次
  504. //其主要目的是找出$、*的位置,以400个字节及手上模块(垃圾佬处买的洋垃圾破模块+自己暴力拆解)的表现,
  505. //此处最多出现四组,完整的最多2组(*后带校验码)
  506. //但完整的gps NMEA-0183应当有6+x($GPGSV有多组),正常都是9组以上数据,即使x不输出,也有6组数据
  507. //(个人观点)最有价值的是$GPGGA、$GPRMC
  508. for(int col=0;col<jsq1;col++){
  509.   //$第一次
  510. if(temp1[col]=='$' && change0){
  511. change0=0;
  512. change1=1;
  513. number1A=col; //记录第一个$号的位置
  514. }
  515. //*第一次
  516. if(temp1[col]=='*' && change1){
  517. change1=0;
  518. change2=1;
  519. number1B=col; //记录第一个*号的位置
  520. }
  521. //////////////////////////////////////////////////////
  522. //$第二次
  523.   if(temp1[col]=='$' && change2){
  524. change2=0;
  525. change3=1;
  526. number2A=col; //记录第2个$号的位置
  527. }
  528. //*第二次
  529. if(temp1[col]=='*' && change3){
  530. change3=0;
  531. change4=1;
  532. number2B=col; //记录第2个*号的位置
  533. }

  534. //////////////////////////////////////////////////////
  535. //$第三次
  536.   if(temp1[col]=='$' && change4){
  537. change4=0;
  538. change5=1;
  539.   number3A=col; //记录第3个$号的位置
  540. }
  541. //*第三次
  542. if(temp1[col]=='*' && change5){
  543. change5=0;
  544. change6=1;
  545. number3B=col; //记录第3个*号的位置
  546. }

  547. //////////////////////////////////////////////////////
  548. //$第四次
  549.   if(temp1[col]=='$' && change6){
  550. change6=0;
  551. change7=1;
  552.   number4A=col; //记录第4个$号的位置
  553. }
  554. //*第四次
  555. if(temp1[col]=='*' && change7){
  556. change7=0;
  557. change8=1;
  558. number4B=col; //记录第4个*号的位置
  559. }

  560. //////////////////////////////////////////////////////
  561. //$第5次
  562.   if(temp1[col]=='$' && change8){
  563. change8=0;
  564. change9=1;
  565.   number5A=col; //记录第5个$号的位置
  566. }
  567. //*第5次
  568. if(temp1[col]=='*' && change9){
  569. change9=0;
  570. change10=1;
  571. number5B=col; //记录第5个*号的位置
  572. }

  573.   //////////////////////////////////////////////////////
  574. //$第6次
  575.   if(temp1[col]=='$' && change10){
  576. change10=0;
  577. change11=1;
  578.   number6A=col; //记录第5个$号的位置
  579. }
  580. //*第6次
  581. if(temp1[col]=='*' && change11){
  582. change11=0;
  583. change12=1;
  584. number6B=col; //记录第6个*号的位置
  585. }

  586.   //////////////////////////////////////////////////////
  587. //$第7次
  588.   if(temp1[col]=='$' && change12){
  589. change12=0;
  590. change13=1;
  591.   number7A=col; //记录第7个$号的位置
  592. }
  593. //*第7次
  594. if(temp1[col]=='*' && change13){
  595. change13=0;
  596. change14=1;
  597. number7B=col; //记录第7个*号的位置
  598. }

  599.     //////////////////////////////////////////////////////
  600. //$第8次
  601.   if(temp1[col]=='$' && change14){
  602. change14=0;
  603. change15=1;
  604.   number8A=col; //记录第8个$号的位置
  605. }
  606. //*第8次
  607. if(temp1[col]=='*' && change15){
  608. change15=0;
  609. change16=1;
  610. number8B=col; //记录第8个*号的位置
  611. }
  612. //////////////////////////////////////////////////////
  613. //$第9次
  614.   if(temp1[col]=='$' && change16){
  615. change16=0;
  616. change17=1;
  617.   number9A=col; //记录第9个$号的位置
  618. }
  619. //*第9次
  620. if(temp1[col]=='*' && change17){
  621. change17=0;
  622. change18=1;
  623. number9B=col; //记录第8个*号的位置
  624. }
  625. //////////////////////////////////////////////////////
  626. //$第10次
  627.   if(temp1[col]=='$' && change18){
  628. change18=0;
  629. change19=1;
  630.   number10A=col; //记录第10个$号的位置
  631. }
  632. //*第10次
  633. if(temp1[col]=='*' && change19){
  634. change19=0;
  635. change20=1;
  636. number10B=col; //记录第10个*号的位置
  637. }

  638.   //////////////////////////////////////////////////////
  639. //$第11次
  640.   if(temp1[col]=='$' && change20){
  641. change20=0;
  642. change21=1;
  643.   number11A=col; //记录第11个$号的位置
  644. }
  645. //*第10次
  646. if(temp1[col]=='*' && change21){
  647. change21=0;
  648. change22=1;
  649. number11B=col; //记录第11个*号的位置
  650. }

  651.    //////////////////////////////////////////////////////
  652. //$第12次
  653.   if(temp1[col]=='$' && change22){
  654. change22=0;
  655. change23=1;
  656.   number12A=col; //记录第12个$号的位置
  657. }
  658. //*第12次
  659. if(temp1[col]=='*' && change23){
  660. change23=0;
  661. change24=1;
  662. number12B=col; //记录第12个*号的位置
  663. }


  664. }
  665. //分别找出$、*的位置后,首先就要验证数据的可靠性
  666. //计算校验码,并与所收到的校验码对比
  667. //计算完整的$-*组数
  668. //Serial.print("wanzhengde $-*geshu=");
  669. if(change24){
  670. //完整的12组$--*
  671. wanzhengdezushu=12;
  672. }else if(change23 || change22){
  673. wanzhengdezushu=11;
  674. }else if(change21 || change20){
  675. wanzhengdezushu=10;
  676. }else if(change19 || change18){
  677. wanzhengdezushu=9;
  678. }else if(change17 || change16){
  679. wanzhengdezushu=8;
  680. }else if(change15 || change14){
  681. wanzhengdezushu=7;
  682. }else if(change13 || change12){
  683. wanzhengdezushu=6;
  684. }else if(change11 || change10){
  685. wanzhengdezushu=5;
  686. }else if(change9 || change8){
  687. wanzhengdezushu=4;
  688. /////////////////////////////////////////////////////////////////
  689. }else if(change7 || change6){
  690. //change7=1是第四组仅找到$,而没有*
  691. //change6=1只找到了完整的3组$--*
  692. wanzhengdezushu=3;
  693. //Serial.println(wanzhengdezushu);
  694. }else if(change5 || change4){
  695. //change5=1是第3组仅找到$,而没有*
  696. //change4=1只找到了完整的2组$--*
  697. wanzhengdezushu=2;
  698. //Serial.println(wanzhengdezushu);
  699. }else if(change3 || change2){
  700. //change3=1是第2组仅找到$,而没有*
  701. //change2=1只找到了完整的1组$--*
  702. wanzhengdezushu=1;
  703. //Serial.println(wanzhengdezushu);
  704. }else if(change1 || change0){
  705. //change1=1是第1组仅找到$,而没有*
  706. //change0=1连第一组的$都没找到,原始状态~~~啥玩意?
  707. wanzhengdezushu=0;
  708. //Serial.println(wanzhengdezushu);
  709. }
  710. }
  711. //子程序数据处理2,进行异或运算的处理(对比校验码)
  712. void shujuchuli2(){
  713. //zifuweizhiB-zifuweizhiA-1;*号本身不参与异或运算,所以差值还要减1
  714. for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
  715. if(col==0)yihuoyunsuan=temp1[col+zifuweizhiA+1];
  716. else yihuoyunsuan=yihuoyunsuan ^ temp1[col+zifuweizhiA+1];
  717. }
  718. //因为定义int的时候,yihuoyunsuan的结果是以10进制DEC表示的,所以需转换为16进制HEX
  719. //因为GPS校验数据0位也进行了传输,所以在转换的时候有必要将情况分类讨论
  720. //(yihuoyunsuan=0)/(0<yihuoyunsuan<17)/(17<yihuoyunsuan)
  721. if(yihuoyunsuan==0){
  722. //校验数10进制为0,直接填充字符串00
  723. jianyan="00";
  724. }else if(yihuoyunsuan>15){
  725. //此时转换为16进制以后,天然有2位,很理想,不用处理
  726. jianyan = String(yihuoyunsuan,HEX);
  727. }else{
  728. //校验数10进制为1-15时,转换为16进制就只有1位数,所以需要在前面填0
  729. jianyan = "0";
  730. jianyan += String(yihuoyunsuan,HEX);
  731. }
  732. //实践中发现,jianyan中的字符是以小写方式存在,虽然Serial.println(yihuoyunsuan,HEX)会以大写方式打印出来
  733. //但直接Serial.println(jianyan)就是小写的,这是啥情况?
  734. //将其字母转换为大写,否则与GPS传输的校验码对比时大小写问题校验失败(GPS传输的校验码为大写的)
  735. jianyan.toUpperCase();
  736. ///////////////////////////////////////////显示异或校验码,方便给GPS编程,虽然还没成功过
  737. //Serial.print("jianyan=");
  738. //Serial.println(jianyan);
  739. //与GPS传输的校验码进行对比
  740. if(jianyan[0]==temp1[zifuweizhiB+1] && jianyan[1]==temp1[zifuweizhiB+2]){
  741. //一致,则说明数据是有效的,输出校验结果
  742. jiaoyanjieguo=1;
  743. }else{
  744. //不一致
  745. jiaoyanjieguo=0;
  746. }
  747. //对校验数组进行清零
  748. jianyan="";
  749. }
  750. //子程序数据处理3,有效的字符串究竟是什么?以及相应的操作
  751. void shujuchuli3(){
  752. /*
  753. 常见的GPS发送字符串如下
  754. $GPGGA,
  755. $GPGLL,
  756. $GPGSA,
  757. $GPGST,
  758. $GPGSV,
  759. $GPRMC,
  760. $GPVTG,
  761. 鉴于最后2位不同,所以用判断$+4、$+5 两个位置的字符来判断所收到的究竟是什么信息
  762. */
  763. if(jiaoyanjieguo){
  764. jiaoyanjieguo=0;//使用后则置0,以免影响后续计算
  765. if(temp1[zifuweizhiA+4]=='G' && temp1[zifuweizhiA+5]=='A'){
  766. //$GPGGA C3-470B有
  767.   for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){

  768. if(temp1[zifuweizhiA+1+col]=='N' || temp1[zifuweizhiA+1+col]=='S')weidubiaoji=col;//纬度标记(纬度半球)
  769. if(temp1[zifuweizhiA+1+col]=='E' || temp1[zifuweizhiA+1+col]=='W')jingdubiaoji=col;//经度标记(经度半球)
  770. }
  771. if(temp1[zifuweizhiA+jingdubiaoji+3]=='1' || temp1[zifuweizhiA+jingdubiaoji+3]=='2'){ //检查gps状态位
  772. //1=非差分定位,2=差分定位,这种情况下,数据是有意义的
  773. dingweiok=1;//已经定位
  774. //Serial.print("UTC time:");
  775. //for(int col=0;col<10;col++) Serial.print(temp1[zifuweizhiA+7+col]);
  776. //Serial.println();
  777. //纬度
  778. memcpy(temp2+35,temp1+zifuweizhiA-9+weidubiaoji, 2);
  779. memcpy(temp2+38,temp1+zifuweizhiA-7+weidubiaoji, 7);

  780. memcpy(temp2+46,temp1+zifuweizhiA+1+weidubiaoji, 1);
  781. //经度
  782. memcpy(temp2+59,temp1+zifuweizhiA+weidubiaoji+3, 3);
  783. memcpy(temp2+63,temp1+zifuweizhiA+weidubiaoji+6, 7);
  784. memcpy(temp2+71,temp1+zifuweizhiA+1+jingdubiaoji, 1);
  785. //可用卫星数
  786. memcpy(temp2+85,temp1+zifuweizhiA+jingdubiaoji+5, 2);


  787. //海拔计算
  788. for(int col=0;col<13;col++) {
  789. if(temp1[zifuweizhiA+jingdubiaoji+8+col]==',' && !altitudeC){
  790. altitudeA=col;
  791. altitudeC=1;
  792. col++;
  793. }

  794. if(temp1[zifuweizhiA+jingdubiaoji+8+col]==',' && altitudeC){
  795. altitudeB=col;
  796. altitudeC=0;
  797. //结束循环
  798. col=13;
  799. }
  800. }

  801. //海拔-999.9--9999.9
  802. if(altitudeB-altitudeA-1==3){
  803. temp2[98]=32;//空格
  804. temp2[99]=32;
  805. temp2[99]=32;
  806. memcpy(temp2+101,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 3);
  807. }else if(altitudeB-altitudeA-1==4){
  808. temp2[98]=32;//空格
  809. temp2[99]=32;
  810. memcpy(temp2+100,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 4);
  811. }else if(altitudeB-altitudeA-1==5){
  812. temp2[98]=32;//空格
  813. memcpy(temp2+99,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 5);
  814. }else if(altitudeB-altitudeA-1==6){
  815. memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 6);
  816. }
  817. // memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, altitudeB-altitudeA-1);
  818. }else{
  819. //剩下的就是,未定位、正在估算,这2种情况都属于数据无意义,所以对输出数组的相应部分进行填充
  820. dingweiok=0;//没有定位
  821. temp2[35]=95;//下划线,纬度
  822. temp2[36]=95;
  823. temp2[38]=95;
  824. temp2[39]=95;
  825. temp2[41]=95;
  826. temp2[42]=95;
  827. temp2[43]=95;
  828. temp2[44]=95;
  829. temp2[46]=95;
  830. //////////////////////////////经度
  831. temp2[59]=95;
  832. temp2[60]=95;
  833. temp2[61]=95;
  834. temp2[63]=95;
  835. temp2[64]=95;
  836. temp2[66]=95;
  837. temp2[67]=95;
  838. temp2[68]=95;
  839. temp2[69]=95;
  840. temp2[71]=95;
  841. //////////////////////////////卫星数、海拔
  842. temp2[85]=95;
  843. temp2[86]=95;
  844. temp2[98]=95;
  845. temp2[99]=95;
  846. temp2[100]=95;
  847. temp2[101]=95;
  848. temp2[103]=95;
  849. }
  850. }else if(temp1[zifuweizhiA+4]=='L' && temp1[zifuweizhiA+5]=='L'){
  851. //$GPGLL
  852. }else if(temp1[zifuweizhiA+4]=='S' && temp1[zifuweizhiA+5]=='A'){
  853. //$GPGSA C3-470B有
  854. }else if(temp1[zifuweizhiA+4]=='S' && temp1[zifuweizhiA+5]=='T'){
  855. //$GPGST
  856. }else if(temp1[zifuweizhiA+4]=='S' && temp1[zifuweizhiA+5]=='V'){
  857. //$GPGSV C3-470B有
  858. }else if(temp1[zifuweizhiA+4]=='M' && temp1[zifuweizhiA+5]=='C'){
  859. //$GPRMC C3-470B有
  860. ///////////////////////////////////////////////////////////////////////////////////
  861. //$GPRMC,143716.000,A,2936.49838,N,10634.13016,E,0.1,273.6,120314,2.1,W,A*13
  862. //时间部分:UTC转为UTC+8,北京时间(时:分:秒)
  863. //时:
  864. jianyan = String(temp1[zifuweizhiA+7]);//复用jianyan这个数组来节约内存
  865. jianyan += temp1[zifuweizhiA+8];
  866. utc8s=jianyan.toInt()+8;
  867. if(utc8s>23)rijinwei=1;//提示后面程序换算为北京时间的时候,日要+1天
  868. utc8s=utc8s%24;//字符串转换为整数,参与运算
  869. //分:
  870. jianyan = String(temp1[zifuweizhiA+9]);//复用jianyan这个数组来节约内存
  871. jianyan += temp1[zifuweizhiA+10];
  872. utc8f=jianyan.toInt();//字符串转换为整数,参与运算
  873. //秒:
  874. jianyan = String(temp1[zifuweizhiA+11]);//复用jianyan这个数组来节约内存
  875. jianyan += temp1[zifuweizhiA+12];
  876. utc8m=jianyan.toInt();//字符串转换为整数,参与运算
  877. ////////////////////////////////////////////////
  878. //提取UTC日期(日、月、年),这个日期位于GPRMC第9个数据中,所以定位第九个逗号的位置即可
  879. jsq2=0;
  880. jsq3=0;
  881. jsq4=0;
  882. jsq5=0;
  883.   for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
  884.   if(temp1[zifuweizhiA+1+col]==',')jsq2++;
  885. if(jsq2==9){
  886. jsq3=col;//找到9第个逗号的前一个位置,循环0开始,0的时候就已经后推了一位置
  887. col=zifuweizhiB-zifuweizhiA;//找到9个逗号就跳出循环
  888. }
  889. if(jsq2<8){
  890. jsq4=col;//找到8第个逗号的前2个位置,即“地面速率(节)”的最后一位
  891. }
  892. if(jsq2<7){
  893. jsq5=col;//找到7第个逗号的前2个位置,即“经度标记”
  894. }
  895. }
  896. //日
  897. jianyan = String(temp1[zifuweizhiA+jsq3+2]);//复用jianyan这个数组来节约内存,9第个逗号前一位后推2个位置
  898. jianyan += temp1[zifuweizhiA+jsq3+3];
  899. utc8r=jianyan.toInt();//字符串转换为整数,参与运算
  900. //月
  901. jianyan = String(temp1[zifuweizhiA+jsq3+4]);//复用jianyan这个数组来节约内存
  902. jianyan += temp1[zifuweizhiA+jsq3+5];
  903. utc8y=jianyan.toInt();//字符串转换为整数,参与运算
  904. //年
  905. jianyan = String(temp1[zifuweizhiA+jsq3+6]);//复用jianyan这个数组来节约内存
  906. jianyan += temp1[zifuweizhiA+jsq3+7];
  907. utc8n=jianyan.toInt();//字符串转换为整数,参与运算
  908. // 地面速率(000.0~999.9节、地面航向(000.0~359.9度
  909. x=jsq4-jsq5-1;
  910. //Serial.print("jsq4-jsq5=");
  911. //Serial.println(x);
  912. if(x==6){
  913. memcpy(temp4+6,temp1+zifuweizhiA+jsq5+3, 6);//地面速率部分
  914. }else if(x==5){
  915. temp4[6]=32;//空格
  916. memcpy(temp4+7,temp1+zifuweizhiA+jsq5+3, 5);//地面速率部分
  917. }else if(x==4){
  918. temp4[6]=32;//空格
  919. temp4[7]=32;//空格
  920. memcpy(temp4+8,temp1+zifuweizhiA+jsq5+3, 4);//地面速率部分
  921. }else if(x==3){
  922. temp4[6]=32;//空格
  923. temp4[7]=32;//空格
  924. temp4[8]=32;//空格
  925. memcpy(temp4+9,temp1+zifuweizhiA+jsq5+3, 3);//地面速率部分
  926. }else {//没数据的情况
  927. temp4[6]=32;//空格
  928. temp4[7]=32;//空格
  929. temp4[8]=95;//空格
  930. temp4[9]=95;//_
  931. temp4[10]=46;//.
  932. temp4[11]=95;//_
  933. }
  934. x=jsq3-jsq4-2;
  935. //Serial.print("jsq3-jsq4=");
  936. //Serial.println(x);
  937. if(x==6){
  938. memcpy(temp4+26,temp1+zifuweizhiA+jsq4+3, 6);// 地面航向部分
  939. }else if(x==5){
  940. temp4[26]=32;//空格
  941. memcpy(temp4+27,temp1+zifuweizhiA+jsq4+3, 5);//地面速率部分
  942. }else if(x==4){
  943. temp4[26]=32;//空格
  944. temp4[27]=32;//空格
  945. memcpy(temp4+28,temp1+zifuweizhiA+jsq4+3, 4);//地面速率部分
  946. }else if(x==3){
  947. temp4[26]=32;//空格
  948. temp4[27]=32;//空格
  949. temp4[28]=32;//空格
  950. memcpy(temp4+29,temp1+zifuweizhiA+jsq4+3, 3);//地面速率部分
  951. }else {//没数据的情况
  952. temp4[26]=32;//空格
  953. temp4[27]=32;//空格
  954. temp4[28]=95;//空格
  955. temp4[29]=46;//.
  956. temp4[30]=95;//_
  957. temp4[31]=95;//_
  958. }
  959. jsq2=0; //防止以后会用,先行清零
  960. jsq3=0;
  961. jsq4=0;
  962. jsq5=0;
  963. //讨论日、月、年进位(大月、小月、平年、闰年的问题)
  964. if(rijinwei){
  965. //先讨论2月的问题
  966. if(utc8y==2 && utc8r==28){
  967. if(utc8n%4==0)utc8r=29;//闰年可加一天
  968. else {
  969. utc8r=1;
  970. yuejinwei=1;
  971. }
  972. }else{
  973. //判断大小月
  974. for(int col=0;col<4;col++){
  975. if(xiaoyue[col]==utc8y)xiaoyueok=1;
  976. }
  977. if(xiaoyueok && utc8r==30){ //小月最后一天
  978. utc8r=1;
  979. yuejinwei=1;
  980. }else if(!xiaoyueok && utc8r==31){ //大月最后一天
  981. utc8r=1;
  982. yuejinwei=1;
  983. }else{
  984. utc8r++;//剩下的情况自加1就可以了
  985. }
  986. }
  987. }
  988. if(yuejinwei && utc8y==12){ //最后一月
  989. utc8y=1;
  990. nianjinwei=1;
  991. }else if(yuejinwei){
  992. utc8y++;
  993. }
  994. if(nianjinwei)utc8n++;
  995. ////////////////
  996. //////////////////////////////////////////////////////////////////////////////////
  997. }else if(temp1[zifuweizhiA+4]=='T' && temp1[zifuweizhiA+5]=='G'){
  998. //$GPVTG
  999. }
  1000. }
  1001. }
  1002. void printDateTime(DateTime dateTime) {
  1003.     //传送年份
  1004. nian=dateTime.year(), DEC;

  1005.     //传送月份
  1006.     yue=dateTime.month(), DEC;
  1007.     //传送月份中的第几天
  1008. ri=dateTime.day(), DEC;
  1009.     //传送小时
  1010. shi=dateTime.hour(), DEC;
  1011.     //传送分钟
  1012. fen=dateTime.minute(), DEC;
  1013.     //传送秒
  1014. miao=dateTime.second(), DEC;
  1015. }


  1016. void lcd1602out(){
  1017. jsq6=jsq6%4;

  1018. //清空第一排的所有内容
  1019.   lcd.setCursor(0, 0);
  1020.   for(int col=0;col<16;col++){
  1021.   lcd.write(1);
  1022.   }

  1023.   lcd.setCursor(0, 0);//回归第一排,第一点
  1024.   for(int col=0;col<27;col++)temp3[col]=0;//清空1602打印数组,备用

  1025. if(jsq8){
  1026.   //蓝牙gps模式

  1027.   if(jsq6==0){

  1028. temp3[0]='G';
  1029. temp3[1]='P';
  1030. temp3[2]='S';
  1031. temp3[3]=32;
  1032. temp3[4]='O';
  1033. temp3[5]='U';
  1034. temp3[6]='T';
  1035. temp3[7]=32;
  1036. memcpy(temp3+8,temp2+16, 8);//时间部分(00/00 00:00:00)

  1037.   }else if(jsq6==1){

  1038.   if(dingweiok){ //已定位的情况下,显示纬度

  1039. temp3[0]='G';
  1040. temp3[1]='P';
  1041. temp3[2]='S';
  1042. temp3[3]=32;
  1043. memcpy(temp3+4,temp2+35, 12);//纬度部分纯数字
  1044.   }else{
  1045.    //未定位的情况下,please wait
  1046. temp3[0]=32;
  1047. temp3[1]=32;
  1048. temp3[2]='P';
  1049. temp3[3]='l';
  1050. temp3[4]='e';
  1051. temp3[5]='a';
  1052. temp3[6]='s';
  1053. temp3[7]='e';
  1054. temp3[8]=32;
  1055. temp3[9]='w';
  1056. temp3[10]='a';
  1057. temp3[11]='i';
  1058. temp3[12]='t';

  1059.   }


  1060. }else if(jsq6==2){


  1061.    if(dingweiok){ //已定位的情况下,显示速度

  1062. memcpy(temp3,temp4, 14);//速度部分(节)

  1063.   }else{
  1064.    //未定位的情况下,please wait
  1065. temp3[0]=32;
  1066. temp3[1]=32;
  1067. temp3[2]='P';
  1068. temp3[3]='l';
  1069. temp3[4]='e';
  1070. temp3[5]='a';
  1071. temp3[6]='s';
  1072. temp3[7]='e';
  1073. temp3[8]=32;
  1074. temp3[9]='w';
  1075. temp3[10]='a';
  1076. temp3[11]='i';
  1077. temp3[12]='t';

  1078.   }

  1079. }else if(jsq6==3){


  1080.   //空气质量检测模式


  1081.    memcpy(temp3,temp2+10, 14);//时间部分(00/00 00:00:00)



  1082. jsq7++; //MQ-2的控制参数1,数秒
  1083. jsq7=jsq7%10;//10秒循环一次

  1084.   if(jsq7==1)fenchentou();//十秒一轮回

  1085. }



  1086. }else{

  1087. //浇花程序的1602第1行显示部分

  1088. x=shishiliuliang*0.1; //实时流量的十位
  1089. if(x==0) temp3[0]=32;
  1090. else temp3[0]=x+48, DEC;

  1091. x=shishiliuliang;
  1092. x=x%10; //实时流量的个位
  1093. temp3[1]=x+48, DEC;

  1094. temp3[2]='.';//小数点

  1095. x=(shishiliuliang*10); //实时流量的十分位
  1096. x=x%10;
  1097. temp3[3]=x+48, DEC;

  1098. temp3[4]='L';
  1099. temp3[5]='/';
  1100. temp3[6]='m';
  1101. temp3[7]='i';
  1102. temp3[8]='n';
  1103. temp3[9]=32;

  1104. temp3[10]='S';
  1105. temp3[11]='D';
  1106. temp3[12]=':';

  1107.   x=shedingjiaoguanliang*0.1; //设定浇灌量的十位
  1108. if(x==0) temp3[13]=32;
  1109. else temp3[13]=x+48, DEC;

  1110. x=shedingjiaoguanliang%10; //设定浇灌量的个位
  1111. temp3[14]=x+48, DEC;


  1112. temp3[15]='L';


  1113. }


  1114.    lcd.print(temp3);


  1115.   //清空第2排的所有内容
  1116.   lcd.setCursor(0, 1);
  1117.   for(int col=0;col<16;col++){
  1118.   lcd.write(1);
  1119.   }

  1120.   lcd.setCursor(0, 1);//回归第2排,第一点
  1121.   for(int col=0;col<27;col++)temp3[col]=0;//清空1602打印数组,备用



  1122.    if(jsq8){
  1123.   //蓝牙gps模式

  1124.   if(jsq6==0){

  1125.   if(dingweiok){ //已定位的情况下,显示卫星、海拔
  1126. temp3[0]='n';
  1127. temp3[1]='u';
  1128. temp3[2]='m';

  1129. memcpy(temp3+3,temp2+84, 3);//卫星数部分(num:00)
  1130. temp3[6]=32;
  1131. temp3[7]=32;
  1132. memcpy(temp3+8,temp2+98, 8);//海拔部分( 000.0 M)
  1133.   }else{
  1134.   //未定位的情况下,Search GPS ing..
  1135.     temp3[0]='S';
  1136. temp3[1]='e';
  1137. temp3[2]='a';
  1138. temp3[3]='r';
  1139. temp3[4]='c';
  1140. temp3[5]='h';
  1141. temp3[6]=32;
  1142. temp3[7]='G';
  1143.   temp3[8]='P';
  1144.   temp3[9]='S';
  1145.   temp3[10]=32;
  1146.   temp3[11]='i';
  1147.   temp3[12]='n';
  1148.   temp3[13]='g';
  1149.     temp3[14]='.';
  1150.   temp3[15]='.';

  1151.   }


  1152.   }else if(jsq6==1){

  1153.   if(dingweiok){ //已定位的情况下,显示经度

  1154. temp3[0]=32;
  1155. temp3[1]=32;
  1156. temp3[2]=32;
  1157. memcpy(temp3+3,temp2+59, 13);//经度部分纯数字

  1158.   }else{
  1159.    //未定位的情况下,Search GPS ing..

  1160.     temp3[0]='S';
  1161. temp3[1]='e';
  1162. temp3[2]='a';
  1163. temp3[3]='r';
  1164. temp3[4]='c';
  1165. temp3[5]='h';
  1166. temp3[6]=32;
  1167. temp3[7]='G';
  1168.   temp3[8]='P';
  1169.   temp3[9]='S';
  1170.   temp3[10]=32;
  1171.   temp3[11]='i';
  1172.   temp3[12]='n';
  1173.   temp3[13]='g';
  1174.     temp3[14]='.';
  1175.   temp3[15]='.';

  1176.   }


  1177. }else if(jsq6==2){


  1178.   if(dingweiok){ //已定位的情况下,显示航向

  1179. memcpy(temp3,temp4+19, 13);//航向部分

  1180.   }else{
  1181.    //未定位的情况下,Search GPS ing..

  1182.     temp3[0]='S';
  1183. temp3[1]='e';
  1184. temp3[2]='a';
  1185. temp3[3]='r';
  1186. temp3[4]='c';
  1187. temp3[5]='h';
  1188. temp3[6]=32;
  1189. temp3[7]='G';
  1190.   temp3[8]='P';
  1191.   temp3[9]='S';
  1192.   temp3[10]=32;
  1193.   temp3[11]='i';
  1194.   temp3[12]='n';
  1195.   temp3[13]='g';
  1196.     temp3[14]='.';
  1197.   temp3[15]='.';

  1198.   }

  1199. }else if(jsq6==3){

  1200. //空气质量检测模式

  1201.    memcpy(temp3,temp2+125, 7);//湿度、温度;
  1202. temp3[7]=32;
  1203. memcpy(temp3+8,temp2+117, 7);//gp2y1010

  1204.    
  1205. }



  1206. }else{

  1207.   //浇花程序的1602第2行显示部分

  1208. temp3[0]='T';
  1209. temp3[1]='o';
  1210. temp3[2]='t';
  1211. temp3[3]='a';
  1212.   temp3[4]='l';
  1213. temp3[5]=':';

  1214.   x=leijiliuliang*0.1; //累计流量的十位
  1215. if(x==0) temp3[6]=32;
  1216. else temp3[6]=x+48, DEC;

  1217. x=leijiliuliang; //累计流量的个位
  1218. x=x%10; //累计流量的个位
  1219. temp3[7]=x+48, DEC;

  1220. temp3[8]='.';

  1221. x=leijiliuliang*10; //累计流量的十分位
  1222.   x=x%10; //累计流量的十分位
  1223. temp3[9]=x+48, DEC;


  1224. x=leijiliuliang*100; //累计流量的百分位
  1225.    x=x%10;
  1226. temp3[10]=x+48, DEC;

  1227. temp3[11]=32;
  1228. temp3[12]='L';

  1229. }


  1230.    lcd.print(temp3);



  1231.   }


  1232.   
  1233. void jiaohuaA(){

  1234.   if(millis()-meimiaoyilunhui>1000) {

  1235.   meimiaoyilunhui=millis();//每一秒还原一次
  1236.   shishiliuliang=jsqLLx/7.5;//计算实时流量(公式:频率=7.5*流量(L/min))
  1237.   leijiliuliang=leijiliuliang+(shishiliuliang/60);//(每秒积分)计数累计流量

  1238.   lcd1602out();//每秒钟刷新显示类容

  1239.   guzhangjiancejsq=guzhangjiancejsq+jsqLLx;//累加频率的数量,来确定是否故障(停水了)
  1240.   jsqLLx=0;//清空每秒频率

  1241. }else{
  1242.    int liuliangjidianping =digitalRead(liuliangji);//读取流量计的电平

  1243.    if(liuliangjidianping == HIGH && !chongfupanduanA){ //高电平 且 本次没计数,就计数
  1244. jsqLLx++;
  1245.     chongfupanduanA=!chongfupanduanA;//本次已计数,则标记已计数
  1246.    }

  1247.     if(liuliangjidianping == LOW && chongfupanduanA)chongfupanduanA=!chongfupanduanA;//低电平,且 计数标记为1,则重置计数标记
  1248. }

  1249. }

  1250. void jiaohuaB(){

  1251. //停水状态的应急处理
  1252. if(millis()-guzhangjianceA>3000) {


  1253. if(guzhangjiancejsq<21){//3秒累计频率小于21,则说明流量小于1L/min,这个时候认定为停水了
  1254. digitalWrite(diancifa, HIGH);//关闭电磁阀
  1255. delay(30000);//保持电池阀关闭状态30秒,散热,以免无水状态,电池阀长期工作
  1256. }

  1257. guzhangjiancejsq=0;//累计频率置0

  1258. guzhangjianceA=millis();//每3秒还原一次

  1259. }

  1260. }



复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-9-1 10:00:51 | 显示全部楼层
hi55234 发表于 2014-8-31 20:57
/*
此程序最大特点为依赖gps的信号周期,已信号周期的发送完毕作为是否执行后续程序的唯一标准
换言 ...

这个程序的现存问题

1、GPS 方面,在GPS没有定位的情况下,jsq6==1、jsq6==2 时1602的显示是相同的内容,无法区分
2、浇花模式,当故障判断程序有效时,目前只是粗暴的进行30秒延迟,且延迟时,1602既无提示,按键也无法操作,等价于假死状态,可以说非常的不友好,需要改进


接下来的改进
关于1,这个好解决,即修改未定位时,相应的显示内容即可
关于2,这个有2种解决方式:
A:粗暴而简单的,不用延迟再判断,直接关了电池阀,然后跳出浇花模式
B:基本友好方式,关闭电池阀,1602显示让人选择,是退出程序呢,还是再试试

A这种模式也有适合的情况,即电磁阀通过软管接水龙头,这样关水就关阀,对软管相对较好
B就要对程序进行一定的调整
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-14 16:32 , Processed in 0.044102 second(s), 23 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表