找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2585|回复: 10
打印 上一主题 下一主题
收起左侧

如何使GPS的经纬度实时刷新(1秒刷新1次)附单片机程序

[复制链接]
跳转到指定楼层
楼主
ID:284050 发表于 2021-9-1 23:28 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
我在网上找了一些解析GPS的程序,并用OLED显示出来。目前可以做到解析和显示,但做不到实时刷新。请高手指点一下。谢谢
IIC的程序就不贴出来了。
单片机源程序如下:
  1. #include <reg51.h>
  2. #include "iic_oled.h"


  3. #define u8 unsigned char
  4. #define u16 unsigned int
  5. #define u32 unsigned long

  6. u8 RX_Buffer[68];                //此数组用于直接储存来自GPS的原始数据
  7. u8 RX_Count = 0;
  8. //u8 Hour = 0,Min_High = 0,Min_Low = 0,Sec_High = 0,Sec_Low = 0;
  9. u8 Month = 0,Day = 0,Month_High = 0, Month_Low = 0,Day_Low = 0 ,Day_High = 0, Year_High = 0,Year_Low = 0;
  10. u16 Year = 0;
  11. bit Flag_GPS_OK = 0;
  12. u8 MaxDay = 0;


  13. u8 xdata Display_GPGGA_Buffer[68]={0};                //用于储存GPGGA的数据




  14. bit Flag_Calc_GPGGA_OK = 0;           //GPGGA完整有效的数据已收到的标志变量


  15. void Uart_Init();
  16. u8 GetMaxDay(u8 Month_Value,u16 Year_Value);
  17. bit IsLeapYear(u16 uiYear);
  18. void Delay500ms()        ;



  19. //****************************************************
  20. //主函数
  21. //****************************************************
  22. void main()
  23. {
  24.         u16 i = 0;

  25.         Uart_Init();                                                                        //串口初始化
  26.         OLED_Init();//初始化OLED
  27.   OLED_Clear();//清屏

  28.         while(1)
  29.         {



  30.                 if (   Flag_GPS_OK  == 1         && RX_Buffer[4] == 'G'
  31.                         && RX_Buffer[6] == ','   && RX_Buffer[13] == '.'
  32.                     )                //确认是否收到"GPGGA"这一帧完整有效的数据
  33.                 {
  34.                         for( i = 0; i < 67 ; i++)                                                  //必须为i<67,因为要确保Display_GPGGA_Buffer[67]为'\0',便于串口发送
  35.                         {
  36.                                 Display_GPGGA_Buffer[i] = RX_Buffer[i];                  //储存到数组中
  37.                         }
  38.                         Flag_Calc_GPGGA_OK = 1;                                                          //收到完整有效数据后,置为1
  39.                         
  40.                 }
  41.                 if(Display_GPGGA_Buffer[28] == 'N')
  42.                 {
  43.                 OLED_ShowChar(0, 0, 'G');
  44.                 OLED_ShowChar(8, 0, 'P');
  45.                 OLED_ShowChar(16, 0, 'S');
  46.                 OLED_ShowChar(24, 0, ':');
  47.                         
  48.                 OLED_ShowChar(0, 2, Display_GPGGA_Buffer[28]);//N
  49.                 OLED_ShowChar(8, 2, ':'); //:
  50.                 OLED_ShowChar(16, 2, Display_GPGGA_Buffer[17]);               
  51.                 OLED_ShowChar(24, 2, Display_GPGGA_Buffer[18]);
  52.                 OLED_ShowChar(32, 2, 127);               
  53.                 OLED_ShowChar(40, 2, Display_GPGGA_Buffer[19]);
  54.                 OLED_ShowChar(48, 2, Display_GPGGA_Buffer[20]);        
  55.                 OLED_ShowChar(56, 2, '.');        
  56.                 OLED_ShowChar(64, 2, Display_GPGGA_Buffer[22]);        
  57.                 OLED_ShowChar(72, 2, Display_GPGGA_Buffer[23]);                        
  58.                 OLED_ShowChar(80, 2, Display_GPGGA_Buffer[24]);                        
  59.                 OLED_ShowChar(88, 2, Display_GPGGA_Buffer[25]);                        
  60.                 OLED_ShowChar(96, 2, Display_GPGGA_Buffer[26]);                                
  61.                 OLED_ShowChar(104, 2, 39);               
  62.                
  63.                 OLED_ShowChar(0, 4, Display_GPGGA_Buffer[42]);//E
  64.                 OLED_ShowChar(8, 4, ':'); //:
  65.                 OLED_ShowChar(16, 4, Display_GPGGA_Buffer[30]);               
  66.                 OLED_ShowChar(24, 4, Display_GPGGA_Buffer[31]);
  67.           OLED_ShowChar(32, 4, Display_GPGGA_Buffer[32]);
  68.                 OLED_ShowChar(40, 4, 127);               
  69.                 OLED_ShowChar(48, 4, Display_GPGGA_Buffer[33]);
  70.                 OLED_ShowChar(56, 4, Display_GPGGA_Buffer[34]);        
  71.                 OLED_ShowChar(64, 4, '.');        
  72.                 OLED_ShowChar(72, 4, Display_GPGGA_Buffer[36]);        
  73.                 OLED_ShowChar(80, 4, Display_GPGGA_Buffer[37]);                        
  74.                 OLED_ShowChar(88, 4, Display_GPGGA_Buffer[38]);                        
  75.                 OLED_ShowChar(96, 4, Display_GPGGA_Buffer[39]);                        
  76.                 OLED_ShowChar(104, 4, Display_GPGGA_Buffer[40]);                                
  77.                 OLED_ShowChar(112, 4, 39);        
  78.         }
  79.                 else
  80.                 {
  81.                 OLED_ShowChar(0, 0, 'G');
  82.                 OLED_ShowChar(8, 0, 'P');
  83.                 OLED_ShowChar(16, 0, 'S');
  84.                 OLED_ShowChar(24, 0, ':');

  85.                 OLED_ShowChar(0, 2, 'n');//N
  86.                 OLED_ShowChar(8, 2, 'o'); //:
  87.                 OLED_ShowChar(16, 2, 't');               
  88.                 OLED_ShowChar(24, 2, 32);
  89.                 OLED_ShowChar(32, 2, 'c');               
  90.                 OLED_ShowChar(40, 2, 'o');
  91.                 OLED_ShowChar(48, 2, 'n');        
  92.                 OLED_ShowChar(56, 2, 'n');        
  93.                 OLED_ShowChar(64, 2, 'e');        
  94.                 OLED_ShowChar(72, 2, 'c');                        
  95.                 OLED_ShowChar(80, 2, 't');                        
  96.                 OLED_ShowChar(88, 2, 32);                        
  97.                 OLED_ShowChar(96, 2, 32);                                
  98.                 OLED_ShowChar(104, 2, 32);               
  99.                
  100.                 OLED_ShowChar(0,4, 32);//E
  101.                 OLED_ShowChar(8,4, 32); //:
  102.                 OLED_ShowChar(16,4, 32);               
  103.                 OLED_ShowChar(24,4, 32);
  104.           OLED_ShowChar(32,4, 32);
  105.                 OLED_ShowChar(40,4, 32);               
  106.                 OLED_ShowChar(48,4, 32);
  107.                 OLED_ShowChar(56,4, 32);        
  108.                 OLED_ShowChar(64,4, 32);        
  109.                 OLED_ShowChar(72,4, 32);        
  110.                 OLED_ShowChar(80,4, 32);                        
  111.                 OLED_ShowChar(88,4, 32);                        
  112.                 OLED_ShowChar(96,4, 32);                        
  113.                 OLED_ShowChar(104,4, 32);                                
  114.                 OLED_ShowChar(112,4, 32);
  115.                
  116.                 }
  117.                
  118.         }
  119. }



  120. void Uart_Init()                                                                     
  121. {
  122.         SCON = 0X50;  //UART方式1;8位UART
  123.         REN  = 1;     //允许串行口接收数据
  124.         PCON = 0x00;  //SMOD=0;波特率不加倍
  125.         TMOD = 0x20;  //T1方式2,用于产生波特率
  126.         TH1  = 0xFD;  //装初值
  127.         TL1  = 0xFD;
  128.         TR1  = 1;     //启动定时器1
  129.         EA   = 1;     //打开全局中断控制
  130.         ES   = 1;     //打开串行口中断        
  131. }


  132. void RECEIVE_DATA(void) interrupt 4 using 3                  //串口中断函数,收到GPS的数据时进入此中断        
  133. {
  134.         u8 temp = 0;
  135.         ES=0;                //先关闭串行口中断
  136. if(RI)
  137. {        
  138.         temp = SBUF;                                                                //接收SBUF中的数据
  139.         if(temp == '

  140. )                                                                //若是统一的数据头,则作为数组第一个元素
  141.         {
  142.                 RX_Count = 0;
  143.                 Flag_GPS_OK = 0;               
  144.         }

  145.         RX_Buffer[RX_Count++] = temp;                                //收到的数据放到数组中

  146.         if(RX_Count >= 66)                                                        //序号大于66的数据无用,统一放到第66位覆盖掉
  147.         {
  148.                 RX_Count = 66;
  149.         }

  150.         if(temp == '*')                                                                //收到*,则完成一帧数据的接收,不管是否完整有效
  151.         {
  152.                 Flag_GPS_OK = 1;                                                //标志变量置为1
  153.         }
  154. }
  155.         RI = 0;                                                                                //接收完成的标志位清零
  156.         ES=1;                                                                                 //重新打开串行口中断

  157. }

