STM32 |
您所在的位置:网站首页 › gps模块获取时间 › STM32 |
模块介绍
ATGM336H定位模块支持GPS系统,BDS(北斗)系统,GLONASS(俄罗斯)系统,伽利略卫星导航系统(欧盟)。这个模块要拿到室外才能接收到信号,且初次初始化或者隔太久时间没有启用会导致获取定位信息的时间很长。 通过GNSS工具可以看到模块能够获取的数据帧有如下格式。 数据转换: 2322.74250 格式:ddmm.mmmmm 11326.27041 格式:ddmm.mmmmm 转换成北纬:23 + 22.74250 / 60 = 23.37904 转换成东经:113 + 26.27041 / 60 = 113.43784 比较不准。。串口输出的数据就是这样的,估计芯片哪里出了问题。。 读取数据可以先用一个缓存数组接收所有的数据,先判断是不是$GNRMC开头的数据帧,如果是的话则逐个字符接收,因为数据帧是以换行符为结尾的,当读取到’\n’则是数据帧的结尾。 定义几个字符数组,用于分别存放UTC时间,经度和纬度的原始数组,经度和纬度的方向。 以逗号为分隔符切割字符串,这里我们需要用到strstr这个函数。 首先定义一个结构体存放几个数组,并宏定义数组的长度。 void ATGM_StructInit() { GNRMC_Info.isGetData = false; GNRMC_Info.isParseData = false; GNRMC_Info.isUsefull = false; memset(GNRMC_Info.GPS_Buffer, 0, GPS_Buffer_Length); memset(GNRMC_Info.UTCTime, 0, UTCTime_Length); memset(GNRMC_Info.latitude, 0, latitude_Length); memset(GNRMC_Info.N_S, 0, N_S_Length); memset(GNRMC_Info.longitude, 0, longitude_Length); memset(GNRMC_Info.E_W, 0, E_W_Length); }首先初始化结构体,先把结构体成员内容全部置零。 void ATGM336H_Init() { GPIO_InitTypeDef GPIO_InitStructure; NVIC_InitTypeDef NVIC_InitStructure; USART_InitTypeDef USART_InitStructure; ATGM_StructInit(); RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //USART1_TX PA.9 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; GPIO_Init(GPIOA, &GPIO_InitStructure); //USART1_RX PA.10 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; GPIO_Init(GPIOA, &GPIO_InitStructure); //配置中断通道 NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn; NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;//优先级最低 NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; NVIC_Init(&NVIC_InitStructure); USART_InitStructure.USART_BaudRate = 9600; USART_InitStructure.USART_WordLength = USART_WordLength_8b; USART_InitStructure.USART_StopBits = USART_StopBits_1; USART_InitStructure.USART_Parity = USART_Parity_No; USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式 USART_Init(USART1, &USART_InitStructure); USART_ITConfig(USART1, USART_IT_RXNE, ENABLE); USART_Cmd(USART1, ENABLE); ClrBuf(); //初始化 }之后配置引脚,配置串口1中断,配置串口。引脚TX我选择PA9,RX选择PA10。TX要选择复用推挽输出,RX选择浮空输入。之后开通NVIC中断通道,配置串口波特率为9600,8位数据位,1位停止位,吴娇艳,无硬件流控制,模式为收发模式,因为我既要接收定位数据,也要打印或发送数据。最后别忘记使能中断和串口。 unsigned int DataIndex = 0; void USART1_IRQHandler() { unsigned char receive; if(USART_GetITStatus(USART1, USART_IT_RXNE) == 1) { receive = USART_ReceiveData(USART1); //读取接收到的数据 if(receive == '$') DataIndex = 0; USART_RX_BUF[DataIndex++] = receive; //GNRMC\GPRMC if(USART_RX_BUF[0] == '$' && USART_RX_BUF[4] == 'M' && USART_RX_BUF[5] == 'C') { if(receive == '\n') { memset(GNRMC_Info.GPS_Buffer, 0, GPS_Buffer_Length); //清空 memcpy(GNRMC_Info.GPS_Buffer, USART_RX_BUF, DataIndex); //保存数据 GNRMC_Info.isGetData = true; DataIndex = 0; memset(USART_RX_BUF, 0, USART_REC_LEN); //清空 } } } }先是定义一个DataIndex作为数组的下标,当读到了$标志表示数据帧开始,将下标置零,之后判断是不是我们要读取的这种格式,如果是则读到’\n’,即把数据转而存储到GPS_Buffer中,并把数据读取标志位置为true。 void ParseGps() { char *subString; char *subStringNext; char i = 0; if (GNRMC_Info.isGetData) { GNRMC_Info.isGetData = false; // printf("\r\n"); // printf(GNRMC_Info.GPS_Buffer); //截取数据帧前六部分 |对地航速 对地航向 日期 //$GNRMC,112536.000,A,2322.75023,N,11326.28605,E,| 0.00, 0.00, 100722,,,A*78 for (i = 0 ; i if ((subString = strstr(GNRMC_Info.GPS_Buffer, ",")) == NULL)//如果没有找到逗号 { return; //ERROR } } else { subString++; if ((subStringNext = strstr(subString, ",")) != NULL) { char usefulBuffer[2]; switch(i) { case 1:memcpy(GNRMC_Info.UTCTime, subString, subStringNext - subString);break; case 2: { memcpy(usefulBuffer, subString, subStringNext - subString);//有效标志位 if(usefulBuffer[0] == 'A') GNRMC_Info.isUsefull = true; else if(usefulBuffer[0] == 'V') GNRMC_Info.isUsefull = false; break; } case 3:memcpy(GNRMC_Info.latitude, subString, subStringNext - subString);break; case 4:memcpy(GNRMC_Info.N_S, subString, subStringNext - subString);break; case 5:memcpy(GNRMC_Info.longitude, subString, subStringNext - subString);break; case 6:memcpy(GNRMC_Info.E_W, subString, subStringNext - subString);break; default:break; } subString = subStringNext; } } } GNRMC_Info.isParseData = true; } }这里进行六次循环,把数据帧分成六部分,用strstr函数找到从子串next指针开始的下一个逗号的位置,并把这个这个位置到子串指针之间的数据分别存到各自的数组中去。六次循环之后便结束,因为后面的数据是对地航速,对地航向和日期,我没有这个需求,有需要的同学可以自己修改。 extern float Lat; extern float Lon; extern char dest[23]; void printGpsBuffer() { //$GNRMC,123211.000,A,2322.74250,N,11326.27041,E,3.21,217.19,100722,,,A*7A if (GNRMC_Info.isParseData) { int i = 0; GNRMC_Info.isParseData = false; if(GNRMC_Info.isUsefull) { float tmp = 0; int j = 0; GNRMC_Info.isUsefull = false; for (i = 0; GNRMC_Info.latitude[i] != '\0'; i++) { if (GNRMC_Info.latitude[i] == '.') { continue; } if (i tmp += (GNRMC_Info.latitude[i] - 48); tmp *= 10; } } for (j = 0; j Lat *= 10; iLat = (int)Lat; GNRMC_Info.latitude[j] = iLat + '0'; Lat -= iLat; } tmp = 0; //113.27041 for (i = 0; GNRMC_Info.longitude[i] != '\0'; i++) { if (GNRMC_Info.longitude[i] == '.') { continue; } if (i tmp += (GNRMC_Info.longitude[i] - 48); tmp *= 10; } } for (j = 0; j Lon *= 10; iLon = (int)Lon; GNRMC_Info.longitude[j] = iLon + '0'; Lon -= iLon; } dest[8] = dest[10] = dest[20] = ','; dest[9] = 'N'; dest[21] = 'E'; dest[22] = '\0'; for(i = 0; i printf("GPS DATA Is Not Useful!"); } } }最后就是数据的转换,要把经纬度数组中的字符提取出来组合成数字。对于纬度,先提取数组前两位的数据作为个位和十位,从第三位开始后面的数据提取出来组成一个浮点数,之后把这个浮点数除以60,最后加上个位和十位的整数,便得到了转换后的纬度。经度同理,区别在于经度有百位。 这里只是简单的没有啥依据的不合理的提取。 提取得到两个浮点数后,把经纬度方向一起存储在dest数组中,组合成完整的包括经纬度方向的数据。 结语数据解析的步骤很繁琐,且模块输出的原始数据不是很准确。后面再试试。 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |