The GP-01 is a high-performance BDS/GNSS multi - constellation satellite navigation receiver SOC module.
It integrates the RF front - end, digital baseband processor, 32 - bit RISC CPU, power management, and active antenna detection and protection functions. It supports multiple satellite navigation systems, including China's BDS, the US GPS, and Russia's GLONASS, enabling multi - system joint positioning.
This article uses the GP-01 - Kit development board as an example to introduce how to obtain the latitude and longitude information from the GP-01 via STM32.
1. Hardware PreparationThe hardware involved in this driver includes the GP-01-Kit, STM32F103C8T6minimum system board, USB - TTL converter, ST - Link, and several jumper wires.
1.1 GP-01 - KitThe GP-01 development board requires a 5V power supply.
Programming can be done via serial port or using ST - Link or J - Link.
1.3 WiringThe wiring between the GP-01 - Kit development board and the STM32F103C8T6, as well as between the STM32F103C8T6 and the USB - TTL converter, is shown in the table below.
In addition, use an Android cable to connect the GP-01-Kit to the serial port for power supply.
2. Software Preparation2.1 MDK ( Keil v5)Refer to online examples for the download method.
2.2 Serial Port Debugging Assistant ( SSCOM)Used to view the latitude and longitude output information obtained by the STM32 UART drive from the GP-01.
3. NMEAThe GP-01 supports the NMEA - 0183 protocol, which outputs data to the serial port after power - on. This data is in the format of all GPS receivers and is the most universal data output format. The NMEA - 0183 protocol defines many sentences, but the most commonly used and widely compatible ones are GPGGA, GPGSA, GPGSV, GPRMC, GPVTG,and GPGLL. To obtain latitude and longitude, focus on the $GNRMC information.
The GPRMC protocol is as follows:
GPRMC (It is recommended to use the minimal GPS data format)
$GPRMC, <1>, <2>, <3>, <4>, <5>, <6>, <7>, <8>, <9>, <10>, <11><CR><LF>
(1) Standard positioning time (UTC time) format: hhmmss.sss.
(2) Positioning status, A = data available, V = data not available.
(3) Latitude, format: ddmm.mmmm.
(4) Latitude hemisphere, N for the northern hemisphere or S for the southern hemisphere.
(5) Longitude, format: dddmm.mmmm.
(6) Longitude hemisphere, E for the eastern hemisphere or W for the western hemisphere.
(7) Relative speed, 0.0 to 1851.8 knots.
(8) Relative track made good, 000.0 to 359.9 degrees. Actual value.
(9) Date format: ddmmyy.
(10) Magnetic variation, 000.0 to 180.0.
(11) Degrees.
(12) Checksum.4. STM32 Program Implementation
Source code acquisition method:
Source code link:https://pan.baidu.com/s/1I8CXlKuAWouwOdgN-9z_1w
Extraction code: AIXK
4.1 Serial Port CodeCommunication between GPS and STM32 uses UART3. Below is the initialization code for UART3:
// Initialize IO UART3
// pclk1: PCLK1 clock frequency (Mhz)
// bound: baud rate
void usart3_init(u32 bound)
{
NVIC_InitTypeDef NVIC_InitStructure;
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); // Enable GPIOB clock
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE); // Enable UART3 clock
USART_DeInit(USART3); // Reset UART3
// USART3_TX PB10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10; // PB10
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; // Alternate push - pull output
GPIO_Init(GPIOB, &GPIO_InitStructure); // Initialize PB10
// USART3_RX PB11
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; // Floating input
GPIO_Init(GPIOB, &GPIO_InitStructure); // Initialize PB11
USART_InitStructure.USART_BaudRate = bound; // Baud rate generally set to 9600
USART_InitStructure.USART_WordLength = USART_WordLength_8b; // 8 - bit data format
USART_InitStructure.USART_StopBits = USART_StopBits_1; // One stop bit
USART_InitStructure.USART_Parity = USART_Parity_No; // No parity bit
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; // No hardware flow control
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; // Reception and transmission modes
USART_Init(USART3, &USART_InitStructure); // Initialize UART3
USART_Cmd(USART3, ENABLE); // Enable UART
// Enable reception interrupt
USART_ITConfig(USART3, USART_IT_RXNE, ENABLE); // Enable interrupt
// Set interrupt priority
NVIC_InitStructure.NVIC_IRQChannel = USART3_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2; // Preemption priority 2
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; // Sub - priority 3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; // Enable IRQ channel
NVIC_Init(&NVIC_InitStructure); // Initialize NVIC registers
TIM7_Int_Init(1000 - 1, 7200 - 1); // 10ms interrupt
USART3_RX_STA = 0; // Reset
TIM_Cmd(TIM7, DISABLE); // Disable Timer7
}
UART3 uses interrupt - based reception to store data in a buffer. The code is as follows:
void USART3_IRQHandler(void)
{
u8 res;
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) // Data received
{
res = USART_ReceiveData(USART3);
if ((USART3_RX_STA & (1 << 15)) == 0) // If the received data batch hasn't been processed, stop receiving other data
{
if (USART3_RX_STA < USART3_MAX_RECV_LEN) // If data can still be received
{
TIM_SetCounter(TIM7, 0); // Clear the counter
if (USART3_RX_STA == 0) // Enable Timer7 interrupt
{
TIM_Cmd(TIM7, ENABLE); // Enable Timer7
}
USART3_RX_BUF[USART3_RX_STA++] = res; // Store the received value
}
else
{
USART3_RX_STA |= 1 << 15; // Force - mark reception as complete
}
}
}
}
4.2 GPS CodeIn gps.h, a structure is defined to store parsed data:
__packed typedef struct
{
u32 latitude; // Latitude, minutes multiplied by 100000, actual value divided by 100000
u8 nshemi; // North/South latitude, N for North; S for South
u32 longitude; // Longitude, minutes multiplied by 100000, actual value divided by 100000
u8 ewhemi; // East/West longitude, E for East; W for West
}nmea_msg;
typedef struct Data
{
float latitude; // Latitude
char N_S; // North/South
float longitude; // Longitude
char E_W; // East/West
}Data;
Parsing GPS data:
// Get the position of the cx - th comma in buf
// Return value: 0 ~ 0XFE, offset of the comma position.
// 0XFF, the cx - th comma does not exist.
u8 NMEA_Comma_Pos(u8 *buf, u8 cx)
{
u8 *p = buf;
while (cx)
{
if (*buf == '*' || *buf < ' ' || *buf > 'z') return 0XFF; // If '*' or invalid character, the cx - th comma does not exist
if (*buf == ',') cx--;
buf++;
}
return buf - p;
// m^n function
// Return value: m to the nth power.
u32 NMEA_Pow(u8 m, u8 n)
{
u32 result = 1;
while (n--) result *= m;
return result;}
// Convert str to a number, ending with ',' or '*'
// buf: storage area for numbers
// dx: decimal places, returned to the calling function
// Return value: converted number
int NMEA_Str2num(u8 *buf, u8 *dx)
{
u8 *p = buf;
u32 ires = 0, fres = 0;
u8 ilen = 0, flen = 0, i;
u8 mask = 0;
int res;
while (1) // Get integer and decimal lengths
{
if (*p == '-') { mask |= 0X02; p++; } // Negative number
if (*p == ',' || (*p == '*')) break; // End encountered
if (*p == '.') { mask |= 0X01; p++; } // Decimal point encountered
else if (*p > '9' || (*p < '0')) // Invalid character
{
ilen = 0;
flen = 0;
break;
}
if (mask & 0X01) flen++;
else ilen++;
p++;
}
if (mask & 0X02) buf++; // Remove negative sign
for (i = 0; i < ilen; i++) // Get integer part
{
ires += NMEA_Pow(10, ilen - 1 - i) * (buf[i] - '0');
}
if (flen > 5) flen = 5; // Max 5 decimal places
*dx = flen; // Decimal places
for (i = 0; i < flen; i++) // Get decimal part
{
fres += NMEA_Pow(10, flen - 1 - i) * (buf[ilen + 1 + i] - '0');
}
res = ires * NMEA_Pow(10, flen) + fres;
if (mask & 0X02) res = -res;
return res;}
// Analyze GNRMC information
// gpsx: nmea message structure
// buf: address of the received GPS data buffer
void NMEA_GNRMC_Analysis(nmea_msg *gpsx, u8 *buf)
{
u8 *p1,dx;
u8 posx;
u32 temp;
float rs;
u8 *p1, dx;
u8 posx;
u32 temp;
float rs;
p1 = (u8*)strstr((const char *)buf, "$GNRMC"); //$GNRMC is often separated from &, so only judge GPRMC.
posx = NMEA_Comma_Pos(p1, 3); // Get latitude
if (posx != 0XFF)
{
temp = NMEA_Str2num(p1 + posx, &dx);
gpsx->latitude = temp / NMEA_Pow(10, dx + 2); // Get degrees
rs = temp % NMEA_Pow(10, dx + 2); // Get minutes
gpsx->latitude = gpsx->latitude * NMEA_Pow(10, 5) + (rs * NMEA_Pow(10, 5 - dx)) / 60; // Convert to degrees
}
posx = NMEA_Comma_Pos(p1, 4); // North or South latitude
if (posx != 0XFF) gpsx->nshemi = *(p1 + posx);
posx = NMEA_Comma_Pos(p1, 5); // Get longitude
if (posx != 0XFF)
{
temp = NMEA_Str2num(p1 + posx, &dx);
gpsx->longitude = temp / NMEA_Pow(10, dx + 2); // Get degrees
rs = temp % NMEA_Pow(10, dx + 2); // Get minutes
gpsx->longitude = gpsx->longitude * NMEA_Pow(10, 5) + (rs * NMEA_Pow(10, 5 - dx)) / 60; // Convert to degrees
}
posx = NMEA_Comma_Pos(p1, 6); // East or West longitude
if (posx != 0XFF) gpsx->ewhemi = *(p1 + posx);
}
4.3 Main Functionint main(void)
{
delay_init(); // Initialize delay function
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); // Set NVIC interrupt grouping 2: 2 bits preemption priority, 2 bits response priority
uart_init(9600); // Initialize UART to 9600
usart3_init(9600); // Initialize UART to 9600
while (1)
{
delay_ms(1);
if (USART3_RX_STA & 0X8000) // Data received
{
USART3_RX_STA = 0; // Start next reception
NMEA_GNRMC_Analysis(&gpsx, (u8*)USART3_RX_BUF);
GPS_Data.longitude = (float)((float)gpsx.longitude / 100000);
GPS_Data.latitude = (float)((float)gpsx.latitude / 100000);
GPS_Data.N_S = ((char)gpsx.nshemi);
GPS_Data.E_W = ((char)gpsx.ewhemi);
printf("Longitude: %f%c, Latitude: %f%c\r\n", GPS_Data.longitude, GPS_Data.E_W, GPS_Data.latitude, GPS_Data.N_S);
}
}
}
5. Implementation ResultsThe obtained positioning data is as follows:
Comments