hi55234 发表于 2014-8-5 11:32:26

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

本帖最后由 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的功率,伤不起啊伤不起~~~




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




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


*/

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

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

String jianyan="";

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


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

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

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

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

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

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

boolean jiaoyanjieguo=0;//校验结果

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

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

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


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

//////////////////////////////////////////////////////////////////////////////////////////////
//1602
//////////////////////////////////////////////////////////////////////////////////////////////

#include <LiquidCrystal.h>

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

byte quan0 = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
byte quan1 = {0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F,0x1F};
////////////////////////////////////////////////////////////////////

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


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

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

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


int dustPin=1;//A1——粉尘电压
int ledPower=14;//pin14(A0)——粉尘控制
int dustVal=0;
int delayTime=280;
int delayTime2=40;
float offTime=9680;
unsigned long dustVal2;
float dustVal3;


unsigned long time2=millis();



void setup() {

//1602
   lcd.createChar(3, quan0); //全0
lcd.createChar(4, quan1);//全1
// set up the lcd's number of columns and rows:
lcd.begin(16, 2);

Serial.begin(9600);
mySerial.begin(9600);
   
pinMode(10, OUTPUT);//硬件SPI片选SS需要输出


pinMode(ledPower,OUTPUT);//gp2y1010控制脚

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

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

if(temp2=='#' && temp2=='/'){
temp2=10;
temp2=13;
}


}

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

if(temp4=='#' && temp4=='/'){
temp4=10;
temp4=13;
}

}


}


void loop(void) {



time2=millis();


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

//日进位,月进位
rijinwei=0;
yuejinwei=0;
nianjinwei=0;

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

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

change1=0;
change2=0;
change3=0;
change4=0;
change5=0;
change6=0;
change7=0;
change8=0;
change9=0;
change10=0;

change11=0;
change12=0;
change13=0;
change14=0;
change15=0;
change16=0;
change17=0;
change18=0;
change19=0;
change20=0;

change21=0;
change22=0;
change23=0;
change24=0;

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

number5A=0;
number6A=0;
number7A=0;
number8A=0;

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

number5B=0;
number6B=0;
number7B=0;
number8B=0;

number9B=0;
number10B=0;
number11B=0;
number12B=0;

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

weidubiaoji=0;//纬度标记
jingdubiaoji=0;//经度标记


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

temp1 = Serial.read();
if(jsq8)Serial.write(temp1);//同步转发数据

//if(temp1 ==10)jsq1--; //砍掉所有换行符
//else if(temp1 ==13)jsq1--; //砍掉所有回车
delayMicroseconds(1150);



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


}

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




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

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

if(wanzhengdezushu>0){ //1

zifuweizhiA=number1A;
zifuweizhiB=number1B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>1){ //2

zifuweizhiA=number2A;
zifuweizhiB=number2B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>2){ //3

zifuweizhiA=number3A;
zifuweizhiB=number3B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>3){ //4

zifuweizhiA=number4A;
zifuweizhiB=number4B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>4){ //5

zifuweizhiA=number5A;
zifuweizhiB=number5B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>5){ //6

zifuweizhiA=number6A;
zifuweizhiB=number6B;
shujuchuli2();
shujuchuli3();

}


if(wanzhengdezushu>6){ //7

zifuweizhiA=number7A;
zifuweizhiB=number7B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>7){ //8

zifuweizhiA=number8A;
zifuweizhiB=number8B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>8){ //9

zifuweizhiA=number9A;
zifuweizhiB=number9B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>9){ //10

zifuweizhiA=number10A;
zifuweizhiB=number10B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>10){ //11

zifuweizhiA=number11A;
zifuweizhiB=number11B;
shujuchuli2();
shujuchuli3();

}

if(wanzhengdezushu>11){ //12

zifuweizhiA=number12A;
zifuweizhiB=number12B;
shujuchuli2();
shujuchuli3();

}



////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////时间部分



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

//////////////////////////////////////////////

if(dingweiok){

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

if(shoushiqidong){ //ds1307 重置时间
shoushiqidong=0;
        //年
   RTC.set(RTC_YEAR, utc8n);
   //月
   RTC.set(RTC_MONTH, utc8y);
   //日
   RTC.set(RTC_DAY, utc8r);
   //时
   RTC.set(RTC_HOUR, utc8s);
   //分       
        RTC.set(RTC_MINUTE, utc8f);
   //秒       
   RTC.set(RTC_SECOND, utc8m);

}

}


x=nian*0.1;
x=x%10;
temp2 = x+48, DEC;
x=nian%10;
temp2 = x+48, DEC;

          
x=yue*0.1;
temp2 = x+48, DEC;
x=yue%10;
temp2 = x+48, DEC;


    x=ri*0.1;
temp2 = x+48, DEC;
x=ri%10;
temp2 = x+48, DEC;
          

x=shi*0.1;
temp2 = x+48, DEC;
x=shi%10;
temp2 = x+48, DEC;


x=fen*0.1;
temp2 = x+48, DEC;
x=fen%10;
temp2 = x+48, DEC;


x=miao*0.1;
temp2 = x+48, DEC;
x=miao%10;
temp2 = x+48, DEC;


//////////////////////////////////////////// 温度、湿度部分

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

x=shidu*0.1;
temp2 = x+48;//湿度十位
x=shidu%10;
temp2 = x+48;//湿度个位


x=wendu*0.1;
temp2 = x+48;//温度十位
x=wendu%10;
temp2 = x+48;//温度个位

///////////////////////////////////////////////1602输出部分

lcd1602out();


/////////////////////////////////////////////





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

time2=millis()-time2;

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

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

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


if (millis() < time2){
time2=millis();
}


}
   
   

   
   
//清空临时数组temp1
for(int col=0;col<450;col++)temp1=0;




while (mySerial.available() > 0) {

temp5 = mySerial.read();
delayMicroseconds(1150);

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

if(temp5=='A')jsq6++;
if(temp5=='B'){

if(jsq6>0)jsq6--;
else jsq6=2;

}

if(temp5=='G')jsq8=!jsq8;

}



   
}






void fenchentou()
{

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

////////////////////////


x=dustVal*4.882*0.001;
if(x==0) temp2 = 32;//空格
else temp2 = x+48, DEC;//千

   x=dustVal*4.882*0.01;
   x=x%10;
   if(x==0 && temp2 == 32) temp2 = 32;//空格 ,在空气质量极好的地反,小于100mv的情况
   else temp2 = x+48, DEC;//百

   x=dustVal*4.882*0.1;
       x=x%10;
temp2 = x+48, DEC;//十

      x=dustVal*4.882;
          x=x%10;
temp2 = x+48, DEC;//个

//dustVal2=585.9375*dustVal-4272;//=(dustVal*5/1024-0.0356)*120000;

//颗粒数

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

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

}


}

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

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

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

//$第一次
if(temp1=='$' && change0){
change0=0;
change1=1;
number1A=col; //记录第一个$号的位置
}
//*第一次
if(temp1=='*' && change1){
change1=0;
change2=1;
number1B=col; //记录第一个*号的位置
}

//////////////////////////////////////////////////////

//$第二次
if(temp1=='$' && change2){
change2=0;
change3=1;
number2A=col; //记录第2个$号的位置
}
//*第二次
if(temp1=='*' && change3){
change3=0;
change4=1;
number2B=col; //记录第2个*号的位置
}

//////////////////////////////////////////////////////

//$第三次
if(temp1=='$' && change4){
change4=0;
change5=1;
number3A=col; //记录第3个$号的位置
}
//*第三次
if(temp1=='*' && change5){
change5=0;
change6=1;
number3B=col; //记录第3个*号的位置
}

//////////////////////////////////////////////////////

//$第四次
if(temp1=='$' && change6){
change6=0;
change7=1;
number4A=col; //记录第4个$号的位置
}
//*第四次
if(temp1=='*' && change7){
change7=0;
change8=1;
number4B=col; //记录第4个*号的位置
}

//////////////////////////////////////////////////////

//$第5次
if(temp1=='$' && change8){
change8=0;
change9=1;
number5A=col; //记录第5个$号的位置
}
//*第5次
if(temp1=='*' && change9){
change9=0;
change10=1;
number5B=col; //记录第5个*号的位置
}

//////////////////////////////////////////////////////

//$第6次
if(temp1=='$' && change10){
change10=0;
change11=1;
number6A=col; //记录第5个$号的位置
}
//*第6次
if(temp1=='*' && change11){
change11=0;
change12=1;
number6B=col; //记录第6个*号的位置
}

//////////////////////////////////////////////////////

//$第7次
if(temp1=='$' && change12){
change12=0;
change13=1;
number7A=col; //记录第7个$号的位置
}
//*第7次
if(temp1=='*' && change13){
change13=0;
change14=1;
number7B=col; //记录第7个*号的位置
}


    //////////////////////////////////////////////////////

//$第8次
if(temp1=='$' && change14){
change14=0;
change15=1;
number8A=col; //记录第8个$号的位置
}
//*第8次
if(temp1=='*' && change15){
change15=0;
change16=1;
number8B=col; //记录第8个*号的位置
}
//////////////////////////////////////////////////////

//$第9次
if(temp1=='$' && change16){
change16=0;
change17=1;
number9A=col; //记录第9个$号的位置
}
//*第9次
if(temp1=='*' && change17){
change17=0;
change18=1;
number9B=col; //记录第8个*号的位置
}
//////////////////////////////////////////////////////

//$第10次
if(temp1=='$' && change18){
change18=0;
change19=1;
number10A=col; //记录第10个$号的位置
}
//*第10次
if(temp1=='*' && change19){
change19=0;
change20=1;
number10B=col; //记录第10个*号的位置
}

