极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 33135|回复: 7

很久没来,arduino都积灰了,oled屏线也断了,各种杯具,放张图+一个程序

[复制链接]
发表于 2014-8-5 11:32:26 | 显示全部楼层 |阅读模式
本帖最后由 hi55234 于 2014-8-29 11:58 编辑

1、纯手工gps提取,可以看得头昏眼花
2、坑爹的蓝牙控制,有接收没回复,发送G,GPS与空气检测相切换,发送A或B、GPS显示信息进行切换
3、最坑爹的地方,程序是以接收GPS信号为前提,不连接GPS信号的话,绝对不会工作的(程序中有这个判断)
最重要的经验,可能是手上的CP2102比较差,反正直接连GPS是木有信号的,必须先连arduino,在转发出来,才能看到gps信号,这个是啥情况(硬件处理能力不足?),各种囧~~~

大致功能:
gps经纬度、速度、海拔、年月日、授时
DHT11温度、湿度
DS1307时间
gp2y1010粉尘
SD卡没接,貌似上SD库后,内存就不够了,gp2y1010数据就没了
MQ2也没接,这可是耗电大户

PS:说耗电,这N手的C3-470B可是有80ma的电流,0.4w的功率,伤不起啊伤不起~~~




下一步:太阳能、蓄电池、自动浇花的再说吧~~~




  1. /*
  2. 2014-088-05
  3. 1、修正1398行,因为多复制了一个冒号,导致1602显示卫星数时出现2个冒号的问题“mun::”


  4. */

  5. #include <MemoryFree.h>
  6. #include <SoftwareSerial.h>

  7. char temp1[450];
  8. 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";
  9. char temp3[27];//因为 u8g.print没有换行符,所以用一个小的临时数组来搞定问题
  10. //temp4为地面速率 + 地面航向
  11. char temp4[34]="speed:999.90 Knot#/course:359.90";
  12. char temp5[10];//接受蓝牙命令
  13. int x;

  14. String jianyan="";

  15. int jsq1,jsq2,jsq3;//jsq3记录的是GPRMC中9第个逗号的前一个位置
  16. int jsq4,jsq5;//jsq4记录的是GPRMC中8第个逗号的前2个位置,jsq5记录的是GPRMC中7第个逗号的前2个位置,找出“地面速率”和“航向”
  17. int jsq6=0;//1602进行循环显示[暂时与蓝牙沟通]
  18. int jsq7=0;//gp2y1010利用gps每秒一次的数据做循环
  19. boolean jsq8=0;//这个布尔量决定蓝牙输出的gps nema-1803信息(作为蓝牙gps模块使用),还是输出检测信息(作为检测模块)


  20. int number1A,number2A,number3A,number4A;//$号的位置
  21. int number1B,number2B,number3B,number4B;//*号的位置

  22. int number5A,number6A,number7A,number8A;//$号的位置
  23. int number5B,number6B,number7B,number8B;//*号的位置

  24. int number9A,number10A,number11A,number12A;//$号的位置
  25. int number9B,number10B,number11B,number12B;//*号的位置

  26. int wanzhengdezushu;//完整的$-*组数

  27. int zifuweizhiA,zifuweizhiB;//字符位置,异或运算的时候用,A是$号的位置,B是*号的位置

  28. //布尔量0-24,最多表示12组完整的$--*字符串的存在
  29. boolean change0,change1,change2,change3,change4,change5,change6,change7,change8;
  30. boolean change9,change10,change11,change12,change13,change14,change15,change16,change17,change18;
  31. boolean change19,change20,change21,change22,change23,change24;

  32. boolean jiaoyanjieguo=0;//校验结果

  33. int yihuoyunsuan;//异或运算——校验结果

  34. int altitudeA,altitudeB;//海拔前逗号、海拔后逗号
  35. boolean altitudeC;
  36. boolean dingweiok;

  37. int weidubiaoji,jingdubiaoji;//经度标记、纬度标记


  38. //UTC +8(北京时间)时、分、秒、年、月、日
  39. int utc8s,utc8f,utc8m,utc8n,utc8y,utc8r;
  40. //小月的数组
  41. int xiaoyue[5]={4,6,9,11};
  42. //日进位,月进位,年进位,大小月判断值
  43. boolean rijinwei,yuejinwei,nianjinwei,xiaoyueok;

  44. //////////////////////////////////////////////////////////////////////////////////////////////
  45. //1602
  46. //////////////////////////////////////////////////////////////////////////////////////////////

  47. #include <LiquidCrystal.h>

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

  50. byte quan0[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
  51. byte quan1[8] = {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
  52. ////////////////////////////////////////////////////////////////////

  53. #include <dht11.h>
  54. dht11 DHT11;
  55. #define DHT11PIN 16 //DHT11 PIN  连接UNO 16(A2)


  56. //ds1307
  57. #include <Wire.h>
  58. #include <RTClib.h>
  59. void printDateTime(DateTime dateTime);
  60. RTC_DS1307 RTC;//创建实例
  61. int nian,yue,ri,shi,fen,miao;
  62. boolean shoushiqidong;//布尔量,授时启动

  63. //硬件spi
  64. #include <SPI.h>

  65. SoftwareSerial mySerial(8, 9); // RX, TX


  66. int dustPin=1;//A1——粉尘电压
  67. int ledPower=14;//pin14(A0)——粉尘控制
  68. int dustVal=0;
  69. int delayTime=280;
  70. int delayTime2=40;
  71. float offTime=9680;
  72. unsigned long dustVal2;
  73. float dustVal3;


  74. unsigned long time2=millis();



  75. void setup() {

  76. //1602
  77.    lcd.createChar(3, quan0); //全0
  78.   lcd.createChar(4, quan1);  //全1
  79.   // set up the lcd's number of columns and rows:
  80.   lcd.begin(16, 2);
  81.   
  82.   Serial.begin(9600);
  83.   mySerial.begin(9600);
  84.    
  85.   pinMode(10, OUTPUT);//硬件SPI片选SS需要输出


  86.   pinMode(ledPower,OUTPUT);//gp2y1010控制脚
  87.   
  88.   //DS1307
  89.    
  90.   Wire.begin(); //初始化总线
  91.   RTC.begin();   //初始化实时时钟
  92.   
  93.   //对temp2进行处理,把“#/”替换成  换行+回车
  94.   for(int col=2;col<135;col++){

  95. if(temp2[col-1]=='#' && temp2[col]=='/'){
  96. temp2[col-1]=10;
  97. temp2[col]=13;
  98. }


  99. }

  100. //对temp4进行处理,把“#/”替换成  换行+回车
  101.   for(int col=2;col<34;col++){

  102. if(temp4[col-1]=='#' && temp4[col]=='/'){
  103. temp4[col-1]=10;
  104. temp4[col]=13;
  105. }

  106. }


  107. }


  108. void loop(void) {



  109. time2=millis();


  110.   //布尔量,授时启动
  111.   shoushiqidong=0;

  112.   //日进位,月进位
  113. rijinwei=0;
  114. yuejinwei=0;
  115. nianjinwei=0;

  116. jsq1=0;//整体计数,是本次串口所获得的整个字节数

  117. //布尔量 1-24,2个一组,可以判断出12组$```*
  118. change0=1;//最开始的一个,必须置1

  119. change1=0;
  120. change2=0;
  121. change3=0;
  122. change4=0;
  123. change5=0;
  124. change6=0;
  125. change7=0;
  126. change8=0;
  127. change9=0;
  128. change10=0;

  129. change11=0;
  130. change12=0;
  131. change13=0;
  132. change14=0;
  133. change15=0;
  134. change16=0;
  135. change17=0;
  136. change18=0;
  137. change19=0;
  138. change20=0;

  139. change21=0;
  140. change22=0;
  141. change23=0;
  142. change24=0;

  143. //number 1-12,记录$号的位置,以便找出特定语句的开始
  144. number1A=0;
  145. number2A=0;
  146. number3A=0;
  147. number4A=0;

  148. number5A=0;
  149. number6A=0;
  150. number7A=0;
  151. number8A=0;

  152. number9A=0;
  153. number10A=0;
  154. number11A=0;
  155. number12A=0;
  156. //number 1-12,记录*号的位置,以便找出“校验码”,从而确定串口传输的完整性
  157. number1B=0;
  158. number2B=0;
  159. number3B=0;
  160. number4B=0;

  161. number5B=0;
  162. number6B=0;
  163. number7B=0;
  164. number8B=0;

  165. number9B=0;
  166. number10B=0;
  167. number11B=0;
  168. number12B=0;

  169. //海拔用的,起点位置,结束位置,布尔量充当开关
  170. altitudeA=0;
  171. altitudeB=0;
  172. altitudeC=0;

  173. weidubiaoji=0;//纬度标记
  174. jingdubiaoji=0;//经度标记


  175. //无条件接受串口的字符,全都给临时数组temp1
  176. while (Serial.available() > 0) {  

  177. temp1[jsq1] = Serial.read();
  178. if(jsq8)Serial.write(temp1[jsq1]);//同步转发数据

  179. //if(temp1[jsq1] ==10)jsq1--; //砍掉所有换行符
  180. //else if(temp1[jsq1] ==13)jsq1--; //砍掉所有回车
  181. delayMicroseconds(1150);



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


  185. }

  186. //如果接受到字符串,处理才有意义(实际上至少是$ X * 3个字符及以上才有处理的意义)
  187. if(jsq1>1){




  188. //子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
  189. shujuchuli1();

  190. //根据不同个数的完整组,分别进行"校验码计算与对比",以确保有效性

  191. if(wanzhengdezushu>0){ //1

  192. zifuweizhiA=number1A;
  193. zifuweizhiB=number1B;
  194. shujuchuli2();
  195. shujuchuli3();

  196. }

  197. if(wanzhengdezushu>1){ //2

  198. zifuweizhiA=number2A;
  199. zifuweizhiB=number2B;
  200. shujuchuli2();
  201. shujuchuli3();

  202. }

  203. if(wanzhengdezushu>2){ //3

  204. zifuweizhiA=number3A;
  205. zifuweizhiB=number3B;
  206. shujuchuli2();
  207. shujuchuli3();

  208. }

  209. if(wanzhengdezushu>3){ //4

  210. zifuweizhiA=number4A;
  211. zifuweizhiB=number4B;
  212. shujuchuli2();
  213. shujuchuli3();

  214. }

  215. if(wanzhengdezushu>4){ //5

  216. zifuweizhiA=number5A;
  217. zifuweizhiB=number5B;
  218. shujuchuli2();
  219. shujuchuli3();

  220. }

  221. if(wanzhengdezushu>5){ //6

  222. zifuweizhiA=number6A;
  223. zifuweizhiB=number6B;
  224. shujuchuli2();
  225. shujuchuli3();

  226. }


  227. if(wanzhengdezushu>6){ //7

  228. zifuweizhiA=number7A;
  229. zifuweizhiB=number7B;
  230. shujuchuli2();
  231. shujuchuli3();

  232. }

  233. if(wanzhengdezushu>7){ //8

  234. zifuweizhiA=number8A;
  235. zifuweizhiB=number8B;
  236. shujuchuli2();
  237. shujuchuli3();

  238. }

  239. if(wanzhengdezushu>8){ //9

  240. zifuweizhiA=number9A;
  241. zifuweizhiB=number9B;
  242. shujuchuli2();
  243. shujuchuli3();

  244. }

  245. if(wanzhengdezushu>9){ //10

  246. zifuweizhiA=number10A;
  247. zifuweizhiB=number10B;
  248. shujuchuli2();
  249. shujuchuli3();

  250. }

  251. if(wanzhengdezushu>10){ //11

  252. zifuweizhiA=number11A;
  253. zifuweizhiB=number11B;
  254. shujuchuli2();
  255. shujuchuli3();

  256. }

  257. if(wanzhengdezushu>11){ //12

  258. zifuweizhiA=number12A;
  259. zifuweizhiB=number12B;
  260. shujuchuli2();
  261. shujuchuli3();

  262. }



  263.   ////////////////////////////////////////////////////////////////////////////////////////////////////////
  264. //////////////////////////////////////////时间部分  



  265.   //获取当前日期和时间
  266.     DateTime now = RTC.now();
  267.       //通过串口传送当前的日期和时间      
  268.       printDateTime(now);
  269. //尚缺一个部分,即授时的条件 授时启动(时间有偏差) + gps已经定位(gps时间本身可用),

  270. //////////////////////////////////////////////

  271. if(dingweiok){

  272. if(yue != utc8y) shoushiqidong=1;       
  273. if(ri != utc8r) shoushiqidong=1;               
  274. if(shi != utc8s) shoushiqidong=1;
  275. if(fen != utc8f) shoushiqidong=1;
  276. if(miao-utc8m>2 || utc8m-miao>2) shoushiqidong=1; //秒允许差3秒

  277. if(shoushiqidong){ //ds1307 重置时间
  278. shoushiqidong=0;
  279.         //年
  280.    RTC.set(RTC_YEAR, utc8n);
  281.    //月
  282.    RTC.set(RTC_MONTH, utc8y);
  283.    //日
  284.    RTC.set(RTC_DAY, utc8r);
  285.    //时
  286.    RTC.set(RTC_HOUR, utc8s);
  287.    //分       
  288.         RTC.set(RTC_MINUTE, utc8f);
  289.    //秒       
  290.    RTC.set(RTC_SECOND, utc8m);

  291. }

  292. }

  293.   
  294. x=nian*0.1;
  295.   x=x%10;
  296.   temp2[7] = x+48, DEC;
  297.   x=nian%10;
  298.   temp2[8] = x+48, DEC;
  299.   
  300.           
  301.   x=yue*0.1;
  302.   temp2[10] = x+48, DEC;
  303.   x=yue%10;
  304.   temp2[11] = x+48, DEC;
  305.   
  306.   
  307.     x=ri*0.1;
  308.   temp2[13] = x+48, DEC;
  309.   x=ri%10;
  310.   temp2[14] = x+48, DEC;
  311.           

  312.   x=shi*0.1;
  313.   temp2[16] = x+48, DEC;
  314.   x=shi%10;
  315.   temp2[17] = x+48, DEC;

  316.   
  317.   x=fen*0.1;
  318.   temp2[19] = x+48, DEC;
  319.   x=fen%10;
  320.   temp2[20] = x+48, DEC;
  321.   
  322.   
  323.   x=miao*0.1;
  324.   temp2[22] = x+48, DEC;
  325.   x=miao%10;
  326.   temp2[23] = x+48, DEC;


  327. //////////////////////////////////////////// 温度、湿度部分

  328.    DHT11.read(DHT11PIN);
  329.    int shidu=DHT11.humidity;
  330.    int wendu=DHT11.temperature-2;

  331. x=shidu*0.1;
  332.   temp2[125] = x+48;//湿度十位
  333.   x=shidu%10;
  334.   temp2[126] = x+48;//湿度个位

  335.   
  336.   x=wendu*0.1;
  337.   temp2[129] = x+48;//温度十位
  338.   x=wendu%10;
  339.   temp2[130] = x+48;//温度个位

  340. ///////////////////////////////////////////////1602输出部分

  341. lcd1602out();


  342. /////////////////////////////////////////////





  343. //打印整个临时数组temp2
  344. if(!jsq8){
  345. Serial.println(temp2);
  346. Serial.println(temp4);
  347. //Serial.println(temp1);

  348. time2=millis()-time2;

  349. Serial.print("time2=");
  350. Serial.println(time2);

  351.     Serial.print("freeMemory()=");
  352.     Serial.println(freeMemory());

  353.         }
  354.        
  355. //做一个保险,对应millis()溢出归零后,millis()<time1,则3秒检测一次循环终止的情况


  356. if (millis() < time2){
  357. time2=millis();
  358. }


  359. }
  360.    
  361.    

  362.    
  363.    
  364. //清空临时数组temp1
  365. for(int col=0;col<450;col++)temp1[col]=0;




  366. while (mySerial.available() > 0) {  

  367. temp5[0] = mySerial.read();
  368. delayMicroseconds(1150);

  369. //做一个保险,保证数组不会溢出,同时也限制了最大字符串的长度(10)
  370. //if(jsq2<10) jsq2++;
  371. //else jsq2=10;

  372. if(temp5[0]=='A')jsq6++;
  373. if(temp5[0]=='B'){

  374. if(jsq6>0)jsq6--;
  375. else jsq6=2;

  376. }

  377. if(temp5[0]=='G')jsq8=!jsq8;

  378. }



  379.    
  380. }






  381. void fenchentou()
  382. {

  383. // ledPower is any digital pin on the arduino connected to Pin 3 on the sensor
  384. digitalWrite(ledPower,LOW); // power on the LED
  385. delayMicroseconds(delayTime);
  386. dustVal=analogRead(dustPin); // read the dust value via pin 5 on the sensor
  387. delayMicroseconds(delayTime2);
  388. digitalWrite(ledPower,HIGH); // turn the LED off
  389. delayMicroseconds(offTime);

  390. ////////////////////////


  391.   x=dustVal*4.882*0.001;
  392.   if(x==0) temp2[117] = 32;//空格
  393.   else temp2[117] = x+48, DEC;//千
  394.   
  395.    x=dustVal*4.882*0.01;
  396.    x=x%10;
  397.    if(x==0 && temp2[117] == 32) temp2[118] = 32;//空格 ,在空气质量极好的地反,小于100mv的情况
  398.    else temp2[118] = x+48, DEC;//百

  399.      x=dustVal*4.882*0.1;
  400.          x=x%10;
  401.   temp2[119] = x+48, DEC;//十
  402.   
  403.       x=dustVal*4.882;
  404.           x=x%10;
  405.   temp2[120] = x+48, DEC;//个
  406.   
  407. //dustVal2=585.9375*dustVal-4272;//=(dustVal*5/1024-0.0356)*120000;

  408. //颗粒数

  409.   if(dustVal>118)
  410. //此拟合公式有效y=0.172*x-0.0999,此时空气质量早就爆表,所以对空气质量分类毫无意义
  411. {

  412. //dustVal3=((dustVal*5/1024)*0.172-0.0999)*1000;
  413. //dustVal3=(dustVal*5/1024)*172-99.9;
  414. dustVal3=dustVal*0.83984375-99.9;

  415. }


  416. }

  417. //////////////////////////////////////////////////////////////////////////////////////
  418. //子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
  419. void shujuchuli1()
  420. {

  421. //这个是典型的先接受,后处理的程序,因为需要逐个检查,所以接收多少字符就要循环多少次
  422. //其主要目的是找出$、*的位置,以400个字节及手上模块(垃圾佬处买的洋垃圾破模块+自己暴力拆解)的表现,
  423. //此处最多出现四组,完整的最多2组(*后带校验码)
  424. //但完整的gps NMEA-0183应当有6+x($GPGSV有多组),正常都是9组以上数据,即使x不输出,也有6组数据
  425. //(个人观点)最有价值的是$GPGGA、$GPRMC

  426. for(int col=0;col<jsq1;col++){

  427.   //$第一次
  428. if(temp1[col]=='$' && change0){
  429. change0=0;
  430. change1=1;
  431. number1A=col; //记录第一个$号的位置
  432. }
  433. //*第一次
  434. if(temp1[col]=='*' && change1){
  435. change1=0;
  436. change2=1;
  437. number1B=col; //记录第一个*号的位置
  438. }

  439. //////////////////////////////////////////////////////

  440. //$第二次
  441.   if(temp1[col]=='$' && change2){
  442. change2=0;
  443. change3=1;
  444. number2A=col; //记录第2个$号的位置
  445. }
  446. //*第二次
  447. if(temp1[col]=='*' && change3){
  448. change3=0;
  449. change4=1;
  450. number2B=col; //记录第2个*号的位置
  451. }

  452. //////////////////////////////////////////////////////

  453. //$第三次
  454.   if(temp1[col]=='$' && change4){
  455. change4=0;
  456. change5=1;
  457.   number3A=col; //记录第3个$号的位置
  458. }
  459. //*第三次
  460. if(temp1[col]=='*' && change5){
  461. change5=0;
  462. change6=1;
  463. number3B=col; //记录第3个*号的位置
  464. }

  465. //////////////////////////////////////////////////////

  466. //$第四次
  467.   if(temp1[col]=='$' && change6){
  468. change6=0;
  469. change7=1;
  470.   number4A=col; //记录第4个$号的位置
  471. }
  472. //*第四次
  473. if(temp1[col]=='*' && change7){
  474. change7=0;
  475. change8=1;
  476. number4B=col; //记录第4个*号的位置
  477. }

  478. //////////////////////////////////////////////////////

  479. //$第5次
  480.   if(temp1[col]=='$' && change8){
  481. change8=0;
  482. change9=1;
  483.   number5A=col; //记录第5个$号的位置
  484. }
  485. //*第5次
  486. if(temp1[col]=='*' && change9){
  487. change9=0;
  488. change10=1;
  489. number5B=col; //记录第5个*号的位置
  490. }

  491.   //////////////////////////////////////////////////////

  492. //$第6次
  493.   if(temp1[col]=='$' && change10){
  494. change10=0;
  495. change11=1;
  496.   number6A=col; //记录第5个$号的位置
  497. }
  498. //*第6次
  499. if(temp1[col]=='*' && change11){
  500. change11=0;
  501. change12=1;
  502. number6B=col; //记录第6个*号的位置
  503. }
  504.   
  505.   //////////////////////////////////////////////////////

  506. //$第7次
  507.   if(temp1[col]=='$' && change12){
  508. change12=0;
  509. change13=1;
  510.   number7A=col; //记录第7个$号的位置
  511. }
  512. //*第7次
  513. if(temp1[col]=='*' && change13){
  514. change13=0;
  515. change14=1;
  516. number7B=col; //记录第7个*号的位置
  517. }


  518.     //////////////////////////////////////////////////////

  519. //$第8次
  520.   if(temp1[col]=='$' && change14){
  521. change14=0;
  522. change15=1;
  523.   number8A=col; //记录第8个$号的位置
  524. }
  525. //*第8次
  526. if(temp1[col]=='*' && change15){
  527. change15=0;
  528. change16=1;
  529. number8B=col; //记录第8个*号的位置
  530. }
  531. //////////////////////////////////////////////////////

  532. //$第9次
  533.   if(temp1[col]=='$' && change16){
  534. change16=0;
  535. change17=1;
  536.   number9A=col; //记录第9个$号的位置
  537. }
  538. //*第9次
  539. if(temp1[col]=='*' && change17){
  540. change17=0;
  541. change18=1;
  542. number9B=col; //记录第8个*号的位置
  543. }
  544. //////////////////////////////////////////////////////

  545. //$第10次
  546.   if(temp1[col]=='$' && change18){
  547. change18=0;
  548. change19=1;
  549.   number10A=col; //记录第10个$号的位置
  550. }
  551. //*第10次
  552. if(temp1[col]=='*' && change19){
  553. change19=0;
  554. change20=1;
  555. number10B=col; //记录第10个*号的位置
  556. }

  557.   //////////////////////////////////////////////////////

  558. //$第11次
  559.   if(temp1[col]=='$' && change20){
  560. change20=0;
  561. change21=1;
  562.   number11A=col; //记录第11个$号的位置
  563. }
  564. //*第10次
  565. if(temp1[col]=='*' && change21){
  566. change21=0;
  567. change22=1;
  568. number11B=col; //记录第11个*号的位置
  569. }

  570.    //////////////////////////////////////////////////////

  571. //$第12次
  572.   if(temp1[col]=='$' && change22){
  573. change22=0;
  574. change23=1;
  575.   number12A=col; //记录第12个$号的位置
  576. }
  577. //*第12次
  578. if(temp1[col]=='*' && change23){
  579. change23=0;
  580. change24=1;
  581. number12B=col; //记录第12个*号的位置
  582. }


  583. }


  584. //分别找出$、*的位置后,首先就要验证数据的可靠性
  585. //计算校验码,并与所收到的校验码对比

  586. //计算完整的$-*组数
  587. //Serial.print("wanzhengde $-*geshu=");


  588. if(change24){
  589. //完整的12组$--*
  590. wanzhengdezushu=12;

  591. }else if(change23 || change22){
  592. wanzhengdezushu=11;
  593. }else if(change21 || change20){
  594. wanzhengdezushu=10;
  595. }else if(change19 || change18){
  596. wanzhengdezushu=9;
  597. }else if(change17 || change16){
  598. wanzhengdezushu=8;
  599. }else if(change15 || change14){
  600. wanzhengdezushu=7;
  601. }else if(change13 || change12){
  602. wanzhengdezushu=6;
  603. }else if(change11 || change10){
  604. wanzhengdezushu=5;
  605. }else if(change9 || change8){
  606. wanzhengdezushu=4;

  607. /////////////////////////////////////////////////////////////////


  608. }else if(change7 || change6){
  609. //change7=1是第四组仅找到$,而没有*
  610. //change6=1只找到了完整的3组$--*
  611. wanzhengdezushu=3;
  612. //Serial.println(wanzhengdezushu);

  613. }else if(change5 || change4){
  614. //change5=1是第3组仅找到$,而没有*
  615. //change4=1只找到了完整的2组$--*
  616. wanzhengdezushu=2;
  617. //Serial.println(wanzhengdezushu);

  618. }else if(change3 || change2){
  619. //change3=1是第2组仅找到$,而没有*
  620. //change2=1只找到了完整的1组$--*
  621. wanzhengdezushu=1;
  622. //Serial.println(wanzhengdezushu);

  623. }else if(change1 || change0){
  624. //change1=1是第1组仅找到$,而没有*
  625. //change0=1连第一组的$都没找到,原始状态~~~啥玩意?
  626. wanzhengdezushu=0;
  627. //Serial.println(wanzhengdezushu);
  628. }



  629. }

  630. //子程序数据处理2,进行异或运算的处理(对比校验码)
  631. void shujuchuli2(){

  632. //zifuweizhiB-zifuweizhiA-1;*号本身不参与异或运算,所以差值还要减1
  633. for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
  634. if(col==0)yihuoyunsuan=temp1[col+zifuweizhiA+1];
  635. else yihuoyunsuan=yihuoyunsuan ^ temp1[col+zifuweizhiA+1];
  636. }


  637. //因为定义int的时候,yihuoyunsuan的结果是以10进制DEC表示的,所以需转换为16进制HEX
  638. //因为GPS校验数据0位也进行了传输,所以在转换的时候有必要将情况分类讨论
  639. //(yihuoyunsuan=0)/(0<yihuoyunsuan<17)/(17<yihuoyunsuan)

  640. if(yihuoyunsuan==0){
  641. //校验数10进制为0,直接填充字符串00
  642. jianyan="00";

  643. }else if(yihuoyunsuan>15){
  644. //此时转换为16进制以后,天然有2位,很理想,不用处理
  645. jianyan = String(yihuoyunsuan,HEX);

  646. }else{
  647. //校验数10进制为1-15时,转换为16进制就只有1位数,所以需要在前面填0
  648. jianyan = "0";
  649. jianyan += String(yihuoyunsuan,HEX);

  650. }

  651. //实践中发现,jianyan中的字符是以小写方式存在,虽然Serial.println(yihuoyunsuan,HEX)会以大写方式打印出来
  652. //但直接Serial.println(jianyan)就是小写的,这是啥情况?
  653. //将其字母转换为大写,否则与GPS传输的校验码对比时大小写问题校验失败(GPS传输的校验码为大写的)
  654. jianyan.toUpperCase();

  655. ///////////////////////////////////////////显示异或校验码,方便给GPS编程,虽然还没成功过
  656. //Serial.print("jianyan=");
  657. //Serial.println(jianyan);

  658. //与GPS传输的校验码进行对比
  659. if(jianyan[0]==temp1[zifuweizhiB+1] && jianyan[1]==temp1[zifuweizhiB+2]){
  660. //一致,则说明数据是有效的,输出校验结果
  661. jiaoyanjieguo=1;
  662. }else{
  663. //不一致
  664. jiaoyanjieguo=0;
  665. }

  666. //对校验数组进行清零
  667. jianyan="";


  668. }


  669. //子程序数据处理3,有效的字符串究竟是什么?以及相应的操作
  670. void shujuchuli3(){

  671. /*
  672. 常见的GPS发送字符串如下
  673. $GPGGA,
  674. $GPGLL,
  675. $GPGSA,
  676. $GPGST,
  677. $GPGSV,
  678. $GPRMC,
  679. $GPVTG,
  680. 鉴于最后2位不同,所以用判断$+4、$+5 两个位置的字符来判断所收到的究竟是什么信息
  681. */
  682. if(jiaoyanjieguo){
  683. jiaoyanjieguo=0;//使用后则置0,以免影响后续计算

  684. if(temp1[zifuweizhiA+4]=='G' && temp1[zifuweizhiA+5]=='A'){
  685. //$GPGGA

  686.   for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
  687.   
  688. if(temp1[zifuweizhiA+1+col]=='N' || temp1[zifuweizhiA+1+col]=='S')weidubiaoji=col;//纬度标记(纬度半球)
  689. if(temp1[zifuweizhiA+1+col]=='E' || temp1[zifuweizhiA+1+col]=='W')jingdubiaoji=col;//经度标记(经度半球)

  690. }  





  691. if(temp1[zifuweizhiA+jingdubiaoji+3]=='1' || temp1[zifuweizhiA+jingdubiaoji+3]=='2'){ //检查gps状态位
  692. //1=非差分定位,2=差分定位,这种情况下,数据是有意义的

  693. dingweiok=1;//已经定位

  694. //Serial.print("UTC time:");
  695. //for(int col=0;col<10;col++)  Serial.print(temp1[zifuweizhiA+7+col]);
  696. //Serial.println();


  697. //纬度
  698. memcpy(temp2+35,temp1+zifuweizhiA+18, 2);

  699. memcpy(temp2+38,temp1+zifuweizhiA+20, 7);

  700. memcpy(temp2+46,temp1+zifuweizhiA+1+weidubiaoji, 1);

  701. //经度
  702. memcpy(temp2+59,temp1+zifuweizhiA+weidubiaoji+3, 3);

  703. memcpy(temp2+63,temp1+zifuweizhiA+weidubiaoji+6, 7);
  704. memcpy(temp2+71,temp1+zifuweizhiA+1+jingdubiaoji, 1);


  705. //可用卫星数
  706. memcpy(temp2+85,temp1+zifuweizhiA+jingdubiaoji+5, 2);


  707. //海拔计算
  708. for(int col=0;col<13;col++)  {
  709. if(temp1[zifuweizhiA+jingdubiaoji+8+col]==',' && !altitudeC){
  710. altitudeA=col;
  711. altitudeC=1;
  712. col++;
  713. }

  714. if(temp1[zifuweizhiA+jingdubiaoji+8+col]==',' && altitudeC){
  715. altitudeB=col;
  716. altitudeC=0;
  717. //结束循环
  718. col=13;
  719. }

  720. }


  721. //海拔-999.9--9999.9
  722. if(altitudeB-altitudeA-1==3){
  723. temp2[98]=32;//空格
  724. temp2[99]=32;
  725. temp2[99]=32;
  726. memcpy(temp2+101,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 3);

  727. }else if(altitudeB-altitudeA-1==4){
  728. temp2[98]=32;//空格
  729. temp2[99]=32;
  730. memcpy(temp2+100,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 4);

  731. }else if(altitudeB-altitudeA-1==5){
  732. temp2[98]=32;//空格
  733. memcpy(temp2+99,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 5);

  734. }else if(altitudeB-altitudeA-1==6){
  735. memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 6);
  736. }

  737. //  memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, altitudeB-altitudeA-1);


  738. }else{


  739. //剩下的就是,未定位、正在估算,这2种情况都属于数据无意义,所以对输出数组的相应部分进行填充
  740. dingweiok=0;//没有定位

  741. temp2[35]=95;//下划线,纬度
  742. temp2[36]=95;

  743. temp2[38]=95;
  744. temp2[39]=95;

  745. temp2[41]=95;
  746. temp2[42]=95;
  747. temp2[43]=95;
  748. temp2[44]=95;

  749. temp2[46]=95;
  750. //////////////////////////////经度

  751. temp2[59]=95;
  752. temp2[60]=95;
  753. temp2[61]=95;

  754. temp2[63]=95;
  755. temp2[64]=95;

  756. temp2[66]=95;
  757. temp2[67]=95;
  758. temp2[68]=95;
  759. temp2[69]=95;

  760. temp2[71]=95;
  761. //////////////////////////////卫星数、海拔

  762. temp2[85]=95;
  763. temp2[86]=95;

  764. temp2[98]=95;
  765. temp2[99]=95;
  766. temp2[100]=95;
  767. temp2[101]=95;

  768. temp2[103]=95;



  769. }

  770. }else if(temp1[zifuweizhiA+4]=='L' && temp1[zifuweizhiA+5]=='L'){
  771. //$GPGLL

  772. }else if(temp1[zifuweizhiA+4]=='S' && temp1[zifuweizhiA+5]=='A'){
  773. //$GPGSA

  774. }else if(temp1[zifuweizhiA+4]=='S' && temp1[zifuweizhiA+5]=='T'){
  775. //$GPGST

  776. }else if(temp1[zifuweizhiA+4]=='S' && temp1[zifuweizhiA+5]=='V'){
  777. //$GPGSV

  778. }else if(temp1[zifuweizhiA+4]=='M' && temp1[zifuweizhiA+5]=='C'){
  779. //$GPRMC
  780. ///////////////////////////////////////////////////////////////////////////////////




  781. //时间部分:UTC转为UTC+8,北京时间(时:分:秒)
  782. //时:
  783. jianyan =  String(temp1[zifuweizhiA+7]);//复用jianyan这个数组来节约内存
  784. jianyan +=  temp1[zifuweizhiA+8];
  785. utc8s=jianyan.toInt()+8;
  786. if(utc8s>23)rijinwei=1;//提示后面程序换算为北京时间的时候,日要+1天
  787. utc8s=utc8s%24;//字符串转换为整数,参与运算


  788. //分:
  789. jianyan =  String(temp1[zifuweizhiA+9]);//复用jianyan这个数组来节约内存
  790. jianyan +=  temp1[zifuweizhiA+10];
  791. utc8f=jianyan.toInt();//字符串转换为整数,参与运算

  792. //秒:
  793. jianyan =  String(temp1[zifuweizhiA+11]);//复用jianyan这个数组来节约内存
  794. jianyan +=  temp1[zifuweizhiA+12];
  795. utc8m=jianyan.toInt();//字符串转换为整数,参与运算

  796. ////////////////////////////////////////////////
  797. //提取UTC日期(日、月、年),这个日期位于GPRMC第9个数据中,所以定位第九个逗号的位置即可

  798. jsq2=0;
  799. jsq3=0;
  800. jsq4=0;
  801. jsq5=0;
  802.   for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
  803.   if(temp1[zifuweizhiA+1+col]==',')jsq2++;
  804. if(jsq2==9){
  805. jsq3=col;//找到9第个逗号的前一个位置,循环0开始,0的时候就已经后推了一位置
  806. col=zifuweizhiB-zifuweizhiA;//找到9个逗号就跳出循环
  807. }

  808. if(jsq2<8){
  809. jsq4=col;//找到8第个逗号的前2个位置,即“地面速率(节)”的最后一位
  810. }

  811. if(jsq2<7){
  812. jsq5=col;//找到7第个逗号的前2个位置,即“经度标记”
  813. }

  814. }  

  815. //日
  816. jianyan =  String(temp1[zifuweizhiA+jsq3+2]);//复用jianyan这个数组来节约内存,9第个逗号前一位后推2个位置
  817. jianyan +=  temp1[zifuweizhiA+jsq3+3];
  818. utc8r=jianyan.toInt();//字符串转换为整数,参与运算

  819. //月
  820. jianyan =  String(temp1[zifuweizhiA+jsq3+4]);//复用jianyan这个数组来节约内存
  821. jianyan +=  temp1[zifuweizhiA+jsq3+5];
  822. utc8y=jianyan.toInt();//字符串转换为整数,参与运算

  823. //年
  824. jianyan =  String(temp1[zifuweizhiA+jsq3+6]);//复用jianyan这个数组来节约内存
  825. jianyan +=  temp1[zifuweizhiA+jsq3+7];
  826. utc8n=jianyan.toInt();//字符串转换为整数,参与运算


  827. // 地面速率(000.0~999.9节、地面航向(000.0~359.9度


  828. x=jsq4-jsq5-1;
  829. //Serial.print("jsq4-jsq5=");
  830. //Serial.println(x);
  831. if(x==6){
  832. memcpy(temp4+6,temp1+zifuweizhiA+jsq5+3, 6);//地面速率部分
  833. }else if(x==5){
  834. temp4[6]=32;//空格
  835. memcpy(temp4+7,temp1+zifuweizhiA+jsq5+3, 5);//地面速率部分
  836. }else if(x==4){
  837. temp4[6]=32;//空格
  838. temp4[7]=32;//空格
  839. memcpy(temp4+8,temp1+zifuweizhiA+jsq5+3, 4);//地面速率部分
  840. }else if(x==3){
  841. temp4[6]=32;//空格
  842. temp4[7]=32;//空格
  843. temp4[8]=32;//空格
  844. memcpy(temp4+9,temp1+zifuweizhiA+jsq5+3, 3);//地面速率部分
  845. }else {//没数据的情况
  846. temp4[6]=32;//空格
  847. temp4[7]=32;//空格
  848. temp4[8]=95;//空格
  849. temp4[9]=95;//_
  850. temp4[10]=46;//.
  851. temp4[11]=95;//_
  852. }



  853. x=jsq3-jsq4-2;
  854. //Serial.print("jsq3-jsq4=");
  855. //Serial.println(x);
  856. if(x==6){
  857. memcpy(temp4+26,temp1+zifuweizhiA+jsq4+3, 6);// 地面航向部分
  858. }else if(x==5){
  859. temp4[26]=32;//空格
  860. memcpy(temp4+27,temp1+zifuweizhiA+jsq4+3, 5);//地面速率部分
  861. }else if(x==4){
  862. temp4[26]=32;//空格
  863. temp4[27]=32;//空格
  864. memcpy(temp4+28,temp1+zifuweizhiA+jsq4+3, 4);//地面速率部分
  865. }else if(x==3){
  866. temp4[26]=32;//空格
  867. temp4[27]=32;//空格
  868. temp4[28]=32;//空格
  869. memcpy(temp4+29,temp1+zifuweizhiA+jsq4+3, 3);//地面速率部分
  870. }else {//没数据的情况
  871. temp4[26]=32;//空格
  872. temp4[27]=32;//空格
  873. temp4[28]=95;//空格
  874. temp4[29]=46;//.
  875. temp4[30]=95;//_
  876. temp4[31]=95;//_
  877. }



  878. jsq2=0; //防止以后会用,先行清零
  879. jsq3=0;
  880. jsq4=0;
  881. jsq5=0;

  882. //讨论日、月、年进位(大月、小月、平年、闰年的问题)
  883. if(rijinwei){

  884. //先讨论2月的问题
  885. if(utc8y==2 && utc8r==28){
  886. if(utc8n%4==0)utc8r=29;//闰年可加一天
  887. else {
  888. utc8r=1;
  889. yuejinwei=1;
  890. }

  891. }else{

  892. //判断大小月
  893. for(int col=0;col<4;col++){
  894. if(xiaoyue[col]==utc8y)xiaoyueok=1;
  895. }

  896. if(xiaoyueok && utc8r==30){ //小月最后一天
  897. utc8r=1;
  898. yuejinwei=1;
  899. }else if(!xiaoyueok && utc8r==31){ //大月最后一天
  900. utc8r=1;
  901. yuejinwei=1;
  902. }else{
  903. utc8r++;//剩下的情况自加1就可以了
  904. }
  905. }

  906. }

  907. if(yuejinwei && utc8y==12){ //最后一月
  908. utc8y=1;
  909. nianjinwei=1;
  910. }else if(yuejinwei){
  911. utc8y++;
  912. }

  913. if(nianjinwei)utc8n++;

  914. ////////////////


  915. //////////////////////////////////////////////////////////////////////////////////
  916. }else if(temp1[zifuweizhiA+4]=='T' && temp1[zifuweizhiA+5]=='G'){
  917. //$GPVTG

  918. }



  919. }

  920. }



  921. void printDateTime(DateTime dateTime) {
  922.     //传送年份
  923.         nian=dateTime.year(), DEC;
  924.        
  925.     //传送月份
  926.     yue=dateTime.month(), DEC;
  927.     //传送月份中的第几天
  928.         ri=dateTime.day(), DEC;
  929.     //传送小时
  930.         shi=dateTime.hour(), DEC;
  931.     //传送分钟
  932.         fen=dateTime.minute(), DEC;
  933.     //传送秒
  934.         miao=dateTime.second(), DEC;
  935. }



  936. void lcd1602out(){

  937. jsq6=jsq6%3;

  938. //清空第一排的所有内容  
  939.   lcd.setCursor(0, 0);
  940.   for(int col=0;col<16;col++){
  941.   lcd.write(3);
  942.   }
  943.   
  944.   lcd.setCursor(0, 0);//回归第一排,第一点
  945.   for(int col=0;col<27;col++)temp3[col]=0;//清空1602打印数组,备用
  946.   
  947. if(jsq8){
  948.   //蓝牙gps模式
  949.   
  950.   if(jsq6==0){

  951. temp3[0]='G';
  952. temp3[1]='P';
  953. temp3[2]='S';
  954. temp3[3]=32;
  955. temp3[4]='O';
  956. temp3[5]='U';
  957. temp3[6]='T';
  958. temp3[7]=32;
  959. memcpy(temp3+8,temp2+16, 8);//时间部分(00/00 00:00:00)
  960.   
  961.   }else if(jsq6==1){
  962.   
  963.   if(dingweiok){ //已定位的情况下,显示纬度
  964.   
  965. temp3[0]='G';
  966. temp3[1]='P';
  967. temp3[2]='S';
  968. temp3[3]=32;
  969. memcpy(temp3+4,temp2+35, 12);//纬度部分纯数字
  970.   }else{
  971.    //未定位的情况下,please wait
  972. temp3[0]=32;
  973. temp3[1]=32;
  974. temp3[2]='P';
  975. temp3[3]='l';
  976. temp3[4]='e';
  977. temp3[5]='a';
  978. temp3[6]='s';
  979. temp3[7]='e';
  980. temp3[8]=32;
  981. temp3[9]='w';
  982. temp3[10]='a';
  983. temp3[11]='i';
  984. temp3[12]='t';
  985.   
  986.   }
  987.   
  988.   
  989. }else if(jsq6==2){


  990.    if(dingweiok){ //已定位的情况下,显示速度
  991.   
  992. memcpy(temp3,temp4, 14);//速度部分(节)

  993.   }else{
  994.    //未定位的情况下,please wait
  995. temp3[0]=32;
  996. temp3[1]=32;
  997. temp3[2]='P';
  998. temp3[3]='l';
  999. temp3[4]='e';
  1000. temp3[5]='a';
  1001. temp3[6]='s';
  1002. temp3[7]='e';
  1003. temp3[8]=32;
  1004. temp3[9]='w';
  1005. temp3[10]='a';
  1006. temp3[11]='i';
  1007. temp3[12]='t';
  1008.   
  1009.   }

  1010. }
  1011.   

  1012.   
  1013. }else{
  1014. //空气质量检测模式

  1015.    if(jsq6<3){
  1016.    memcpy(temp3,temp2+10, 14);//时间部分(00/00 00:00:00)
  1017.    
  1018.    }

  1019. jsq7++; //gp2y1010的控制参数1,数秒
  1020. jsq7=jsq7%10;//10秒循环一次

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

  1022. }
  1023.   

  1024.    lcd.print(temp3);

  1025.   
  1026.   //清空第2排的所有内容  
  1027.   lcd.setCursor(0, 1);
  1028.   for(int col=0;col<16;col++){
  1029.   lcd.write(3);
  1030.   }
  1031.   
  1032.   lcd.setCursor(0, 1);//回归第2排,第一点
  1033.   for(int col=0;col<27;col++)temp3[col]=0;//清空1602打印数组,备用
  1034.   
  1035.   
  1036.   
  1037.    if(jsq8){
  1038.   //蓝牙gps模式
  1039.   
  1040.   if(jsq6==0){

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

  1045. memcpy(temp3+3,temp2+84, 3);//卫星数部分(num:00)
  1046. temp3[6]=32;
  1047. temp3[7]=32;
  1048. memcpy(temp3+8,temp2+98, 8);//海拔部分( 000.0 M)
  1049.   }else{
  1050.   //未定位的情况下,Search GPS ing..
  1051.     temp3[0]='S';
  1052. temp3[1]='e';
  1053. temp3[2]='a';
  1054. temp3[3]='r';
  1055. temp3[4]='c';
  1056. temp3[5]='h';
  1057. temp3[6]=32;
  1058. temp3[7]='G';
  1059.   temp3[8]='P';
  1060.   temp3[9]='S';
  1061.   temp3[10]=32;
  1062.   temp3[11]='i';
  1063.   temp3[12]='n';
  1064.   temp3[13]='g';
  1065.     temp3[14]='.';
  1066.   temp3[15]='.';
  1067.   
  1068.   }
  1069.   
  1070.   
  1071.   }else if(jsq6==1){
  1072.   
  1073.   if(dingweiok){ //已定位的情况下,显示经度
  1074.   
  1075. temp3[0]=32;
  1076. temp3[1]=32;
  1077. temp3[2]=32;
  1078. memcpy(temp3+3,temp2+59, 13);//经度部分纯数字
  1079.   
  1080.   }else{
  1081.    //未定位的情况下,Search GPS ing..
  1082.    
  1083.     temp3[0]='S';
  1084. temp3[1]='e';
  1085. temp3[2]='a';
  1086. temp3[3]='r';
  1087. temp3[4]='c';
  1088. temp3[5]='h';
  1089. temp3[6]=32;
  1090. temp3[7]='G';
  1091.   temp3[8]='P';
  1092.   temp3[9]='S';
  1093.   temp3[10]=32;
  1094.   temp3[11]='i';
  1095.   temp3[12]='n';
  1096.   temp3[13]='g';
  1097.     temp3[14]='.';
  1098.   temp3[15]='.';
  1099.   
  1100.   }
  1101.   
  1102.   
  1103. }else if(jsq6==2){


  1104.   if(dingweiok){ //已定位的情况下,显示航向
  1105.   
  1106. memcpy(temp3,temp4+19, 13);//航向部分
  1107.   
  1108.   }else{
  1109.    //未定位的情况下,Search GPS ing..
  1110.    
  1111.     temp3[0]='S';
  1112. temp3[1]='e';
  1113. temp3[2]='a';
  1114. temp3[3]='r';
  1115. temp3[4]='c';
  1116. temp3[5]='h';
  1117. temp3[6]=32;
  1118. temp3[7]='G';
  1119.   temp3[8]='P';
  1120.   temp3[9]='S';
  1121.   temp3[10]=32;
  1122.   temp3[11]='i';
  1123.   temp3[12]='n';
  1124.   temp3[13]='g';
  1125.     temp3[14]='.';
  1126.   temp3[15]='.';
  1127.   
  1128.   }

  1129. }
  1130.   

  1131.   
  1132. }else{
  1133. //空气质量检测模式

  1134.    if(jsq6<3){
  1135.    memcpy(temp3,temp2+125, 7);//湿度、温度;
  1136. temp3[7]=32;
  1137. memcpy(temp3+8,temp2+117, 7);//gp2y1010
  1138.    
  1139.    }


  1140. }
  1141.   
  1142.   
  1143.    lcd.print(temp3);
  1144.   
  1145.   
  1146.   
  1147.   }
