UART
概述
通用异步接收器/发送器(UART)是已知处理特定需求对于各种宽范围适配接口(RS232,RS485,RS422...)的一个组件。串口提供了一个在不同器件间宽范围的适配和便宜的方法来实现全双攻或半双工数据交换。
ESP32芯片有3个串口控制器。它们和其他厂商生产的串口设备兼容。ESP32集成的所有的串口控制器具有相同的寄存器用来编程和灵活。在本文中,这些控制器指UART0,UART1和UART2。
功能概述
以下概述简单描述了在ESP32和其他串口设备建立通讯用到的方法和数据类型。概述显示了一个典型的编写ESP32的串口驱动的工作流程,并且分为了以下几个部分:
1.设置通讯参数-波特率,数据位,停止位等。
2.设置通讯管脚-串口连接到的管脚。
3.驱动安装-为串口驱动定位ESP32的资源。
4.运行串口通讯-发送/接收数据。
5.使用中断-在特定事件里出发中断。
6删除驱动-如果不再需要串口通讯,释放ESP32的资源。
使串口工作至少需要前面的四步,最后两步可选。
驱动用uart_port_t来定义,响应三个串口控制器中的一个。这些定义在以下函数调用中出现。
设置通讯参数
有两个办法来设置串口的通讯参数。一种是通过调用uart_param_conifg()并在uart_config_t结构体里提供配置参数,来一下子实现。
另一种方法是调用专用的函数来分别配置指定的参数:
.波特率-uart_set_baudrate()
.发送位-uart_set_word_length(),从uart_word_length_t中选择。
.校验控制-uart_set_parity(),从uart_parity_t中选择。
.停止位-uart_set_stop_bits(),从uart_stop_bits_t中选择。
.硬件流控模式-uart_set_hw_flow_ctrl(),从uart_hw_flowcontrol_t中选择。
.通讯模式-uart_set_mode()从uart_mode_t中选择。
配置举例:
const int uart_num = UART_NUM_2;
uart_config_t uart_config = {
.baud_rate = 115200,
.date_bits = UART_DATA_8_BITS,
.parity = UART_PARITY_DISABLE,
.stop_bits = UART_STOP_BITS_1,
.flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS,
.rx_flow_ctrl_thress = 122,
};
// Configure UART parameters
ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));
以上所有函数有一个_get_等价方法用来获取当前设置。比如 uart_get_baudrate()。
设置通讯管脚
接下来,配置通讯参数以后,我们设置串口将要连接到的物理管脚号。这可以通过一步来完成,调用函数uart_set_pin()并提供引脚号,这个驱动将会为Tx,Rx,RTS和CTS信号使用。
我们可以通过进入一个宏UART_PIN_NO_CHANGE来代替引脚号,这样当前被分配的引脚将不会改变。如果管脚确认没有使用,也可以用这个宏。
// Set UART pins(TX: IO16 (UART2 default), RX: IO17 (UART2 default), RTS: IO18, CTS: IO19)
ESP_ERROR_CHECK(uart_set_pin(UART_NUM_2, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, 18, 19));
驱动安装
一旦驱动的配置完成,我们调用uart_driver_install()来安装驱动。作为结果,串口需要的一些资源将会被配置。资源的类型/大小会被函数调用的参数制定和关注:
.发送缓冲区的大小
.接收缓冲区的大小
.事件队列句句柄和大小
.和中断有关的标志位
举例:
// Setup UART buffered IO with event queue
const int uart_buffer_size = (1024 * 2);
QueueHandle_t uart_queue;
// Install UART DRIVER using an event queue here
ESP_ERROR_CHECK(uart_driver_install(UART_NUM_2, uart_buffer_size, \
uart_buffer_size, 10, &uart_queue, 0));
如果完成了以上步骤,我们已经准备号链接串口并检查通讯。
运行串口通讯
串口中断的处理处于串口的硬件FSM控制下,发送的数据将会放入发送FIFO缓冲区,FSM将数据序列化并发送出去。接收数据也是类似处理,但却是反过来的。进来的串流被FSM处理并移动到接收FIFO缓冲区。因此,API的通讯函数任务被限制从各自的缓冲区写和读数据,比如 uart_write_bytes() 来发送数据,或者 uart_read_bytes() 来读接收数据。
发送
用来写数据到发送FIFO缓冲区的基本API函数是uart_tx_chars()。如果缓冲区含有没被发送的字符,这个函数将写适当的数据,退出并报告实际写的字节数。
有一个‘伙伴’函数 uart_wait_tx_done(),等待直到数据发送出去并且发送FIFO是空的。
// wait for packet to be sent
const int uart_num = UART_NUM_2;
ESP_ERROR_CHECK(uart_wait_tx_done(uart_num, 100)); //wait timeout is 100 RTOS ticks (TickType_t)
更容易工作的函数是 uart_write_bytes()。它建立了一个中间等级的环形缓冲区并在复制疏导到环形缓冲区后退出。当FIFO有空的位置,数据在后台被中断从环形缓冲区移到FIFO。下面的代码演示了这个函数的使用。
// Write data to UART.
char* test_str = "This is a test string.\n";
uart_write_bytes(uart_num, (const char*)test_str, strlen(test_str));
有个和上面相似的函数,在发送数据后增加一个串口打断 - uart_write_bytes_with_break()。‘串口打断信号’表示保持TX线低电平一段比一个数据帧略长的时间。
// Wrtie data to UART, end with a break signal.
uart_write_bytes_with_break(uart_num, "test break\n", strlen("test break\n"), 100);
接收
为了取回串口接收到并保存在接收FIFO的数据,使用函数 uart_read_bytes()。你可以预先检查接收FIFO里课件的字节数,通过调用 uart_get_buffered_data_len()。下面是使用这个函数的例子:
// Read data from UART
const int uart_num = UART_NUM_2;
uint8_t data[128];
int length = 0;
ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, (size_t*)&length));
length = uart_read_bytes(uart_num, data, length, 100);
如果接收FIFO里的数据没有用且可以废弃,调用 uart_flush()。
软件流控
当硬件流控不能用,可以用 uart_set_rts() 和 uart_set_dtr() 来手动设置RTS和DTR信号的点评高低。
通讯模式选择
串口控制器支持通讯模式集。模式的选择可以在使用函数 uart_set_mode() 时执行。一旦指定模式被选择,串口驱动将根据模式处理外部外围设备的行为。比如可以通过RTS线控制RS485驱动芯片来允许半双工RS485通讯。
// Setup UART in rs485 half duplex mode
ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));
使用中断
有19个中断来报告串口的特殊状态或者检测到的错误。全部可见中断的列表在ESP32技术参考手册里有描述。调用uart_enable_intr_mask()来使能指定的中断,调用uart_disable_intr_mask()来关闭制定的中断。所有中断的掩码在UART_INTR_MASK里可见。注册一个句柄用来服务中断是用uart_isr_register(),释放句柄用uart_isr_free()。一旦句柄被调用,使用uart_clear_intr_status()来清除中断状态位。
API提供了方便的办法来处理上边讨论的中断,通过把他们包装进专门的函数:
. 事件侦测 - 在uart_event_type_t里定义了几个事件,使用FreeRTOS的队列功能可以把它们报告给用户的应用。当调用驱动安装里描述的uart_driver_install()函数时,你可以使能这个功能。使用例子在peripherals/uart_events里。
.队列空间门限或发送超时到达 - 发送或接收中断队列缓冲区被字数的特殊数字填充,或在发送或接收数据一段时间后,产生的中断。为了使用这些中断,首先配置各自缓冲区长度的门限值和和超时门限值,使用uart_intr_config_t结构体配置它们并调用uart_intr_config()函数。然后用uart_enable_rx_intr()和uart_enable_tx_intr()使能中断。相应的用uart_disable_rx_intr()和uart_disable_tx_intr()来禁止中断。
.模式侦测 - 侦测同样的字符被发送了多次产生的中断。允许配置、使能、禁止中断的函数是uart_enable_pattern_det_intr()和cpp:func:uart_disable_pattern_det_intr.
宏
API提供了一些宏来定义配置参数。比如UART_FIFO_LEN定义硬件FIFO缓冲区的长度,UART_BITRATE_MAX给了被串口支持的最大波特率,等。
删除驱动
如果用uart_driver_install()来给一些特殊时段建立通讯,然后不再需要了,可以通过调用uart_driver_delete()移除驱动,来释放相关资源。
RS485特殊通讯选项概述
!以下UART_REGISTER.UART_OPTION_BIT记号将被用来
中间这部分不打算翻译了。
应用举例
配置串口设置并安装串口驱动来读写,用串口1接口:peripherals/uart_echo.
演示如何报告通讯事件变量,如何使用模式侦测中断:peripherals/uart_events.
用同一个串口使用两个独立的freertos任务发送和接收:peripherals/uart_async_rxtxtasks.
使用同步i/o复用描述串口文件:peripherals/uart_select.
建立串口驱动来通过rs485接口进行半双工通讯:peripherals/uart_echo_rs485.这个例子和uart_echo相似,但是提供了通过rs485接口芯片连接到esp32管脚进行通讯。