//////////////////////////////////////////////////////

//$第11次
if(temp1=='$' && change20){
change20=0;
change21=1;
number11A=col; //记录第11个$号的位置
}
//*第10次
if(temp1=='*' && change21){
change21=0;
change22=1;
number11B=col; //记录第11个*号的位置
}

   //////////////////////////////////////////////////////

//$第12次
if(temp1=='$' && change22){
change22=0;
change23=1;
number12A=col; //记录第12个$号的位置
}
//*第12次
if(temp1=='*' && change23){
change23=0;
change24=1;
number12B=col; //记录第12个*号的位置
}


}


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

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


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

}else if(change23 || change22){
wanzhengdezushu=11;
}else if(change21 || change20){
wanzhengdezushu=10;
}else if(change19 || change18){
wanzhengdezushu=9;
}else if(change17 || change16){
wanzhengdezushu=8;
}else if(change15 || change14){
wanzhengdezushu=7;
}else if(change13 || change12){
wanzhengdezushu=6;
}else if(change11 || change10){
wanzhengdezushu=5;
}else if(change9 || change8){
wanzhengdezushu=4;

/////////////////////////////////////////////////////////////////


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

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

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

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



}

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

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


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

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

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

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

}

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

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

//与GPS传输的校验码进行对比
if(jianyan==temp1 && jianyan==temp1){
//一致,则说明数据是有效的,输出校验结果
jiaoyanjieguo=1;
}else{
//不一致
jiaoyanjieguo=0;
}

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


}


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

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

if(temp1=='G' && temp1=='A'){
//$GPGGA

for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){

if(temp1=='N' || temp1=='S')weidubiaoji=col;//纬度标记(纬度半球)
if(temp1=='E' || temp1=='W')jingdubiaoji=col;//经度标记(经度半球)

}





if(temp1=='1' || temp1=='2'){ //检查gps状态位
//1=非差分定位,2=差分定位,这种情况下,数据是有意义的

dingweiok=1;//已经定位

//Serial.print("UTC time:");
//for(int col=0;col<10;col++)Serial.print(temp1);
//Serial.println();


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

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

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

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

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


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


//海拔计算
for(int col=0;col<13;col++){
if(temp1==',' && !altitudeC){
altitudeA=col;
altitudeC=1;
col++;
}

if(temp1==',' && altitudeC){
altitudeB=col;
altitudeC=0;
//结束循环
col=13;
}

}


//海拔-999.9--9999.9
if(altitudeB-altitudeA-1==3){
temp2=32;//空格
temp2=32;
temp2=32;
memcpy(temp2+101,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 3);

}else if(altitudeB-altitudeA-1==4){
temp2=32;//空格
temp2=32;
memcpy(temp2+100,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 4);

}else if(altitudeB-altitudeA-1==5){
temp2=32;//空格
memcpy(temp2+99,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 5);

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

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


}else{


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

temp2=95;//下划线,纬度
temp2=95;

temp2=95;
temp2=95;

temp2=95;
temp2=95;
temp2=95;
temp2=95;

temp2=95;
//////////////////////////////经度

temp2=95;
temp2=95;
temp2=95;

temp2=95;
temp2=95;

temp2=95;
temp2=95;
temp2=95;
temp2=95;

temp2=95;
//////////////////////////////卫星数、海拔

temp2=95;
temp2=95;

temp2=95;
temp2=95;
temp2=95;
temp2=95;

temp2=95;



}

}else if(temp1=='L' && temp1=='L'){
//$GPGLL

}else if(temp1=='S' && temp1=='A'){
//$GPGSA

}else if(temp1=='S' && temp1=='T'){
//$GPGST

}else if(temp1=='S' && temp1=='V'){
//$GPGSV

}else if(temp1=='M' && temp1=='C'){
//$GPRMC
///////////////////////////////////////////////////////////////////////////////////




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


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

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

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

jsq2=0;
jsq3=0;
jsq4=0;
jsq5=0;
for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
if(temp1==',')jsq2++;
if(jsq2==9){
jsq3=col;//找到9第个逗号的前一个位置,循环0开始,0的时候就已经后推了一位置
col=zifuweizhiB-zifuweizhiA;//找到9个逗号就跳出循环
}

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

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

}

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

//月
jianyan =String(temp1);//复用jianyan这个数组来节约内存
jianyan +=temp1;
utc8y=jianyan.toInt();//字符串转换为整数,参与运算

//年
jianyan =String(temp1);//复用jianyan这个数组来节约内存
jianyan +=temp1;
utc8n=jianyan.toInt();//字符串转换为整数,参与运算


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


x=jsq4-jsq5-1;
//Serial.print("jsq4-jsq5=");
//Serial.println(x);
if(x==6){
memcpy(temp4+6,temp1+zifuweizhiA+jsq5+3, 6);//地面速率部分
}else if(x==5){
temp4=32;//空格
memcpy(temp4+7,temp1+zifuweizhiA+jsq5+3, 5);//地面速率部分
}else if(x==4){
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+8,temp1+zifuweizhiA+jsq5+3, 4);//地面速率部分
}else if(x==3){
temp4=32;//空格
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+9,temp1+zifuweizhiA+jsq5+3, 3);//地面速率部分
}else {//没数据的情况
temp4=32;//空格
temp4=32;//空格
temp4=95;//空格
temp4=95;//_
temp4=46;//.
temp4=95;//_
}



x=jsq3-jsq4-2;
//Serial.print("jsq3-jsq4=");
//Serial.println(x);
if(x==6){
memcpy(temp4+26,temp1+zifuweizhiA+jsq4+3, 6);// 地面航向部分
}else if(x==5){
temp4=32;//空格
memcpy(temp4+27,temp1+zifuweizhiA+jsq4+3, 5);//地面速率部分
}else if(x==4){
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+28,temp1+zifuweizhiA+jsq4+3, 4);//地面速率部分
}else if(x==3){
temp4=32;//空格
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+29,temp1+zifuweizhiA+jsq4+3, 3);//地面速率部分
}else {//没数据的情况
temp4=32;//空格
temp4=32;//空格
temp4=95;//空格
temp4=46;//.
temp4=95;//_
temp4=95;//_
}



jsq2=0; //防止以后会用,先行清零
jsq3=0;
jsq4=0;
jsq5=0;

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

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

}else{

//判断大小月
for(int col=0;col<4;col++){
if(xiaoyue==utc8y)xiaoyueok=1;
}

if(xiaoyueok && utc8r==30){ //小月最后一天
utc8r=1;
yuejinwei=1;
}else if(!xiaoyueok && utc8r==31){ //大月最后一天
utc8r=1;
yuejinwei=1;
}else{
utc8r++;//剩下的情况自加1就可以了
}
}

}

if(yuejinwei && utc8y==12){ //最后一月
utc8y=1;
nianjinwei=1;
}else if(yuejinwei){
utc8y++;
}

if(nianjinwei)utc8n++;

////////////////


//////////////////////////////////////////////////////////////////////////////////
}else if(temp1=='T' && temp1=='G'){
//$GPVTG

}



}

}



void printDateTime(DateTime dateTime) {
    //传送年份
        nian=dateTime.year(), DEC;
       
    //传送月份
    yue=dateTime.month(), DEC;
    //传送月份中的第几天
        ri=dateTime.day(), DEC;
    //传送小时
        shi=dateTime.hour(), DEC;
    //传送分钟
        fen=dateTime.minute(), DEC;
    //传送秒
        miao=dateTime.second(), DEC;
}



void lcd1602out(){

jsq6=jsq6%3;

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

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

if(jsq8){
//蓝牙gps模式

if(jsq6==0){

temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='O';
temp3='U';
temp3='T';
temp3=32;
memcpy(temp3+8,temp2+16, 8);//时间部分(00/00 00:00:00)

}else if(jsq6==1){

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

temp3='G';
temp3='P';
temp3='S';
temp3=32;
memcpy(temp3+4,temp2+35, 12);//纬度部分纯数字
}else{
   //未定位的情况下,please wait
temp3=32;
temp3=32;
temp3='P';
temp3='l';
temp3='e';
temp3='a';
temp3='s';
temp3='e';
temp3=32;
temp3='w';
temp3='a';
temp3='i';
temp3='t';

}


}else if(jsq6==2){


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

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

}else{
   //未定位的情况下,please wait
temp3=32;
temp3=32;
temp3='P';
temp3='l';
temp3='e';
temp3='a';
temp3='s';
temp3='e';
temp3=32;
temp3='w';
temp3='a';
temp3='i';
temp3='t';

}

}



}else{
//空气质量检测模式

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

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

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

}


   lcd.print(temp3);


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

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



   if(jsq8){
//蓝牙gps模式

if(jsq6==0){

if(dingweiok){ //已定位的情况下,显示卫星、海拔
temp3='n';
temp3='u';
temp3='m';

memcpy(temp3+3,temp2+84, 3);//卫星数部分(num:00)
temp3=32;
temp3=32;
memcpy(temp3+8,temp2+98, 8);//海拔部分( 000.0 M)
}else{
//未定位的情况下,Search GPS ing..
    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}


}else if(jsq6==1){

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

temp3=32;
temp3=32;
temp3=32;
memcpy(temp3+3,temp2+59, 13);//经度部分纯数字

}else{
   //未定位的情况下,Search GPS ing..
   
    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}


}else if(jsq6==2){


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

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

}else{
   //未定位的情况下,Search GPS ing..
   
    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}

}



}else{
//空气质量检测模式

   if(jsq6<3){
   memcpy(temp3,temp2+125, 7);//湿度、温度;
temp3=32;
memcpy(temp3+8,temp2+117, 7);//gp2y1010
   
   }


}


   lcd.print(temp3);



}