复制代码

本帖子中包含更多资源

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

x
回复

使用道具 举报

 楼主| 发表于 2014-9-1 15:35:31 | 显示全部楼层
本帖最后由 hi55234 于 2014-9-1 15:37 编辑
  1. /*
  2. 1、修正GPS未定时,1602上显示的内容
  3. 2、修改浇花时故障检测程序的运行方式,30秒检测,没水流的话,直接跳出程序
  4. 3、赋予串口控制命令与实体按钮相同的意义

  5. PS:特别注意,这个程序用的DS18B20库是改过的,读取耗时96ms的样子,原始的750ms,9600的GPS根本无法正常运行
  6. PS2:如果没有DHT11,就把相应的程序注释掉,否则,会非常耗时,以至于影响程序的正常运行

  7. 此程序最大特点为依赖gps的信号周期,已信号周期的发送完毕作为是否执行后续程序的唯一标准
  8. 换言之,就是离了gps这程序就不会动了,显然这不够科学,需要改进(浇花的程序已经不用GPS信号了)

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

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

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

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

  17. #include <SoftwareSerial.h>
  18. SoftwareSerial gps(8, 9); // RX, TX
  19. char temp1[450];//临时数组1,放gps数据的
  20. 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";
  21. char temp3[27];//1602显示(特定一行)输出的类容(因为 u8g.print没有换行符,所以用一个小的临时数组来搞定问题)
  22. //temp4为地面速率 + 地面航向
  23. char temp4[34]="speed:999.90 Knot#/course:359.90";
  24. char temp5[10];//接受蓝牙命令(没蓝牙的情况下,就通过串口助手直接发送命令)

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

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

  62. #include <LiquidCrystal.h>

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

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

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

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

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

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



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

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

  124.   pinMode(14,INPUT);//切换浇花与其他模式的控制角
  125.   pinMode(16,INPUT); //切换jsq6++,注意复用
  126.   pinMode(17,INPUT); //切换jsq6--,注意复用

  127.   pinMode(liuliangji,INPUT); //流量计接12
  128.   pinMode(diancifa, OUTPUT); //电磁阀接13
  129.   digitalWrite(diancifa, HIGH); //控制继电器关(开)电磁阀,这个主要是由继电器的有效电频决定,电磁阀接继电器常开(本例中继电器LOW有效)

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

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

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

  148. void loop() {

  149. if(jsq8){

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

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


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

  182. }else{

  183. //浇花主程序///////////////////////////////////////////////////////////

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

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


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

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

  192. }

  193. /*-------------------------end------------------------------*/

  194. }


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

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

  198. //做一个保险,保证数组不会溢出,同时也限制了最大字符串的长度(10)
  199. //if(jsq2<10) jsq2++;
  200. //else jsq2=10;
  201. if(temp5[0]=='A'){
  202. if(jsq8)jsq6++;
  203. else {
  204. shedingjiaoguanliang=shedingjiaoguanliang+tiaojieliang;
  205. if(shedingjiaoguanliang>99)shedingjiaoguanliang=99;//最多设定浇灌99L
  206. }
  207. anjianzuseB=!anjianzuseB;
  208. time2=millis();
  209. }

  210. if(temp5[0]=='B'){

  211. if(jsq8){

  212. if(jsq6>0)jsq6--;
  213. else jsq6=3;

  214. }else {
  215. shedingjiaoguanliang=shedingjiaoguanliang-tiaojieliang;
  216. if(shedingjiaoguanliang<0)shedingjiaoguanliang=0;//最少设定浇灌0L
  217. }
  218. anjianzuseB=!anjianzuseB;
  219. time2=millis();

  220. }

  221. if(temp5[0]=='G'){

  222. jsq8=!jsq8;
  223. anjianzuseA=!anjianzuseA;
  224. //切换模式之后,对浇花部分进行操作(即停止浇花)
  225. digitalWrite(diancifa, HIGH);//关闭电磁阀
  226. shedingjiaoguanliang=0;//清空设定浇灌量
  227. leijiliuliang=0;//清空累计流量
  228. guzhangjianceA=millis();//同时清空故障检测的时间,否则一开始就是故障状态
  229. time1=millis();

  230. }
  231. }

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

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

  235. jsq8=!jsq8;
  236. anjianzuseA=!anjianzuseA;
  237. //切换模式之后,对浇花部分进行操作(即停止浇花)
  238. digitalWrite(diancifa, HIGH);//关闭电磁阀
  239. shedingjiaoguanliang=0;//清空设定浇灌量
  240. leijiliuliang=0;//清空累计流量
  241. guzhangjianceA=millis();//同时清空故障检测的时间,否则一开始就是故障状态
  242. time1=millis();

  243.    }

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


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

  246. int qiehuandianpingB =digitalRead(17);//读取切换jsq6 OR 设定流量
  247. if(!anjianzuseB&&qiehuandianpingB == HIGH){ //高电平 就切换
  248. if(jsq8)jsq6++;
  249. else {
  250. shedingjiaoguanliang=shedingjiaoguanliang+tiaojieliang;
  251. if(shedingjiaoguanliang>99)shedingjiaoguanliang=99;//最多设定浇灌99L
  252. }
  253. anjianzuseB=!anjianzuseB;
  254. time2=millis();
  255.    }


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

  259. if(jsq6>0)jsq6--;
  260. else jsq6=3;

  261. }else {
  262. shedingjiaoguanliang=shedingjiaoguanliang-tiaojieliang;
  263. if(shedingjiaoguanliang<0)shedingjiaoguanliang=0;//最少设定浇灌0L
  264. }
  265. anjianzuseB=!anjianzuseB;
  266. time2=millis();
  267.    }

  268. if(anjianzuseB && millis()-time2>1000)anjianzuseB=!anjianzuseB;//切换 jsq6 OR 设定流量 频率最大每秒一次




  269. }



  270. void luanqizaobaA()
  271. {
  272. //布尔量,授时启动
  273.   shoushiqidong=0;

  274.   //日进位,月进位
  275. rijinwei=0;
  276. yuejinwei=0;
  277. nianjinwei=0;

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

  416.   //获取当前日期和时间
  417.     DateTime now = RTC.now();
  418.       //通过串口传送当前的日期和时间
  419.       printDateTime(now);
  420. //尚缺一个部分,即授时的条件 授时启动(时间有偏差) + gps已经定位(gps时间本身可用),
  421. //////////////////////////////////////////////
  422. if(dingweiok){
  423. if(yue != utc8y) shoushiqidong=1;
  424. if(ri != utc8r) shoushiqidong=1;
  425. if(shi != utc8s) shoushiqidong=1;
  426. if(fen != utc8f) shoushiqidong=1;
  427. if(miao-utc8m>2 || utc8m-miao>2) shoushiqidong=1; //秒允许差3秒
  428. if(shoushiqidong){ //ds1307 重置时间
  429. shoushiqidong=0;
  430. //年
  431.    RTC.set(RTC_YEAR, utc8n);
  432.    //月
  433.    RTC.set(RTC_MONTH, utc8y);
  434.    //日
  435.    RTC.set(RTC_DAY, utc8r);
  436.    //时
  437.    RTC.set(RTC_HOUR, utc8s);
  438.    //分
  439. RTC.set(RTC_MINUTE, utc8f);
  440.    //秒
  441.    RTC.set(RTC_SECOND, utc8m);
  442. }
  443. }

  444. x=nian*0.1;
  445.   x=x%10;
  446.   temp2[7] = x+48, DEC;
  447.   x=nian%10;
  448.   temp2[8] = x+48, DEC;


  449.   x=yue*0.1;
  450.   temp2[10] = x+48, DEC;
  451.   x=yue%10;
  452.   temp2[11] = x+48, DEC;


  453.     x=ri*0.1;
  454.   temp2[13] = x+48, DEC;
  455.   x=ri%10;
  456.   temp2[14] = x+48, DEC;

  457.   x=shi*0.1;
  458.   temp2[16] = x+48, DEC;
  459.   x=shi%10;
  460.   temp2[17] = x+48, DEC;

  461.   x=fen*0.1;
  462.   temp2[19] = x+48, DEC;
  463.   x=fen%10;
  464.   temp2[20] = x+48, DEC;


  465.   x=miao*0.1;
  466.   temp2[22] = x+48, DEC;
  467.   x=miao%10;
  468.   temp2[23] = x+48, DEC;
  469. }
  470. void luanqizaobaC()
  471. {

  472. //////////////////////////////////////////// 温度、湿度部分
  473.    //DS18B20 取温度
  474.    sensors.requestTemperatures();
  475.    int wendu=sensors.getTempCByIndex(0);
  476.    //DHT11取湿度
  477.       DHT11.read(DHT11PIN);
  478.    int shidu=DHT11.humidity;

  479. x=shidu*0.1;
  480.   temp2[125] = x+48;//湿度十位
  481.   x=shidu%10;
  482.   temp2[126] = x+48;//湿度个位

  483.   x=wendu*0.1;
  484.   temp2[129] = x+48;//温度十位
  485.   x=wendu%10;
  486.   temp2[130] = x+48;//温度个位
  487. //打印整个临时数组temp2
  488. if(jsq6==3){
  489. Serial.println(temp2);
  490. Serial.println(temp4);
  491. //Serial.println(temp1);
  492.     Serial.print("freeMemory()=");
  493.     Serial.println(freeMemory());
  494. }





  495. //清空临时数组temp1
  496. for(int col=0;col<450;col++)temp1[col]=0;



  497. }
  498. void fenchentou()
  499. {

  500. ////////////////////////

  501. dustVal=analogRead(MQ2Pin);

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

  505.    x=dustVal*4.882*0.01;
  506.    x=x%10;
  507.    if(x==0 && temp2[117] == 32) temp2[118] = 32;//空格 ,在空气质量极好的地反,小于100mv的情况
  508.    else temp2[118] = x+48, DEC;//百
  509.      x=dustVal*4.882*0.1;
  510.   x=x%10;
  511.   temp2[119] = x+48, DEC;//十

  512.       x=dustVal*4.882;
  513.    x=x%10;
  514.   temp2[120] = x+48, DEC;//个



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

  551. //////////////////////////////////////////////////////
  552. //$第三次
  553.   if(temp1[col]=='$' && change4){
  554. change4=0;
  555. change5=1;
  556.   number3A=col; //记录第3个$号的位置
  557. }
  558. //*第三次
  559. if(temp1[col]=='*' && change5){
  560. change5=0;
  561. change6=1;
  562. number3B=col; //记录第3个*号的位置
  563. }

  564. //////////////////////////////////////////////////////
  565. //$第四次
  566.   if(temp1[col]=='$' && change6){
  567. change6=0;
  568. change7=1;
  569.   number4A=col; //记录第4个$号的位置
  570. }
  571. //*第四次
  572. if(temp1[col]=='*' && change7){
  573. change7=0;
  574. change8=1;
  575. number4B=col; //记录第4个*号的位置
  576. }

  577. //////////////////////////////////////////////////////
  578. //$第5次
  579.   if(temp1[col]=='$' && change8){
  580. change8=0;
  581. change9=1;
  582.   number5A=col; //记录第5个$号的位置
  583. }
  584. //*第5次
  585. if(temp1[col]=='*' && change9){
  586. change9=0;
  587. change10=1;
  588. number5B=col; //记录第5个*号的位置
  589. }

  590.   //////////////////////////////////////////////////////
  591. //$第6次
  592.   if(temp1[col]=='$' && change10){
  593. change10=0;
  594. change11=1;
  595.   number6A=col; //记录第5个$号的位置
  596. }
  597. //*第6次
  598. if(temp1[col]=='*' && change11){
  599. change11=0;
  600. change12=1;
  601. number6B=col; //记录第6个*号的位置
  602. }

  603.   //////////////////////////////////////////////////////
  604. //$第7次
  605.   if(temp1[col]=='$' && change12){
  606. change12=0;
  607. change13=1;
  608.   number7A=col; //记录第7个$号的位置
  609. }
  610. //*第7次
  611. if(temp1[col]=='*' && change13){
  612. change13=0;
  613. change14=1;
  614. number7B=col; //记录第7个*号的位置
  615. }

  616.     //////////////////////////////////////////////////////
  617. //$第8次
  618.   if(temp1[col]=='$' && change14){
  619. change14=0;
  620. change15=1;
  621.   number8A=col; //记录第8个$号的位置
  622. }
  623. //*第8次
  624. if(temp1[col]=='*' && change15){
  625. change15=0;
  626. change16=1;
  627. number8B=col; //记录第8个*号的位置
  628. }
  629. //////////////////////////////////////////////////////
  630. //$第9次
  631.   if(temp1[col]=='$' && change16){
  632. change16=0;
  633. change17=1;
  634.   number9A=col; //记录第9个$号的位置
  635. }
  636. //*第9次
  637. if(temp1[col]=='*' && change17){
  638. change17=0;
  639. change18=1;
  640. number9B=col; //记录第8个*号的位置
  641. }
  642. //////////////////////////////////////////////////////
  643. //$第10次
  644.   if(temp1[col]=='$' && change18){
  645. change18=0;
  646. change19=1;
  647.   number10A=col; //记录第10个$号的位置
  648. }
  649. //*第10次
  650. if(temp1[col]=='*' && change19){
  651. change19=0;
  652. change20=1;
  653. number10B=col; //记录第10个*号的位置
  654. }

  655.   //////////////////////////////////////////////////////
  656. //$第11次
  657.   if(temp1[col]=='$' && change20){
  658. change20=0;
  659. change21=1;
  660.   number11A=col; //记录第11个$号的位置
  661. }
  662. //*第10次
  663. if(temp1[col]=='*' && change21){
  664. change21=0;
  665. change22=1;
  666. number11B=col; //记录第11个*号的位置
  667. }

  668.    //////////////////////////////////////////////////////
  669. //$第12次
  670.   if(temp1[col]=='$' && change22){
  671. change22=0;
  672. change23=1;
  673.   number12A=col; //记录第12个$号的位置
  674. }
  675. //*第12次
  676. if(temp1[col]=='*' && change23){
  677. change23=0;
  678. change24=1;
  679. number12B=col; //记录第12个*号的位置
  680. }


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

  785. if(temp1[zifuweizhiA+1+col]=='N' || temp1[zifuweizhiA+1+col]=='S')weidubiaoji=col;//纬度标记(纬度半球)
  786. if(temp1[zifuweizhiA+1+col]=='E' || temp1[zifuweizhiA+1+col]=='W')jingdubiaoji=col;//经度标记(经度半球)
  787. }
  788. if(temp1[zifuweizhiA+jingdubiaoji+3]=='1' || temp1[zifuweizhiA+jingdubiaoji+3]=='2'){ //检查gps状态位
  789. //1=非差分定位,2=差分定位,这种情况下,数据是有意义的
  790. dingweiok=1;//已经定位
  791. //Serial.print("UTC time:");
  792. //for(int col=0;col<10;col++) Serial.print(temp1[zifuweizhiA+7+col]);
  793. //Serial.println();
  794. //纬度
  795. memcpy(temp2+35,temp1+zifuweizhiA-9+weidubiaoji, 2);
  796. memcpy(temp2+38,temp1+zifuweizhiA-7+weidubiaoji, 7);

  797. memcpy(temp2+46,temp1+zifuweizhiA+1+weidubiaoji, 1);
  798. //经度
  799. memcpy(temp2+59,temp1+zifuweizhiA+weidubiaoji+3, 3);
  800. memcpy(temp2+63,temp1+zifuweizhiA+weidubiaoji+6, 7);
  801. memcpy(temp2+71,temp1+zifuweizhiA+1+jingdubiaoji, 1);
  802. //可用卫星数
  803. memcpy(temp2+85,temp1+zifuweizhiA+jingdubiaoji+5, 2);


  804. //海拔计算
  805. for(int col=0;col<13;col++) {
  806. if(temp1[zifuweizhiA+jingdubiaoji+8+col]==',' && !altitudeC){
  807. altitudeA=col;
  808. altitudeC=1;
  809. col++;
  810. }

  811. if(temp1[zifuweizhiA+jingdubiaoji+8+col]==',' && altitudeC){
  812. altitudeB=col;
  813. altitudeC=0;
  814. //结束循环
  815. col=13;
  816. }
  817. }

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

  1022.     //传送月份
  1023.     yue=dateTime.month(), DEC;
  1024.     //传送月份中的第几天
  1025. ri=dateTime.day(), DEC;
  1026.     //传送小时
  1027. shi=dateTime.hour(), DEC;
  1028.     //传送分钟
  1029. fen=dateTime.minute(), DEC;
  1030.     //传送秒
  1031. miao=dateTime.second(), DEC;
  1032. }


  1033. void lcd1602out(){
  1034. jsq6=jsq6%4;

  1035. //清空第一排的所有内容
  1036.   lcd.setCursor(0, 0);
  1037.   for(int col=0;col<16;col++){
  1038.   lcd.write(1);
  1039.   }

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

  1042. if(jsq8){
  1043.   //蓝牙gps模式

  1044.   if(jsq6==0){

  1045. temp3[0]='G';
  1046. temp3[1]='P';
  1047. temp3[2]='S';
  1048. temp3[3]=32;
  1049. temp3[4]='O';
  1050. temp3[5]='U';
  1051. temp3[6]='T';
  1052. temp3[7]=32;
  1053. memcpy(temp3+8,temp2+16, 8);//时间部分(00/00 00:00:00)

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

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

  1056. temp3[0]='G';
  1057. temp3[1]='P';
  1058. temp3[2]='S';
  1059. temp3[3]=32;
  1060. memcpy(temp3+4,temp2+35, 12);//纬度部分纯数字
  1061.   }else{
  1062.    //未定位的情况下,please wait
  1063. temp3[0]=32;
  1064. temp3[1]='l';
  1065. temp3[2]='a';
  1066. temp3[3]='t';
  1067. temp3[4]='.';
  1068. temp3[5]=32;
  1069. temp3[6]='a';
  1070. temp3[7]='n';
  1071. temp3[8]='d';
  1072. temp3[9]=32;
  1073. temp3[10]='L';
  1074. temp3[11]='O';
  1075. temp3[12]='N';
  1076. temp3[13]='G';
  1077. temp3[14]='.';

  1078.   }


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


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

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

  1082.   }else{
  1083.    //未定位的情况下,please wait
  1084. temp3[0]='s';
  1085. temp3[1]='p';
  1086. temp3[2]='e';
  1087. temp3[3]='e';
  1088. temp3[4]='d';
  1089. temp3[5]='&';
  1090. temp3[6]='d';
  1091. temp3[7]='i';
  1092. temp3[8]='r';
  1093. temp3[9]='e';
  1094. temp3[10]='c';
  1095. temp3[11]='t';
  1096. temp3[12]='i';
  1097.   temp3[13]='o';
  1098. temp3[14]='n';

  1099.   }

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


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


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



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

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

  1106. }



  1107. }else{

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

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

  1112. x=shishiliuliang;
  1113. x=x%10; //实时流量的个位
  1114. temp3[1]=x+48, DEC;

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

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

  1119. temp3[4]='L';
  1120. temp3[5]='/';
  1121. temp3[6]='m';
  1122. temp3[7]='i';
  1123. temp3[8]='n';
  1124. temp3[9]=32;

  1125. temp3[10]='S';
  1126. temp3[11]='D';
  1127. temp3[12]=':';

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

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


  1133. temp3[15]='L';


  1134. }


  1135.    lcd.print(temp3);


  1136.   //清空第2排的所有内容
  1137.   lcd.setCursor(0, 1);
  1138.   for(int col=0;col<16;col++){
  1139.   lcd.write(1);
  1140.   }

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



  1143.    if(jsq8){
  1144.   //蓝牙gps模式

  1145.   if(jsq6==0){

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

  1150. memcpy(temp3+3,temp2+84, 3);//卫星数部分(num:00)
  1151. temp3[6]=32;
  1152. temp3[7]=32;
  1153. memcpy(temp3+8,temp2+98, 8);//海拔部分( 000.0 M)
  1154.   }else{
  1155.   //未定位的情况下,Search GPS ing..
  1156.     temp3[0]='S';
  1157. temp3[1]='e';
  1158. temp3[2]='a';
  1159. temp3[3]='r';
  1160. temp3[4]='c';
  1161. temp3[5]='h';
  1162. temp3[6]=32;
  1163. temp3[7]='G';
  1164.   temp3[8]='P';
  1165.   temp3[9]='S';
  1166.   temp3[10]=32;
  1167.   temp3[11]='i';
  1168.   temp3[12]='n';
  1169.   temp3[13]='g';
  1170.     temp3[14]='.';
  1171.   temp3[15]='.';

  1172.   }


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

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

  1175. temp3[0]=32;
  1176. temp3[1]=32;
  1177. temp3[2]=32;
  1178. memcpy(temp3+3,temp2+59, 13);//经度部分纯数字

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

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

  1197.   }


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


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

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

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

  1203.     temp3[0]='S';
  1204. temp3[1]='e';
  1205. temp3[2]='a';
  1206. temp3[3]='r';
  1207. temp3[4]='c';
  1208. temp3[5]='h';
  1209. temp3[6]=32;
  1210. temp3[7]='G';
  1211.   temp3[8]='P';
  1212.   temp3[9]='S';
  1213.   temp3[10]=32;
  1214.   temp3[11]='i';
  1215.   temp3[12]='n';
  1216.   temp3[13]='g';
  1217.     temp3[14]='.';
  1218.   temp3[15]='.';

  1219.   }

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

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

  1222.    memcpy(temp3,temp2+125, 7);//湿度、温度;
  1223. temp3[7]=32;
  1224. memcpy(temp3+8,temp2+117, 7);//gp2y1010


  1225. }



  1226. }else{

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

  1228. temp3[0]='T';
  1229. temp3[1]='o';
  1230. temp3[2]='t';
  1231. temp3[3]='a';
  1232.   temp3[4]='l';
  1233. temp3[5]=':';

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

  1237. x=leijiliuliang; //累计流量的个位
  1238. x=x%10; //累计流量的个位
  1239. temp3[7]=x+48, DEC;

  1240. temp3[8]='.';

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


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

  1247. temp3[11]=32;
  1248. temp3[12]='L';

  1249. }


  1250.    lcd.print(temp3);



  1251.   }


  1252. void jiaohuaA(){

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

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

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

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

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

  1262.    if(liuliangjidianping == HIGH && !chongfupanduanA){ //高电平 且 本次没计数,就计数
  1263. jsqLLx++;
  1264.     chongfupanduanA=!chongfupanduanA;//本次已计数,则标记已计数
  1265.    }

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

  1268. }

  1269. void jiaohuaB(){

  1270. //停水状态的应急处理
  1271. if(millis()-guzhangjianceA>30000) {


  1272. if(guzhangjiancejsq<210){//3秒累计频率小于21,则说明流量小于1L/min,这个时候认定为停水了

  1273.   jsq8=!jsq8;//跳出浇花模式

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

  1279. }

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



  1281. }

  1282. }
