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);