hi55234 发表于 2014-9-1 15:35:31

本帖最后由 hi55234 于 2014-9-1 15:37 编辑

/*
1、修正GPS未定时,1602上显示的内容
2、修改浇花时故障检测程序的运行方式,30秒检测,没水流的话,直接跳出程序
3、赋予串口控制命令与实体按钮相同的意义

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

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

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

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

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

*/
#include <MemoryFree.h>//剩余内存查询
//////////////////////////////////////////////////////////////////////////////////////////////
//GPS
//////////////////////////////////////////////////////////////////////////////////////////////

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

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

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

#include <LiquidCrystal.h>

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

byte quan0 = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//////////////////////////////////////////////////////////////////////////////////////////////
//DS18B20 温度
//////////////////////////////////////////////////////////////////////////////////////////////
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(10);// 数字接口10
DallasTemperature sensors(&oneWire);
//////////////////////////////////////////////////////////////////////////////////////////////
//DHT11 湿度
//////////////////////////////////////////////////////////////////////////////////////////////
#include <dht11.h>
dht11 DHT11;
#define DHT11PIN 11 //DHT11 PIN 11
//////////////////////////////////////////////////////////////////////////////////////////////
//ds1307
//////////////////////////////////////////////////////////////////////////////////////////////
#include <Wire.h>
#include <RTClib.h>
void printDateTime(DateTime dateTime);
RTC_DS1307 RTC;//创建实例
int nian,yue,ri,shi,fen,miao;
boolean shoushiqidong;//布尔量,授时启动
//////////////////////////////////////////////////////////////////////////////////////////////
//MQ-2
//////////////////////////////////////////////////////////////////////////////////////////////
int MQ2Pin=1;//A1——粉尘电压
int dustVal=0;

//////////////////////////////////////////////////////////////////////////////////////////////
//浇花的一些定义
//////////////////////////////////////////////////////////////////////////////////////////////
int liuliangji=12;
int diancifa=13;
unsigned long meimiaoyilunhui=millis();//每秒一轮回

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

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

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



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

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

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

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

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

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

if(temp2=='#' && temp2=='/'){
temp2=10;
temp2=13;
}
}
//对temp4进行处理,把“#/”替换成 换行+回车
for(int col=2;col<34;col++){
if(temp4=='#' && temp4=='/'){
temp4=10;
temp4=13;
}
}
}

void loop() {

if(jsq8){

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

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


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

}else{

//浇花主程序///////////////////////////////////////////////////////////

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

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


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

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

}

/*-------------------------end------------------------------*/

}


while (Serial.available() > 0) {

temp5 = Serial.read();
delayMicroseconds(1150);

//做一个保险,保证数组不会溢出,同时也限制了最大字符串的长度(10)
//if(jsq2<10) jsq2++;
//else jsq2=10;
if(temp5=='A'){
if(jsq8)jsq6++;
else {
shedingjiaoguanliang=shedingjiaoguanliang+tiaojieliang;
if(shedingjiaoguanliang>99)shedingjiaoguanliang=99;//最多设定浇灌99L
}
anjianzuseB=!anjianzuseB;
time2=millis();
}

if(temp5=='B'){

if(jsq8){

if(jsq6>0)jsq6--;
else jsq6=3;

}else {
shedingjiaoguanliang=shedingjiaoguanliang-tiaojieliang;
if(shedingjiaoguanliang<0)shedingjiaoguanliang=0;//最少设定浇灌0L
}
anjianzuseB=!anjianzuseB;
time2=millis();

}

if(temp5=='G'){

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

}
}

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

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

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

   }

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


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

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


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

if(jsq6>0)jsq6--;
else jsq6=3;

}else {
shedingjiaoguanliang=shedingjiaoguanliang-tiaojieliang;
if(shedingjiaoguanliang<0)shedingjiaoguanliang=0;//最少设定浇灌0L
}
anjianzuseB=!anjianzuseB;
time2=millis();
   }

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




}



