STM32G070串口接收GPS北斗模块数据
串口接收GPS模块数据,只连接MCU的接收脚和GPS模块发送脚。
MCU的发送脚用来打印调试数据等用途。
串口通信程序:
/** **************************************************************************************************** * @file gps_uart1_bsp.h * @author * @version V1.0 * @date 2023-02-22 * @brief * @license **************************************************************************************************** * @attention * 接收GPS模块数据 串口1,中断接收方式,RXNE和IDLE * **************************************************************************************************** */ #ifndef __GPS_UART_BSP_H #define __GPS_UART_BSP_H //#include "./SYSTEM/sys/sys.h" #include "stm32g0xx_hal.h" /** *是否使用RT—thread操作系统 * WIFI_USING_RT_THREAD_OS用于定义系统文件夹是否支持OS * 0,不支持OS * 1,支持OS */ #define GPS_USING_RT_THREAD_OS 1 /* 如果使用os,则包括下面的头文件即可. */ #if GPS_USING_RT_THREAD_OS #include <rtthread.h> /* os 使用 */ #endif /* 引脚定义 */ #define GPS_UART_TX_GPIO_PORT GPIOB #define GPS_UART_TX_GPIO_PIN GPIO_PIN_6 #define GPS_UART_TX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PC口时钟使能 */ #define GPS_UART_RX_GPIO_PORT GPIOB #define GPS_UART_RX_GPIO_PIN GPIO_PIN_7 #define GPS_UART_RX_GPIO_CLK_ENABLE() do{ __HAL_RCC_GPIOB_CLK_ENABLE(); }while(0) /* PC口时钟使能 */ #define GPS_UART_INTERFACE USART1 #define GPS_UART_IRQn USART1_IRQn void GPS_UART_IRQHandler(void); //在中断USART3_4_IRQn中调用,见stm32****_it.c #define GPS_UART_CLK_ENABLE() do{ __HAL_RCC_UART1_CLK_ENABLE(); }while(0) /* UART5时钟使能 */ /* UART收发缓冲大小 */ #define GPS_UART_RX_BUF_SIZE 384 #define GPS_UART_TX_BUF_SIZE 16 #ifdef GPS_USING_RT_THREAD_OS /*防止多个线程访问WIFI,调用wifi接口函数时使用*/ void gps_lock(void); //获取互斥量,得到gps void gps_unlock(void); //释放互斥量,失去gps /*用于接收帧处理函数与接收中断通信*/ uint8_t gps_take_sem(rt_int32_t timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 #endif /* 操作函数 */ void gps_delay_ms(uint16_t n); /*等待GPS应答的延时函数*/ void gps_uart_printf(char *fmt, ...); /* GPS UART printf */ void gps_uart_sendData(uint8_t *p_frame,uint16_t len);/* 向GPS UART发送8位数据组*/ void gps_uart_rx_restart(void); /* GPS UART重新开始接收数据 */ uint8_t *gps_uart_rx_get_frame(void); /* 获取GPS UART接收到的一帧数据 */ uint16_t gps_uart_rx_get_frame_len(void); /* 获取GPS UART接收到的一帧数据的长度 */ void gps_uart_init(uint32_t baudrate); /* GPS UART初始化 */ #endif
/** **************************************************************************************************** * @file gps_uart_bsp.c * @author * @version V1.0 * @date 2023-02-22 * @brief * @license **************************************************************************************************** * @attention * 接收GPS模块数据 串口1,中断接收方式,RXNE和IDLE * **************************************************************************************************** */ #include <gps_uart1_bsp.h> #include "usart.h" #include <stdarg.h> #include <stdio.h> #include <string.h> static UART_HandleTypeDef gps_uart_handle; /* GPS UART */ static struct { uint8_t buf[GPS_UART_RX_BUF_SIZE]; /* 帧接收缓冲 */ struct { uint16_t len : 15; /* 帧接收长度,sta[14:0] */ uint16_t finsh : 1; /* 帧接收完成标志,sta[15] */ } sta; /* 帧状态信息 */ } gps_uart_rx_frame = {0}; /* GPS UART接收帧缓冲信息结构体 */ static uint8_t g_uart_tx_buf[GPS_UART_TX_BUF_SIZE]; /* GPS UART发送缓冲 */ #if GPS_USING_RT_THREAD_OS /* 定义信号量*/ rt_sem_t GPS_RX_IT_sem = RT_NULL; /* 定义互斥量控制块 */ static rt_mutex_t GPS_usart_mux = RT_NULL; // 防止多个线程同时使用WIFI及相应的串口外设 #endif /** * @brief 等待GPS应答的延时函数 * @param 无 * @retval 无 */ //static void gps_delay_one_ms(void)/*等待GPS应答的延时函数*/ { uint16_t i; /* 下面的时间是通过逻辑分析仪测试得到的。 工作条件:CPU主频72MHz ,MDK编译环境,1级优化 循环次数为10时,SCL频率 = 205KHz 循环次数为7时,SCL频率 = 347KHz, SCL高电平时间1.5us,SCL低电平时间2.87us 循环次数为5时,SCL频率 = 421KHz, SCL高电平时间1.25us,SCL低电平时间2.375us */ for (i = 0; i < 1366; i++); } //__weak void gps_delay_ms(uint16_t n) { uint16_t i; for (i = 0; i < n; i++) gps_delay_one_ms(); } /** * @brief GPS UART printf * @param fmt: 待打印的数据 * @retval 无 */ void gps_uart_printf(char *fmt, ...) { va_list ap;//定义一具VA_LIST型的变量,包括 #include <stdarg.h> uint16_t len; va_start(ap, fmt);//用VA_START宏初始化变量刚定义的VA_LIST变量 vsprintf((char *)g_uart_tx_buf, fmt, ap);//具VA_LIST型的变量 va_end(ap);//最后用VA_END宏结束可变参数的获取 len = strlen((const char *)g_uart_tx_buf); HAL_UART_Transmit(&gps_uart_handle, g_uart_tx_buf, len, HAL_MAX_DELAY); } /** * @brief 向GPS UART发送8位数据组 * @param p_frame: 首个BYTE地址,len:字节数 * @retval 无 */ void gps_uart_sendData(uint8_t *p_frame,uint16_t len)// 向GPS UART发送8位数据组 { HAL_UART_Transmit(&gps_uart_handle, p_frame, len, HAL_MAX_DELAY); } /** * @brief GPS UART重新开始接收数据 * @param 无 * @retval 无 */ void gps_uart_rx_restart(void) { //memset( gps_uart_rx_frame.buf,0,sizeof(gps_uart_rx_frame.buf));//清零 gps_uart_rx_frame.sta.len = 0; gps_uart_rx_frame.sta.finsh = 0; } /** * @brief 获取GPS UART接收到的一帧数据 * @param 无 * @retval NULL: 未接收到一帧数据 * 其他: 接收到的一帧数据 */ uint8_t *gps_uart_rx_get_frame(void) { if (gps_uart_rx_frame.sta.finsh == 1) { gps_uart_rx_frame.buf[gps_uart_rx_frame.sta.len] = '\0';//末尾加字符串结束符 return gps_uart_rx_frame.buf; } else { return NULL; } } /** * @brief 获取GPS UART接收到的一帧数据的长度 * @param 无 * @retval 0 : 未接收到一帧数据 * 其他: 接收到的一帧数据的长度 */ uint16_t gps_uart_rx_get_frame_len(void) { if (gps_uart_rx_frame.sta.finsh == 1) { return gps_uart_rx_frame.sta.len; } else { return 0; } } /** * @brief GPS UART初始化 * @param baudrate: UART通讯波特率 * @retval 无 */ void gps_uart_init(uint32_t baudrate) { gps_uart_handle.Instance = GPS_UART_INTERFACE; /* GPS UART */ gps_uart_handle.Init.BaudRate = baudrate; /* 波特率 */ gps_uart_handle.Init.WordLength = UART_WORDLENGTH_8B; /* 数据位 */ gps_uart_handle.Init.StopBits = UART_STOPBITS_1; /* 停止位 */ gps_uart_handle.Init.Parity = UART_PARITY_NONE; /* 校验位 */ gps_uart_handle.Init.Mode = UART_MODE_TX_RX; /* 收发模式 */ gps_uart_handle.Init.HwFlowCtl = UART_HWCONTROL_NONE; /* 无硬件流控 */ gps_uart_handle.Init.OverSampling = UART_OVERSAMPLING_16; /* 过采样 */ HAL_UART_Init(&gps_uart_handle); /* 使能GPS UART * HAL_UART_Init()会调用函数HAL_UART_MspInit() * 该函数定义在文件usart.c中 */ HAL_NVIC_SetPriority(GPS_UART_IRQn, 0, 0); HAL_NVIC_EnableIRQ(GPS_UART_IRQn); __HAL_UART_ENABLE_IT(&gps_uart_handle, UART_IT_IDLE);// 开空闲中断 __HAL_UART_ENABLE_IT(&gps_uart_handle, UART_IT_RXNE);// 开接收非空中断 #if GPS_USING_RT_THREAD_OS /* 创建一个互斥信号*/ GPS_usart_mux = rt_mutex_create("gps_mux",RT_IPC_FLAG_PRIO); if (GPS_usart_mux == RT_NULL) rt_kprintf("error@ %s %s:%d,The mux for gps uart can‘t be created!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 /* 创建一个信号*/ GPS_RX_IT_sem = rt_sem_create("binary_sem", 0, RT_IPC_FLAG_FIFO); if (GPS_RX_IT_sem == RT_NULL) rt_kprintf("error@ %s %s:%d,The semphore for gps uart can‘t be created!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 #endif } /** * @brief GPS_UART互斥锁 * @param baudrate: UART通讯波特率 * @retval 无 */ #if GPS_USING_RT_THREAD_OS void gps_lock(void) { rt_mutex_take( GPS_usart_mux,RT_WAITING_FOREVER); //获取互斥量 } void gps_unlock(void) { rt_mutex_release( GPS_usart_mux ); //释放互斥量 } #endif /** * @brief 线程调用的应用函数与串口通信中断同步信号 * @param timeout: 延时多少ticks * @retval 无 */ #if GPS_USING_RT_THREAD_OS uint8_t gps_take_sem(rt_int32_t timeout) { rt_err_t uwRet = RT_EOK; //GPS_RX_IT_sem->value =0;//信号值清零 uwRet = rt_sem_take(GPS_RX_IT_sem, timeout);//等待信号量 if(-RT_ETIMEOUT == uwRet){ rt_kprintf("error@ %s %s:%d, GPS_RX_IT_sem:time out!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 return 1;//超时 } if(-RT_ERROR == uwRet){ rt_kprintf("error@ %s %s:%d,GPS_RX_IT_sem:ERROR!r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 return 2;//错误 } /* 如果信号接收完成并且正确 */ return 0; } uint8_t gps_release_sem(void) { rt_sem_release(GPS_RX_IT_sem);//放出信号量 return 0; } #endif /** * @brief GPS UART中断回调函数 * @param 无 * @retval 无 */ void GPS_UART_IRQHandler(void) { uint8_t tmp; if (__HAL_UART_GET_FLAG(&gps_uart_handle, UART_FLAG_ORE) != RESET) /* UART接收过载错误中断 */ { __HAL_UART_CLEAR_OREFLAG(&gps_uart_handle); /* 清除接收过载错误中断标志 */ (void)gps_uart_handle.Instance->ISR;//SR; /* 先读SR寄存器,再读DR寄存器 */ (void)gps_uart_handle.Instance->RDR;//DR; } if (__HAL_UART_GET_FLAG(&gps_uart_handle, UART_FLAG_RXNE) != RESET) /* UART接收中断 */ { HAL_UART_Receive(&gps_uart_handle, &tmp, 1, HAL_MAX_DELAY); /* UART接收数据 */ if(gps_uart_rx_frame.sta.finsh ==1 ) return; if (gps_uart_rx_frame.sta.len < (GPS_UART_RX_BUF_SIZE - 1)) /* 判断UART接收缓冲是否溢出 * 留出一位给结束符'\0' */ { gps_uart_rx_frame.buf[gps_uart_rx_frame.sta.len] = tmp; /* 将接收到的数据写入缓冲 */ gps_uart_rx_frame.sta.len++; /* 更新接收到的数据长度 */ } else /* UART接收缓冲溢出 */ { gps_uart_rx_frame.sta.len = 0; /* 覆盖之前收到的数据 */ gps_uart_rx_frame.buf[gps_uart_rx_frame.sta.len] = tmp; /* 将接收到的数据写入缓冲 */ gps_uart_rx_frame.sta.len++; /* 更新接收到的数据长度 */ } } if (__HAL_UART_GET_FLAG(&gps_uart_handle, UART_FLAG_IDLE) != RESET) /* UART总线空闲中断 */ { gps_uart_rx_frame.sta.finsh = 1; /* 标记帧接收完成 */ __HAL_UART_CLEAR_IDLEFLAG(&gps_uart_handle); /* 清除UART总线空闲中断 */ #if GPS_USING_RT_THREAD_OS gps_release_sem(); /* 发送信号,通知帧接收完成 */ #endif } }
在中断程序stm32g0xx_it.c中,添加代码如下
/** * @brief This function handles USART1 global interrupt / USART1 wake-up interrupt through EXTI line 25. */ void USART1_IRQHandler(void) { /* USER CODE BEGIN USART1_IRQn 0 */ GPS_UART_IRQHandler(); /* USER CODE END USART1_IRQn 0 */ // HAL_UART_IRQHandler(&huart1); /* USER CODE BEGIN USART1_IRQn 1 */ /* USER CODE END USART1_IRQn 1 */ }
GPS模块数据解析程序:
gps_driver.h
/** **************************************************************************************************** * @file gps_driver.h * @author * @version V1.0 * @date 2023-02-22 * @brief * @license **************************************************************************************************** * @attention * AT指令操作WIFI模块的硬件驱动函数 * **************************************************************************************************** */ #ifndef __GPS_DRIVER_H #define __GPS_DRIVER_H #include "stm32g0xx_hal.h" //$ GNGLL,<1>,<2>,<3>,<4>,<5>,<6>,<7><8> //$ GNGLL,2253.7220,N,11350.7025,E,012842.000,A,A4D //<1> 纬度 ddmm.mmmmm(度分) 10个char //<2> 纬度半球 N(北半球)或 S(南半球)1个char //<3> 经度 dddmm.mmmmm(度分)11个char //<4> 经度半球 E(东经)或 W(西经) //<5> UTC 时间:hhmmss(时分秒)6个char //<6> 定位状态,A=有效定位,V=无效定位 1个char //<7> 模式指示(A=自主定位,D=差分,E=估算,N=数据无效) 1个char //<8> 校验和 typedef struct { char latitude[10+1]; //纬度 char longitude[11+1]; //经度 char north[1+1]; char east[1+1]; char UTC[10+1]; char validPosition[1+1]; //定位有效A 定位无效V }gps_gll_type; //$GNRMC,132506.000,A,2233.87430,N,11407.13740,E,0.00,244.71,080522,,,A,V*0A //$GNRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>,<13>,*CS //RMC推荐的最少专用导航数据 //<1> 132506.000:定位点的UTC时间,hhmmss.sss(时分秒.毫秒)格式 //<2> A: 定位状态,A=定位,V=未定位 //<3> 2233.87430:纬度ddmm.mmmm(度分)格式(前导位数不足补0) //<4> N:纬度半球N(北半球)或S(南半球) //<5> 11407.13740:经度dddmm.mmmm(度分)格式(前导位数不足补0) //<6> E:经度半球E(东经)或W(西经) //<7> 0.00:对地航速,单位:Knots,范围:000.0-999.9 //<8> 244.71:对地航向,单位:度,以真北为参考基准,二维方向指向,相当于二维罗盘 //<9> 080522:定位到UTC日期,格式:ddmmyy(日月年) //<10> :磁偏角,单位:度,范围:000-180 //<11> :磁偏角方向,E:东,W:西 //<12> A:定位模式标志,A:自主模式,E:估算模式,N:数据无效,D:差分模式 //<13> V:导航状态标志,V表示系统不输出导航状态信息 //<CS> *0A:校验和 typedef struct { char latitude[10+1]; //纬度 char longitude[11+1]; //经度 char north[1+1]; //北半球 char east[1+1]; //东半球 char UTC_time[10+1]; //UTC 时间 char UTC_date[6+1]; //UTC 日期 char validPosition[1+1]; //定位有效A 定位无效V }gps_rmc_type; void gps_setup(void);//启动GPS线程,开串口,收GPS报文 uint8_t gps_get_gll(uint32_t timeout);//经纬度,时间 uint8_t gps_get_rmc(uint32_t timeout);//经纬度,时间,日期 __weak void gps_callback(void); #endif
gps_driver.h
线程函数 完成 根据GPS数据修改STM32内RTC,并计算太阳位置。
#include <gps_driver.h> #include <gps_uart1_bsp.h> #include <sunPosition.h> #include "usart.h" #include <stdarg.h> #include <stdio.h> #include <string.h> #include <stdlib.h> #include "rtc.h" #include <sunPosition.h> #include <timeformat.h> #include "main.h" gps_gll_type gps_gll; gps_rmc_type gps_rmc; volatile spa_data mspa_data; /* RT-Thread 定义线程控制块指针 */ static rt_thread_t gps_read_thread = RT_NULL; /* *********************************************** * 函 数 名: gps_read_thread_entry * 功能说明: 线程程序,启动串口与GPS模块通信,将GPS字符串转为UTC时间和经纬度 * 形 参:无 * 返 回 值: 无 * 全局变量: ************************************************ */ static void gps_read_thread_entry(void* parameter)/*通过与GPS通信,得到经纬度、UTC时间等*/ { static int32_t time; static int32_t date; int32_t temp; float longitude; float latitude; float ftemp; RTC_TimeTypeDef sTime = {0}; RTC_DateTypeDef sDate = {0}; rt_enter_critical(); /* 进入临界段,禁切换线程 */ gps_uart_init(9600); /* GPS UART初始化 */ /* 退出临界段 */ rt_exit_critical(); /* 退出临界段,可切换线程 */ while(1) { // while(0 != gps_get_gll(1000)){};//阻塞方式,通过串口获得经纬度,时间 while(0 != gps_get_rmc(1000)){};//阻塞方式,通过串口获得经纬度,时间 if(gps_rmc.validPosition[0] !='A') continue; /*无效GPS数据*/ /*GPS字符串转为数值*/ __disable_irq();//因中断处理gps_gll,需要关总中断 /*转换与赋值*/ gps_rmc.UTC_time[6] ='\0'; time = atoi(gps_rmc.UTC_time);// BCD编码hh mm ss 字符串按照10进制转为数值 date = atoi(gps_rmc.UTC_date);// BCD编码dd mm yy 字符串按照10进制转为数值 longitude = atof(gps_rmc.longitude);// BCD编码ddd mm.mmmm latitude = atof(gps_rmc.latitude); // BCD编码 dd mm.mmmm /*分割数据*/ temp = time%100; sTime.Seconds = temp; temp = time/100; temp = temp%100; sTime.Minutes = temp; temp = time/10000; temp = temp%100; sTime.Hours = temp; /*分割数据*/ temp = date%100; sDate.Year = temp; temp = date/100; temp = temp%100; sDate.Month = temp; temp = date/10000; temp = temp%100; sDate.Date = temp; /*解析数据*/ temp = (int32_t)(longitude); temp = temp/100; ftemp = longitude - temp*100; ftemp = ftemp/60; longitude = ftemp + temp; /*解析数据*/ temp = (int32_t)(latitude); temp = temp/100; ftemp = latitude - temp*100; ftemp = ftemp/60; latitude = ftemp + temp; //更新RTC时间为NTC时间 sTime.SubSeconds = 0x0; sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE; sTime.StoreOperation = RTC_STOREOPERATION_RESET; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } sDate.WeekDay = RTC_WEEKDAY_MONDAY; if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } __enable_irq();//因中断处理gps_gll,需要开总中断 /*BCD编码转为16进制编码*/ mspa_data.year = Bcd2ToByte(sDate.Year); mspa_data.month = Bcd2ToByte(sDate.Month); mspa_data.day = Bcd2ToByte(sDate.Date); /*BCD编码转为16进制编码*/ mspa_data.hour = Bcd2ToByte(sTime.Hours); mspa_data.minute = Bcd2ToByte(sTime.Minutes); mspa_data.second = Bcd2ToByte(sTime.Seconds); /*BCD编码转为16进制编码*/ mspa_data.longitude = longitude; mspa_data.latitude = latitude; mspa_data.timezone =8;//北京时间,为东8区 rt_kprintf("GPS SUNPOS! %s %s:%d\r\n", __FILE__, __FUNCTION__, __LINE__); // 根据日期算天数 date2days_cal( (spa_data*)&mspa_data); // 计算太阳信息 sunpos_cal((spa_data*)&mspa_data); // 打印spa_data sunpos_print((spa_data*)&mspa_data); gps_callback(); } } /** * @brief gps_callback * @param * @retval * */ __weak void gps_callback(void) { rt_kprintf(" %s %s:%d\r\n", __FILE__, __FUNCTION__, __LINE__); }; /** * @brief gps_setup * @param * @retval * */ void gps_setup(void) { /*创建线程控制块,并赋给一个该类型指针变量f*/ gps_read_thread = /* 线程控制块指针 */ rt_thread_create( "wifi_regs", /* 线程名字 */ gps_read_thread_entry, /* 线程入口函数 */ RT_NULL, /* 线程入口函数参数 */ 1024, /* 线程栈大小 */ 1, /* 线程的优先级 */ 200); /* 线程时间片 */ /* 启动线程,开启调度 */ if (gps_read_thread != RT_NULL){ rt_thread_startup(gps_read_thread); return; } rt_kprintf("error@ %s %s:%d\r\n", __FILE__, __FUNCTION__, __LINE__);//当前行所在文件名、函数名、第**行代码 } /** * @brief gps_get_gll 经纬度,时间 * @param * timeout: 等待超时时间 * @retval 0 : 函数执行成功 * 1 : 等待期望应答超时,函数执行失败 */ //$ GNGLL,<1>,<2>,<3>,<4>,<5>,<6>,<7><8> //$ GNGLL,2253.7220,N,11350.7025,E,012842.000,A,A4D //<1> 纬度 ddmm.mmmmm(度分) 10个char //<2> 纬度半球 N(北半球)或 S(南半球)1个char //<3> 经度 dddmm.mmmmm(度分)11个char //<4> 经度半球 E(东经)或 W(西经) //<5> UTC 时间:hhmmss(时分秒)10个char //<6> 定位状态,A=有效定位,V=无效定位 1个char //<7> 模式指示(A=自主定位,D=差分,E=估算,N=数据无效) 1个char //<8> 校验和 2个char uint8_t gps_get_gll(uint32_t timeout)//经纬度,时间 { uint8_t *ret = NULL; uint8_t ubRet; uint16_t len; char *frame_start; char *frame_end; char *p_start; char *p_end; gps_uart_rx_restart(); if (timeout == 0) { return 2; } else { receive: ubRet = gps_take_sem(timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 if( ubRet ==0){//从通信帧中查找ack ret = gps_uart_rx_get_frame(); if (ret == NULL){// ret没有字符串 gps_uart_rx_restart();//清零RX缓冲 return 2; } frame_start=strstr((const char *)ret, "GLL"); if (frame_start== NULL)//在ret字符串中查找 "GNGLL" { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } frame_end= 51+frame_start; /*纬度字符串*/ //<1> 纬度 ddmm.mmmmm(度分) 10个char p_start = strstr((const char *)frame_start, ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } if(p_end>=frame_end) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!=10) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_gll.latitude, p_start+1, len); gps_gll.latitude[len] ='\0'; /*北半球字符串*/ //<2> 纬度半球 N(北半球)或 S(南半球)1个char p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } if(p_end>=frame_end) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!=1) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_gll.north, p_start+1, len); gps_gll.north[len] ='\0'; /*经度字符串*/ //<3> 经度 dddmm.mmmmm(度分)11个char p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } if(p_end>=frame_end) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!=11) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_gll.longitude, p_start+1, len); gps_gll.longitude[len] ='\0'; /*东半球字符串*/ //<4> 经度半球 E(东经)或 W(西经) p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } if(p_end>=frame_end) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!=1) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_gll.east, p_start+1, len); gps_gll.east[len] ='\0'; /*时间字符串*/ //<5> UTC 时间:hhmmss(时分秒)10个char p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } if(p_end>=frame_end) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!=10) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_gll.UTC, p_start+1, len); gps_gll.UTC[len] ='\0'; /*定位状态字符串 定位状态,A=有效定位,V=无效定位*/ //<6> 定位状态,A=有效定位,V=无效定位 1个char p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } if(p_end>=frame_end) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!=1) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_gll.validPosition, p_start+1, len); gps_gll.validPosition[len] ='\0'; return 0; } if(ubRet ==1){ /*超时,没有接收数据*/ return 1; } if(ubRet ==2){ /*错误,没有接收数据*/ return 2; } return 0; } } //串口助手:$GNRMC,095554.000,A,2318.1327,N,11319.7252,E,000.0,005.7,081215,,,A*73 // 需要根据具体报文编写 // $GNRMC,132506.000,A,2233.87430,N,11407.13740,E,0.00,244.71,080522,,,A,V*0A //$GNRMC,<1>,<2>,<3>,<4>,<5>,<6>,<7>,<8>,<9>,<10>,<11>,<12>,<13>,*CS //RMC推荐的最少专用导航数据 #define UTC_TIME_1 10 /* 10BYTE*/ //<1> 132506.000:定位点的UTC时间,hhmmss.sss(时分秒.毫秒)格式 10BYTE #define LOCATE_STATE_2 1 /* 1 BYTE*/ //<2> A: 定位状态,A=定位,V=未定位 #define LATITUDE_3 9 /* 9 BYTE ,必须根据GPS模块修改*/ //<3> 2233.8743:纬度ddmm.mmmm(度分)格式(前导位数不足补0) #define IS_NORTHERN_HEMISPHERE_4 1 /* 1 BYTE*/ //<4> N:纬度半球N(北半球)或S(南半球) #define LONGITUDE_5 10 /* 10 BYTE ,必须根据GPS模块修改*/ //<5> 11407.1374:经度dddmm.mmmm(度分)格式(前导位数不足补0) #define IS_EASTERN_HEMISPHERE_6 1 /* 1 BYTE,这里没有用*/ //<6> E:经度半球E(东经)或W(西经) #define NAVIGATIONAL_SPEED_7 5 /* 5 BYTE*,这里没有用*/ //<7> 0.00:对地航速,单位:Knots,范围:000.0-999.9 #define NAVIGATIONAL_DIRECTION_8 6 /* 6 BYTE,这里没有用*/ //<8> 244.71:对地航向,单位:度,以真北为参考基准,二维方向指向,相当于二维罗盘 #define UTC_DATE_9 6 /* 6 BYTE*/ //<9> 080522:定位到UTC日期,格式:ddmmyy(日月年) #define MAGNETIC_DECLINATION_10 3 /* 3 BYTE,这里没有用*/ //<10> :磁偏角,单位:度,范围:000-180 #define MAGNETIC_DECLINATION_ORIENT_11 1 /* 1 BYTE,这里没有用*/ //<11> :磁偏角方向,E:东,W:西 #define LOCATION_MODE_12 1 /* 1 BYTE,这里没有用*/ //<12> A:定位模式标志,A:自主模式,E:估算模式,N:数据无效,D:差分模式 #define PILOT_STATE_13 1 /* 1 BYTE,这里没有用*/ //<13> V:导航状态标志,V表示系统不输出导航状态信息 #define CHECK_SUM_14 2 /* 2 BYTE,这里没有用*/ //<CS> *0A:校验和 // $GNRMC 6, 逗号 10, 各参数数据BYTES #define RMC_FOLLOW_USED_BYTES 6+10+UTC_TIME_1+LOCATE_STATE_2+LONGITUDE_5+IS_NORTHERN_HEMISPHERE_4+LATITUDE_3+IS_EASTERN_HEMISPHERE_6+NAVIGATIONAL_SPEED_7+NAVIGATIONAL_DIRECTION_8+UTC_DATE_9 uint8_t gps_get_rmc(uint32_t timeout)//经纬度,时间 { uint8_t *pframe = NULL; uint8_t ubRet; uint16_t len; char *frame_start; char *p_start; char *p_end; gps_uart_rx_restart(); if (timeout == 0) { return 2; } else { receive: ubRet = gps_take_sem(timeout);//已接收帧,但串口没有接收到新的字节。等待这种情况 if( ubRet ==0){//从通信帧中查找ack pframe = gps_uart_rx_get_frame(); if (pframe == NULL){// ret没有字符串 gps_uart_rx_restart();//清零RX缓冲 return 2; } frame_start=strstr((const char *)pframe , "RMC"); if (frame_start== NULL)//在ret字符串中查找 "GNRMC" { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } if(gps_uart_rx_get_frame_len()< RMC_FOLLOW_USED_BYTES) goto receive;//通信帧中没有足够的字符,再次接收新的帧 //<1> 132506.000:定位点的UTC时间,hhmmss.sss(时分秒.毫秒)格式 10BYTE p_start = strstr((const char *)frame_start, ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= UTC_TIME_1) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_rmc.UTC_time, p_start+1, UTC_TIME_1); gps_rmc.UTC_time[UTC_TIME_1] ='\0'; //<2> A: 定位状态,A=定位,V=未定位 p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= LOCATE_STATE_2) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_rmc.validPosition, p_start+1, LOCATE_STATE_2); gps_rmc.validPosition[LOCATE_STATE_2] ='\0'; //<3> 2233.8743:纬度ddmm.mmmm(度分)格式(前导位数不足补0) p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= LATITUDE_3) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_rmc.latitude, p_start+1,LATITUDE_3); gps_rmc.latitude[LATITUDE_3] ='\0'; //<4> N:纬度半球N(北半球)或S(南半球) p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= IS_NORTHERN_HEMISPHERE_4) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_rmc.north, p_start+1,IS_NORTHERN_HEMISPHERE_4); gps_rmc.north[IS_NORTHERN_HEMISPHERE_4] ='\0'; //<5> 11407.13740:经度dddmm.mmmm(度分)格式(前导位数不足补0) p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= LONGITUDE_5) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_rmc.longitude, p_start+1,LONGITUDE_5); gps_rmc.longitude[LONGITUDE_5] ='\0'; //<6> E:经度半球E(东经)或W(西经) p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= IS_EASTERN_HEMISPHERE_6) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_rmc.east, p_start+1,IS_EASTERN_HEMISPHERE_6); gps_rmc.east[IS_EASTERN_HEMISPHERE_6] ='\0'; //<7> 0.00:对地航速,单位:Knots,范围:000.0-999.9 p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= NAVIGATIONAL_SPEED_7) { //gps_uart_rx_restart();//清零RX缓冲 //goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } //memcpy(gps_rmc.east, p_start+1,NAVIGATIONAL_SPEED_7); //gps_rmc.east[NAVIGATIONAL_SPEED_7] ='\0'; //<8> 244.71:对地航向,单位:度,以真北为参考基准,二维方向指向,相当于二维罗盘 p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= NAVIGATIONAL_DIRECTION_8) { //gps_uart_rx_restart();//清零RX缓冲 //goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } //memcpy(gps_rmc.east, p_start+1,NAVIGATIONAL_DIRECTION_8); //gps_rmc.east[NAVIGATIONAL_DIRECTION_8] ='\0'; //<9> 080522:定位到UTC日期,格式:ddmmyy(日月年) p_start = strstr((const char *)(p_end), ","); if (p_start== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } p_end = strstr((const char *)(p_start+1), ","); if (p_end== NULL)//在ret字符串中查找 "," { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } len = p_end - ( p_start+1 ) ; if(len!= UTC_DATE_9) { gps_uart_rx_restart();//清零RX缓冲 goto receive;//从通信帧中没有找到目标字符串,再次接收新的帧 } memcpy(gps_rmc.UTC_date, p_start+1,UTC_DATE_9); gps_rmc.UTC_date[UTC_DATE_9] ='\0'; return 0; } if(ubRet ==1){ /*超时,没有接收数据*/ return 1; } if(ubRet ==2){ /*错误,没有接收数据*/ return 2; } return 0; } }
测试算例:
在串口助手ASCII格式,发送: $GNRMC,095554.000,A,2318.1327,N,11359.7252,E,000.0,005.7,040315,,,A*73
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET10 - 预览版1新功能体验(一)