极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

12
返回列表 发新帖
楼主: hi55234

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

[复制链接]
 楼主| 发表于 2014-9-1 15:34:40 | 显示全部楼层
本帖最后由 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. }
复制代码
回复 支持 反对

使用道具 举报

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

本版积分规则

Archiver|联系我们|极客工坊

GMT+8, 2026-6-15 06:56 , Processed in 0.102541 second(s), 16 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

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