void luanqizaobaA()
{
//布尔量,授时启动
shoushiqidong=0;

//日进位,月进位
rijinwei=0;
yuejinwei=0;
nianjinwei=0;

//布尔量 1-24,2个一组,可以判断出12组$```*
change0=1;//最开始的一个,必须置1
change1=0;
change2=0;
change3=0;
change4=0;
change5=0;
change6=0;
change7=0;
change8=0;
change9=0;
change10=0;
change11=0;
change12=0;
change13=0;
change14=0;
change15=0;
change16=0;
change17=0;
change18=0;
change19=0;
change20=0;
change21=0;
change22=0;
change23=0;
change24=0;
//number 1-12,记录$号的位置,以便找出特定语句的开始
number1A=0;
number2A=0;
number3A=0;
number4A=0;
number5A=0;
number6A=0;
number7A=0;
number8A=0;
number9A=0;
number10A=0;
number11A=0;
number12A=0;
//number 1-12,记录*号的位置,以便找出“校验码”,从而确定串口传输的完整性
number1B=0;
number2B=0;
number3B=0;
number4B=0;
number5B=0;
number6B=0;
number7B=0;
number8B=0;
number9B=0;
number10B=0;
number11B=0;
number12B=0;
//海拔用的,起点位置,结束位置,布尔量充当开关
altitudeA=0;
altitudeB=0;
altitudeC=0;
weidubiaoji=0;//纬度标记
jingdubiaoji=0;//经度标记
//子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
shujuchuli1();
//根据不同个数的完整组,分别进行"校验码计算与对比",以确保有效性
if(wanzhengdezushu>0){ //1
zifuweizhiA=number1A;
zifuweizhiB=number1B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>1){ //2
zifuweizhiA=number2A;
zifuweizhiB=number2B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>2){ //3
zifuweizhiA=number3A;
zifuweizhiB=number3B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>3){ //4
zifuweizhiA=number4A;
zifuweizhiB=number4B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>4){ //5
zifuweizhiA=number5A;
zifuweizhiB=number5B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>5){ //6
zifuweizhiA=number6A;
zifuweizhiB=number6B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>6){ //7
zifuweizhiA=number7A;
zifuweizhiB=number7B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>7){ //8
zifuweizhiA=number8A;
zifuweizhiB=number8B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>8){ //9
zifuweizhiA=number9A;
zifuweizhiB=number9B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>9){ //10
zifuweizhiA=number10A;
zifuweizhiB=number10B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>10){ //11
zifuweizhiA=number11A;
zifuweizhiB=number11B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>11){ //12
zifuweizhiA=number12A;
zifuweizhiB=number12B;
shujuchuli2();
shujuchuli3();
}
}
void luanqizaobaB()
{
////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////时间部分

//获取当前日期和时间
    DateTime now = RTC.now();
      //通过串口传送当前的日期和时间
      printDateTime(now);
//尚缺一个部分,即授时的条件 授时启动(时间有偏差) + gps已经定位(gps时间本身可用),
//////////////////////////////////////////////
if(dingweiok){
if(yue != utc8y) shoushiqidong=1;
if(ri != utc8r) shoushiqidong=1;
if(shi != utc8s) shoushiqidong=1;
if(fen != utc8f) shoushiqidong=1;
if(miao-utc8m>2 || utc8m-miao>2) shoushiqidong=1; //秒允许差3秒
if(shoushiqidong){ //ds1307 重置时间
shoushiqidong=0;
//年
   RTC.set(RTC_YEAR, utc8n);
   //月
   RTC.set(RTC_MONTH, utc8y);
   //日
   RTC.set(RTC_DAY, utc8r);
   //时
   RTC.set(RTC_HOUR, utc8s);
   //分
RTC.set(RTC_MINUTE, utc8f);
   //秒
   RTC.set(RTC_SECOND, utc8m);
}
}

x=nian*0.1;
x=x%10;
temp2 = x+48, DEC;
x=nian%10;
temp2 = x+48, DEC;


x=yue*0.1;
temp2 = x+48, DEC;
x=yue%10;
temp2 = x+48, DEC;


    x=ri*0.1;
temp2 = x+48, DEC;
x=ri%10;
temp2 = x+48, DEC;

x=shi*0.1;
temp2 = x+48, DEC;
x=shi%10;
temp2 = x+48, DEC;

x=fen*0.1;
temp2 = x+48, DEC;
x=fen%10;
temp2 = x+48, DEC;


x=miao*0.1;
temp2 = x+48, DEC;
x=miao%10;
temp2 = x+48, DEC;
}
void luanqizaobaC()
{

//////////////////////////////////////////// 温度、湿度部分
   //DS18B20 取温度
   sensors.requestTemperatures();
   int wendu=sensors.getTempCByIndex(0);
   //DHT11取湿度
      DHT11.read(DHT11PIN);
   int shidu=DHT11.humidity;

x=shidu*0.1;
temp2 = x+48;//湿度十位
x=shidu%10;
temp2 = x+48;//湿度个位

x=wendu*0.1;
temp2 = x+48;//温度十位
x=wendu%10;
temp2 = x+48;//温度个位
//打印整个临时数组temp2
if(jsq6==3){
Serial.println(temp2);
Serial.println(temp4);
//Serial.println(temp1);
    Serial.print("freeMemory()=");
    Serial.println(freeMemory());
}





//清空临时数组temp1
for(int col=0;col<450;col++)temp1=0;



}
void fenchentou()
{

////////////////////////

dustVal=analogRead(MQ2Pin);

x=dustVal*4.882*0.001;
if(x==0) temp2 = 32;//空格
else temp2 = x+48, DEC;//千

   x=dustVal*4.882*0.01;
   x=x%10;
   if(x==0 && temp2 == 32) temp2 = 32;//空格 ,在空气质量极好的地反,小于100mv的情况
   else temp2 = x+48, DEC;//百
   x=dustVal*4.882*0.1;
x=x%10;
temp2 = x+48, DEC;//十

      x=dustVal*4.882;
   x=x%10;
temp2 = x+48, DEC;//个



}
//////////////////////////////////////////////////////////////////////////////////////
//子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
void shujuchuli1()
{
//这个是典型的先接受,后处理的程序,因为需要逐个检查,所以接收多少字符就要循环多少次
//其主要目的是找出$、*的位置,以400个字节及手上模块(垃圾佬处买的洋垃圾破模块+自己暴力拆解)的表现,
//此处最多出现四组,完整的最多2组(*后带校验码)
//但完整的gps NMEA-0183应当有6+x($GPGSV有多组),正常都是9组以上数据,即使x不输出,也有6组数据
//(个人观点)最有价值的是$GPGGA、$GPRMC
for(int col=0;col<jsq1;col++){
//$第一次
if(temp1=='$' && change0){
change0=0;
change1=1;
number1A=col; //记录第一个$号的位置
}
//*第一次
if(temp1=='*' && change1){
change1=0;
change2=1;
number1B=col; //记录第一个*号的位置
}
//////////////////////////////////////////////////////
//$第二次
if(temp1=='$' && change2){
change2=0;
change3=1;
number2A=col; //记录第2个$号的位置
}
//*第二次
if(temp1=='*' && change3){
change3=0;
change4=1;
number2B=col; //记录第2个*号的位置
}

//////////////////////////////////////////////////////
//$第三次
if(temp1=='$' && change4){
change4=0;
change5=1;
number3A=col; //记录第3个$号的位置
}
//*第三次
if(temp1=='*' && change5){
change5=0;
change6=1;
number3B=col; //记录第3个*号的位置
}

//////////////////////////////////////////////////////
//$第四次
if(temp1=='$' && change6){
change6=0;
change7=1;
number4A=col; //记录第4个$号的位置
}
//*第四次
if(temp1=='*' && change7){
change7=0;
change8=1;
number4B=col; //记录第4个*号的位置
}

//////////////////////////////////////////////////////
//$第5次
if(temp1=='$' && change8){
change8=0;
change9=1;
number5A=col; //记录第5个$号的位置
}
//*第5次
if(temp1=='*' && change9){
change9=0;
change10=1;
number5B=col; //记录第5个*号的位置
}

//////////////////////////////////////////////////////
//$第6次
if(temp1=='$' && change10){
change10=0;
change11=1;
number6A=col; //记录第5个$号的位置
}
//*第6次
if(temp1=='*' && change11){
change11=0;
change12=1;
number6B=col; //记录第6个*号的位置
}

//////////////////////////////////////////////////////
//$第7次
if(temp1=='$' && change12){
change12=0;
change13=1;
number7A=col; //记录第7个$号的位置
}
//*第7次
if(temp1=='*' && change13){
change13=0;
change14=1;
number7B=col; //记录第7个*号的位置
}

    //////////////////////////////////////////////////////
//$第8次
if(temp1=='$' && change14){
change14=0;
change15=1;
number8A=col; //记录第8个$号的位置
}
//*第8次
if(temp1=='*' && change15){
change15=0;
change16=1;
number8B=col; //记录第8个*号的位置
}
//////////////////////////////////////////////////////
//$第9次
if(temp1=='$' && change16){
change16=0;
change17=1;
number9A=col; //记录第9个$号的位置
}
//*第9次
if(temp1=='*' && change17){
change17=0;
change18=1;
number9B=col; //记录第8个*号的位置
}
//////////////////////////////////////////////////////
//$第10次
if(temp1=='$' && change18){
change18=0;
change19=1;
number10A=col; //记录第10个$号的位置
}
//*第10次
if(temp1=='*' && change19){
change19=0;
change20=1;
number10B=col; //记录第10个*号的位置
}

//////////////////////////////////////////////////////
//$第11次
if(temp1=='$' && change20){
change20=0;
change21=1;
number11A=col; //记录第11个$号的位置
}
//*第10次
if(temp1=='*' && change21){
change21=0;
change22=1;
number11B=col; //记录第11个*号的位置
}

   //////////////////////////////////////////////////////
//$第12次
if(temp1=='$' && change22){
change22=0;
change23=1;
number12A=col; //记录第12个$号的位置
}
//*第12次
if(temp1=='*' && change23){
change23=0;
change24=1;
number12B=col; //记录第12个*号的位置
}


}
//分别找出$、*的位置后,首先就要验证数据的可靠性
//计算校验码,并与所收到的校验码对比
//计算完整的$-*组数
//Serial.print("wanzhengde $-*geshu=");
if(change24){
//完整的12组$--*
wanzhengdezushu=12;
}else if(change23 || change22){
wanzhengdezushu=11;
}else if(change21 || change20){
wanzhengdezushu=10;
}else if(change19 || change18){
wanzhengdezushu=9;
}else if(change17 || change16){
wanzhengdezushu=8;
}else if(change15 || change14){
wanzhengdezushu=7;
}else if(change13 || change12){
wanzhengdezushu=6;
}else if(change11 || change10){
wanzhengdezushu=5;
}else if(change9 || change8){
wanzhengdezushu=4;
/////////////////////////////////////////////////////////////////
}else if(change7 || change6){
//change7=1是第四组仅找到$,而没有*
//change6=1只找到了完整的3组$--*
wanzhengdezushu=3;
//Serial.println(wanzhengdezushu);
}else if(change5 || change4){
//change5=1是第3组仅找到$,而没有*
//change4=1只找到了完整的2组$--*
wanzhengdezushu=2;
//Serial.println(wanzhengdezushu);
}else if(change3 || change2){
//change3=1是第2组仅找到$,而没有*
//change2=1只找到了完整的1组$--*
wanzhengdezushu=1;
//Serial.println(wanzhengdezushu);
}else if(change1 || change0){
//change1=1是第1组仅找到$,而没有*
//change0=1连第一组的$都没找到,原始状态~~~啥玩意?
wanzhengdezushu=0;
//Serial.println(wanzhengdezushu);
}
}
//子程序数据处理2,进行异或运算的处理(对比校验码)
void shujuchuli2(){
//zifuweizhiB-zifuweizhiA-1;*号本身不参与异或运算,所以差值还要减1
for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
if(col==0)yihuoyunsuan=temp1;
else yihuoyunsuan=yihuoyunsuan ^ temp1;
}
//因为定义int的时候,yihuoyunsuan的结果是以10进制DEC表示的,所以需转换为16进制HEX
//因为GPS校验数据0位也进行了传输,所以在转换的时候有必要将情况分类讨论
//(yihuoyunsuan=0)/(0<yihuoyunsuan<17)/(17<yihuoyunsuan)
if(yihuoyunsuan==0){
//校验数10进制为0,直接填充字符串00
jianyan="00";
}else if(yihuoyunsuan>15){
//此时转换为16进制以后,天然有2位,很理想,不用处理
jianyan = String(yihuoyunsuan,HEX);
}else{
//校验数10进制为1-15时,转换为16进制就只有1位数,所以需要在前面填0
jianyan = "0";
jianyan += String(yihuoyunsuan,HEX);
}
//实践中发现,jianyan中的字符是以小写方式存在,虽然Serial.println(yihuoyunsuan,HEX)会以大写方式打印出来
//但直接Serial.println(jianyan)就是小写的,这是啥情况?
//将其字母转换为大写,否则与GPS传输的校验码对比时大小写问题校验失败(GPS传输的校验码为大写的)
jianyan.toUpperCase();
///////////////////////////////////////////显示异或校验码,方便给GPS编程,虽然还没成功过
//Serial.print("jianyan=");
//Serial.println(jianyan);
//与GPS传输的校验码进行对比
if(jianyan==temp1 && jianyan==temp1){
//一致,则说明数据是有效的,输出校验结果
jiaoyanjieguo=1;
}else{
//不一致
jiaoyanjieguo=0;
}
//对校验数组进行清零
jianyan="";
}
//子程序数据处理3,有效的字符串究竟是什么?以及相应的操作
void shujuchuli3(){
/*
常见的GPS发送字符串如下
$GPGGA,
$GPGLL,
$GPGSA,
$GPGST,
$GPGSV,
$GPRMC,
$GPVTG,
鉴于最后2位不同,所以用判断$+4、$+5 两个位置的字符来判断所收到的究竟是什么信息
*/
if(jiaoyanjieguo){
jiaoyanjieguo=0;//使用后则置0,以免影响后续计算
if(temp1=='G' && temp1=='A'){
//$GPGGA C3-470B有
for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){

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

memcpy(temp2+46,temp1+zifuweizhiA+1+weidubiaoji, 1);
//经度
memcpy(temp2+59,temp1+zifuweizhiA+weidubiaoji+3, 3);
memcpy(temp2+63,temp1+zifuweizhiA+weidubiaoji+6, 7);
memcpy(temp2+71,temp1+zifuweizhiA+1+jingdubiaoji, 1);
//可用卫星数
memcpy(temp2+85,temp1+zifuweizhiA+jingdubiaoji+5, 2);


//海拔计算
for(int col=0;col<13;col++) {
if(temp1==',' && !altitudeC){
altitudeA=col;
altitudeC=1;
col++;
}

if(temp1==',' && altitudeC){
altitudeB=col;
altitudeC=0;
//结束循环
col=13;
}
}

//海拔-999.9--9999.9
if(altitudeB-altitudeA-1==3){
temp2=32;//空格
temp2=32;
temp2=32;
memcpy(temp2+101,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 3);
}else if(altitudeB-altitudeA-1==4){
temp2=32;//空格
temp2=32;
memcpy(temp2+100,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 4);
}else if(altitudeB-altitudeA-1==5){
temp2=32;//空格
memcpy(temp2+99,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 5);
}else if(altitudeB-altitudeA-1==6){
memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 6);
}
// memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, altitudeB-altitudeA-1);
}else{
//剩下的就是,未定位、正在估算,这2种情况都属于数据无意义,所以对输出数组的相应部分进行填充
dingweiok=0;//没有定位
temp2=95;//下划线,纬度
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
//////////////////////////////经度
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
//////////////////////////////卫星数、海拔
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
}
}else if(temp1=='L' && temp1=='L'){
//$GPGLL
}else if(temp1=='S' && temp1=='A'){
//$GPGSA C3-470B有
}else if(temp1=='S' && temp1=='T'){
//$GPGST
}else if(temp1=='S' && temp1=='V'){
//$GPGSV C3-470B有
}else if(temp1=='M' && temp1=='C'){
//$GPRMC C3-470B有
///////////////////////////////////////////////////////////////////////////////////
//$GPRMC,143716.000,A,2936.49838,N,10634.13016,E,0.1,273.6,120314,2.1,W,A*13
//时间部分:UTC转为UTC+8,北京时间(时:分:秒)
//时:
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8s=jianyan.toInt()+8;
if(utc8s>23)rijinwei=1;//提示后面程序换算为北京时间的时候,日要+1天
utc8s=utc8s%24;//字符串转换为整数,参与运算
//分:
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8f=jianyan.toInt();//字符串转换为整数,参与运算
//秒:
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8m=jianyan.toInt();//字符串转换为整数,参与运算
////////////////////////////////////////////////
//提取UTC日期(日、月、年),这个日期位于GPRMC第9个数据中,所以定位第九个逗号的位置即可
jsq2=0;
jsq3=0;
jsq4=0;
jsq5=0;
for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
if(temp1==',')jsq2++;
if(jsq2==9){
jsq3=col;//找到9第个逗号的前一个位置,循环0开始,0的时候就已经后推了一位置
col=zifuweizhiB-zifuweizhiA;//找到9个逗号就跳出循环
}
if(jsq2<8){
jsq4=col;//找到8第个逗号的前2个位置,即“地面速率(节)”的最后一位
}
if(jsq2<7){
jsq5=col;//找到7第个逗号的前2个位置,即“经度标记”
}
}
//日
jianyan = String(temp1);//复用jianyan这个数组来节约内存,9第个逗号前一位后推2个位置
jianyan += temp1;
utc8r=jianyan.toInt();//字符串转换为整数,参与运算
//月
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8y=jianyan.toInt();//字符串转换为整数,参与运算
//年
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8n=jianyan.toInt();//字符串转换为整数,参与运算
// 地面速率(000.0~999.9节、地面航向(000.0~359.9度
x=jsq4-jsq5-1;
//Serial.print("jsq4-jsq5=");
//Serial.println(x);
if(x==6){
memcpy(temp4+6,temp1+zifuweizhiA+jsq5+3, 6);//地面速率部分
}else if(x==5){
temp4=32;//空格
memcpy(temp4+7,temp1+zifuweizhiA+jsq5+3, 5);//地面速率部分
}else if(x==4){
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+8,temp1+zifuweizhiA+jsq5+3, 4);//地面速率部分
}else if(x==3){
temp4=32;//空格
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+9,temp1+zifuweizhiA+jsq5+3, 3);//地面速率部分
}else {//没数据的情况
temp4=32;//空格
temp4=32;//空格
temp4=95;//空格
temp4=95;//_
temp4=46;//.
temp4=95;//_
}
x=jsq3-jsq4-2;
//Serial.print("jsq3-jsq4=");
//Serial.println(x);
if(x==6){
memcpy(temp4+26,temp1+zifuweizhiA+jsq4+3, 6);// 地面航向部分
}else if(x==5){
temp4=32;//空格
memcpy(temp4+27,temp1+zifuweizhiA+jsq4+3, 5);//地面速率部分
}else if(x==4){
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+28,temp1+zifuweizhiA+jsq4+3, 4);//地面速率部分
}else if(x==3){
temp4=32;//空格
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+29,temp1+zifuweizhiA+jsq4+3, 3);//地面速率部分
}else {//没数据的情况
temp4=32;//空格
temp4=32;//空格
temp4=95;//空格
temp4=46;//.
temp4=95;//_
temp4=95;//_
}
jsq2=0; //防止以后会用,先行清零
jsq3=0;
jsq4=0;
jsq5=0;
//讨论日、月、年进位(大月、小月、平年、闰年的问题)
if(rijinwei){
//先讨论2月的问题
if(utc8y==2 && utc8r==28){
if(utc8n%4==0)utc8r=29;//闰年可加一天
else {
utc8r=1;
yuejinwei=1;
}
}else{
//判断大小月
for(int col=0;col<4;col++){
if(xiaoyue==utc8y)xiaoyueok=1;
}
if(xiaoyueok && utc8r==30){ //小月最后一天
utc8r=1;
yuejinwei=1;
}else if(!xiaoyueok && utc8r==31){ //大月最后一天
utc8r=1;
yuejinwei=1;
}else{
utc8r++;//剩下的情况自加1就可以了
}
}
}
if(yuejinwei && utc8y==12){ //最后一月
utc8y=1;
nianjinwei=1;
}else if(yuejinwei){
utc8y++;
}
if(nianjinwei)utc8n++;
////////////////
//////////////////////////////////////////////////////////////////////////////////
}else if(temp1=='T' && temp1=='G'){
//$GPVTG
}
}
}
void printDateTime(DateTime dateTime) {
    //传送年份
nian=dateTime.year(), DEC;

    //传送月份
    yue=dateTime.month(), DEC;
    //传送月份中的第几天
ri=dateTime.day(), DEC;
    //传送小时
shi=dateTime.hour(), DEC;
    //传送分钟
fen=dateTime.minute(), DEC;
    //传送秒
miao=dateTime.second(), DEC;
}


