首页 > 解决方案 > 我想使用 STM32F0 和 Truestudio 从 NMEA 语句中解析 GNSS 数据

问题描述

从 NMEA 句子中解析 GPS 数据时我遇到了困难。我正在使用 Quectel L89 GNSS 模块(波特率:115200)和 Truestudio IDE。我曾使用 CubeMX 制作程序的骨架结构。

我曾尝试同时HAL_UART_RxCpltCallback使用HAL_UART_Receive_ITHAL_UART_Receive_IT独立使用。我有时能读取数据,有时不能。问题是原始数据从 $GPRMC 开始并以 $PSTMCPU 结束,而从 ST 读取数据有时 rec_buffer 从 $GPRMC(正常条件)开始,有时从 $GNVTG(错误条件)开始。

我将如何确保 rec_buffer 始终从 $GPRMC 开始

我在 while(1) 中调用它:

  HAL_UART_Receive_IT(&huart2, rec_buff, 2400);  // from GPS UART

我也试过这个:

void HAL_UART_RxCpltCallback(   UART_HandleTypeDef *    huart   )
{
    if (huart->Instance == USART2)  //GPS UART
    {
        HAL_UART_Transmit(&huart1, &rec_buff[0], 1, 10);
        HAL_UART_Receive_IT(&huart2, rrc_buff, 2400);   
    }
}

L89 原始数据:

$GPRMC,094640.000,A,2838.86700,N,07711.56483,E,0.4,99.3,050119,,,A*5E
$GPGGA,094640.000,2838.86700,N,07711.56483,E,1,08,1.0,226.91,M,-35.9,M,,*42
$GNGNS,094640.000,2838.86700,N,07711.56483,E,ANNNNN,08,1.0,0226.9,-35.9,,*78
$GPVTG,99.3,T,,M,0.4,N,0.7,K,A*3D
$GPGST,094640.000,46.0,26.0,17.7,0.2,25.7,18.2,19.6*68
$GPGBS,094640.000,25.7,18.2,19.6,,,,*4B
$GNGSA,A,3,23,09,03,16,26,22,27,07,,,,,1.9,1.0,1.6*28
$GNGSA,A,3,,,,,,,,,,,,,1.9,1.0,1.6*22
$GPGSV,3,1,11,16,70,076,27,03,58,227,30,23,52,331,36,26,44,046,18*78
$GPGSV,3,2,11,22,44,198,21,09,24,316,34,27,19,137,19,07,16,266,27*70
$GPGSV,3,3,11,31,14,058,,14,10,112,,08,09,164,20,,,,*45
$PSTMPRES,14.7,-4.3,3.4,4.7,8.1,-34.9,-10.0,14.5,-8.6,,,,,,,,,,,,,,,,*05
$PSTMVRES,0.3,-0.0,0.0,-0.0,0.3,0.0,-0.5,-0.5,0.1,,,,,,,,,,,,,,,,*0B
$PSTMTG,2034,553618.0000,8,128199118,10,-46760.0000,002a,1025,0,0,10,2034,553618.0000,10,2034,553618.0000,6*5A
$PSTMTS,1,23,87178102.875,-44634.02,01,36,107871,1,9650745.91,13059080.41,21268551.81,-1601.01,2104.54,-615.14,-60384.66,6.69,0,0.00,0.00,0,0,0,0*01
$PSTMTS,1,09,88801609.812,-43889.80,01,34,102805,1,16028885.38,3193585.53,20890300.53,-1492.86,2210.83,804.75,142511.90,11.66,0,0.00,0.00,0,0,0,0*07
$PSTMTS,1,03,86575601.125,-48258.84,01,30,78613,1,13348561.56,22507400.16,4720188.47,-3.99,659.00,-3098.78,52480.77,6.38,0,0.00,0.00,0,0,0,0*2D
$PSTMTS,1,16,85874269.688,-47283.16,01,27,75521,1,-1886095.16,22466622.38,13519219.09,-747.65,-1602.10,2568.93,-3251.94,5.72,0,0.00,0.00,0,0,0,0*2A
$PSTMTS,1,26,3381954.688,-49146.08,00,18,53036,1,-8037289.25,15873771.62,19660297.47,-1174.67,-2217.50,1326.00,26300.98,7.53,0,0.00,0.00,0,0,0,0*3C
$PSTMTS,1,22,3609068.188,-49215.92,00,21,27316,1,10235851.56,24348322.31,-2780494.62,-516.89,-162.93,-3068.35,-184537.24,7.77,0,0.00,0.00,0,0,0,0*08
$PSTMTS,1,27,5418358.750,-44043.68,00,19,77495,1,-10438473.00,23018353.00,-7765070.44,-768.74,651.32,3023.75,-13120.58,14.66,0,0.00,0.00,0,0,0,0*23
$PSTMTS,1,07,90050798.438,-44830.90,01,27,76584,1,25565687.72,6701073.97,4735275.25,-590.77,171.17,3061.98,17221.07,16.12,0,0.00,0.00,0,0,0,0*04
$PSTMTS,1,08,454836.875,-43869.36,00,20,3383,0,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0.00,0,0.00,0.00,0,0,0,0*2B
$PSTMNOTCHSTATUS,3786017,0,2449,0,2,5420680,0,3824,0,2*57
$PSTMADCDATA,943,903,,,,,,*48
$PSTMANTENNASTATUS,0*4D
$PSTMSBAS,0,0,,,,*19
$PSTMCPU,48.64,-1,49*41