复制代码
回复 支持 1 反对 0

使用道具 举报

发表于 2014-8-6 09:10:32 | 显示全部楼层
本帖最后由 yuqingshan 于 2014-8-7 08:15 编辑

LZ的“大杂汇”程序代码有些长,不过正是想找很久的程序了,谢谢。
我的接线:

Mega2560->LCD1602
GND->RW
12->RS
11->E
5->D4
4->D5
3->D6
2->D7

Mega2560->GPS
0->RX
1->TX

Mega2560->DS1307
20(SDA)->SDA
21(SCL)->SCL

其他模块没有连。



图01-晚上接好线,显示乱码,只有“1474mV”数字变化。


图02-早上显示:全为:0000,也是只有“2548mV”数字变化。


图03-准备上班前:显示正常,没有接DH11模块,没有湿度、温度显示。


有以下问题请教:
1.没有出现LZ的GPS其他信息。如:Search GPS ing.. 以及经度、纬度等。
2.显示的北京时间慢2-3分钟,不是准确。
3.按Mega2560板上RESET键后,LCD1602屏变全黑,再没有显示了,要重新关电源,再开机才恢复。

4.运行一天后发现很多BUG啊,几分钟后不知神马就停下来了,停在某一时间,没有什么反应
5.有时就剩下分和秒在动,其他全00/00 00:00,不过3分钟后又停了。
6.有时分和秒不断重复3分钟的循环,一直到停止。
看LZ的代码非常多,很辛苦编写,不过还未能实用。但我的E文太烂了,无从下手,敬请原谅。谢谢。