void lcd1602out(){
jsq6=jsq6%4;

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

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

if(jsq8){
//蓝牙gps模式

if(jsq6==0){

temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='O';
temp3='U';
temp3='T';
temp3=32;
memcpy(temp3+8,temp2+16, 8);//时间部分(00/00 00:00:00)

}else if(jsq6==1){

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

temp3='G';
temp3='P';
temp3='S';
temp3=32;
memcpy(temp3+4,temp2+35, 12);//纬度部分纯数字
}else{
   //未定位的情况下,please wait
temp3=32;
temp3='l';
temp3='a';
temp3='t';
temp3='.';
temp3=32;
temp3='a';
temp3='n';
temp3='d';
temp3=32;
temp3='L';
temp3='O';
temp3='N';
temp3='G';
temp3='.';

}


}else if(jsq6==2){


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

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

}else{
   //未定位的情况下,please wait
temp3='s';
temp3='p';
temp3='e';
temp3='e';
temp3='d';
temp3='&';
temp3='d';
temp3='i';
temp3='r';
temp3='e';
temp3='c';
temp3='t';
temp3='i';
temp3='o';
temp3='n';

}

}else if(jsq6==3){


//空气质量检测模式


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



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

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

}



}else{

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

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

x=shishiliuliang;
x=x%10; //实时流量的个位
temp3=x+48, DEC;

temp3='.';//小数点

x=(shishiliuliang*10); //实时流量的十分位
x=x%10;
temp3=x+48, DEC;

temp3='L';
temp3='/';
temp3='m';
temp3='i';
temp3='n';
temp3=32;

temp3='S';
temp3='D';
temp3=':';

x=shedingjiaoguanliang*0.1; //设定浇灌量的十位
if(x==0) temp3=32;
else temp3=x+48, DEC;

x=shedingjiaoguanliang%10; //设定浇灌量的个位
temp3=x+48, DEC;


temp3='L';


}


   lcd.print(temp3);


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

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



   if(jsq8){
//蓝牙gps模式

if(jsq6==0){

if(dingweiok){ //已定位的情况下,显示卫星、海拔
temp3='n';
temp3='u';
temp3='m';

memcpy(temp3+3,temp2+84, 3);//卫星数部分(num:00)
temp3=32;
temp3=32;
memcpy(temp3+8,temp2+98, 8);//海拔部分( 000.0 M)
}else{
//未定位的情况下,Search GPS ing..
    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}


}else if(jsq6==1){

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

temp3=32;
temp3=32;
temp3=32;
memcpy(temp3+3,temp2+59, 13);//经度部分纯数字

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

    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}


}else if(jsq6==2){


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

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

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

    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}

}else if(jsq6==3){

//空气质量检测模式

   memcpy(temp3,temp2+125, 7);//湿度、温度;
temp3=32;
memcpy(temp3+8,temp2+117, 7);//gp2y1010


}



}else{

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

temp3='T';
temp3='o';
temp3='t';
temp3='a';
temp3='l';
temp3=':';

x=leijiliuliang*0.1; //累计流量的十位
if(x==0) temp3=32;
else temp3=x+48, DEC;

x=leijiliuliang; //累计流量的个位
x=x%10; //累计流量的个位
temp3=x+48, DEC;

temp3='.';

x=leijiliuliang*10; //累计流量的十分位
x=x%10; //累计流量的十分位
temp3=x+48, DEC;


x=leijiliuliang*100; //累计流量的百分位
   x=x%10;
temp3=x+48, DEC;

temp3=32;
temp3='L';

}


   lcd.print(temp3);



}


void jiaohuaA(){

if(millis()-meimiaoyilunhui>1000) {

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

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

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

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

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

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

}

void jiaohuaB(){

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


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

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

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

}

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



}

}

yuqingshan 发表于 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文太烂了,无从下手,敬请原谅。谢谢。

