Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
GPS
学习笔记
RT-Thread 入门学习笔记:使用虚拟GPS设备验证GPS nmea解析
发布于 2022-02-23 12:52:57 浏览:1339
订阅该版
[tocm] [RT-Thread 入门学习笔记 - 目录](https://club.rt-thread.org/ask/article/3420.html) ## 引言 - 抽象一个虚拟的GPS 字符设备,用于验证GPS nmea 数据的解析 - 熟悉 RT-Thread ringbuffer 的使用 ## 虚拟GPS - gps_vdev.c : 注册一个虚拟的GPS设备 ```c #include
#include
#ifndef VGPS_DEVICE_NAME #define VGPS_DEVICE_NAME "gps" #endif #define VGPS_DEVICE_FIFO_SIZE 512 #define DBG_TAG "vgps.dev" #define DBG_LVL DBG_LOG #include
static struct rt_device _vgps_dev; static rt_thread_t vgps_dev_thread = RT_NULL; struct rt_ringbuffer *vgps_dev_fifo = RT_NULL; static char rmc_buf[] = "$GPRMC,031024.000,A,3115.6422,N,12127.5490,E,0.58,98.86,180918,,,A*5A\r\n"; static rt_err_t _vgps_dev_init(rt_device_t dev) { return RT_EOK; } static rt_err_t _vgps_dev_open(rt_device_t dev, rt_uint16_t oflag) { if (dev == RT_NULL) return -RT_ERROR; return RT_EOK; } static rt_err_t _vgps_dev_close(rt_device_t dev) { if (dev == RT_NULL) return -RT_ERROR; return RT_EOK; } rt_size_t _vgps_dev_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size) { return rt_ringbuffer_get(vgps_dev_fifo, buffer, size); } rt_size_t _vgps_dev_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size) { LOG_I("%s : buffer = %s, size = %d\r\n", __func__, buffer, size); return RT_EOK; } static rt_err_t _vgps_dev_control(rt_device_t dev, int cmd, void *args) { if (dev == RT_NULL) return -RT_ERROR; switch (cmd) { default: break; } return RT_EOK; } #ifdef RT_USING_DEVICE_OPS const static struct rt_device_ops gps_vdev_ops = { _vgps_dev_init, _vgps_dev_open, _vgps_dev_close, _vgps_dev_read, _vgps_dev_write, _vgps_dev_control }; #endif static int vgps_device_register(const char *name, void *user_data) { _vgps_dev.type = RT_Device_Class_Char; _vgps_dev.rx_indicate = RT_NULL; _vgps_dev.tx_complete = RT_NULL; #ifdef RT_USING_DEVICE_OPS _vgps_dev.ops = &gps_vdev_ops; #else _vgps_dev.init = _vgps_dev_init; _vgps_dev.open = _vgps_dev_open; _vgps_dev.close = _vgps_dev_close; _vgps_dev.read = _vgps_dev_read; _vgps_dev.write = _vgps_dev_write; _vgps_dev.control = _vgps_dev_control; #endif _vgps_dev.user_data = user_data; /* register device */ rt_device_register(&_vgps_dev, name, RT_DEVICE_FLAG_RDWR); return 0; } void vgps_device_thread_entry(void *param) { rt_thread_mdelay(5000); while (1) { rt_thread_mdelay(1000); if (_vgps_dev.rx_indicate != RT_NULL) { rmc_buf[26] = rt_tick_get() % 10 + 0x30; rmc_buf[35] = rt_tick_get() % 9 + 0x30; rt_ringbuffer_put(vgps_dev_fifo, rmc_buf, rt_strlen(rmc_buf)); _vgps_dev.rx_indicate(&_vgps_dev, rt_strlen(rmc_buf)); } } } rt_err_t vgps_device_fifo_init(void) { vgps_dev_fifo = rt_ringbuffer_create(VGPS_DEVICE_FIFO_SIZE); if (vgps_dev_fifo == RT_NULL) { LOG_E("%s : fifo create error!", __func__); return -RT_ERROR; } return RT_EOK; } rt_err_t vgps_device_init(void) { rt_err_t ret = RT_EOK; vgps_device_fifo_init(); vgps_device_register(VGPS_DEVICE_NAME, RT_NULL); if (vgps_dev_thread != RT_NULL) { LOG_I("%s gps vdev thread already!", __func__); return -RT_ERROR; } vgps_dev_thread = rt_thread_create("gps_vdev", vgps_device_thread_entry, RT_NULL, 1024, 20, 30); if (vgps_dev_thread != RT_NULL) { ret = rt_thread_startup(vgps_dev_thread); LOG_D("%s gps vdev thread ok!", __func__); } else { LOG_E("%s gps vdev thread failed!", __func__); } return ret; } INIT_DEVICE_EXPORT(vgps_device_init); ``` ## GPS解析 - app_gps.c : 接收并解析 GPS数据 ```c #include
#include
#include
#define DBG_TAG "vgps.app" #define DBG_LVL DBG_LOG #include
#define GPS_RX_BUF_MAX_LEN 1024 #define DBG_BUFF_MAX_LEN 256 #define VGPS_DEVICE_NAME "gps" static rt_sem_t gps_rx_sem = RT_NULL; static char gps_rx_buf[GPS_RX_BUF_MAX_LEN] = { 0 }; static double latitude = 0x00; static double longitude = 0x00; static rt_device_t gps_device = RT_NULL; /* [DEBUG] for float printf */ int nmea_printf(const char *fmt, ...) { va_list args; static char rt_log_buf[DBG_BUFF_MAX_LEN] = { 0 }; va_start(args, fmt); int length = vsnprintf(rt_log_buf, sizeof(rt_log_buf) - 1, fmt, args); rt_kputs(rt_log_buf); return length; } static rt_err_t vgps_rx_ind(rt_device_t dev, rt_size_t size) { rt_sem_release(gps_rx_sem); return RT_EOK; } rt_err_t vgps_device_open(void) { rt_err_t ret = RT_EOK; gps_device = rt_device_find(VGPS_DEVICE_NAME); if (gps_device == RT_NULL) { LOG_E("%s : Err, not find device [%s]", __func__, VGPS_DEVICE_NAME); return -RT_ERROR; } ret = rt_device_open(gps_device, RT_DEVICE_FLAG_RDWR); if (ret != RT_EOK) { LOG_E("%s:Err, open device!", __func__, ret); return -RT_ERROR; } ret = rt_device_set_rx_indicate(gps_device, vgps_rx_ind); if (ret != RT_EOK) { LOG_E("%s:error=%d!", __func__, ret); } return ret; } rt_size_t vgps_device_read(void *buffer, rt_size_t length) { if (gps_device == RT_NULL) { LOG_E("%s Err, open device first!", __func__); return 0; } return rt_device_read(gps_device, 0, buffer, length); } /* parse nmea string */ void gps_nmea_parse(char *buf, rt_uint32_t len) { nmea_rmc_t nmea_rmc_buf = { 0 }; int nmea_type = nmea_pack_type(buf, len); if (nmea_type == GPRMC) { nmea_parse_rmc(buf, len, &nmea_rmc_buf); latitude = lat_lon_convert(nmea_rmc_buf.lat); longitude = lat_lon_convert(nmea_rmc_buf.lon); nmea_printf("\r\nlat = %lf\r\n", latitude); nmea_printf("lon = %lf\r\n", longitude); } } /* gsp receive task */ static void gps_rx_thread(void *param) { char ch = 0; int cnt = 0; LOG_D("gps_thread_entry\n"); vgps_device_open(); rt_thread_mdelay(2000); while (1) { while (vgps_device_read(&ch, 1) != 1) { rt_sem_take(gps_rx_sem, RT_WAITING_FOREVER); } gps_rx_buf[cnt++] = ch; if (ch == '\n' || ch == '\0') { if (cnt < GPS_RX_BUF_MAX_LEN) gps_rx_buf[cnt] = '\0'; gps_nmea_parse(gps_rx_buf, rt_strlen(gps_rx_buf)); cnt = 0; rt_memset(gps_rx_buf, 0, GPS_RX_BUF_MAX_LEN); } } } /* vgps application init */ int vgps_app_init(void) { rt_thread_t tid = RT_NULL; gps_rx_sem = rt_sem_create("gps_rx", 0, RT_IPC_FLAG_FIFO); if (gps_rx_sem == RT_NULL) { LOG_E("create gps_rx_sem failed."); return -RT_ERROR; } tid = rt_thread_create("gps_rx", gps_rx_thread, RT_NULL, 2048, 20, 30); if (tid != RT_NULL) { rt_thread_startup(tid); LOG_D("%s gps_rx ok!", __func__); } else { LOG_E("%s gps_rx failed!", __func__); } return RT_EOK; } INIT_APP_EXPORT(vgps_app_init); ``` ## NMEA解析库 - 我重新整理了一下:nmealib,可以参考: `https://gitee.com/zhangsz0516/rtt_nmea` ## 例程位置 ` https://gitee.com/zhangsz0516/rtt_nmea/tree/master/bsp/simulator_vgps ` ## 演示效果 ![2022-02-23_124749.png](https://oss-club.rt-thread.org/uploads/20220223/d59041a1845d06424c1d09905422ed38.png) ## ringbuffer 用于设备读取 - device read 可以读取任意的长度的字符,普通的字符数组,无法满足要求 - 虚拟设备需要像真实的物理设备一样【吐数据】 - 主要API ```c rt_ringbuffer_create : 动态创建, rt_ringbuffer_put : 压入数据 rt_ringbuffer_get : 获取数据 ``` ## 小结 - 为啥搞个虚拟的设备?主要是为了快速验证GPS nmea解析 - 如何使用真实(物理)设备?参考虚拟gps设备的实现 - 学到了什么? RT-Thread ringbuffer 的使用
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
张世争
学以致用
文章
131
回答
813
被采纳
177
关注TA
发私信
相关文章
1
debug工具没法接收到gps接的usart2发送的数据
2
gps rmc软件包不能获取数据
3
lwgps和spl06似乎有冲突,两者无法并存
4
使用lwgps如何获得gps数据
5
大家调试过的GPS模块有哪些?
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
USB
DMA
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
FAL
rt-smart
ESP8266
I2C_IIC
UART
WIZnet_W5500
ota在线升级
PWM
cubemx
flash
freemodbus
BSP
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
flashDB
GD32
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
SFUD
msh
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
813
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
149
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
3
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部