本帖子中包含更多资源

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

x
回复 支持 反对

使用道具 举报

发表于 2014-8-7 22:24:44 | 显示全部楼层
这不是1602吗?不是OLED啊????!!!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-31 21:25:08 | 显示全部楼层
yuqingshan 发表于 2014-8-6 09:10
LZ的“大杂汇”程序代码有些长,不过正是想找很久的程序了,谢谢。
我的接线:

1、要授时,GPS能定位成功是前提
2、要显示经纬度,就必须切换显示信息,在这版程序中,切换是由串口所发送的字符确定的
3、如果没有接DHT11,就最好注释掉相应的程序,否则一旦运行相应的库,耗时过多,就会导致GPS的串口数据接收不完整,如果不完整程度较高,导致程序不能判断GPS的定位情况的话,那么即便GPS定位成功,也不会授时的
回复 支持 反对

使用道具 举报

 楼主| 发表于 2014-8-31 21:36:29 | 显示全部楼层









详情看这个帖子http://www.geek-workshop.com/for ... id=10775&page=1
并不是任意版本的DS18B20库都能这么改


  1. /*
  2. PS:特别注意,这个程序用的DS18B20库是改过的,读取耗时96ms的样子,原始的750ms,9600的GPS根本无法正常运行
  3. PS2:如果没有DHT11,就把相应的程序注释掉,否则,会非常耗时,以至于影响程序的正常运行

  4. 此程序最大特点为依赖gps的信号周期,已信号周期的发送完毕作为是否执行后续程序的唯一标准
  5. 换言之,就是离了gps这程序就不会动了,显然这不够科学,需要改进(浇花的程序已经不用GPS信号了)

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

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

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

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

  14. #include <SoftwareSerial.h>
  15. SoftwareSerial gps(8, 9); // RX, TX
  16. char temp1[450];//临时数组1,放gps数据的
  17. 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";
  18. char temp3[27];//1602显示(特定一行)输出的类容(因为 u8g.print没有换行符,所以用一个小的临时数组来搞定问题)
  19. //temp4为地面速率 + 地面航向
  20. char temp4[34]="speed:999.90 Knot#/course:359.90";
  21. char temp5[10];//接受蓝牙命令(没蓝牙的情况下,就通过串口助手直接发送命令)

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

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

  59. #include <LiquidCrystal.h>

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

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

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

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

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

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



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

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

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

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

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

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

  146. void loop() {

  147. if(jsq8){

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

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


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

  180. }else{

  181. //浇花主程序///////////////////////////////////////////////////////////

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

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


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

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

  190. }

  191. /*-------------------------end------------------------------*/

  192. }


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

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

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

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

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

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

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


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

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

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

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

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




  246. }



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

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

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

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

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

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


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

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


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

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

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

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

  474.    

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



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

  482. ////////////////////////

  483. dustVal=analogRead(MQ2Pin);

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

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

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



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

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

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

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

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

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

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

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

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


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

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

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


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

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

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

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


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

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

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

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

  1026.   if(jsq6==0){

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

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

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

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

  1058.   }


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


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

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

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

  1077.   }

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


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


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



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

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

  1084. }



  1085. }else{

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

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

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

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

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

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

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

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

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


  1111. temp3[15]='L';


  1112. }


  1113.    lcd.print(temp3);


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

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



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

  1123.   if(jsq6==0){

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

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

  1150.   }


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

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

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

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

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

  1175.   }


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


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

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

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

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

  1197.   }

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

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

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

  1203.    
  1204. }



  1205. }else{

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

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

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

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

  1219. temp3[8]='.';

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


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

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

  1228. }


  1229.    lcd.print(temp3);



  1230.   }


  1231.   
  1232. void jiaohuaA(){

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

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

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

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

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

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

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

  1248. }

  1249. void jiaohuaB(){

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


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

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

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

  1258. }

  1259. }



复制代码

本帖子中包含更多资源

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

x
回复 支持 反对

使用道具 举报

发表于 2015-12-8 15:26:55 | 显示全部楼层
干货,顶一个,楼主辛苦了
回复 支持 反对

使用道具 举报

发表于 2016-2-14 21:58:33 | 显示全部楼层
特来学习。
回复 支持 反对

使用道具 举报

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

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-19 17:38 , Processed in 0.055750 second(s), 23 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

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