潇洒哥 发表于 2014-8-7 22:24:44

这不是1602吗?不是OLED啊????!!!

hi55234 发表于 2014-8-31 21:25:08

yuqingshan 发表于 2014-8-6 09:10 static/image/common/back.gif
LZ的“大杂汇”程序代码有些长,不过正是想找很久的程序了,谢谢。
我的接线:



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

hi55234 发表于 2014-8-31 21:36:29










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


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

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

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

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

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

*/
#include <MemoryFree.h>//剩余内存查询
//////////////////////////////////////////////////////////////////////////////////////////////
//GPS
//////////////////////////////////////////////////////////////////////////////////////////////

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

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

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

#include <LiquidCrystal.h>

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

byte quan0 = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
//////////////////////////////////////////////////////////////////////////////////////////////
//DS18B20 温度
//////////////////////////////////////////////////////////////////////////////////////////////
#include <OneWire.h>
#include <DallasTemperature.h>
OneWire oneWire(10);// 数字接口10
DallasTemperature sensors(&oneWire);
//////////////////////////////////////////////////////////////////////////////////////////////
//DHT11 湿度
//////////////////////////////////////////////////////////////////////////////////////////////
#include <dht11.h>
dht11 DHT11;
#define DHT11PIN 11 //DHT11 PIN 11
//////////////////////////////////////////////////////////////////////////////////////////////
//ds1307
//////////////////////////////////////////////////////////////////////////////////////////////
#include <Wire.h>
#include <RTClib.h>
void printDateTime(DateTime dateTime);
RTC_DS1307 RTC;//创建实例
int nian,yue,ri,shi,fen,miao;
boolean shoushiqidong;//布尔量,授时启动
//////////////////////////////////////////////////////////////////////////////////////////////
//MQ-2
//////////////////////////////////////////////////////////////////////////////////////////////
int MQ2Pin=1;//A1——粉尘电压
int dustVal=0;

//////////////////////////////////////////////////////////////////////////////////////////////
//浇花的一些定义
//////////////////////////////////////////////////////////////////////////////////////////////
int liuliangji=12;
int diancifa=13;
unsigned long meimiaoyilunhui=millis();//每秒一轮回

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

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

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



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

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

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

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

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

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

if(temp2=='#' && temp2=='/'){
temp2=10;
temp2=13;
}
}
//对temp4进行处理,把“#/”替换成 换行+回车
for(int col=2;col<34;col++){
if(temp4=='#' && temp4=='/'){
temp4=10;
temp4=13;
}
}
}

void loop() {

if(jsq8){

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

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


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

}else{

//浇花主程序///////////////////////////////////////////////////////////

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

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


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

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

}

/*-------------------------end------------------------------*/

}


while (Serial.available() > 0) {

temp5 = Serial.read();
delayMicroseconds(1150);

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

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

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

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

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


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

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

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

if(jsq6>0)jsq6--;
else jsq6=3;

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




}



