ESP-IDF学习笔记-UART的使用
ESP32中串口的使用与STM32中大有不同。在ESP32中使用串口,需要配置串口,设置引脚,安装驱动之后才能使用。接收和发送数据也不是直接向寄存器写数据,而是先存到FIFO中,交由ESP32自动发送。其中断的使用更是结合了FreeRTOS的特性进行的。
先摆上官方文档。
本文参考于这篇文章
一,串口的配置步骤
一个串口的典型使用步骤如下:
- 使用
uart_param_config()
设置UART参数 - 使用
art_set_pin()
分配UART引脚 - 使用
uart_driver_install()
安装UART驱动 - 使用
uart_read_bytes()
/uart_write_bytes()
收发数据 - (可选)新建task读取事件队列处理中断事件
- (可选)删除驱动释放资源
其中,1、2、3步可以调换顺序。
二,配置的具体步骤
同STM32HAL库的句柄一样,ESP32中使用一个uart_port_t
类型的UART_NUM_x
变量识别不同的UART控制器,在调用函数时需指明。
其中UART_NUM_MAX
表示该芯片最大的uart控制器数,上面的x最大为UART_NUM_MAX-1
。
ESP32中默认使用UART_NUM_0
作为log库的输出。
UART参数的配置
UART参数的配置主要用两种方式,一种是使用uart_param_config
+结构体一次性配置;另一种是使用分离函数进行配置。、
单步配置(结构体)
使用的函数原型:
1 | esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config) |
参数:
uart_num
使用的UART编号uart_config
配置的结构体
返回:
- ESP_OK Success
- ESP_FALL Parameter error
uart_config_t
结构体成员:
成员 | 类型 | 作用 | 可用参数 |
---|---|---|---|
baud_rate | int | 波特率 | 宏定义UART_BITRATE_MAX 为支持的最大波特率 |
data_bits | uart_word_length_t | 数据位长度 | UART_DATA_X_BITS (X=5~8 )或UART_DATA_BITS_MAX |
parity | uart_parity_t | 校验位 | UART_PARITY_X (X=DISABLE ,EVEN ,ODD ) |
stop_bits | uart_stop_bits_t | 停止位 | UART_STOP_BITS_X (X=1,1_5,2,MAX) |
flow_ctrl | uart_hw_flowcontrol_t | 硬件流控制 | UART_HW_FLOWCTRL_X (X=DISABLE ,RTS ,CTS ,CTS_RTS ,MAX ) |
rx_flow_ctrl_thresh | uint8_t | 硬件流控制阈值 | — |
source_clk | uart_sclk_t | 时钟源选择 | UART_SCLK_X (X=APB ,RTC ,XTAL ,DEFAULT (APB)) |
如果不使用硬件流控制,可以使用 uart_set_rts()
和 uart_set_dtr()
软件流控制。
使用例:
1 |
|
多步配置
多步配置的函数表如下:
欲配置的参数 | 函数 |
---|---|
波特率(Baud rate) | uart_set_baudrate() |
传输数据位长(Number of transmitted bits) | uart_set_word_length() selected out of uart_word_length_t |
奇偶校验(parity control) | uart_set_parity() selected out of uart_parity_t |
停止位数(Number of stop bits) | uart_set_stop_bits() selected out of uart_stop_bits_t |
硬件流控方式(Hardware flow control mode) | uart_set_hw_flow_ctrl() selected out of uart_hw_flowcontrol_t |
通信方式(Communication mode) | uart_set_mode() selected out of uart_mode_t |
同时,上面的每个函数都有一个_get_
对应对象来检查当前设置的值。例如,要检查当前波特率值,调用uart_get_baudrate()
。
分配引脚
使用的函数原型
1 | esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num) |
参数:
uart_num
使用的串口编号tx_io_num
TX引脚rx_io_num
RX引脚rts_io_num
RTS引脚cts_io_num
CTS引脚
返回:
- ESP_OK Success
- ESP_FALL Parameter error
对于后四个参数,可以使用宏UART_PIN_NO_CHANGE
保留已经配置的引脚或者默认引脚。
如果设置的GPIO有该功能的IOMUX(复用),则信号会直接接到该引脚而不通过GPIO矩阵,这样能够支持更高的速率。例如。ESP32S3中IO43是默认的U0TXD,IO44是默认的U0RXD;IO17–U1TXD,IO18–U1RXD。
ESP32提供了一些宏用来定义这些能直连的引脚,参考官方文档,或者见本章高级用法篇。
内部信号能够被输出到多个GPIO,但只有一个GPIO能输入。
经实际测试,ESP32S3的UART好像不能换引脚。
使用例:
1 |
|
安装驱动
使用的函数原型:
1 | esp_err_t uart_driver_install(uart_port_t uart_num, int rx_buffer_size, int tx_buffer_size, int queue_size, QueueHandle_t *uart_queue, int intr_alloc_flags); |
参数:
uart_num
使用的串口编号rx_buffer_size
接收缓冲区大小tx_buffer_size
发送缓冲区大小queue_size
事件队列大小uart_queue
事件队列句柄,如果成功,这里会有一个新的事件队列。如果设为NULL
将不使用intr_alloc_flags
用于分配中断的标志。传入一个或多个ESP_INTR_FLAG_*
(详见esp_intr_alloc.h),不能使用ESP_INTR_FLAG_IRAM(在meunconfig中设置)
返回:
- ESP_OK Success
- ESP_FALL Parameter error
安装UART驱动程序,同时,UART ISR处理器将被附加到运行该函数的同一个CPU核心上。Rx_buffer_size
应该大于UART_FIFO_LEN
。Tx_buffer_size
应该是**0或者大于UART_FIFO_LEN
**。
UART_FIFO_LEN
是一个宏定义,定义硬件FIFO的大小
如果发送缓存区为0,则使用uart_write_bytes()
时会阻塞发送。
例子:
1 | uart_driver_install(UART_NUM_0,1024,512,0,NULL,0); |
收发数据
发数据
使用的函数原型:
1 | int uart_write_bytes(uart_port_t uart_num, const void *src, size_t size); |
参数:
uart_num
使用的串口编号src
数据地址size
数据长度
返回:
- (-1) Parameter error
- OTHERS (>=0) The number of bytes pushed to the TX FIFO
如果缓冲区为0,该函数会阻塞直到所有数据被发送或者所有数据被加入FIFO。
缓冲区中的数据会被UART ISR逐步转移到FIFO。(有点像32的Transmit_IT)。
函数uart_write_bytes_with_break()
与其功能类似,但会在结束时添加串行中断信号。“串行中断信号”意味着 Tx 线保持低电平的时间长于一个数据帧。
uart_tx_chars()
也能将数据写入Tx FIFO,但不会等待可用空间,而是立即放入硬件FIFO。
uart_wait_tx_done()
用于监听发送缓冲区,在缓冲区为空时返回。
1 | // Wait for packet to be sent |
接数据
使用的函数原型:
1 | int uart_read_bytes(uart_port_t uart_num, void *buf, uint32_t length, TickType_t ticks_to_wait) |
ticks_to_wait
是超时时间,值是RTOS的ticks。
使用该函数前应使用uart_get_buffered_data_len()
获得缓冲区数据的长度。比如:
1 | // Read data from UART. |
清除缓冲区:
1 | esp_err_t uart_flush(uart_port_t uart_num); |
清除RX缓冲区的内容。
1 | esp_err_t uart_flush_input(uart_port_t uart_num); |
清除输入缓存区内容(如果想等待发送完成,请使用uart_wait_tx_done
)。
使用中断
这里提到的中断与一般的中断不同,这里应该叫UART事件。中断触发后读取的中断源被当做事件添加到队列中,使用FreeRTOS的一个线程进行读取,处理,得到像中断的效果。
使用事件处理需要在安装驱动时开启事件队列。
1 |
|
UART 默认的事件处理 没有使用esp_event.h
中的事件循环(EventLoop
)。而是使用队列传输事件对象(一个uart_event_t
类型的结构体)这个结构体包含了事件类型和UART_DATA
事件携带的数据。
1 | /** |
其中,uart_event_type_t
包含以下事件:
1 | /** |
其中,最后一个事件UART_PATTERN_DET
是使用uart_enable_pattern_det_baud_intr()
启用pattern detect后的触发事件,用于解析特定格式的数据如AT+CGMI
。
安装完驱动后,当有事件发生时,会自动向队列中填充信息,一般使用一个任务来进行及时处理。
1 |
|
删除驱动
1 | esp_err_t uart_driver_delete(uart_port_t uart_num); |
使用该函数释放资源。
三,高级用法
其他模式
UART 控制器支持多种通信模式,使用函数 uart_set_mode()
可以选择模式。选择特定模式后,UART 驱动程序将处理已连接 UART 设备的相应行为。
1 | esp_err_t uart_set_mode(uart_port_t uart_num, uart_mode_t mode); |
参数:
mode
使用的模式
该函数必须在uart_driver_install()
之后使用。
支持的参数如下:
参数 | 模式 |
---|---|
UART_MODE_UART | 普通UART |
UART_MODE_RS485_HALF_DUPLEX | half duplex RS485 UART mode control by RTS pin |
UART_MODE_IRDA | 类似于红外协议的模式 |
UART_MODE_RS485_COLLISION_DETECT | RS485 collision detection UART mode (used for test purposes) |
UART_MODE_RS485_APP_CTRL | application control RS485 UART mode (used for test purposes) |
具体使用参考官方文档
pattern_detect
在检测到重复接收/发送同一字符的“模式”时触发中断。例如,模式检测可用于检测命令字符串末尾是否存在特定数量的相同字符(“模式”)。
- 配置并启用此中断:调用
uart_enable_pattern_det_baud_intr()
- 禁用中断:调用
uart_disable_pattern_det_intr()
用法参见peripherals/uart/uart_events
自定义UART中断
如果不想使用默认的 UART 中断(如上文的 UART 事件 Queue 等高级API)或者自己另有别的绝妙之用,可以注册自己的UART中断。
- 使用
uart_isr_register()
注册中断 - 使用
uart_isr_free()
释放注册的中断
写的中断 ISR 程序需要尽可能简短,不要忘了在处理中断前后调用uart_clear_intr_status()
清除中断标志。
一些宏
1 | UART_GPIO43_DIRECT_CHANNEL |