Operation of GPS positioning module based on GD32 development board

Based on the introduction in the previous chapter, this chapter will introduce how to use the gps positioning module based on the gd32 development board.

1. Official code analysis

    The official test routine of punctual atom, the logic of the test code is relatively simple, the main thing is to call the function atk_mo1218_init() to initialize, and then call the API function of the SkyTraq binary protocol to configure the ATK-MO1218 module. After the configuration is correct, ATK- The MO1218 module will continuously output data according to the configured measurement frequency, and then call the function atk_mo1218_update() to obtain each data information output by the ATK-MO1218 module, and then print it to the serial port debugging assistant.

6bc2bf6dbfcaa8436e26427e40dd6bed.png

void demo_run(void)
{
    uint8_t ret;
    
    //初始化
    ret = atk_mo1218_init(38400);
    if (ret != 0)
    {
        printf("ATK-MO1218 init failed!\r\n");
        while (1)
        {
            LED0_TOGGLE();
            delay_ms(200);
        }
    }
    
    //配置
    ret  = atk_mo1218_factory_reset(ATK_MO1218_FACTORY_RESET_REBOOT);
    ret += atk_mo1218_config_output_type(ATK_MO1218_OUTPUT_NMEA, ATK_MO1218_SAVE_SRAM_FLASH);
    ret += atk_mo1218_config_nmea_msg(1, 1, 1, 1, 1, 1, 0, ATK_MO1218_SAVE_SRAM_FLASH);
    ret += atk_mo1218_config_position_rate(ATK_MO1218_POSITION_RATE_5HZ, ATK_MO1218_SAVE_SRAM_FLASH);
    ret += atk_mo1218_config_gnss_for_navigation(ATK_MO1218_GNSS_GPS_BEIDOU, ATK_MO1218_SAVE_SRAM_FLASH);
    if (ret != 0)
    {
        printf("ATK-MO1218 configure failed!\r\n");
        while (1)
        {
            LED0_TOGGLE();
            delay_ms(200);
        }
    }
     
    while (1)
    {
        uint8_t ret;
        atk_mo1218_time_t utc;
        atk_mo1218_position_t position;
        int16_t altitude;
        uint16_t speed;
        atk_mo1218_fix_info_t fix_info;
        atk_mo1218_visible_satellite_info_t gps_satellite_info = {0};
        atk_mo1218_visible_satellite_info_t beidou_satellite_info = {0};
        uint8_t satellite_index;
        
        while (1)
        {
            //获取 ATK-MO1218 模块输出的各个数据信息
            ret = atk_mo1218_update(&utc, &position, &altitude, &speed, &fix_info, NULL, NULL, 5000);
            if (ret == ATK_MO1218_EOK)
            {
                /* UTC */
                printf("UTC Time: %04d-%02d-%02d %02d:%02d:%02d.%03d\r\n", utc.year, utc.month, utc.day, utc.hour, utc.minute, utc.second, utc.millisecond);
                
                //经纬度 (放大了100000)
                printf("Position: %d.%d'%s %d.%d'%s\r\n", position.longitude.degree / 100000, position.longitude.degree % 100000, (position.longitude.indicator == ATK_MO1218_LONGITUDE_EAST) ? "E" : "W", position.latitude.degree / 100000, position.latitude.degree % 100000, (position.latitude.indicator == ATK_MO1218_LATITUDE_NORTH) ? "N" : "S");
                
                //海拔高度 (放大了10)
                printf("Altitude: %d.%dm\r\n", altitude / 10, altitude % 10);
                
                // 速度(放大了10)
                printf("Speed: %d.%dKm/H\r\n", speed / 10, speed % 10);
                
                //定位质量
                printf("Fix quality: %s\r\n", (fix_info.quality == ATK_MO1218_GPS_UNAVAILABLE) ? "Unavailable" : ((fix_info.quality == ATK_MO1218_GPS_VALID_SPS) ? "SPS mode" : "differential GPS mode"));
                
                //用于定位的卫星数量
                printf("Satellites Used: %d\r\n", fix_info.satellite_num);
                
                //定位方式
                printf("Fix type: %s\r\n", (fix_info.type == ATK_MO1218_FIX_NOT_AVAILABLE) ? "Unavailable" : ((fix_info.type == ATK_MO1218_FIX_2D) ? "2D" : "3D"));
                
                //用于定位的卫星编号
                for (satellite_index=0; satellite_index<fix_info.satellite_num; satellite_index++)
                {
                    if (satellite_index == 0)
                    {
                        printf("Satellite ID:");
                    }
                    printf(" %d", fix_info.satellite_id[satellite_index]);
                    if (satellite_index == fix_info.satellite_num - 1)
                    {
                        printf("\r\n");
                    }
                }
                
                //位置、水平、垂直精度因子(放大了10)
                printf("PDOP: %d.%d\r\n", fix_info.pdop / 10, fix_info.pdop % 10);
                printf("HDOP: %d.%d\r\n", fix_info.hdop / 10, fix_info.hdop % 10);
                printf("VDOP: %d.%d\r\n", fix_info.vdop / 10, fix_info.vdop % 10);
                
                //可见的gps,北斗卫星数量
                printf("Number of GPS visible satellite: %d\r\n", gps_satellite_info.satellite_num);
                printf("Number of Beidou visible satellite: %d\r\n", beidou_satellite_info.satellite_num);
                
                printf("\r\n");
            }
            else
            {
                //ATK-MO1218模块未定位时,不输出NMEA协议的GSV语句,
                //导致因获取不到可见GPS、北斗卫星的信息而超时失败,
                //此时可将函数atk_mo1218_update()的入参gps_satellite_info和beidou_satellite_info传入NULL,
                //从而获取未定位时的其它数据
                printf("Error!\r\n");
            }
            
            delay_ms(1000);
        }
    }
}

        It is worth mentioning that since the length of the data sent by the ATK-MO1218 module to the main control chip through UART is not fixed , the main control chip cannot directly judge the length of the received data from the ATK-MO1218 module. Whether frame data is complete. For this situation of receiving variable-length data through UART , you can judge whether the transmission of a frame is completed by whether the UART bus is idle. It happens that the UART of STM32 provides the bus idle interrupt function, so you can enable the UART bus idle interrupt, and interrupt Do corresponding processing.