void luanqizaobaA()
{
//布尔量,授时启动
shoushiqidong=0;

//日进位,月进位
rijinwei=0;
yuejinwei=0;
nianjinwei=0;

//布尔量 1-24,2个一组,可以判断出12组$```*
change0=1;//最开始的一个,必须置1
change1=0;
change2=0;
change3=0;
change4=0;
change5=0;
change6=0;
change7=0;
change8=0;
change9=0;
change10=0;
change11=0;
change12=0;
change13=0;
change14=0;
change15=0;
change16=0;
change17=0;
change18=0;
change19=0;
change20=0;
change21=0;
change22=0;
change23=0;
change24=0;
//number 1-12,记录$号的位置,以便找出特定语句的开始
number1A=0;
number2A=0;
number3A=0;
number4A=0;
number5A=0;
number6A=0;
number7A=0;
number8A=0;
number9A=0;
number10A=0;
number11A=0;
number12A=0;
//number 1-12,记录*号的位置,以便找出“校验码”,从而确定串口传输的完整性
number1B=0;
number2B=0;
number3B=0;
number4B=0;
number5B=0;
number6B=0;
number7B=0;
number8B=0;
number9B=0;
number10B=0;
number11B=0;
number12B=0;
//海拔用的,起点位置,结束位置,布尔量充当开关
altitudeA=0;
altitudeB=0;
altitudeC=0;
weidubiaoji=0;//纬度标记
jingdubiaoji=0;//经度标记
//子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
shujuchuli1();
//根据不同个数的完整组,分别进行"校验码计算与对比",以确保有效性
if(wanzhengdezushu>0){ //1
zifuweizhiA=number1A;
zifuweizhiB=number1B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>1){ //2
zifuweizhiA=number2A;
zifuweizhiB=number2B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>2){ //3
zifuweizhiA=number3A;
zifuweizhiB=number3B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>3){ //4
zifuweizhiA=number4A;
zifuweizhiB=number4B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>4){ //5
zifuweizhiA=number5A;
zifuweizhiB=number5B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>5){ //6
zifuweizhiA=number6A;
zifuweizhiB=number6B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>6){ //7
zifuweizhiA=number7A;
zifuweizhiB=number7B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>7){ //8
zifuweizhiA=number8A;
zifuweizhiB=number8B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>8){ //9
zifuweizhiA=number9A;
zifuweizhiB=number9B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>9){ //10
zifuweizhiA=number10A;
zifuweizhiB=number10B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>10){ //11
zifuweizhiA=number11A;
zifuweizhiB=number11B;
shujuchuli2();
shujuchuli3();
}
if(wanzhengdezushu>11){ //12
zifuweizhiA=number12A;
zifuweizhiB=number12B;
shujuchuli2();
shujuchuli3();
}
}
void luanqizaobaB()
{
////////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////时间部分

//获取当前日期和时间
    DateTime now = RTC.now();
      //通过串口传送当前的日期和时间
      printDateTime(now);
//尚缺一个部分,即授时的条件 授时启动(时间有偏差) + gps已经定位(gps时间本身可用),
//////////////////////////////////////////////
if(dingweiok){
if(yue != utc8y) shoushiqidong=1;
if(ri != utc8r) shoushiqidong=1;
if(shi != utc8s) shoushiqidong=1;
if(fen != utc8f) shoushiqidong=1;
if(miao-utc8m>2 || utc8m-miao>2) shoushiqidong=1; //秒允许差3秒
if(shoushiqidong){ //ds1307 重置时间
shoushiqidong=0;
//年
   RTC.set(RTC_YEAR, utc8n);
   //月
   RTC.set(RTC_MONTH, utc8y);
   //日
   RTC.set(RTC_DAY, utc8r);
   //时
   RTC.set(RTC_HOUR, utc8s);
   //分
RTC.set(RTC_MINUTE, utc8f);
   //秒
   RTC.set(RTC_SECOND, utc8m);
}
}

x=nian*0.1;
x=x%10;
temp2 = x+48, DEC;
x=nian%10;
temp2 = x+48, DEC;

   
x=yue*0.1;
temp2 = x+48, DEC;
x=yue%10;
temp2 = x+48, DEC;


    x=ri*0.1;
temp2 = x+48, DEC;
x=ri%10;
temp2 = x+48, DEC;
   
x=shi*0.1;
temp2 = x+48, DEC;
x=shi%10;
temp2 = x+48, DEC;

x=fen*0.1;
temp2 = x+48, DEC;
x=fen%10;
temp2 = x+48, DEC;


x=miao*0.1;
temp2 = x+48, DEC;
x=miao%10;
temp2 = x+48, DEC;
}
void luanqizaobaC()
{

//////////////////////////////////////////// 温度、湿度部分
   //DS18B20 取温度
   sensors.requestTemperatures();
   int wendu=sensors.getTempCByIndex(0);
   //DHT11取湿度
      DHT11.read(DHT11PIN);
   int shidu=DHT11.humidity;

x=shidu*0.1;
temp2 = x+48;//湿度十位
x=shidu%10;
temp2 = x+48;//湿度个位

x=wendu*0.1;
temp2 = x+48;//温度十位
x=wendu%10;
temp2 = x+48;//温度个位
//打印整个临时数组temp2
if(jsq6==3){
Serial.println(temp2);
Serial.println(temp4);
//Serial.println(temp1);
    Serial.print("freeMemory()=");
    Serial.println(freeMemory());
}

   

   
   
//清空临时数组temp1
for(int col=0;col<450;col++)temp1=0;



}
void fenchentou()
{

////////////////////////

dustVal=analogRead(MQ2Pin);

x=dustVal*4.882*0.001;
if(x==0) temp2 = 32;//空格
else temp2 = x+48, DEC;//千

   x=dustVal*4.882*0.01;
   x=x%10;
   if(x==0 && temp2 == 32) temp2 = 32;//空格 ,在空气质量极好的地反,小于100mv的情况
   else temp2 = x+48, DEC;//百
   x=dustVal*4.882*0.1;
x=x%10;
temp2 = x+48, DEC;//十

      x=dustVal*4.882;
   x=x%10;
temp2 = x+48, DEC;//个



}
//////////////////////////////////////////////////////////////////////////////////////
//子程序数据处理1,计算出“完整的$-*组数”,以及每组的起始位置
void shujuchuli1()
{
//这个是典型的先接受,后处理的程序,因为需要逐个检查,所以接收多少字符就要循环多少次
//其主要目的是找出$、*的位置,以400个字节及手上模块(垃圾佬处买的洋垃圾破模块+自己暴力拆解)的表现,
//此处最多出现四组,完整的最多2组(*后带校验码)
//但完整的gps NMEA-0183应当有6+x($GPGSV有多组),正常都是9组以上数据,即使x不输出,也有6组数据
//(个人观点)最有价值的是$GPGGA、$GPRMC
for(int col=0;col<jsq1;col++){
//$第一次
if(temp1=='$' && change0){
change0=0;
change1=1;
number1A=col; //记录第一个$号的位置
}
//*第一次
if(temp1=='*' && change1){
change1=0;
change2=1;
number1B=col; //记录第一个*号的位置
}
//////////////////////////////////////////////////////
//$第二次
if(temp1=='$' && change2){
change2=0;
change3=1;
number2A=col; //记录第2个$号的位置
}
//*第二次
if(temp1=='*' && change3){
change3=0;
change4=1;
number2B=col; //记录第2个*号的位置
}

//////////////////////////////////////////////////////
//$第三次
if(temp1=='$' && change4){
change4=0;
change5=1;
number3A=col; //记录第3个$号的位置
}
//*第三次
if(temp1=='*' && change5){
change5=0;
change6=1;
number3B=col; //记录第3个*号的位置
}

//////////////////////////////////////////////////////
//$第四次
if(temp1=='$' && change6){
change6=0;
change7=1;
number4A=col; //记录第4个$号的位置
}
//*第四次
if(temp1=='*' && change7){
change7=0;
change8=1;
number4B=col; //记录第4个*号的位置
}

//////////////////////////////////////////////////////
//$第5次
if(temp1=='$' && change8){
change8=0;
change9=1;
number5A=col; //记录第5个$号的位置
}
//*第5次
if(temp1=='*' && change9){
change9=0;
change10=1;
number5B=col; //记录第5个*号的位置
}

//////////////////////////////////////////////////////
//$第6次
if(temp1=='$' && change10){
change10=0;
change11=1;
number6A=col; //记录第5个$号的位置
}
//*第6次
if(temp1=='*' && change11){
change11=0;
change12=1;
number6B=col; //记录第6个*号的位置
}

//////////////////////////////////////////////////////
//$第7次
if(temp1=='$' && change12){
change12=0;
change13=1;
number7A=col; //记录第7个$号的位置
}
//*第7次
if(temp1=='*' && change13){
change13=0;
change14=1;
number7B=col; //记录第7个*号的位置
}

    //////////////////////////////////////////////////////
//$第8次
if(temp1=='$' && change14){
change14=0;
change15=1;
number8A=col; //记录第8个$号的位置
}
//*第8次
if(temp1=='*' && change15){
change15=0;
change16=1;
number8B=col; //记录第8个*号的位置
}
//////////////////////////////////////////////////////
//$第9次
if(temp1=='$' && change16){
change16=0;
change17=1;
number9A=col; //记录第9个$号的位置
}
//*第9次
if(temp1=='*' && change17){
change17=0;
change18=1;
number9B=col; //记录第8个*号的位置
}
//////////////////////////////////////////////////////
//$第10次
if(temp1=='$' && change18){
change18=0;
change19=1;
number10A=col; //记录第10个$号的位置
}
//*第10次
if(temp1=='*' && change19){
change19=0;
change20=1;
number10B=col; //记录第10个*号的位置
}

//////////////////////////////////////////////////////
//$第11次
if(temp1=='$' && change20){
change20=0;
change21=1;
number11A=col; //记录第11个$号的位置
}
//*第10次
if(temp1=='*' && change21){
change21=0;
change22=1;
number11B=col; //记录第11个*号的位置
}

   //////////////////////////////////////////////////////
//$第12次
if(temp1=='$' && change22){
change22=0;
change23=1;
number12A=col; //记录第12个$号的位置
}
//*第12次
if(temp1=='*' && change23){
change23=0;
change24=1;
number12B=col; //记录第12个*号的位置
}


}
//分别找出$、*的位置后,首先就要验证数据的可靠性
//计算校验码,并与所收到的校验码对比
//计算完整的$-*组数
//Serial.print("wanzhengde $-*geshu=");
if(change24){
//完整的12组$--*
wanzhengdezushu=12;
}else if(change23 || change22){
wanzhengdezushu=11;
}else if(change21 || change20){
wanzhengdezushu=10;
}else if(change19 || change18){
wanzhengdezushu=9;
}else if(change17 || change16){
wanzhengdezushu=8;
}else if(change15 || change14){
wanzhengdezushu=7;
}else if(change13 || change12){
wanzhengdezushu=6;
}else if(change11 || change10){
wanzhengdezushu=5;
}else if(change9 || change8){
wanzhengdezushu=4;
/////////////////////////////////////////////////////////////////
}else if(change7 || change6){
//change7=1是第四组仅找到$,而没有*
//change6=1只找到了完整的3组$--*
wanzhengdezushu=3;
//Serial.println(wanzhengdezushu);
}else if(change5 || change4){
//change5=1是第3组仅找到$,而没有*
//change4=1只找到了完整的2组$--*
wanzhengdezushu=2;
//Serial.println(wanzhengdezushu);
}else if(change3 || change2){
//change3=1是第2组仅找到$,而没有*
//change2=1只找到了完整的1组$--*
wanzhengdezushu=1;
//Serial.println(wanzhengdezushu);
}else if(change1 || change0){
//change1=1是第1组仅找到$,而没有*
//change0=1连第一组的$都没找到,原始状态~~~啥玩意?
wanzhengdezushu=0;
//Serial.println(wanzhengdezushu);
}
}
//子程序数据处理2,进行异或运算的处理(对比校验码)
void shujuchuli2(){
//zifuweizhiB-zifuweizhiA-1;*号本身不参与异或运算,所以差值还要减1
for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
if(col==0)yihuoyunsuan=temp1;
else yihuoyunsuan=yihuoyunsuan ^ temp1;
}
//因为定义int的时候,yihuoyunsuan的结果是以10进制DEC表示的,所以需转换为16进制HEX
//因为GPS校验数据0位也进行了传输,所以在转换的时候有必要将情况分类讨论
//(yihuoyunsuan=0)/(0<yihuoyunsuan<17)/(17<yihuoyunsuan)
if(yihuoyunsuan==0){
//校验数10进制为0,直接填充字符串00
jianyan="00";
}else if(yihuoyunsuan>15){
//此时转换为16进制以后,天然有2位,很理想,不用处理
jianyan = String(yihuoyunsuan,HEX);
}else{
//校验数10进制为1-15时,转换为16进制就只有1位数,所以需要在前面填0
jianyan = "0";
jianyan += String(yihuoyunsuan,HEX);
}
//实践中发现,jianyan中的字符是以小写方式存在,虽然Serial.println(yihuoyunsuan,HEX)会以大写方式打印出来
//但直接Serial.println(jianyan)就是小写的,这是啥情况?
//将其字母转换为大写,否则与GPS传输的校验码对比时大小写问题校验失败(GPS传输的校验码为大写的)
jianyan.toUpperCase();
///////////////////////////////////////////显示异或校验码,方便给GPS编程,虽然还没成功过
//Serial.print("jianyan=");
//Serial.println(jianyan);
//与GPS传输的校验码进行对比
if(jianyan==temp1 && jianyan==temp1){
//一致,则说明数据是有效的,输出校验结果
jiaoyanjieguo=1;
}else{
//不一致
jiaoyanjieguo=0;
}
//对校验数组进行清零
jianyan="";
}
//子程序数据处理3,有效的字符串究竟是什么?以及相应的操作
void shujuchuli3(){
/*
常见的GPS发送字符串如下
$GPGGA,
$GPGLL,
$GPGSA,
$GPGST,
$GPGSV,
$GPRMC,
$GPVTG,
鉴于最后2位不同,所以用判断$+4、$+5 两个位置的字符来判断所收到的究竟是什么信息
*/
if(jiaoyanjieguo){
jiaoyanjieguo=0;//使用后则置0,以免影响后续计算
if(temp1=='G' && temp1=='A'){
//$GPGGA C3-470B有
for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){

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

memcpy(temp2+46,temp1+zifuweizhiA+1+weidubiaoji, 1);
//经度
memcpy(temp2+59,temp1+zifuweizhiA+weidubiaoji+3, 3);
memcpy(temp2+63,temp1+zifuweizhiA+weidubiaoji+6, 7);
memcpy(temp2+71,temp1+zifuweizhiA+1+jingdubiaoji, 1);
//可用卫星数
memcpy(temp2+85,temp1+zifuweizhiA+jingdubiaoji+5, 2);


//海拔计算
for(int col=0;col<13;col++) {
if(temp1==',' && !altitudeC){
altitudeA=col;
altitudeC=1;
col++;
}

if(temp1==',' && altitudeC){
altitudeB=col;
altitudeC=0;
//结束循环
col=13;
}
}

//海拔-999.9--9999.9
if(altitudeB-altitudeA-1==3){
temp2=32;//空格
temp2=32;
temp2=32;
memcpy(temp2+101,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 3);
}else if(altitudeB-altitudeA-1==4){
temp2=32;//空格
temp2=32;
memcpy(temp2+100,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 4);
}else if(altitudeB-altitudeA-1==5){
temp2=32;//空格
memcpy(temp2+99,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 5);
}else if(altitudeB-altitudeA-1==6){
memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, 6);
}
// memcpy(temp2+98,temp1+zifuweizhiA+jingdubiaoji+9+altitudeA, altitudeB-altitudeA-1);
}else{
//剩下的就是,未定位、正在估算,这2种情况都属于数据无意义,所以对输出数组的相应部分进行填充
dingweiok=0;//没有定位
temp2=95;//下划线,纬度
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
//////////////////////////////经度
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
//////////////////////////////卫星数、海拔
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
temp2=95;
}
}else if(temp1=='L' && temp1=='L'){
//$GPGLL
}else if(temp1=='S' && temp1=='A'){
//$GPGSA C3-470B有
}else if(temp1=='S' && temp1=='T'){
//$GPGST
}else if(temp1=='S' && temp1=='V'){
//$GPGSV C3-470B有
}else if(temp1=='M' && temp1=='C'){
//$GPRMC C3-470B有
///////////////////////////////////////////////////////////////////////////////////
//$GPRMC,143716.000,A,2936.49838,N,10634.13016,E,0.1,273.6,120314,2.1,W,A*13
//时间部分:UTC转为UTC+8,北京时间(时:分:秒)
//时:
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8s=jianyan.toInt()+8;
if(utc8s>23)rijinwei=1;//提示后面程序换算为北京时间的时候,日要+1天
utc8s=utc8s%24;//字符串转换为整数,参与运算
//分:
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8f=jianyan.toInt();//字符串转换为整数,参与运算
//秒:
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8m=jianyan.toInt();//字符串转换为整数,参与运算
////////////////////////////////////////////////
//提取UTC日期(日、月、年),这个日期位于GPRMC第9个数据中,所以定位第九个逗号的位置即可
jsq2=0;
jsq3=0;
jsq4=0;
jsq5=0;
for(int col=0;col<zifuweizhiB-zifuweizhiA-1;col++){
if(temp1==',')jsq2++;
if(jsq2==9){
jsq3=col;//找到9第个逗号的前一个位置,循环0开始,0的时候就已经后推了一位置
col=zifuweizhiB-zifuweizhiA;//找到9个逗号就跳出循环
}
if(jsq2<8){
jsq4=col;//找到8第个逗号的前2个位置,即“地面速率(节)”的最后一位
}
if(jsq2<7){
jsq5=col;//找到7第个逗号的前2个位置,即“经度标记”
}
}
//日
jianyan = String(temp1);//复用jianyan这个数组来节约内存,9第个逗号前一位后推2个位置
jianyan += temp1;
utc8r=jianyan.toInt();//字符串转换为整数,参与运算
//月
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8y=jianyan.toInt();//字符串转换为整数,参与运算
//年
jianyan = String(temp1);//复用jianyan这个数组来节约内存
jianyan += temp1;
utc8n=jianyan.toInt();//字符串转换为整数,参与运算
// 地面速率(000.0~999.9节、地面航向(000.0~359.9度
x=jsq4-jsq5-1;
//Serial.print("jsq4-jsq5=");
//Serial.println(x);
if(x==6){
memcpy(temp4+6,temp1+zifuweizhiA+jsq5+3, 6);//地面速率部分
}else if(x==5){
temp4=32;//空格
memcpy(temp4+7,temp1+zifuweizhiA+jsq5+3, 5);//地面速率部分
}else if(x==4){
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+8,temp1+zifuweizhiA+jsq5+3, 4);//地面速率部分
}else if(x==3){
temp4=32;//空格
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+9,temp1+zifuweizhiA+jsq5+3, 3);//地面速率部分
}else {//没数据的情况
temp4=32;//空格
temp4=32;//空格
temp4=95;//空格
temp4=95;//_
temp4=46;//.
temp4=95;//_
}
x=jsq3-jsq4-2;
//Serial.print("jsq3-jsq4=");
//Serial.println(x);
if(x==6){
memcpy(temp4+26,temp1+zifuweizhiA+jsq4+3, 6);// 地面航向部分
}else if(x==5){
temp4=32;//空格
memcpy(temp4+27,temp1+zifuweizhiA+jsq4+3, 5);//地面速率部分
}else if(x==4){
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+28,temp1+zifuweizhiA+jsq4+3, 4);//地面速率部分
}else if(x==3){
temp4=32;//空格
temp4=32;//空格
temp4=32;//空格
memcpy(temp4+29,temp1+zifuweizhiA+jsq4+3, 3);//地面速率部分
}else {//没数据的情况
temp4=32;//空格
temp4=32;//空格
temp4=95;//空格
temp4=46;//.
temp4=95;//_
temp4=95;//_
}
jsq2=0; //防止以后会用,先行清零
jsq3=0;
jsq4=0;
jsq5=0;
//讨论日、月、年进位(大月、小月、平年、闰年的问题)
if(rijinwei){
//先讨论2月的问题
if(utc8y==2 && utc8r==28){
if(utc8n%4==0)utc8r=29;//闰年可加一天
else {
utc8r=1;
yuejinwei=1;
}
}else{
//判断大小月
for(int col=0;col<4;col++){
if(xiaoyue==utc8y)xiaoyueok=1;
}
if(xiaoyueok && utc8r==30){ //小月最后一天
utc8r=1;
yuejinwei=1;
}else if(!xiaoyueok && utc8r==31){ //大月最后一天
utc8r=1;
yuejinwei=1;
}else{
utc8r++;//剩下的情况自加1就可以了
}
}
}
if(yuejinwei && utc8y==12){ //最后一月
utc8y=1;
nianjinwei=1;
}else if(yuejinwei){
utc8y++;
}
if(nianjinwei)utc8n++;
////////////////
//////////////////////////////////////////////////////////////////////////////////
}else if(temp1=='T' && temp1=='G'){
//$GPVTG
}
}
}
void printDateTime(DateTime dateTime) {
    //传送年份
nian=dateTime.year(), DEC;

    //传送月份
    yue=dateTime.month(), DEC;
    //传送月份中的第几天
ri=dateTime.day(), DEC;
    //传送小时
shi=dateTime.hour(), DEC;
    //传送分钟
fen=dateTime.minute(), DEC;
    //传送秒
miao=dateTime.second(), DEC;
}


