标题:
最简GPS数据接收程序
[打印本页]
作者:
dingmingzhou
时间:
2015-6-2 16:33
标题:
最简GPS数据接收程序
本帖最后由 dingmingzhou 于 2015-7-14 14:20 编辑
写在前面的话:一段时间以来,以8051为对象学单片机。有写感受,写出来和大家共商酌。一开始我也是从流水灯、数码管、1602、12864一路赶来,感觉单片机这玩意,就是“SWRD”这几下子:S(Set):设置--设置寄存器、变量……;W(Wrte):就是写数据写命令;R(Read):就是读数据;D(display):就是显示.也没神魔大意思,但是,遵从规则--器件和C语言规则是必须的,头疼人的时候,都是这“规则”闹得,把他拿下,多半就艳阳天了。
最近俺看上TFT彩屏了,还没研究出个啥来,不多啰嗦,估计也离不开 SWRD这几下子。
GPS,没接触前,感觉这东西可是一个“高、大、上”的东西。神妙莫测,没出下手----卫星在天上呢!其实有了GPS模块,研究了一下材料(2天呀),没想到,这东西比DS18B20\DS1302都好搞---就是串口以4800(或9600)比特率输出一串串格式化的ASCII串,且每秒钟更新一次。呵呵。处理这个字符串基本有两种法子:一是:”下载“整串,在进行复制、截取、转换;二是”单抠“有用的、想要的东西。鉴于51单片机片内RAM的拮据、处理浮点数的囧态,下面贴上来的程序是按第二种法子做的。说明如下:
1、只”抠“经纬度及方向、海拔、速度、时间、日期、方位角这几项
2、定义单项的字符数组,分别赋值,并规整成 通常的格式,以便显示时,顺序显示字符数组元素。
3、本程序仅是数据包解析部分,显示函数没写,想着把TFT搞懂了,显在那上边,过一把瘾。
4、程序是按照我自己的理解去写的、也去参考别人的。或有BUG多多,不反对拍砖。
程序清单
作者:
dingmingzhou
时间:
2015-6-2 17:27
本帖最后由 dingmingzhou 于 2015-7-14 14:23 编辑
#include<reg52.h>
#define uchar unsigned char
#define uint unsigned int
/***********GPS数据存储数组***********/
uchar JD[10]; //经度准备存为***.**.**. 形式,
uchar JD_a; //经度方向
uchar WD[9]; //纬度准备存为**.**.**.形式,
uchar WD_a; //纬度方向
uchar date[9];//日期准备存为**-**-** 形式
uchar time[9];//时间准备存为**:**:** 形式。
uchar speed[6];//速度准备存为 ***.*形式
uchar high[8];//高度准备存为 ****.* 形式
uchar angle[6]; //方位角准备存为 ***.* 形式
bit lock; //定位状态 0 ,1
/*********串口中断及数据处理需要的变量***********/
uchar tmp; //串口数据缓冲
uchar seg_count; //逗号计数器
uchar byte_count; //位数计数器
uchar cmd_number; //命令类型 0:无效;1:GGA;2:RMC
uchar mode; //0:结束模式,1:命令模式,2:数据模式
uchar buf_full=0; //设定语句接收完成,相应数据有效。0:无效。
uchar cmd[5]; //命令内容存储数组
/****************** 系统初始化*************/
void sys_init()
{
SCON = 0x50; /* 定时器1 M0=0,M1=1,REN=1 */
TMOD = 0x20; /* TMOD: 定时器1模式2自动重装*/
TH1 = 0xfa; /* 11.0592MHZ 波特率4800*/
TL1 = 0xfa;
ES=1;
TR1=1;
EA=1;
}
/****************** 显示函数*************/
void display()
{
;
}
/****************** 主函数********************/
main()
{
uchar Bhh,Bdd,Bmm,Byy; //格伦威治时间转换为北京时间变量
unsigned long mn; //定义经度纬度局部变量
uint mnn;
sys_init(); //系统初始化
while(1)
{
switch(tmp) //传来的数据(即ASCII码,一个ASCII码是8位,一个字节)进行对号入座
{
case ': //起始符
cmd_number=0; //命令类型清空
mode=1; //接收命令模式 0:结束模式,1:命令模式,2:数据模式
byte_count=0; //接收位数清空,位数计数器=0;标记一种(如高度、速度等)数据多少位
break;
case ',': //分隔符,它分隔各种数据
seg_count++; //逗号计数加1 ,一个”,”号前是一个有效数据
byte_count=0; //接收位数清空
break;
case '*': //一旦遇到*, 如下处理:
switch(cmd_number) //命令类型共2种???
{
case 1: {buf_full|=0x01; break;}//或上的0x01标志第1种命令
case 2: {buf_full|=0x04; break;}//或上的0x04标志第2种命令
}
mode=0; //结束模式
while(buf_full==0x05) //如果GGA和RMC语句都解析完成。
{
EA=0; REN=0; // 显示时关中断和串口接收,
buf_full=0; //为下一个循环做准备
display(); //显示函数。
EA=1; REN=1; // 显示完成再打开中断和串口。
}
break; //跳出 switch(tmp)去重新寻找“$”符号。
default: //到这里是tmp不等于“*”和“,”及“$”的情况下。
if(mode==1) //判断命令种类
{
cmd[byte_count]=tmp; //接收字符放入类型缓存
if(byte_count>=4) //如果类型数据接收完毕,只判断语句名
{
if((cmd[2]=='G')&&(cmd[3]=='G')&&(cmd[4]=='A'))
{
cmd_number=1; //GGA
mode=2;
seg_count=0;
byte_count=0;
}
if((cmd[2]=='R')&&(cmd[3]=='M')&&(cmd[4]=='C'))
{
cmd_number=2; //RMC
mode=2;
seg_count=0;
byte_count=0;
}
}
}else if(mode==2)
{
switch (cmd_number)
{
case 1: //接收GPGGA
if((seg_count==9)&&(byte_count<7))high[byte_count]=tmp;//高度是7位
high[byte_count+1] ='\0'; //高度输出的位数不固定,但byte_count+1个元素一定应该加'\0'.
break; //跳出 switch (cmd_number)
case 2: //接收GPRMC
switch(seg_count)
{
case 1: //UTC时间暂存
if(byte_count<6)time[byte_count]=tmp;
break;
case 2: //定位判断
if(byte_count<1) //状态
{ if (tmp=='A') lock=1; else lock=0; }
break;
case 3: //纬度处理小数点后的数据
if(byte_count<9)WD[byte_count]=tmp;
if(byte_count==8)
{
mn=((WD[5]-'0')*1000+(WD[6]-'0')*100+(WD[7]-'0')*10+(WD[8]-'0'))*60; //仅处理4位小数位
mnn=mn/10000;
WD[3]=WD[2];
WD[4]=WD[3];
WD[2]='.';
WD[5]='.';
WD[6]= mnn/10+'0';
WD[7]= mnn%10+'0';
WD[8]= '\0';
}
break;
case 4: //纬度方向处理
if(byte_count<1)WD_a=tmp;
break;
case 5: //经度处理小数点后的数据
if(byte_count<10) JD[byte_count]=tmp;
if(byte_count==9)
{
mn=((JD[6]-'0')*1000+(JD[7]-'0')*100+(JD[8]-'0')*10+(JD[9]-'0'))*60; //仅处理4位小数位
mnn=mn/10000;
JD[4]=JD[3];
JD[5]=JD[4];
JD[3]='.';
JD[6]='.';
JD[7]=mnn/10+'0';
JD[8]=mnn%10+'0';
JD[9]='\0';
}
break;
case 6: //经度方向处理
if(byte_count<1)JD_a=tmp;
break;
case 7: //速度是格式输出 //本量程处理于540节以下即1000公里/小时以内,一位小数点。
if(byte_count<5)speed[byte_count]=tmp;
if(byte_count==4)
{
mn=((speed[0]-'0')*1000+(speed[1]-'0')*100+(speed[2]-'0')*10+(speed[4]-'0'))*185;
mnn=mn/100; // 此时速度仍然被扩大了10倍。
if(mnn/1000==0)speed[0]=0x20; //高位消隐
else speed[0]=mnn/1000+'0';
if((mnn/1000==0)&&((mnn%1000 )/100)==0)speed[1]=0x20;//高位消隐
else speed[1]=(mnn%1000 )/100+'0';
if(((mnn/1000==0)&&((mnn%1000 )/100)==0)&&((mnn%100)/10==0))speed[2]=0x20; //高位消隐
else speed[2]=(mnn%100)/10+'0';
speed[4]=mnn%10+'0'; // 小数位
speed[5]='\0';
}
break;
case 8: //方位角处理
if(byte_count<5) angle[byte_count]=tmp;
angle[5]='\0';
break;
case 9: //日期处理
if(byte_count<6)date[byte_count]=tmp;
if( byte_count==5)
{
Bhh=((time[0]-'0')*10+time[1]-'0')+8;//加8小时转换北京时间 加8小时会影响日期,故需调整
Bdd=(date[0]-'0')*10+(date[1]-'0');
Bmm=(date[2]-'0')*10+(date[3]-'0');
Byy=(date[4]-'0')*10+(date[5]-'0');
if(Bhh>23)
{
Bhh-=24;
Bdd+=1;
if(Bmm==2&&Bmm==4&&Bmm==6&&Bmm==9&&Bmm==11)
{
if(Bdd>30){Bdd=1; Bmm++;}
} else if(Bdd>31){ Bdd=1; Bmm++;}
if(Byy % 4 == 0 )
{
if(Bdd > 29 && Bmm ==2){ Bdd=1;Bmm++; } //闰年的二月是29天
} else if(Bdd>28 &&Bmm ==2){Bdd=1;Bmm++;}
if(Bmm>12){Bmm-=12;Byy++;}
}
/*以下重新整理time[]和date[]数组*/
time[0]=Bhh/10+'0'; //把日期数组整理成 hh:mm:ss
time[1]=Bhh%10+'0';
time[3]=time[2];
time[4]=time[3];
time[2]=':';
time[6]=time[4];
time[7]=time[5];
time[5]=':';
time[8]='\0';
date[0]=Byy/10+'0';//把日期数组整理成 yy-mo-dd
date[1]=Byy%10+'0';
date[2]='-';
date[3]=Bmm/10+'0';
date[4]=Bmm%10+'0';
date[5]='-';
date[6]=Bdd/10+'0';
date[7]=Bdd%10+'0';
date[8]='\0';
}
break;
default: break;
}
break; //跳出 switch (cmd_number)
}
}
byte_count++; //接收数位加1
break; //跳出 switch(tmp)
}
}
}
/****************** 中断服务函数*************/
void uart(void) interrupt 4 //串口接收中断
{
tmp=SBUF;
RI=0;
}
/********************************************/
复制代码
作者:
Sandra
时间:
2017-12-20 15:25
这个就是拿液晶屏能显示的程序吗
作者:
tieq1952
时间:
2017-12-22 15:20
学习了
作者:
lizuimo
时间:
2017-12-23 15:13
可不可以把原工程发上来呀
作者:
jackykele
时间:
2018-1-27 16:31
正要学习这方面的东西
作者:
qjzyx
时间:
2018-1-28 11:48
谢谢分享
作者:
jackykele
时间:
2018-1-30 09:22
好资料,学习一下,谢谢分享
作者:
bayga456
时间:
2018-2-5 23:52
学习了,总结的在理。
作者:
钱情锦绣
时间:
2019-1-5 14:35
只有GPS天线搞出来才高大上,有模块不是什么问题
作者:
Royal丶豪
时间:
2019-1-14 19:33
第一个CASE 为什么会报错
欢迎光临 (http://www.51hei.com/bbs/)
Powered by Discuz! X3.1