任何帮助/建议将不胜感激。

感谢克里福德的建议。我需要解析来自 RMC、VTG、GGA 和 GSA 的数据。我无法更改波特率,也无法停止专有语句。

标签: gpsembeddedst

解决方案


GNSS 的输出没有任何“错误”;这样的设备输出一些标准的和专有的句子是正常的。您有责任将模块配置为仅输出您需要的句子或解析句子并丢弃您不想要的句子。

向 GNSS 发送以下命令以禁用除 RMC 语句之外的所有可配置语句:

$PSMTSETPAR,1201,0X00000040*75

您需要在每次启动时发送此配置,或通过以下方式将配置保存在非易失性存储器中:

$PSMTSAVEPAR*58

有可能模块会输出其他不可配置的语句(具体模块我不熟悉);您可能仍需要在主机上执行解析和过滤。这就像解析谈话者 ID 和格式说明符并丢弃您不感兴趣的句子一样简单。有很多方法可以做到这一点;你的问题没有显示出这样的尝试。

你的代码太“低级”了——IEC61162-1(NMEA 0183)句子格式是面向行的,但HAL_UART_Receive_IT()只会在没有任何协议知识的情况下抓取一大块数据,并且与句子结构完全异步——你可以很容易地在句子中间开始和结束。此外HAL_UART_RxCpltCallback(),发生在中断上下文中 - 这不是接收大块数据并对其进行解析的地方。您首先需要一些更高级别的串行 I/O 代码,它将传入的数据缓冲到队列中并支持面向行的输入。

然后,您需要处理每一行 - 丢弃那些不感兴趣的行。从这个意义上说,这是一个过于宽泛的问题,并且与 GNSS 数据解析没有具体关系——这不是你的问题,正如我所说的比它低级——你需要构建一个合适的串行 I/O 基础设施。

另一个问题是您等待接收 2400 个字符,您将获得块中的数据,并且只有最近收到的才是有效的。如果需要实时接收当前位置;你不能那样做。

我不是 ST HAL 专家,不会选择使用它;它的记录很差。看起来你应该做的HAL_UART_RxCpltCallback是将接收到的数据放入一个 FIFO 缓冲区中,该缓冲区将由其他线程处理(即不在中断上下文中);由于 NMEA 句子的长度可变,您需要在单个字符的基础上执行此操作。一种可能更简单的方法是使用零超时轮询 HALL 接收缓冲区并累积字符直到有一行可用。然后,您可以检查该行以查看它是否是 RMC 句子,然后对其进行处理。例如,以下允许对串行输入进行非阻塞处理。如果不需要执行其他功能,则可以将超时时间延长为无限期地等待每个字符:

// Strictly NMEA0183 requires only 81 byte sentence buffer, but 
// L89 appears to output non-compliant proprietary sentences.
static char line_buffer[1024];
int line_buffer_index = 0;

for (;;)
{
    HAL_StatusTypeDef rx_status = HAL_OK ;
    while( rx_status == HAL_OK )
    {
        // Receive a character if available (zero timeout)
        char ch = 0;
        HAL_StatusTypeDef rx_status = HAL_UART_Receive( &huart2, ch, 1, 0 ) ;

        // If character received and not the LF following the previous CR
        if( rx_status == HAL_OK && ch != `\n ` )
        {
            // If the end of the sentence...
            if( ch == `\r ` )
            {
                // terminate the line
                line_buffer[line_buffer_index] = `\0` ;

                // Start a new line
                line_buffer_index = 0 ;

                // Check if line is an RMC from a GNSS
                if( line_buffer_index > 6 &&
                    memcmp( line_buffer, "$G", 2) == 0 &&
                    memcmp( &line_buffer[3], "RMC", 3) == 0 )
                {
                    // Process RMC
                    processRMC( line_buffer ) ;
                }
            }
            else
            {
                // add character to line buffer
                line_buffer[line_buffer_index] = ch ;
                line_buffer_index++ ;
                if( line_buffer_index > sizeof(line_buffer) - 1 )
                {
                    // Line too long, discard all
                    line_buffer_index = 0 ;
                } 
            }
        }
    }

    // do other work here if necessary
}

推荐阅读