void ATK_MO1218_UART_IRQHandler(void)
{
    uint8_t tmp;
    
    if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_ORE) != RESET)       
    {
        __HAL_UART_CLEAR_OREFLAG(&g_uart_handle);                           
        (void)g_uart_handle.Instance->SR;                                   
        (void)g_uart_handle.Instance->DR;
    }
    
    if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_RXNE) != RESET)       
    {
        HAL_UART_Receive(&g_uart_handle, &tmp, 1, HAL_MAX_DELAY);           
        
        if (g_uart_rx_frame.sta.len < (ATK_MO1218_UART_RX_BUF_SIZE - 1))    
                                                                            
                                                                             
        {
            g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp;            
            g_uart_rx_frame.sta.len++;                                      
        }
        else                                                               
        {
            g_uart_rx_frame.sta.len = 0;                                 
            g_uart_rx_frame.buf[g_uart_rx_frame.sta.len] = tmp;             
            g_uart_rx_frame.sta.len++;                                    
        }
    }
    
    if (__HAL_UART_GET_FLAG(&g_uart_handle, UART_FLAG_IDLE) != RESET)       
    {
        g_uart_rx_frame.sta.finsh = 1;                                      
        
        __HAL_UART_CLEAR_IDLEFLAG(&g_uart_handle);                          
    }
}

2. Hardware

        The development board uses GD32F450, the serial port uses USART5, and the pins are PC6 and PC7. The DuPont line can be connected according to the equipment requirements.

      Use four Dupont wires to connect to the power supply 3.3V of the development board, GND and PC6, PC7 pins.
 

3. Software

        The NEMA protocol is a communication protocol for GPS devices, which defines a series of standard message formats for transmitting information such as the position, speed and time of GPS devices. When using gd32 for NEMA protocol analysis, the following steps can be taken:

1. Configure serial communication parameters, such as baud rate, data bits, stop bits and parity bits, etc.

2. Receive data through the serial port, and analyze each time a complete NEMA protocol message is received.

3. Parse the message header to determine the message type and data length.

4. Parse the message body and extract the required information such as position, speed and time.

5. Process or store the parsed data for subsequent use.

        It should be noted that the message format in the NEMA protocol is relatively complex, and the parsing process needs to carefully handle the meaning and data type of each field to avoid parsing errors. At the same time, due to the fast data transmission rate of the GPS device, it is necessary to adopt an appropriate caching mechanism to ensure that the data will not be lost or analyzed repeatedly.

Reference Code:

#include "gd32f30x.h"
#include <stdio.h>
#include <string.h>


/* 定义串口接收缓冲区大小 */
#define RX_BUF_SIZE  128
/* 定义NEMA协议消息类型枚举 */
typedef enum {
    NEMA_MSG_GPGGA,   // GGA消息
    NEMA_MSG_GPVTG,   // VTG消息
    NEMA_MSG_GPGSA,   // GSA消息
    NEMA_MSG_GPGSV,   // GSV消息
    NEMA_MSG_UNKNOWN, // 未知消息
} nema_msg_type_t;
/* 定义NEMA协议消息结构体 */
typedef struct {
    nema_msg_type_t type;   // 消息类型
    uint32_t time;          // 时间
    float latitude;         // 纬度
    float longitude;        // 经度
    float altitude;         // 海拔高度
    float speed;            // 速度
    float course;           // 航向
    uint8_t num_satellites; // 卫星数
} nema_msg_t;


