Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
原创征文
串口驱动
rt-thread 驱动篇 之 serialX 阻塞超时返回
发布于 2023-08-21 08:41:08 浏览:1371
订阅该版
[tocm] ## 前言 尽管仍然很多痴男怨女在 v1 v2 身上跌倒、跌倒、继续跌倒,仍然阻止不了他们飞蛾扑火式的被 v1 v2 的缺陷所吸引而殉情。 它一如既往的保持着优良的特性,也有可能是很多人没发现,主要是接受它的人很少。不过,这不影响今天它带来新的特性。 ### 阻塞超时 我们一直强调,它有与之前非同一般的两个概念“阻塞”“非阻塞”。虽然 v2 热火朝天的提出了这两个概念,但是实现的效果却不尽人意。 在之前的正式文档里,我没胆量承认一个事实,那就是,**阻塞读在无数据可读的时候将永远阻塞下去**。某些应用场景并不希望这样,我们希望等待某设备响应,若干时间后无响应超时,我们返回继续做其它工作,而不是被无响应的设备永久占用。 给某些论坛提问里的解答时,我提到过几次 serialX 可以通过以下技术手段应对这种场景。 #### 方法一 使用非阻塞模式打开,超时读过程伪代码可能如下这样: ``` while(timeout > 0) { read sleep 1 timeout -= 1 } if (timeout == 0) { // timeout here } else { // no timeout } ``` #### 方法二 使用完成中断 indicate 回调函数发消息,这也是官方提供的读串口设备的“标准”方式 ``` static void serial_thread_entry(void *parameter) { char ch; while (1) { /* 从串口读取一个字节的数据,没有读取到则等待接收信号量 */ while (rt_device_read(serial, -1, &ch, 1) != 1) { /* 阻塞等待接收信号量,等到信号量后再次读取数据 */ rt_sem_take(&rx_sem, timeout); } ... } } ``` > 注:此段代码改编自官方文档 大多数人第一次使用 rtt 的串口设备也是用这段代码测试的。但是,serialX 不提倡大家使用 indicate 回调函数。 serialX 有它自己的特性,它有它自己的优美性,那就是尽可能不给应用层代码带来麻烦,不要写太复杂难懂的逻辑,不要给应用层引入莫名未知的后果。 我们希望在不影响不改变之前的使用的前提下,`rt_device_read` 能够在预定的时间内超时返回退出,并不是用于阻塞下去,同时 `rt_device_read` 返回 `-RT_ETIMEOUT` 错误码。应用层可以根据 `rt_device_read` 返回值 - == 0 无数据 - > 0 有数据 - < 0 有错误(`-RT_ETIMEOUT` 超时) 分别处理不同情况。 #### serialX 的实现 首先,`rtdef.h` 添加定义,用于设备超时配置 ``` #define RT_DEVICE_CTRL_TIMEOUT 0x30 /**< timeout for blocking */ ``` 其次,`struct rt_serial_device` 添加 `rt_tick_t timeout_tick;` 变量,设备超时时间 tick 。 然后,`rt_serial_control` 函数添加超时配置宏选项处理 ``` case RT_DEVICE_CTRL_TIMEOUT: rt_tick_t timeout_tick = (rt_tick_t)args; serial->timeout_tick = timeout_tick; break; ``` 最后,在 `serialX.c` 文件中所有涉及到阻塞的地方(包括读写,不包含 flush)修改 `rt_completion_wait` 第二个参数为 `serial->timeout_tick`。并当 `rt_completion_wait` 返回 `-RT_ETIMEOUT` 时退出当前读写操作返回应用层。 > 注意:特别说明,我们希望一个设备以阻塞模式打开时,默认的阻塞超时时间是“永久”,所以,每次 `rt_device_open` 后 serialX 设定阻塞超时时间时间是 `RT_WAITING_FOREVER` 。如果需要指定某超时时间需要 `rt_device_control(serial_dev, RT_DEVICE_CTRL_TIMEOUT, &timeout);` ``` rt_tick_t timeout = 50; if (rt_device_open(scpi_uart_dev, RT_DEVICE_OFLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | RT_DEVICE_OFLAG_BLOCKING) != RT_EOK) { rt_kprintf("Open device: %s failed\n", UART_DEV_NAME); return; } rt_device_control(serial_dev, RT_DEVICE_CTRL_TIMEOUT, &timeout); rt_ssize_t ret = rt_device_read(serial_dev, -1, &recvbuf[0], 128); if (ret == -RT_ETIMEOUT) { rt_device_close(serial_dev); return; } else { } ``` 这就是今天我们要讲的第三种方法,相比前两种,这种方法更优雅些,代码逻辑也清晰。 ## 总结 欢迎大家入坑 serialX。
13
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
出出啊
恃人不如自恃,人之为己者不如己之自为也
文章
43
回答
1518
被采纳
342
关注TA
发私信
相关文章
1
串口驱动不自动进初始化
2
RTT 针对stm32lx系列低功耗串口驱动bug
推荐文章
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
I2C_IIC
ESP8266
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
C++_cpp
MicroPython
本月问答贡献
xusiwei1236
8
个答案
2
次被采纳
踩姑娘的小蘑菇
1
个答案
2
次被采纳
用户名由3_15位
9
个答案
1
次被采纳
bernard
4
个答案
1
次被采纳
RTT_逍遥
3
个答案
1
次被采纳
本月文章贡献
聚散无由
2
篇文章
15
次点赞
catcatbing
2
篇文章
5
次点赞
Wade
2
篇文章
4
次点赞
Ghost_Girls
1
篇文章
6
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部