void lcd1602out(){
jsq6=jsq6%4;

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

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

if(jsq8){
//蓝牙gps模式

if(jsq6==0){

temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='O';
temp3='U';
temp3='T';
temp3=32;
memcpy(temp3+8,temp2+16, 8);//时间部分(00/00 00:00:00)

}else if(jsq6==1){

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

temp3='G';
temp3='P';
temp3='S';
temp3=32;
memcpy(temp3+4,temp2+35, 12);//纬度部分纯数字
}else{
   //未定位的情况下,please wait
temp3=32;
temp3=32;
temp3='P';
temp3='l';
temp3='e';
temp3='a';
temp3='s';
temp3='e';
temp3=32;
temp3='w';
temp3='a';
temp3='i';
temp3='t';

}


}else if(jsq6==2){


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

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

}else{
   //未定位的情况下,please wait
temp3=32;
temp3=32;
temp3='P';
temp3='l';
temp3='e';
temp3='a';
temp3='s';
temp3='e';
temp3=32;
temp3='w';
temp3='a';
temp3='i';
temp3='t';

}

}else if(jsq6==3){


//空气质量检测模式


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



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

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

}



}else{

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

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

x=shishiliuliang;
x=x%10; //实时流量的个位
temp3=x+48, DEC;

temp3='.';//小数点

x=(shishiliuliang*10); //实时流量的十分位
x=x%10;
temp3=x+48, DEC;

temp3='L';
temp3='/';
temp3='m';
temp3='i';
temp3='n';
temp3=32;

temp3='S';
temp3='D';
temp3=':';

x=shedingjiaoguanliang*0.1; //设定浇灌量的十位
if(x==0) temp3=32;
else temp3=x+48, DEC;

x=shedingjiaoguanliang%10; //设定浇灌量的个位
temp3=x+48, DEC;


temp3='L';


}


   lcd.print(temp3);


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

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



   if(jsq8){
//蓝牙gps模式

if(jsq6==0){

if(dingweiok){ //已定位的情况下,显示卫星、海拔
temp3='n';
temp3='u';
temp3='m';

memcpy(temp3+3,temp2+84, 3);//卫星数部分(num:00)
temp3=32;
temp3=32;
memcpy(temp3+8,temp2+98, 8);//海拔部分( 000.0 M)
}else{
//未定位的情况下,Search GPS ing..
    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}


}else if(jsq6==1){

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

temp3=32;
temp3=32;
temp3=32;
memcpy(temp3+3,temp2+59, 13);//经度部分纯数字

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

    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}


}else if(jsq6==2){


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

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

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

    temp3='S';
temp3='e';
temp3='a';
temp3='r';
temp3='c';
temp3='h';
temp3=32;
temp3='G';
temp3='P';
temp3='S';
temp3=32;
temp3='i';
temp3='n';
temp3='g';
    temp3='.';
temp3='.';

}

}else if(jsq6==3){

//空气质量检测模式

   memcpy(temp3,temp2+125, 7);//湿度、温度;
temp3=32;
memcpy(temp3+8,temp2+117, 7);//gp2y1010

   
}



}else{

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

temp3='T';
temp3='o';
temp3='t';
temp3='a';
temp3='l';
temp3=':';

x=leijiliuliang*0.1; //累计流量的十位
if(x==0) temp3=32;
else temp3=x+48, DEC;

x=leijiliuliang; //累计流量的个位
x=x%10; //累计流量的个位
temp3=x+48, DEC;

temp3='.';

x=leijiliuliang*10; //累计流量的十分位
x=x%10; //累计流量的十分位
temp3=x+48, DEC;


x=leijiliuliang*100; //累计流量的百分位
   x=x%10;
temp3=x+48, DEC;

temp3=32;
temp3='L';

}


   lcd.print(temp3);



}



void jiaohuaA(){

if(millis()-meimiaoyilunhui>1000) {

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

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

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

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

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

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

}

void jiaohuaB(){

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


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

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

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

}

}



MoonShine 发表于 2015-12-8 15:26:55

干货,顶一个,楼主辛苦了

ncyaoyi 发表于 2016-2-14 21:58:33

特来学习。
页: [1]
查看完整版本: 很久没来,arduino都积灰了,oled屏线也断了,各种杯具,放张图+一个程序