/* 定义全局变量 */
static uint8_t rx_buf[RX_BUF_SIZE];
static uint8_t rx_index = 0;
static nema_msg_t nema_msg;


/* 串口接收中断处理函数 */
void USART5_IRQHandler(void)
{
    if (RESET != usart_interrupt_flag_get(USART5, USART_INT_FLAG_RBNE)) {
        /* 读取接收数据寄存器 */
        uint8_t data = usart_data_receive(USART5);
        /* 判断是否接收到换行符 */
        if (data == '\n') {
            /* 解析NEMA协议消息 */
            if (0 == strncmp((const char *)rx_buf, "$GPGGA,", 7)) {
                /* GGA消息 */
                nema_msg.type = NEMA_MSG_GPGGA;
                /* 解析消息体 */
                sscanf((const char *)rx_buf, "$GPGGA,%lu,%f,%c,%f,%c,%d,%d,%f,%f,M,%f,M,,",
                    &nema_msg.time, &nema_msg.latitude, &latitude_dir, &nema_msg.longitude,
                    &longitude_dir, &nema_msg.fix_quality, &nema_msg.num_satellites,
                    &nema_msg.hdop, &nema_msg.altitude, &nema_msg.geoid_sep);
            } else if (0 == strncmp((const char *)rx_buf, "$GPVTG,", 7)) {
                /* VTG消息 */
                nema_msg.type = NEMA_MSG_GPVTG;
                /* 解析消息体 */
                sscanf((const char *)rx_buf, "$GPVTG,%f,T,%f,M,%f,N,%f,K",
                    &nema_msg.course, &nema_msg.course_true, &nema_msg.speed, &nema_msg.speed_knots);
            } else if (0 == strncmp((const char *)rx_buf, "$GPGSA,", 7)) {
                /* GSA消息 */
                nema_msg.type = NEMA_MSG_GPGSA;
                /* 解析消息体 */
                sscanf((const char *)rx_buf, "$GPGSA,%c,%d,%d,%d,%d,%d,%d,%d,%d,%f,%f,%f",
                    &nema_msg.fix_mode, &nema_msg.fix_type, &nema_msg.sat1, &nema_msg.sat2,
                    &nema_msg.sat3, &nema_msg.sat4, &nema_msg.sat5, &nema_msg.sat6,
                    &nema_msg.sat7, &nema_msg.pdop, &nema_msg.hdop, &nema_msg.vdop);
            } else if (0 == strncmp((const char *)rx_buf, "$GPGSV,", 7)) {
                /* GSV消息 */
                nema_msg.type = NEMA_MSG_GPGSV;
                /* 解析消息体 */
                sscanf((const char *)rx_buf, "$GPGSV,%d,%d,%d",
                    &nema_msg.num_msgs, &nema_msg.msg_num, &nema_msg.num_sats);
            } else {
                /* 未知消息 */
                nema_msg.type = NEMA_MSG_UNKNOWN;
            }
            /* 清空接收缓冲区 */
            memset(rx_buf, 0, sizeof(rx_buf));
            rx_index = 0;
        } else {
            /* 累加接收缓冲区 */
            rx_buf[rx_index++] = data;
        }
    }
}


int main(void)
{
    /* 配置串口通信参数 */
    usart_deinit(USART5);
    usart_baudrate_set(USART5, 38400);
    usart_word_length_set(USART5, USART_WL_8BIT);
    usart_stop_bit_set(USART5, USART_STB_1BIT);
    usart_parity_config(USART5, USART_PM_NONE);
    usart_receive_config(USART5, USART_RECEIVE_ENABLE);
    usart_interrupt_enable(USART5, USART_INT_RBNE);
    nvic_enable_irq(NVIC_USART5_IRQ);
    usart_enable(USART5);


    /* 解析NEMA协议消息 */
    while (1) {
        if (nema_msg.type != NEMA_MSG_UNKNOWN) {
            /* 处理解析出来的数据 */
            // ...
            /* 清空消息结构体 */
            memset(&nema_msg, 0, sizeof(nema_msg));
        }
    }
}

Actually transplanted the punctual atomic routines to the gd32 development board, the test is as follows:

f304fc5ea73f23cea23eb6185436d2a9.png

The UTC time is obtained and printed, and the UTC time is 8:56, adding 8 is the local time, and the local time is 16:56, which is consistent with the actual and expected.

Personal Official Account: Embedded Learning and Practice

28ca10adad322f0efa1fe553c860b683.png

Guess you like

Origin blog.csdn.net/weixin_46158019/article/details/130998729