Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
串口
二氧化碳传感器串口调试问题
发布于 2021-11-05 15:12:17 浏览:800
订阅该版
背景:senseAIR S8二氧化碳传感器需要串口先发送一串字符串给传感器,然后MCU接收一段传感器发送回的字符串进行解析 刚学习了串口消息队列收发和事件之后,打算采用两个线程,一个发送字符串给传感器,一个接收传感器发回的字符串,然后用接收完成事件来同步两个线程。 问题:当前这份代码,启动程序后,接收线程一直在等待,接收不到消息。但是调试时,就可以接收到,并且发送一次,会接收两次,一次是有用的字符串,一次是没用的字符串。 想请教大佬,如何调整这个思路,让程序运行的时候,自动执行MCU发送给传感器的代码。这个思路还是没想明白。 ```c //串口接收完成事件 static struct rt_event event; #define EVENT_FLAG3 (1 << 3) #define SAMPLE_UART_NAME "uart3" unsigned char CO2_TxBuffer[8] = { 0xFE, 0x04, 0x00, 0x03, 0x00, 0x01, 0xD5, 0xC5 }; /* 串口设备句柄 */ static rt_device_t serial; /* 消息队列控制块 */ static struct rt_messagequeue rx_mq; rt_uint16_t CO2_HIGH_NUM = 0; rt_uint16_t CO2_LOW_NUM = 0; rt_uint16_t Co2_concentration = 0; #define THREAD_PRIORITY 25 #define THREAD_STACK_SIZE 4096 #define THREAD_TIMESLICE 10 /* 串口接收消息结构*/ struct rx_msg { rt_device_t dev; rt_size_t size; }; /* 接收数据回调函数 */ static rt_err_t uart_input(rt_device_t dev, rt_size_t size) { struct rx_msg msg; rt_err_t result; msg.dev = dev; msg.size = size; result = rt_mq_send(&rx_mq, &msg, sizeof(msg)); if (result == -RT_EFULL) { /* 消息队列满 */ rt_kprintf("message queue full!\n"); } return result; } ALIGN(RT_ALIGN_SIZE) static void recieve_thread_entry(void *parameter) { struct rx_msg msg; rt_err_t result; rt_uint32_t rx_length; static char rx_buffer[10]; while (1) { rt_memset(&msg, 0, sizeof(msg)); /* 从消息队列中读取消息*/ result = rt_mq_recv(&rx_mq, &msg, sizeof(msg), RT_WAITING_FOREVER); if (result == RT_EOK) { /* 从串口读取数据*/ rx_length = rt_device_read(msg.dev, 0, rx_buffer, msg.size); rx_buffer[rx_length] = '\0'; if (rx_buffer[0]==0xFE&&rx_buffer[1]==0x04&&rx_buffer[2]==0x02) { CO2_HIGH_NUM=rx_buffer[3]; CO2_LOW_NUM=rx_buffer[4]; Co2_concentration=(CO2_HIGH_NUM<<8)+CO2_LOW_NUM; rt_kprintf("Co2_concentration: %4d ppm! \r\n",Co2_concentration); } rt_device_write(serial, 0, rx_buffer, rx_length); rt_event_send(&event, EVENT_FLAG3); rt_thread_mdelay(200); } } } static void send_thread_entry(void *parameter) { rt_uint32_t e; while (1) { if (rt_event_recv(&event, (EVENT_FLAG3), RT_EVENT_FLAG_OR | RT_EVENT_FLAG_CLEAR, RT_WAITING_FOREVER, &e) == RT_EOK) { rt_device_write(serial, 0, CO2_TxBuffer, sizeof(CO2_TxBuffer)); rt_kprintf("co2 send success! \r\n"); } } } int sensor_co2_task() { rt_err_t ret = RT_EOK; static char msg_pool[256]; rt_err_t result; /* 初始化事件对象 */ result = rt_event_init(&event, "event", RT_IPC_FLAG_PRIO); if (result != RT_EOK) { rt_kprintf("init event failed.\n"); return -1; } /* 查找串口设备 */ serial = rt_device_find(SAMPLE_UART_NAME); if (!serial) { rt_kprintf("find %s failed!\n", SAMPLE_UART_NAME); return RT_ERROR; } rt_kprintf("find %s success!\n", SAMPLE_UART_NAME); /* 初始化消息队列 */ rt_mq_init(&rx_mq, "rx_mq", msg_pool, /* 存放消息的缓冲区 */ sizeof(struct rx_msg), /* 一条消息的最大长度 */ sizeof(msg_pool), /* 存放消息的缓冲区大小 */ RT_IPC_FLAG_FIFO); /* 如果有多个线程等待,按照先来先得到的方法分配消息 */ /* 以 DMA 接收及轮询发送方式打开串口设备 */ rt_device_open(serial, RT_DEVICE_FLAG_DMA_RX); /* 设置接收回调函数 */ rt_device_set_rx_indicate(serial, uart_input); /* 发送字符串 */ // / rt_device_write(serial, 0, str, (sizeof(str) - 1)); /* 创建 serial 线程 */ rt_thread_t re_thread = rt_thread_create("serial_recieve", recieve_thread_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); /* 创建成功则启动线程 */ if (re_thread != RT_NULL) { rt_thread_startup(re_thread); } else { ret = RT_ERROR; } /* 创建 serial 线程 */ rt_thread_t send_thread = rt_thread_create("serial_send", send_thread_entry, RT_NULL, THREAD_STACK_SIZE, THREAD_PRIORITY, THREAD_TIMESLICE); /* 创建成功则启动线程 */ if (send_thread != RT_NULL) { rt_thread_startup(send_thread); } else { ret = RT_ERROR; } rt_device_write(serial, 0, CO2_TxBuffer, sizeof(CO2_TxBuffer)); return ret; } ```
查看更多
出出啊
2021-11-05
恃人不如自恃,人之为己者不如己之自为也
1. 152 行的 `rt_device_write(serial, 0, CO2_TxBuffer, sizeof(CO2_TxBuffer));` 这句,可以放到 send_thread_entry 线程入口函数 while 循环之前。 2. `recieve_thread_entry` 线程和 `uart_input` 这个中断回调函数之间进行通信,使用邮箱传递 size 值就好(不传递也没问题),接收线程收到 `uart_input` 发的信号后,进行 rt_device_read 。 3. 鉴于你使用的这种设备,它每包数据长度应该是固定的,是固定字节数的。每次 `rt_device_read` 返回的 rx_length 并不一定是完整包长度值。因此,`rx_buffer[rx_length] = '\0';` 这个操作是很危险的,可能破坏数据。—— 你说的接收两次数据,可能是因为这里引起的。 中断回调函数 `uart_input` 可以给 `recieve_thread_entry` 发信号量。接收线程每次执行 `rt_device_read` 的时候需要判断返回值**够不够**你想要的数据量。如果不够,继续 `rt_device_read`。如果超了,需要取出你需要的个数的数据,进行解析处理。剩下的仍然留在你的应用缓冲区内,等待下次信号。 接收完成 `rt_device_write(serial, 0, rx_buffer, rx_length);` 回传操作是设备要求的吗? 接收完成给发送线程发事件通知它发读取命令。从这里看,这俩线程完全可以合并成一个线程。 发请求,等待中断回调函数里的信号,读取数据,解析数据,延时,发下一次请求。。。。。。
3
个回答
默认排序
按发布时间排序
李肯陪你玩赚嵌入式
认证专家
2021-11-05
2022年度和2023年度RT-Thread社区优秀开源布道师,COC深圳城市开发者社区主理人,专注于嵌入式物联网的架构设计
你要实现操作传感器的逻辑是不是: step1: MCU发数据给传感器 -》 step2: 传感器回复数据 -》 step3: MCU接受数据 -》 step4: MCU解析数据 -》 step5: 取得传感器数据做更进一步处理 以此为一个完整操作,然后周期性比如1秒种,重复上面的步骤。 如果是这个样的话,我建议你可以改一改思路,这样或许清晰些: 还是两个线程A/B, ```c A线程(发送解析): while (1) { //send tx-buffer to sensor //step1 //wait sensor-rsp buffer to handle //step5 (waiting setp4 finished) //delay times to next cycle } B线程(接受数据): while (1) { //recv sensor data // step3 //parse sendor data // step4 } UART callbak: { //recved uart data // step2 } ``` 其中step5和step可以用消息队列来传递数据,也相当于做了同步控制。
小小李sunny
2021-11-05
这家伙很懒,什么也没写!
你的串口接收线程的代码应该是copy的官方文档中的例程吧,这里接收到串口的数据后,又通过串口把接收的数据给发出去了,不知道你的CO2传感器接收到这样的数据是不是又回复了什么信息呢 ![image.png](https://oss-club.rt-thread.org/uploads/20211105/1a9e22106a9cd727da029a0c659784d8.png) 另外,你说的程序运行时,自动执行MCU发送给传感器的代码,这里没太明白是什么意思。你的send_thread_entry不正是执行了这样的操作么。
撰写答案
登录
注册新账号
关注者
1
被浏览
800
关于作者
CQKDCZY
这家伙很懒,什么也没写!
提问
2
回答
0
被采纳
0
关注TA
发私信
相关问题
1
串口DMA发送数据时,数据被覆盖
2
关于串口DMA模式下rt_device_close问题
3
利用stm32f427实现usb转串口,电脑端什么也没有识别到
4
finsh 控制台 适配 RS 485请大神指点????
5
uart_sample.c 中,读串口设备时偏移量pos要设置为-1而不是0?
6
【结贴】at_device软件包中对串口接收数据缺少判断导致数据接收异常
7
串口无法接受数据,但可以发送
8
串口如何有效的清除掉接收缓冲,而不必一个一个的去读取
9
串口接收使用方式问题
10
雅特力FINSH问题
推荐文章
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组件
最新文章
1
HC32F4A0 SD卡挂载及热插拔的实现
2
vscode插件 - RT-Thread Studio项目助手 | 跨平台开发
3
Console串口使用说明
4
WATCHDOG设备驱动开发
5
【NXP-MCXA153】eFlexPWM驱动移植
热门标签
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
GD32
flashDB
socket
中断
编译报错
Debug
rt_mq_消息队列_msg_queue
SFUD
keil_MDK
msh
ulog
MicroPython
C++_cpp
本月问答贡献
出出啊
1517
个答案
342
次被采纳
小小李sunny
1444
个答案
290
次被采纳
张世争
812
个答案
177
次被采纳
crystal266
547
个答案
161
次被采纳
whj467467222
1222
个答案
148
次被采纳
本月文章贡献
出出啊
1
篇文章
2
次点赞
小小李sunny
1
篇文章
1
次点赞
张世争
1
篇文章
2
次点赞
crystal266
2
篇文章
2
次点赞
whj467467222
2
篇文章
2
次点赞
回到
顶部
发布
问题
分享
好友
手机
浏览
扫码手机浏览
投诉
建议
回到
底部