当前位置:网站首页>STM32 - positioning module atgm336h, data analysis, longitude and latitude extraction
STM32 - positioning module atgm336h, data analysis, longitude and latitude extraction
2022-07-21 19:49:00 【chfens】
Module introduction
ATGM336H Positioning module support GPS System ,BDS( Beidou ) System ,GLONASS( Russia ) System , Galileo satellite navigation system ( The European Union ). This module needs to be taken outdoors to receive signals , And initial initialization or not enabling after a long time will lead to a long time to obtain location information .
You can use the integrated software setup module provided by Zhongke microelectronics , You can set the parameters of serial port output , Baud rate and other parameters .
This paper introduces STM32 The serial port receives the data of the positioning module , And analyze the data , The original data of longitude and latitude are obtained after analysis , Convert the original longitude and latitude data into accurate longitude and latitude information and store it in the array , You can print or continue serial port transmission to other devices , Transmission to... Will be introduced later ESP32, And save to SPIFFS in . The above figure is an example of the data frame output by the module to the upper computer through the serial port .
adopt GNSS The tool can see that the data frame that the module can obtain has the following format . among RMC Data is the simplest location information , After getting this string of data , Can be GNRMC The first six data extraction , Namely UTC Time , Data valid flag bit , latitude , Latitude , longitude , Longitude direction . At this time, the longitude and latitude are only raw data , It needs to be converted into accurate data .
RMC The data sample of is
$GNRMC,123211.000,A,2295.33602,N,11326.27041,E,3.21,217.19,100722,,,A*7A
Procedural thinking
Data conversion :
2322.74250 Format :ddmm.mmmmm
11326.27041 Format :ddmm.mmmmm
Convert to north latitude :23 + 22.74250 / 60 = 23.37904
Convert to east longitude :113 + 26.27041 / 60 = 113.43784
Quite inaccurate .. The data output from the serial port is like this , It is estimated that there is something wrong with the chip ..
To read data, you can first receive all the data with a cache array , First judge whether it is $GNRMC The first data frame , If so, receive character by character , Because the data frame ends with a newline , When read to ’\n’ Is the end of the data frame .
Define several character arrays , For storing separately UTC Time , The original array of longitude and latitude , The direction of longitude and latitude .
Cut the string with comma as separator , Here we need to use strstr This function .
Return to point str1 For the first time str2 A pointer to the position of , When str1 There is no str2 Return null pointer . We can define a substring pointer , Use this function to find commas in data frames , Reuse memcpy Function divides the data into corresponding arrays .
#include "ATGM336H.h"
#include "string.h"
#define GPS_Buffer_Length 80
#define UTCTime_Length 11
#define latitude_Length 11
#define N_S_Length 2
#define longitude_Length 12
#define E_W_Length 2
char USART_RX_BUF[USART_REC_LEN]; // Receive buffer , Maximum USART_REC_LEN Bytes .
typedef struct SaveData
{
char GPS_Buffer[GPS_Buffer_Length];
char isGetData; // Data acquisition completion flag bit
char isParseData; // Parsing completion flag bit
char UTCTime[UTCTime_Length]; //UTC Time
char latitude[latitude_Length]; // latitude
char N_S[N_S_Length]; //N/S
char longitude[longitude_Length]; // longitude
char E_W[E_W_Length]; //E/W
char isUsefull; // Information valid flag bit
}GNRMC;
First, define a structure to store several arrays , And macro defines the length of the array .
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);
}
First initialize the structure , First set all the contents of the structure members to zero .
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);
// Configure interrupt channel
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3 ;// The lowest priority
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; // Transceiver mode
USART_Init(USART1, &USART_InitStructure);
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
USART_Cmd(USART1, ENABLE);
ClrBuf(); // initialization
}
Then configure the pin , Configure serial port 1 interrupt , Configure serial port . Pin TX I choose PA9,RX choice PA10.TX To select multiplex push-pull output ,RX Select floating input . Then open NVIC Interrupt channel , Configure serial port baud rate as 9600,8 Digit bit ,1 Bit stop bit , Wu Jiaoyan , No hardware flow control , The mode is send / receive , Because I want to receive location data , Also print or send data . Finally, don't forget to enable interrupts and serial ports .
unsigned int DataIndex = 0;
void USART1_IRQHandler()
{
unsigned char receive;
if(USART_GetITStatus(USART1, USART_IT_RXNE) == 1)
{
receive = USART_ReceiveData(USART1); // Read received data
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); // Empty
memcpy(GNRMC_Info.GPS_Buffer, USART_RX_BUF, DataIndex); // Save the data
GNRMC_Info.isGetData = true;
DataIndex = 0;
memset(USART_RX_BUF, 0, USART_REC_LEN); // Empty
}
}
}
}
First, define a DataIndex As subscript of array , When I read it $ The flag indicates the beginning of the data frame , Set subscript to zero , Then judge whether it is the format we want to read , If so, read ’\n’, That is to store the data in GPS_Buffer in , And the position of the data reading flag is 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);
// Intercept the first six parts of the data frame | Ground speed Heading to the ground date
//$GNRMC,112536.000,A,2322.75023,N,11326.28605,E,| 0.00, 0.00, 100722,,,A*78
for (i = 0 ; i <= 6 ; i++)
{
if (i == 0)
{
if ((subString = strstr(GNRMC_Info.GPS_Buffer, ",")) == NULL)// If no comma is found
{
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);// Valid flag bits
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;
}
}
Here are six cycles , Divide the data frame into six parts , use strstr Function to find the substring next The position of the next comma at the beginning of the pointer , And save the data from this position to the substring pointer into their respective arrays . After six cycles , Because the following data is the ground speed , Heading and date to the ground , I don't have this need , Students who need it can modify it by themselves .
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 <= 1)
{
Lat = (GNRMC_Info.latitude[0] - 48) * 10 + (GNRMC_Info.latitude[1] - 48);
// Take out bits and tens
}
else
{
tmp += (GNRMC_Info.latitude[i] - 48);
tmp *= 10;
}
}
for (j = 0; j <= 5; j++)
{
tmp /= 10;
}
Lat += tmp / 60;
//23 22.74250
//23.xxxxx
int iLat = 0;
iLat = (int)Lat;
GNRMC_Info.latitude[0] = iLat / 10 + '0';
GNRMC_Info.latitude[1] = iLat % 10 + '0';
GNRMC_Info.latitude[2] = '.';
Lat -= iLat;
for (j = 3; j < 10; 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 <= 2)
{
Lon = (((GNRMC_Info.longitude[0] - 48) * 10 + (GNRMC_Info.longitude[1] - 48)) * 10) + (GNRMC_Info.longitude[2] - 48);
// Take out bits, tens and hundreds
}
else
{
tmp += (GNRMC_Info.longitude[i] - 48);
tmp *= 10;
}
}
for (j = 0; j <= 5; j++)
{
tmp /= 10;
}
int iLon = 0;
//113.43784
Lon += tmp / 60;
iLon = (int)Lon;
GNRMC_Info.longitude[0] = iLon / 100 + '0';
GNRMC_Info.longitude[1] = (iLon % 100) / 10 + '0';
GNRMC_Info.longitude[2] = iLon % 10 + '0';
GNRMC_Info.longitude[3] = '.';
Lon -= iLon;
for (j = 4; j < 11; 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 < 22; i++)
{
if(i <= 7)
dest[i] = GNRMC_Info.latitude[i];
if(i >= 11 && i <= 19)
dest[i] = GNRMC_Info.longitude[i - 11];
}
//printf("\r\ndest = ");
printf(dest);
//printf("\r\n");
}
else
{
printf("GPS DATA Is Not Useful!");
}
}
}
Finally, data conversion , We need to put Characters are extracted and combined into numbers . For the latitude , First extract the data of the first two bits of the array as one bit and ten bit , Starting from the third place, the following data is extracted to form a floating-point number , Then divide this floating-point number by 60, Finally, add an integer with one and ten digits , Then we get the converted latitude . Longitude is the same , The difference is that there are hundreds of longitudes .
Here is just a simple unreasonable extraction without any basis .
After extracting two floating-point numbers , Store the longitude and latitude directions together in dest Array , Combine into complete data including longitude and latitude directions .
Conclusion
The steps of data analysis are cumbersome , And the raw data output by the module is not very accurate . Try again later .
边栏推荐
- TypeScript基础学习笔记
- [C practice] [ATOI] Simulation Implementation
- 426. 将二叉搜索树转化为排序的双向链表
- 无线定位技术实验三 基于信号强度的位置指纹定位仿真
- 我的UI自動化測試的感悟
- Harbor scanner from principle to construction
- cuMemcpyHtoDAsync failed: invalid argument
- Project Management Maturity Model and project quantitative management
- NXP i.MX 8m mini core board specifications, quad core arm cortex-a53 + arm cortex-m4
- The 22 pictures show you in-depth analysis of prefix, infix, suffix expressions and expression evaluation
猜你喜欢
Content with element type "resultmap" must match "(constructor?, id*, result*, association*, collection*, discriminato?) “
电磁场与电磁波实验二 熟悉Matlab PDEtool在二维电磁问题的应用
攻防世界----favorite_number
NR modulation 4-AM
22张图带你深入剖析前缀、中缀、后缀表达式以及表达式求值
STM32——定位模块ATGM336H,数据解析,提取经纬度
动作活体检测能力,构建安全可靠的支付级“刷脸”体验
技術帖 | A40i最常見的3種網卡軟件問題,為你逐一分析
Gradle项目构建工具入门
How Jenkins sends e-mail? The automation veteran will teach you
随机推荐
「新品发布」B2B连接器版本NXP i.MX 8M Mini工业核心板
NXP i.MX 8M Mini 核心板规格参数,四核ARM Cortex-A53 + ARM Cortex-M4
How to remove Baidu advertisements
动作活体检测能力,构建安全可靠的支付级“刷脸”体验
What is the difference between the tag attribute href of a reference URL and Src?
TikTok卖家该怎么更好的引流?
Tiktok sellers how to better drainage?
Deep learning - (5) class of data imbalance_ weight
Siyuan synchronization problem: cloud object not found v2.1.0
电磁场与电磁波实验三 熟悉Mathematica软件在电磁场领域的应用
Learning notes introduction to explain
NXP i.MX 8m Mini development board specifications, quad core arm cortex-a53 + arm cortex-m4
Electromagnetic field and electromagnetic wave experiment three familiar with the application of Mathematica software in the field of electromagnetic field
全志A40i开发板硬件说明书——100%国产+工业级方案(下)
How Jenkins sends e-mail? The automation veteran will teach you
ImportError: DLL load failed while importing win32gui: 找不到指定的模块。
序列模型(一)- 循环序列模型
全志A40i开发板硬件说明书——100%国产+工业级方案(上)
Electromagnetic field and electromagnetic wave experiment II familiar with the application of MATLAB PDETOOL in two-dimensional electromagnetic problems
Jenkins怎么发邮件,自动化大老手把手教你