复制代码

全部资料51hei下载地址:
改版.rar (57.14 KB, 下载次数: 16)

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏2 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:702863 发表于 2021-9-2 09:43 | 只看该作者
将接收缓存RX_Buffer改成环形缓存LOOP_Buffer,即串口中断每次按字节写入环形缓存中。新增缓存数组GPS_Buffer,while(1)循环体遍历按字节取出LOOP_Buffer的数据存储到GPS_Buffer中,并判断是否完帧,最后OLED显示。
回复

使用道具 举报

板凳
ID:702863 发表于 2021-9-2 10:04 | 只看该作者
a1093941419 发表于 2021-9-2 09:43
将接收缓存RX_Buffer改成环形缓存LOOP_Buffer,即串口中断每次按字节写入环形缓存中。新增缓存数组GPS_Buff ...

或者更简单的说,程序应该设计成串口中断一边接收,主体部分一边解析,而不是等到串口都接收完成再去解析。
回复

使用道具 举报

地板
ID:401564 发表于 2021-9-2 10:36 | 只看该作者
我这两天也是在搞这上GPS,数据有点多,不过也是慢慢的理清了
定义一个结构体
串口中断一边接收,主函数一边处理数据
串口接收到一帧的完整数据之后,直接用结构体复制过来,感觉比数组好用
struct                                                           //GPS_Buffer结构
{
char GPS_Buffer[80];                                //留80个地址来存放GPS的数据
}xdata GPS_Buffer0,GPS_Buffer1;                 //两个结构变量,让串口接收和保存不相互影响

