rt-thread 串口接收过程
在 RT-Thread 操作系统中,串口(UART)接收数据是一个涉及硬件驱动框架、设备驱动模型和应用程序交互的过程。以下是详细的中文解析:
核心流程:中断驱动 + 环形缓冲区 + 线程同步
-
硬件中断触发(底层硬件驱动负责)
- 当串口的接收寄存器(例如 RxD)接收到一个字符(或达到 FIFO 触发阈值)时,硬件会触发一个接收中断(如
USART_IT_RXNE)。 - RT-Thread 为该串口注册的中断服务程序(
static void rt_hw_serial_isr(struct rt_serial_device *serial))会被 CPU 调用。
- 当串口的接收寄存器(例如 RxD)接收到一个字符(或达到 FIFO 触发阈值)时,硬件会触发一个接收中断(如
-
中断服务程序(ISR)处理(设备驱动实现)
- 读取数据: ISR 通过读取硬件寄存器(如
DR),将接收到的一个或多个字节从串口硬件读取出来。 - 写入环形缓冲区(RX Ring Buffer): ISR 将读取到的字节依次存入为该串口分配的接收环形缓冲区(
rx_buffer)。- 关键点: ISR 的执行速度必须极快。它只做最低限度的必要操作:读硬件、存缓冲区。所有复杂的处理和解析都应该放在应用线程中进行。
- 数据处理标志(可选): 对于简单的需求,ISR 可能会根据接收到的内容(如特定的起始字节、结束符)设置标志位(
rx_indicate)。但这在高数据量或复杂协议中不常用。 - 发送线程通知(核心): ISR 最核心的任务之一是调用
rt_hw_serial_isr(serial, RT_SERIAL_EVENT_RX_DMADONE | RT_SERIAL_EVENT_RX_INDICATE)(或类似,具体名称可能略有差异)。- 这个函数内部会将串口的接收事件(如
RT_SERIAL_EVENT_RX_INDICATE)和接收到的数据量信息传递给上层的设备驱动框架。
- 这个函数内部会将串口的接收事件(如
- 读取数据: ISR 通过读取硬件寄存器(如
-
设备驱动框架处理接收事件
- 框架收到
RT_SERIAL_EVENT_RX_INDICATE事件后,主要做两件事:- 更新可接收计数: 增加串口设备对象的
rx_notice或类似计数变量,表示有新的数据可用。 - 唤醒等待线程: 检查是否有应用程序线程正在通过
rt_device_read()或rt_sem_take()等方式阻塞(挂起)等待接收数据。如果有,框架会发送一个信号(如释放信号量、发送邮箱消息) 唤醒这些等待的线程。
- 更新可接收计数: 增加串口设备对象的
- 框架收到
-
应用程序读取数据(用户线程)
- 应用程序通常会创建一个独立的线程来主动读取串口数据。
- 使用设备操作 API:应用程序调用标准接口
rt_device_read(serial_dev, -1, buffer, size)来尝试读取数据。serial_dev: 之前通过rt_device_find()找到的串口设备对象。-1: 表示无限等待(RT_WAITING_FOREVER),直到有数据到来。也可以设置超时时间(如rt_tick_from_millisecond(100))。buffer: 用户提供的缓冲区地址,用于存放读取的数据。size: 用户希望读取的最大字节数。
- 阻塞与读取:
- 有数据可读: 如果环形缓冲区中有数据,
rt_device_read会立刻从环形缓冲区中拷贝最多size个字节到buffer中,并返回实际读取的字节数。此时线程不会阻塞。 - 无数据可读: 如果环形缓冲区为空:
- 如果调用
rt_device_read时指定了RT_WAITING_FOREVER,则调用线程会被挂起(阻塞),并放入该串口设备的接收等待队列中。 - 当步骤3中的驱动框架发出“有数据到达”的信号时,RT-Thread 调度器会唤醒这个被挂起的线程。
- 线程被唤醒后,
rt_device_read函数内部会再次尝试从环形缓冲区拷贝数据到用户buffer。
- 如果调用
- 有数据可读: 如果环形缓冲区中有数据,
关键组件与设计思想
- 硬件中断 (ISR): 最底层响应,处理实时性最高的硬件读取。
- 接收环形缓冲区 (RX Ring Buffer):
- 位于设备驱动层(通常在
struct rt_serial_device结构中定义)。 - 作用: 在接收中断(ISR)和应用程序读取线程之间进行解耦和缓冲。它允许 ISR 快速接收数据,而应用线程可以在稍后的时间以自己的节奏读取数据。
- 避免数据丢失: 缓冲区大小需合理设置。如果应用线程读取太慢,导致环形缓冲区满,新接收的数据会被丢弃(硬件可能产生溢出错误,也需要 ISR 处理)。
- 位于设备驱动层(通常在
- 设备驱动框架:
- 提供统一的设备操作接口 (
open/close/read/write/control)。 - 管理设备状态和等待队列。
- 负责在收到驱动事件(如
RT_SERIAL_EVENT_RX_INDICATE)时唤醒等待数据的线程。
- 提供统一的设备操作接口 (
- 线程同步机制:
- 信号量/事件集/邮箱: 设备驱动框架使用这些内核对象来实现接收线程的阻塞等待和唤醒通知。
rt_device_read函数的阻塞行为正是通过挂起在驱动框架管理的信号量/等待队列上实现的。
- 应用线程: 执行数据处理(解析协议、响应等)的逻辑应放在这里,而不是在 ISR 中。
总结流程图
+------------------------+ +----------------------------+ +-----------------+ +-------------------+
| 串口硬件收到数据 |----->| 硬件中断触发 (RXNE) |----->| 中断服务程序 (ISR) |----->| 1. 从硬件读取数据 |
| (例如:USART RxD Line) | | (中断向量跳转) | | | | 2. 存入接收环形缓冲区 |
+------------------------+ +----------------------------+ | |----->| 3. 通知驱动框架 |
+---------^--------+ +-------------------+
|
|
+------------------+ +----------------------+ +----------------------v--------------------+ +-------------------------+
| 应用线程 |<-----| 1. 拷贝数据到用户buffer |<-----| rt_device_read(...) | | |
| (用户数据处理逻辑) | | 2. 返回实际读取字节数 | | | | |
| |----->| (非阻塞:立即返回) | | * 检查环形缓冲区是否有数据? |----->| |
+------------------+ +----------------------+ | - 有数据:读取并返回 | | |
^ | - 无数据且超时设置 != RT_NULL: | | RT-Thread 内核调度器 |
| | 等待指定时间,超时则返回0或-ETIMEOUT | | (负责线程阻塞和唤醒) |
| | - 无数据且超时 == RT_WAITING_FOREVER: | | |
| | 调用线程被挂起(阻塞),进入等待队列 |<-----| |
| +------------------------------------------+ | |
| | |
| +------------------------------------------------------+<-----------------------+
| | 设备驱动框架收到 ISR 通知 |
| | (rt_hw_serial_isr(RT_SERIAL_EVENT_RX_INDICATE)) |
+---------| 1. 更新可接收计数 |
| 2. 发送信号唤醒在 rt_device_read 中阻塞的线程 |
+------------------------------------------------------+
简单来说:
硬件接收数据触发中断 -> 中断程序快速把数据存入内存缓冲区 -> 中断程序通知系统框架"有新数据了" -> 系统框架唤醒等待读取数据的应用程序线程 -> 被唤醒的应用程序线程调用 rt_device_read 函数从缓冲区拷贝数据到自己的内存空间进行处理。
这种设计确保了硬件中断处理的高效性(避免在中断中执行复杂操作),同时为应用程序提供了灵活、同步的数据读取方式。
RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南
RT-Thread文档_RT-Thread 潘多拉 STM32L475 上手指南
资料下载
佚名
2023-02-22 18:23:17
RT-Thread学习笔记 --(6)RT-Thread线程间通信学习过程总结
前两篇文章总结了RT-Thread多线程以及多线程同步的学习过程,关于前两篇学习总结,可以查看之前的文章。
资料下载
龙献益
2022-01-25 18:50:59
记录——基于 RT-Thread 实现 USB 虚拟串口
记录——基于 RT-Thread 实现 USB 虚拟串口记录一下我在正点原子 F429 阿波罗开发板上实现 USB 虚拟串口的
资料下载
佚名
2021-12-02 17:21:05
如何使用RT-Thread的串口设备
控)输出了字符 2、0、1、8 和字符串 Hello RT-Thread!。输入字符 ‘A’,串口 2 接收到将其错位后输出。实验现象如图所示:
RT-Thread学习笔记 RT-Thread的架构概述
RT-Thread 简介 作为一名 RTOS 的初学者,也许你对 RT-Thread 还比较陌生。然而,随着你的深入接触,你会逐渐发现 RT-Thread
2022-07-09 11:27:42
RT-Thread全球技术大会:POSIX FILE select的调用过程
在上午RT-Thread全球技术大会,RT-Thread开发者详细介绍了POSIX FILE select的调用过程。如下图:
2022-05-28 10:56:52
RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制
RT-Thread全球技术大会:Kconfig在RT-Thread中的工作机制 审核编辑:彭静
2022-05-27 14:49:12
RT-Thread全球技术大会:萤石研发团队使用RT-Thread的技术挑战
RT-Thread全球技术大会:研发团队使用RT-Thread的技术挑战 审核编辑:彭静
2022-05-27 11:36:17
在RT-Thread实现USB虚拟串口的过程记录
记录——基于 RT-Thread 实现 USB 虚拟串口记录一下我在正点原子 F429 阿波罗开发板上实现 USB 虚拟串口的
换一换
- 如何分清usb-c和type-c的区别
- 中国芯片现状怎样?芯片发展分析
- vga接口接线图及vga接口定义
- 芯片的工作原理是什么?
- 华为harmonyos是什么意思,看懂鸿蒙OS系统!
- 什么是蓝牙?它的主要作用是什么?
- ssd是什么意思
- 汽车电子包含哪些领域?
- TWS蓝牙耳机是什么意思?你真的了解吗
- 什么是单片机?有什么用?
- 升压电路图汇总解析
- plc的工作原理是什么?
- 再次免费公开一肖一吗
- 充电桩一般是如何收费的?有哪些收费标准?
- ADC是什么?高精度ADC是什么意思?
- dtmb信号覆盖城市查询
- EDA是什么?有什么作用?
- 苹果手机哪几个支持无线充电的?
- type-c四根线接法图解
- 华为芯片为什么受制于美国?
- 怎样挑选路由器?
- 元宇宙概念股龙头一览
- 锂电池和铅酸电池哪个好?
- 什么是场效应管?它的作用是什么?
- 如何进行编码器的正确接线?接线方法介绍
- 虚短与虚断的概念介绍及区别
- 晶振的作用是什么?
- 大疆无人机的价格贵吗?大约在什么价位?
- 苹果nfc功能怎么复制门禁卡
- amoled屏幕和oled区别
- 单片机和嵌入式的区别是什么
- 复位电路的原理及作用
- BLDC电机技术分析
- dsp是什么意思?有什么作用?
- 苹果无线充电器怎么使用?
- iphone13promax电池容量是多少毫安
- 芯片的组成材料有什么
- 特斯拉充电桩充电是如何收费的?收费标准是什么?
- 直流电机驱动电路及原理图
- 传感器常见类型有哪些?
- 自举电路图
- 通讯隔离作用
- 苹果笔记本macbookpro18款与19款区别
- 新斯的指纹芯片供哪些客户
- 伺服电机是如何进行工作的?它的原理是什么?
- 无人机价钱多少?为什么说无人机烧钱?
- 以太网VPN技术概述
- 手机nfc功能打开好还是关闭好
- 十大公认音质好的无线蓝牙耳机
- 元宇宙概念龙头股一览