Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
UART
设备驱动
《RT-Thread设备驱动开发指南》—— 基础篇之UART设备驱动开发
发布于 2023-06-19 10:16:27 浏览:3323
订阅该版
[tocm] ### RT-Thread设备驱动开发 #### 第2章 UART设备驱动开发 ##### UART介绍 UART(Universal Asynchronous Receiver/Transmitter,通用异步收发传输器)也常被称为串口。UART作为异步串口通信协议的一种,工作原理是将传输数据的每个字符一位接一位地传输。UART是在应用程序开发过程中使用频率最高的数据总线。在嵌入式设计中,UART常用于主机与辅助设备通信,如嵌入式设备与外接模块(Wi-Fi、蓝牙模块等)的通信,嵌入式设备与PC监视器的通信,或用于两个嵌入式设备之间的通信。 UART串口属于字符设备的一种,它的硬件连接也比较简单,只要两根传输线就可以实现双向通信:一根线(TX)发送数据,另一根线(RX)接收数据。 UART串口通信有几个重要的参数,分别是波特率、起始位、数据位、停止位和奇偶检验位,对于两个使用UART串口通信的端口,这些参数必须匹配,否则通信将无法正常完成。 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/14443e1fa676d9867b09ed1e8ce4fd34.png.webp) **数据格式包含起始位、数据位、奇偶校验位、停止位。** **起始位**:表示数据传输的开始,电平逻辑为“0”。 **数据位**:数据位通常为8bit的数据(一个字节),但也可以是其他大小,例如5bit、6bit、7bit,表示传输数据的位数。 **奇偶校验位**:用于接收方对接收到的数据进行校验,校验一个二进制数中“1”的个数为偶数(偶校验)或奇数(奇校验),以此来校验数据传送的正确性,使用时也可以不需要此位。 **停止位**:表示一帧数据的结束,电平逻辑为“1”。 **波特率**:串口通信时的速率,它用单位时间内传输的二进制代码的有效位数来表示,其单位为bit/s。常见的波特率值有4800、9600、14400、38400、115200等,数值越大数据传输越快,波特率为115200表示每秒传输115200位数据。 ##### UART v2.0版本的UART框架和驱动讲解 **UART层级结构** ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/62b0c5c882a1419a2aad0b34b1a02bb3.png.webp) 1)I/O设备管理层向应用层提供rt_device_read/write等标准接口,应用层可以通过这些标准接口访问UART设备。 2)UART设备驱动框架源码文件为serial_v2.c,位于RT-Thread源码的components\drivers\serial文件夹中。抽象出的UART设备驱动框架和平台无关,是一层通用的软件层。UART设备驱动框架提供以下功能。 ①对接上层的I/O设备管理层,以让应用层调用I/O设备管理层提供的统一接口对UART进行操作。 ②UART设备驱动框架向UART设备驱动层提供UART设备操作方法接口struct rt_uart_ops(如configure、control、putc、getc、transmit),驱动开发者需要实现这些接口。 ③提供设备注册管理接口rt_hw_serial_register和中断处理接口rt_hw_serial_isr。 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/88cc19efeeb2104fbc34217c4de68e08.png.webp) 3)UART设备驱动源码文件为drv_usartv2.c,放在具体bsp目录下,v2表示对接在串口v2版本的设备驱动框架上。UART设备驱动的实现与平台相关,它操作具体的MCU UART控制器。UART设备驱动需要实现UART设备的操作方法struct rt_uart_ops,以提供访问和控制UART硬件的能力。这一层也负责调用rt_hw_serial_register函数将UART设备注册到操作系统。最后还需调用中断处理接口rt_hw_serial_isr,通知UART设备驱动框架层处理数据。 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/ff9bc9cdfab7733712a349fc74080c3b.png.webp) 4)最下面一层是MCU外接的UART模块,如UART通信模块、RS-232芯片或者RS-485芯片电路模块等,这样MCU就可以与外接模块进行数据通信了。 **UART设备驱动开发的主要任务就是实现串口设备操作方法接口struct rt_uart_ops,然后注册串口设备。** 查看代码,串口初始化: ```c int rt_hw_usart_init(void) { rt_size_t obj_num = sizeof(uart_obj) / sizeof(struct stm32_uart); struct serial_configure config = RT_SERIAL_CONFIG_DEFAULT; rt_err_t result = 0; stm32_uart_get_dma_config(); for (int i = 0; i < obj_num; i++) { uart_obj[i].config = &uart_config[i]; uart_obj[i].serial.ops = &stm32_uart_ops; uart_obj[i].serial.config = config; /* register UART device */ result = rt_hw_serial_register(&uart_obj[i].serial, uart_obj[i].config->name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX | RT_DEVICE_FLAG_INT_TX | uart_obj[i].uart_dma_flag , NULL); RT_ASSERT(result == RT_EOK); } return result; } ``` **创建UART设备**。对UART设备来说,在驱动开发时需要先从struct rt_serial_device结构中派生出新的串口设备模型,然后根据自己的设备类型定义私有数据域。特别是在可能有多个类似设备的情况下(例如串口1、串口2),设备接口可以共用同一套接口,不同的只是各自的数据域(例如寄存器基地址)。 例如,STM32的UART设备模型从struct rt_serial_device派生,并增加了STM32UART的特有数据结构,如STM32串口句柄、串口配置信息、DMA结构信息等。 ```c /* stm32 uart dirver class */ struct stm32_uart { UART_HandleTypeDef handle; struct stm32_uart_config *config; #ifdef RT_SERIAL_USING_DMA struct { DMA_HandleTypeDef handle; rt_size_t last_index; } dma_rx; struct { DMA_HandleTypeDef handle; } dma_tx; #endif rt_uint16_t uart_dma_flag; **struct rt_serial_device serial;** }; ``` **实现UART设备的操作方法** ```c struct rt_uart_ops { rt_err_t (*configure)(struct rt_serial_device *serial, struct serial_configure *cfg); rt_err_t (*control)(struct rt_serial_device *serial, int cmd, void *arg); int (*putc)(struct rt_serial_device *serial, char c); int (*getc)(struct rt_serial_device *serial); rt_size_t (*transmit)(struct rt_serial_device *serial, rt_uint8_t *buf, rt_size_t size, rt_uint32_t tx_flag); }; ``` ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/023962a04ef7a8904b5c8512c74f9d36.png) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/6448c6b7ff7629e4f53ecc51229d8994.png) 这些操作方法会完成串口的基本操作,例如:configure方法用于配置串口(波特率等);control方法用于控制串口;putc方法用于串口向外发送字符数据;getc方法用于串口获取字符数据;transmit方法用于数据发送,主要是进行多字节数据的发送。下面继续讲解如何实现这些操作方法。 **注册UART设备** UART设备的操作方法实现后需要注册设备到操作系统,注册UART设备的接口是rt_err_t rt_hw_serial_register(struct rt_serial_device *serial,const char *name,rt_uint32_t flag, void *data)。 **UART设备中断处理** ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/95fe37b5b73355730232914b66a7aea8.png.webp) ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/b3b011692e3318af52ebe206957f6c6d.png.webp) **增加DMA模式** 增加UART设备DMA模式,需要首先对每个UART的DMA进行配置,接着进行DMA初始化和中断处理,最后完成DMA发送。以下是DMA配置代码。 **驱动配置** RT-Thread使用SCons构建工程,使用**基于Kconfig机制的menuconfig工具**配置工程。因此不仅要实现驱动,还要实现驱动相关的配置选项:一是**Kconfig配置**,配置好的配置文件将会在menuconfig工具中形成对应的配置界面;二是进行**SConscript配置**,配置好后,相应的驱动文件将会被添加到工程中。后面各章的驱动相关配置选项与此类似,如无特殊配置将不再赘述。 **1.Kconfig配置** 下面参考bsp/stm32/stm32f407-atk-explorer/board/Kconfig文件配置串口驱动的相关选项,如下所示: ```c menuconfig BSP_USING_UART bool "Enable UART" default y select RT_USING_SERIAL if BSP_USING_UART config BSP_USING_UART0 bool "Enable UART0" default y config BSP_UART0_RX_USING_DMA bool "Enable UART0 RX DMA" depends on BSP_USING_UART0 select RT_SERIAL_USING_DMA default n config BSP_USING_UART1 bool "Enable UART1" default n config BSP_UART1_RX_USING_DMA bool "Enable UART1 RX DMA" depends on BSP_USING_UART1 select RT_SERIAL_USING_DMA default n config BSP_USING_UART2 bool "Enable UART2" default n config BSP_UART2_RX_USING_DMA bool "Enable UART2 RX DMA" depends on BSP_USING_UART2 select RT_SERIAL_USING_DMA default n config BSP_USING_UART3 bool "Enable UART3" default n config BSP_UART3_RX_USING_DMA bool "Enable UART3 RX DMA" depends on BSP_USING_UART3 select RT_SERIAL_USING_DMA default n config BSP_USING_UART4 bool "Enable UART4" default n config BSP_UART4_RX_USING_DMA bool "Enable UART4 RX DMA" depends on BSP_USING_UART4 select RT_SERIAL_USING_DMA default n config BSP_USING_UART5 bool "Enable UART5" default n config BSP_UART5_RX_USING_DMA bool "Enable UART5 RX DMA" depends on BSP_USING_UART5 select RT_SERIAL_USING_DMA default n config BSP_USING_UART6 bool "Enable UART6" default n config BSP_UART6_RX_USING_DMA bool "Enable UART6 RX DMA" depends on BSP_USING_UART6 select RT_SERIAL_USING_DMA default n config BSP_USING_UART7 bool "Enable UART7" default n config BSP_UART7_RX_USING_DMA bool "Enable UART7 RX DMA" depends on BSP_USING_UART7 select RT_SERIAL_USING_DMA default n endif ``` 代码段中相关宏的说明如下所示。 BSP_USING_UART:串口驱动代码对应的宏定义,这个宏控制串口驱动相关代码是否会添加到工程中。 RT_USING_SERIAL:串口驱动框架代码对应的宏定义,这个宏控制串口驱动框架的相关代码是否会添加到工程中。 BSP_USING_UART1:串口设备1对应的宏定义,这个宏控制串口设备1是否会注册到系统中。 BSP_UART1_RX_USING_DMA:串口设备1使用DMA接收数据。 **2.SConscript配置** 在HAL_Drivers/SConscript文件中为串口驱动添加判断选项,代码如下所示。这是一段Python代码,表示如果定义了宏BSP_USING_UART,则drv_uart.c会被添加到工程的源文件中。 ``` if GetDepend(['RT_USING_SERIAL']): src += ['drv_usart.c'] ``` 注册设备之后,UART设备将以字符设备的形式在I/O设备管理器中存在。系统启动并开始运行后,可以在终端使用**list_device命令**看到注册的设备包含了UART设备,之后则可以使用UART设备驱动框架提供的统一API对UART设备进行操作。 ##### 小结 在RT-Thread中,将UART外设抽象为UART设备,并结合UART设备的通用操作方法与驱动框架思想设计出UART设备驱动框架,这为开发者提供了更便利的设备控制方式。同时,这使基于UART设备编写出来的应用代码更具兼容性与通用性。开发者还需要注意以下两点。 1)操作方法的名称可以自定义,但不要脱离实际意义,并且需要遵守代码规范。**所有的操作方法/函数都属于内部函数,在函数实现时,需要使用*static*进行修饰。**本条注意事项对每种驱动都适用,后面章节将不再赘述。 2)在进入与退出中断时,**需要调用中断进入和中断退出函数**,如下所示。本条注意事项对每种驱动都适用,后面章节将不再赘述。 ![screenshot_image.png](https://oss-club.rt-thread.org/uploads/20230619/c308258f58aebb26b91e5c324398cb0e.png) **最后感谢架构师李肯的赠书!!!**
1
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
YZRD
这家伙很懒,什么也没写!
文章
21
回答
216
被采纳
19
关注TA
发私信
相关文章
1
rt thread 2.0.2 usart 接收缓存问题
2
关于STM32串口通信的问题
3
STM32F1+RTT串口接收终端数据丢失问题
4
UART TX丢数据?
5
RTT打开串口的时候如何自定义波特率呢?
6
STM32F4的USART数据接收问题
7
串口1234使用问题
8
串口接收回调函数
9
LPC18xx UART问题讨论
10
x1000串口配置的失败问题
推荐文章
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
WIZnet_W5500
UART
ota在线升级
PWM
cubemx
freemodbus
flash
packages_软件包
BSP
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
中断
Debug
编译报错
msh
SFUD
rt_mq_消息队列_msg_queue
keil_MDK
ulog
MicroPython
C++_cpp
本月问答贡献
a1012112796
20
个答案
3
次被采纳
张世争
11
个答案
3
次被采纳
踩姑娘的小蘑菇
7
个答案
3
次被采纳
rv666
9
个答案
2
次被采纳
用户名由3_15位
13
个答案
1
次被采纳
本月文章贡献
程序员阿伟
9
篇文章
2
次点赞
hhart
3
篇文章
4
次点赞
RTT_逍遥
1
篇文章
6
次点赞
大龄码农
1
篇文章
5
次点赞
ThinkCode
1
篇文章
1
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部