Gps模块的应用

Posted by 肥仔 on September 30, 2020

GPS模块的应用

前言

ATGM336H-5N这个模块,主要是想在自己作的配送车上,增加GPS模块,好用来定位以及定点配送。然而实际效果,,,,室内基本无信号,室外只能收到时间挫,具体待总结。

数据格式

GNGPBD 分别代表 双模模式GPS 模式北斗模式 $表示一帧的开始

基本上提取的都是$GPRMC(最简定位信息)里面的数据

数据样式如下:

天线状态输出

$GPTXT,01,01,01,ANTENNA OK*35

Ok 代表天线已经检测到, open 代表天线断开

更多信息,可以参考模块配套资料

代码解析

主要分为4个部分

  • 数据读取
  • 数据解析
  • 数据打印,
  • 错误提醒

数据读取部分

首先,要确保连线无误,单片机能正常读取卫星信号

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#define GpsSerial ss
#define DebugSerial Serial
#include <SoftwareSerial.h>
//RX和TX
SoftwareSerial ss(7, 8);
void setup(){
  GpsSerial.begin(9600);
  DebugSerial.begin(9600);

}
void loop(){
 while(GpsSerial.available()){
      byte gpsData = GpsSerial.read();
     DebugSerial.write(gpsData);
     }
}

之后构建结构体保存数据,并读取指定帧的数据!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
void gpsRead(){
    while(GpsSerial.available()){
//      byte gpsData = GpsSerial.read();
//      DebugSerial.write(gpsData);

      gpsRxBuffer[ii++] = GpsSerial.read();
      if(ii == gpsRxBufferLength) clrGpsRxBuffer();
 
      
    }
    //DebugSerial.write("test");
    char * GPS_BufferHead;
    char * GPS_BufferTail;
    if((GPS_BufferHead = strstr(gpsRxBuffer,"$GPRMC,")) !=NULL || (GPS_BufferHead = strstr(gpsRxBuffer,"$GNRMC,")) != NULL)
    { 
      if(((GPS_BufferTail = strstr(GPS_BufferHead,"\r\n")) !=NULL) && (GPS_BufferTail >GPS_BufferHead)){
        memcpy(save_data.GPS_Buffer,GPS_BufferHead,GPS_BufferTail-GPS_BufferHead);
        save_data.isGetData = true;
        clrGpsRxBuffer();
      }
    }
}
void clrGpsRxBuffer(){
   memset(gpsRxBuffer,0,gpsRxBufferLength);//清空
   ii = 0;
}

数据解析部分

剔除为空的数据,将有用的数据保存在结构体内

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
void paraGpsBuffer(){
  char *subString;
  char *subStringText;
  if(save_data.isGetData){
    save_data.isGetData = false;
    DebugSerial.println("********************");
    DebugSerial.println(save_data.GPS_Buffer);
    for (int i =0;i<=6;i++){
      if (i == 0){
        if((subString = strstr(save_data.GPS_Buffer,",")) == NULL)
        errorLog(1);
      }
      else{
        subString++;
        if((subStringText = strstr(subString,",")) != NULL)
        {
          char usefullBuffer[2];
          switch(i){
            case 1: memcpy(save_data.UTCTime,subString,subStringText-subString);
              break;//获取UTC时间
            case 2:memcpy(usefullBuffer,subString,subStringText-subString);
              break; //获取UTC时间
            case 3:memcpy(save_data.latitude,subString,subStringText-subString);
              break;//获取纬度信息
            case 4:memcpy(save_data.N_S,subString,subStringText-subString);
              break; //获取N/S
            case 5: memcpy(save_data.longitute,subString,subStringText-subString);
              break; //获取经度信息
            case 6:memcpy(save_data.E_W,subString,subStringText-subString);
              break;
            default:
              break;
          }
          subString = subStringText;
          save_data.isParaseData = true;
          if(usefullBuffer[0]=='A'){
            save_data.isUsefull = true;
          }
          else if(usefullBuffer[0]='V'){
            save_data.isUsefull =false;
          }
          else{
            errorLog(2); //解析错误
          }
        }
      }
    }
  }
}

数据打印

判断数据是否解析成功,之后在判断数据是否有用,之后再打印结构体的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
void printGpsBuffer(){
  if(save_data.isParaseData){
    save_data.isParaseData = false;
    
    DebugSerial.print("save_data.UTCTime =");
    DebugSerial.println(save_data.UTCTime);
    if(save_data.isUsefull){
      DebugSerial.print("save_data.latitude = ");
      DebugSerial.println(save_data.latitude);
      DebugSerial.print("save_data.N_S=");
      DebugSerial.println(save_data.N_S);
      DebugSerial.print("save_data.longitute = ");
      DebugSerial.println(save_data.longitute);
      DebugSerial.print("save_data.E_W = ");
      DebugSerial.println(save_data.E_W);

    }
    else{
        DebugSerial.println("GPS DTAT is not usefull");
    }

  }
}

错误提示

出现错误时,13号灯会连续闪烁

1
2
3
4
5
6
7
8
9
10
void errorLog(int num){
  DebugSerial.print("ERROR");
  DebugSerial.println(num);
  while(1){
    digitalWrite(L,LOW);
    delay(300);
    digitalWrite(L,HIGH);
    delay(300);
  }
}

初始化部分

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
#define GpsSerial ss
#define DebugSerial Serial
#include <SoftwareSerial.h>
//结构体
 struct {
   char GPS_Buffer[80];
   bool isGetData;  //是否获得数据
   bool isParaseData;//是否解析完成
   char UTCTime[11]; //UTC时间
   char latitude[12];  //纬度
   char N_S[2];    //N/S
   char longitute[12]; //经度
   char E_W[2];  //E/W
   bool isUsefull; //定位信息是否有效
 }save_data;
 int L =13 ;
 const unsigned int gpsRxBufferLength = 600;
 char gpsRxBuffer[gpsRxBufferLength];
 unsigned int ii = 0;
// The serial connection to the GPS module
//RX和TX
SoftwareSerial ss(7, 8);
 int i = 0 ;

c内置函数的应用

  • char *strstr(const char *haystack, const char *needle);

    strstr(str1,str2) 函数用于判断字符串str2是否是str1的子串。如果是,则该函数返回str2在str1中首次出现的地址;否则,返回NULL。

  • void *memcpy(void *destin, void *source, unsigned n);

    函数的功能是从源内存地址的起始位置开始拷贝若干个字节到目标内存地址中,即从源source中拷贝n个字节到目标destin中

  • void *memset(void *s, int ch, size_t n); 将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法