GPS_Buffer1=GPS_Buffer0; //这个是在串口中断中完成的

在主函数中把GPS_Buffer1结构体中的数据提取出来处理就可以了,先处理好数据,时间一到就刷新
回复

使用道具 举报

5#
ID:284050 发表于 2021-9-2 12:37 | 只看该作者
本帖最后由 川人在柳 于 2021-9-2 12:41 编辑
a1093941419 发表于 2021-9-2 10:04
或者更简单的说,程序应该设计成串口中断一边接收,主体部分一边解析,而不是等到串口都接收完成再去解析 ...

你这样说,感觉有点明白了。晚上回去试试。我的理解是给中断一个数组(目前程序中的RX_Buffer),让他存串口接收到的数据;然后再while(1)里面再给一个数组LOOP_Buffer。当RX_Buffer接收完数据后,再把RX_Buffer数据给LOOP_Buffer。
回复

使用道具 举报

6#
ID:284050 发表于 2021-9-2 12:40 | 只看该作者
Y_G_G 发表于 2021-9-2 10:36
我这两天也是在搞这上GPS,数据有点多,不过也是慢慢的理清了
定义一个结构体
串口中断一边接收,主函数一边 ...

谢谢回复。你这个说法似乎和你的楼上说的差不多。我的理解是给中断一个数组(目前程序中的RX_Buffer),让他存串口接收到的数据;然后再while(1)里面再给一个LOOP_Buffer,当RX_Buffer接收完数据后,再把RX_Buffer数据给LOOP_Buffer。
回复

