尝试DIY一个空气净化器 (7) 尝试为控制器加上GPS授时
测试程序1:功能:小内存提取GPS中的2行数据
优点:理论可行,小于350字节一次性发送无误,实际上GPS测试也无误
缺点:严格测试(650字节)一次性发送,GPRMC收不到,估计是延迟上有问题,且没有做校验
char temp1,GPGGA,GPRMC;
String test1= "";
int jsq1,jsq2,jsq3;
boolean change0,change1,change2,change3;
void setup() {
Serial.begin(9600);
}
void loop() {
jsq1=0;
jsq2=0;
jsq3=0;
change0=0;
change1=0;
change2=0;
change3=0;
while (Serial.available() > 0) {//监听串口输入
change0=1;
if(!change1){
if(jsq1<4){
temp1=Serial.read();
delayMicroseconds(1200);
jsq1++; //jsq1最终值为4,temp1:0-4共计5个字节
if(jsq1==4){//值得注意的是,此时,temp1并没有赋值
temp1=Serial.read(); //为temp1赋值
delayMicroseconds(1200);
panduan1();//此时,收集到5个字符,可以进行判断
}
}else{
//传递过程,temp1只有5个字节
temp1=temp1;
temp1=temp1;
temp1=temp1;
temp1=temp1;
temp1=Serial.read();
delayMicroseconds(1200);
panduan1();
}
///////////////////////////////////////////////////////////////////////////
}else if(change2){
//GPGGA
GPGGA=Serial.read();
delayMicroseconds(1200);
if(GPGGA=='*'){ //GPGGA字符串的结束
change1=0;//恢复以前的状态,继续由临时数组temp1判断
change2=0;//不再执行这段代码
jsq1=0;//计数器1还原
}else jsq1++;
//////////////////////////////////////////////////////////////////////////
}else if(change3){
//GPRMC
GPRMC=Serial.read();
delayMicroseconds(1200);
if(GPRMC=='*'){
change1=0;//恢复以前的状态,继续由临时数组temp1判断
change2=0;//不再执行这段代码
jsq1=0;//计数器1还原
}else jsq1++;
}
}
//最后的收尾工作
if(change0){
Serial.print("GPGGA=");
Serial.println(GPGGA);
Serial.print("GPRMC=");
Serial.println(GPRMC);
Serial.println("----------------------");
//置0
for(int col=0;col<80;col++)GPGGA=0;
for(int col=0;col<80;col++)GPRMC=0;
}
}
void panduan1(){
//清空字符串,且数组转字符串
//神奇的地球,数组==“字符串”貌似不能成立
test1 = "";
test1 += temp1;
test1 += temp1;
test1 += temp1;
test1 += temp1;
test1 += temp1;
if(test1=="GPGGA"){//字符串GPGGA
Serial.println("find GPGGA");
change1=1;
change2=1;
change3=0;
//交接工作,接下来的数据都会给GPGGA
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
jsq1=5;
}else if(test1=="GPRMC"){//字符串GPRMC
Serial.println("find GPRMC");
change1=1;
change2=0;
change3=1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
jsq1=5;
}
} 提个问题:空气净化器应该在屋子里使用吧?gps 能工作正常么? zoologist 发表于 2014-3-31 19:35 static/image/common/back.gif
提个问题:空气净化器应该在屋子里使用吧?gps 能工作正常么?
空气净化器的控制模块与净化器是可以分离的,以无线进行连接,所以,控制器本身可以充当空气质量检测器~~
PS:考窗边的话,GPS可以定位~~~获得时间就更不在话下 程序2,加入异或校验:
char temp1,GPGGA,GPRMC;
String test1= "";
int jsq1,jsq2,jsq3;
boolean change1,change2,change3;
int GPGGAlong,GPRMClong;//GPGGA、GPRMC的长度
int yihuoyunsuan;
boolean jiaoyanjieguoA,jiaoyanjieguoB;
void setup() {
Serial.begin(9600);
}
void loop() {
jsq1=0;
jsq2=0;
jsq3=0;
change1=0;
change2=0;
change3=0;
GPGGAlong=0;
GPRMClong=0;
jiaoyanjieguoA=0;
jiaoyanjieguoB=0;
while (Serial.available() > 0) {//监听串口输入
if(!change1){
if(jsq1<4){
temp1=Serial.read();
delayMicroseconds(1200);
jsq1++; //jsq1最终值为4,temp1:0-4共计5个字节
if(jsq1==4){//值得注意的是,此时,temp1并没有赋值
temp1=Serial.read(); //为temp1赋值
delayMicroseconds(1200);
panduan1();//此时,收集到5个字符,可以进行判断
}
}else{
//传递过程,temp1只有5个字节
temp1=temp1;
temp1=temp1;
temp1=temp1;
temp1=temp1;
temp1=Serial.read();
delayMicroseconds(1200);
panduan1();
}
///////////////////////////////////////////////////////////////////////////
}else if(change2){
//GPGGA
GPGGA=Serial.read();
delayMicroseconds(1200);
if(GPGGA=='*'){ //GPGGA字符串的结束
change1=0;//恢复以前的状态,继续由临时数组temp1判断
change2=0;//不再执行这段代码
GPGGAlong=jsq1-2;//记录这段字符串的长度GPGGAlong=jsq1-3+1(0位有一个字节)
jsq1=0;//计数器1还原
}else jsq1++;
//////////////////////////////////////////////////////////////////////////
}else if(change3){
//GPRMC
GPRMC=Serial.read();
delayMicroseconds(1200);
if(GPRMC=='*'){
change1=0;//恢复以前的状态,继续由临时数组temp1判断
change2=0;//不再执行这段代码
GPRMClong=jsq1-2;
jsq1=0;//计数器1还原
}else jsq1++;
}
}
/////////////////////////////////////////////////////异或运算,验证其数据可信
if(GPGGAlong>0){ //字符串GPGGA的验证
for(int col=0;col<GPGGAlong;col++){
if(col==0)yihuoyunsuan=GPGGA;
else yihuoyunsuan=yihuoyunsuan ^ GPGGA;
}
panduan2();
if(test1==GPGGA && test1==GPGGA){
//一致,则说明数据是有效的,输出校验结果
jiaoyanjieguoA=1;
}else{
//不一致
jiaoyanjieguoA=0;
}
}
if(GPRMClong>0){//字符串GPRMC的验证
for(int col=0;col<GPRMClong;col++){
if(col==0)yihuoyunsuan=GPRMC;
else yihuoyunsuan=yihuoyunsuan ^ GPRMC;
}
panduan2();
if(test1==GPRMC && test1==GPRMC){
//一致,则说明数据是有效的,输出校验结果
jiaoyanjieguoB=1;
}else{
//不一致
jiaoyanjieguoB=0;
}
}
/////////////////////////////////////////////////
if(jiaoyanjieguoA && jiaoyanjieguoB){
Serial.print("GPGGA=");
Serial.println(GPGGA);
Serial.print("GPRMC=");
Serial.println(GPRMC);
Serial.println("----------------------");
}
//最后的收尾工作
if(GPRMClong>0 || GPGGAlong>0){
//置0
for(int col=0;col<80;col++)GPGGA=0;
for(int col=0;col<80;col++)GPRMC=0;
}
}
void panduan1(){ //找到特定字符串的开始
//清空字符串,且数组转字符串
//神奇的地球,数组==“字符串”貌似不能成立
test1 = "";
test1 += temp1;
test1 += temp1;
test1 += temp1;
test1 += temp1;
test1 += temp1;
if(test1=="GPGGA"){//字符串GPGGA
Serial.println("find GPGGA");
change1=1;
change2=1;
change3=0;
//交接工作,接下来的数据都会给GPGGA
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
jsq1=5;
}else if(test1=="GPRMC"){//字符串GPRMC
Serial.println("find GPRMC");
change1=1;
change2=0;
change3=1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
jsq1=5;
}
}
void panduan2(){ //异或运算的结果转化为字符串,以便于比较
if(yihuoyunsuan==0){
//校验数10进制为0,直接填充字符串00
test1="00";
}else if(yihuoyunsuan>15){
//此时转换为16进制以后,天然有2位,很理想,不用处理
test1 = String(yihuoyunsuan,HEX);
}else{
//校验数10进制为1-15时,转换为16进制就只有1位数,所以需要在前面填0
test1 = "0";
test1 += String(yihuoyunsuan,HEX);
}
test1.toUpperCase();//将其字母转换为大写
} hi55234 发表于 2014-3-31 21:52 static/image/common/back.gif
空气净化器的控制模块与净化器是可以分离的,以无线进行连接,所以,控制器本身可以充当空气质量检测器~~ ...
有道理,不错啊
GPStest:14/4/1 22:55:12
altitude= 255
weixingshu= 5
latitude= latitude:xxxx.xxxx N
longitude= longitude:xxxxx.xxxx E
仅适用于经纬度小数点后4位的情况,如果是5位的,则要做相应的修改
至于通用的又要复杂一点,要判断逗号的位置,类似于提取年月日的过程(部分数据长度不确定),所以,这里以节约资源的名义偷工减料了
char temp1,GPGGA,GPRMC;
String test1= "";
String latitude = ""; //纬度
String longitude = ""; //经度
int jsq1,jsq2,jsq3;
boolean change1,change2,change3;
int GPGGAlong,GPRMClong;//GPGGA、GPRMC的长度
int yihuoyunsuan;
boolean jiaoyanjieguoA,jiaoyanjieguoB;
//UTC +8(北京时间)时、分、秒、年、月、日
int utc8s,utc8f,utc8m,utc8n,utc8y,utc8r;
//小月的数组
int xiaoyue={4,6,9,11};
//日进位,月进位,年进位,大小月判断值
boolean rijinwei,yuejinwei,nianjinwei,xiaoyueok;
boolean dingweiok;//定位ok
int weixingshu;//有效卫星数
int altitude; //海拔
void setup() {
Serial.begin(9600);
}
void loop() {
jsq1=0;
jsq2=0;
jsq3=0;
change1=0;
change2=0;
change3=0;
GPGGAlong=0;
GPRMClong=0;
jiaoyanjieguoA=0;
jiaoyanjieguoB=0;
//日进位,月进位
rijinwei=0;
yuejinwei=0;
nianjinwei=0;
xiaoyueok=0;
dingweiok=0;//默认未定位
weixingshu=0;//有效卫星数
altitude=0; //海拔
while (Serial.available() > 0) {//监听串口输入
if(!change1){
if(jsq1<4){
temp1=Serial.read();
delayMicroseconds(1200);
jsq1++; //jsq1最终值为4,temp1:0-4共计5个字节
if(jsq1==4){//值得注意的是,此时,temp1并没有赋值
temp1=Serial.read(); //为temp1赋值
delayMicroseconds(1200);
panduan1();//此时,收集到5个字符,可以进行判断
}
}else{
//传递过程,temp1只有5个字节
temp1=temp1;
temp1=temp1;
temp1=temp1;
temp1=temp1;
temp1=Serial.read();
delayMicroseconds(1200);
panduan1();
}
///////////////////////////////////////////////////////////////////////////
}else if(change2){
//GPGGA
GPGGA=Serial.read();
delayMicroseconds(1200);
if(GPGGA=='*'){ //GPGGA字符串的结束
change1=0;//恢复以前的状态,继续由临时数组temp1判断
change2=0;//不再执行这段代码
GPGGAlong=jsq1-2;//记录这段字符串的长度GPGGAlong=jsq1-3+1(0位有一个字节)
jsq1=0;//计数器1还原
}else jsq1++;
//////////////////////////////////////////////////////////////////////////
}else if(change3){
//GPRMC
GPRMC=Serial.read();
delayMicroseconds(1200);
if(GPRMC=='*'){
change1=0;//恢复以前的状态,继续由临时数组temp1判断
change2=0;//不再执行这段代码
GPRMClong=jsq1-2;
jsq1=0;//计数器1还原
}else jsq1++;
}
}
/////////////////////////////////////////////////////异或运算,验证其数据可信
if(GPGGAlong>0){ //字符串GPGGA的验证
for(int col=0;col<GPGGAlong;col++){
if(col==0)yihuoyunsuan=GPGGA;
else yihuoyunsuan=yihuoyunsuan ^ GPGGA;
}
panduan2();
if(test1==GPGGA && test1==GPGGA){
//一致,则说明数据是有效的,输出校验结果
jiaoyanjieguoA=1;
}else{
//不一致
jiaoyanjieguoA=0;
}
}
if(GPRMClong>0){//字符串GPRMC的验证
for(int col=0;col<GPRMClong;col++){
if(col==0)yihuoyunsuan=GPRMC;
else yihuoyunsuan=yihuoyunsuan ^ GPRMC;
}
panduan2();
if(test1==GPRMC && test1==GPRMC){
//一致,则说明数据是有效的,输出校验结果
jiaoyanjieguoB=1;
}else{
//不一致
jiaoyanjieguoB=0;
}
}
/////////////////////////////////////////////////
if(jiaoyanjieguoA && jiaoyanjieguoB){ //要求GPGGA、GPRMC同时通过奇偶验证才能进行下一步
gpstime(); //gps时间提取,日月年、时分秒、转为北京时间
Serial.println(test1);//这个字符串是gpstime
jingduweidu();//拾取经度、维度
if(dingweiok)haiba();//在定位有效的情况下拾取海拔、有效卫星数
Serial.print("altitude= ");
Serial.println(altitude);
Serial.print("weixingshu= ");
Serial.println(weixingshu);
Serial.print("latitude= ");
Serial.println(latitude);
Serial.print("longitude= ");
Serial.println(longitude);
Serial.print("GPGGA=");
Serial.println(GPGGA);
Serial.print("GPRMC=");
Serial.println(GPRMC);
Serial.println("----------------------");
}
//最后的收尾工作
if(GPRMClong>0 || GPGGAlong>0){
//置0
for(int col=0;col<80;col++)GPGGA=0;
for(int col=0;col<80;col++)GPRMC=0;
}
}
void panduan1(){ //找到特定字符串的开始
//清空字符串,且数组转字符串
//神奇的地球,数组==“字符串”貌似不能成立
test1 = String(temp1);
test1 += temp1;
test1 += temp1;
test1 += temp1;
test1 += temp1;
if(test1=="GPGGA"){//字符串GPGGA
// Serial.println("find GPGGA");
change1=1;
change2=1;
change3=0;
//交接工作,接下来的数据都会给GPGGA
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
GPGGA=temp1;
jsq1=5;
}else if(test1=="GPRMC"){//字符串GPRMC
//Serial.println("find GPRMC");
change1=1;
change2=0;
change3=1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
GPRMC=temp1;
jsq1=5;
}
}
void panduan2(){ //异或运算的结果转化为字符串,以便于比较
if(yihuoyunsuan==0){
//校验数10进制为0,直接填充字符串00
test1="00";
}else if(yihuoyunsuan>15){
//此时转换为16进制以后,天然有2位,很理想,不用处理
test1 = String(yihuoyunsuan,HEX);
}else{
//校验数10进制为1-15时,转换为16进制就只有1位数,所以需要在前面填0
test1 = "0";
test1 += String(yihuoyunsuan,HEX);
}
test1.toUpperCase();//将其字母转换为大写
}
void gpstime(){
//时间部分:UTC转为UTC+8,北京时间(时:分:秒)
//时:
test1 =String(GPRMC);//复用test1这个数组来节约内存
test1 +=GPRMC;
utc8s=test1.toInt()+8;
if(utc8s>23)rijinwei=1;//提示后面程序换算为北京时间的时候,日要+1天
utc8s=utc8s%24;//字符串转换为整数,参与运算
//分:
test1 =String(GPRMC);//复用test1这个数组来节约内存
test1 +=GPRMC;
utc8f=test1.toInt();//字符串转换为整数,参与运算
//秒:
test1 =String(GPRMC);//复用test1这个数组来节约内存
test1 +=GPRMC;
utc8m=test1.toInt();//字符串转换为整数,参与运算
////////////////////////////////////////////////
//提取UTC日期(日、月、年),这个日期位于GPRMC第9个数据中,所以定位第九个逗号的位置即可
jsq2=0;
jsq3=0;
for(int col=0;col<80;col++){
if(GPRMC==',')jsq2++;
if(jsq2==9){
jsq3=col;//找到9第个逗号的前一个位置,循环0开始,0的时候就已经后推了一位置
col=80;//找到9个逗号就跳出循环
}
}
//日
test1 =String(GPRMC);//复用test1这个数组来节约内存,9第个逗号前一位后推2个位置
test1 +=GPRMC;
utc8r=test1.toInt();//字符串转换为整数,参与运算
//月
test1 =String(GPRMC);//复用test1这个数组来节约内存
test1 +=GPRMC;
utc8y=test1.toInt();//字符串转换为整数,参与运算
//年
test1 =String(GPRMC);//复用test1这个数组来节约内存
test1 +=GPRMC;
utc8n=test1.toInt();//字符串转换为整数,参与运算
jsq2=0; //防止以后会用,先行清零
jsq3=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++;
////////////////
test1 = "GPStest:";
test1 += utc8n;
test1 += "/";
test1 += utc8y;
test1 += "/";
test1 += utc8r;
test1 += " ";
test1 += utc8s;
test1 += ":";
test1 += utc8f;
test1 += ":";
test1 += utc8m;
}
void jingduweidu(){
if(GPRMC=='A'){//已定位
dingweiok=1;//已定位
latitude = "latitude:"; //纬度
for(int col=19;col<28;col++) latitude += GPRMC;
latitude += " ";
latitude += GPRMC;
longitude = "longitude:"; //经度
for(int col=31;col<41;col++)longitude += GPRMC;
longitude += " ";
longitude += GPRMC;
}
}
void haiba(){
//有效卫星数
test1 =String(GPGGA);
test1 +=GPGGA;
weixingshu=test1.toInt();//字符串转换为整数,参与运算
//海拔
//找到开始的逗号,与结束的逗号位置
for(int col=47;col<64;col++){
if(GPGGA==',' && jsq2==0)jsq2=col;//海拔开始的逗号
if(col>jsq2){
if(GPGGA==','){
jsq3=col;//海拔结束的逗号
col=64;//跳出循环
}
}
}
//拾取海拔高度
for(int col=jsq2+1;col<jsq3;col++){
if(col==jsq2+1)test1 =String(GPGGA);
else test1 +=GPGGA;
}
altitude=test1.toInt();//字符串转换为整数,参与运算;
}
可以在蓝牙gps、空气检测模块之间切换
页:
[1]