使用道具 举报

7#
ID:401564 发表于 2021-9-2 19:52 | 只看该作者
川人在柳 发表于 2021-9-2 12:40
谢谢回复。你这个说法似乎和你的楼上说的差不多。我的理解是给中断一个数组(目前程序中的RX_Buffer), ...

我这个是懒人做法,GPS_Buffer1始终保存的是上一帧数据,不用检测什么接收完成没有
GPS_Buffer0在中断中完成后自动把数据复制到GPS_Buffer1
用结构的好处就是可以直接GPS_Buffer1=GPS_Buffer0
回复

使用道具 举报

8#
ID:284050 发表于 2021-9-3 11:29 | 只看该作者
a1093941419 发表于 2021-9-2 09:43
将接收缓存RX_Buffer改成环形缓存LOOP_Buffer,即串口中断每次按字节写入环形缓存中。新增缓存数组GPS_Buff ...

自己晚上试了一下,没有搞定。感觉还是不能特别理解你讲的内容。
回复

使用道具 举报

9#
ID:284050 发表于 2021-9-3 11:30 | 只看该作者
Y_G_G 发表于 2021-9-2 19:52
我这个是懒人做法,GPS_Buffer1始终保存的是上一帧数据,不用检测什么接收完成没有
GPS_Buffer0在中断中完 ...

能开源一下你的关于GPS数据解析的代码么
回复

使用道具 举报

10#
ID:401564 发表于 2021-9-3 22:51 | 只看该作者
川人在柳 发表于 2021-9-3 11:30
能开源一下你的关于GPS数据解析的代码么

我在现在也是还在调试中
我接收的信息是最简的GPS定位信息      $GNRMC

Uart_Isr() interrupt 4    串口中断函数负责接收GPS数据和保存,接收到一个帧的数据就保存

GPS_Data_Disp()   这个函数是负责把GPS_Buffer1.GPS_Buffer[] 中的GPS相关信息提取出来的,因为室内没有GPS信号,找了ATGM336H-5N数据手册上数据进行调试,因为数据手册上给我数据并不是完整的$GNRMC帧信息,考虑到会乱码,所以,在读取数组的时候是用++a这种形式去读取的
调试好之后,有了完整的GPS信息,可以直接指定GPS_Buffer1.GPS_Buffer[] 数组位置进行读取,代码就没有那么乱了

其实这个东西没那么难的
1,先保证串口程序是一定正确的,这个好反复验证,不能仿真,以实际开发板结果为准,有时候串口出问题,接收一两字节就没有问题,接收多了就有问题
2,串口接收到   $GNRMC  或者你自己想要的字符之后,就开始保存,不然就不用保存
3,GPS信息是以ASCII字符发送的,不是字符串,是字符,比如5,串口接收到的数据就是'5',也就是53
$GNRMC,084852.000,A,2236.9453,N,11408.4790,E,0.53,292.44,141216,,,A*7
5

以上的信息就是一帧的信息,逗号,小数点,*都是
调试的时候可以检测','就是逗号,数据是以逗号分隔
你可以数相关信息在什么位置,也可以检测逗号来提取
我这个代码也可以用,可以接收和提取GPS信息,试了一下,GPS的经纬度定位基本就是我这楼位置,一般来说,GPS定位准确了,就可以认为其它的信息也是准确的了 uart.rar (1.81 KB, 下载次数: 18)


回复

使用道具 举报

11#
ID:982011 发表于 2021-11-17 22:04 | 只看该作者
楼主:4g模块用的是什么样的?
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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