ESP32-S3學習筆記<3>:UART的應用
- 1. 頭文件包含
- 2. UART的配置
- 2.1 uart_num的選擇
- 2.2 uart_config的設定
- 2.2.1 baud_rate/波特率設置
- 2.2.2 data_bits/數據位數設置
- 2.2.3 parity/奇偶校驗位設置
- 2.2.4 stop_bits/停止位設置
- 2.2.5 flow_ctrl/流控位設置
- 2.2.6 rx_flow_ctrl_thresh/接收流控門限設置
- 2.2.6 lp_source_clk/指定時鐘源
- 3. UART使用的GPIO的配置
- 4. UART驅動的加載
- 5. 獲取緩沖中的數據量
- 6. 讀取和寫入數據
- 7. 示例
1. 頭文件包含
#include "driver/gpio.h"
#include "hal/gpio_types.h"
#include "driver/uart.h"
#include "esp_err.h"
2. UART的配置
使用如下函數配置UART:
esp_err_t uart_param_config(uart_port_t uart_num, const uart_config_t *uart_config);
各個參數的含義:
2.1 uart_num的選擇
這個參數用來選擇配置哪個UART。可用的選項有:
typedef enum {UART_NUM_0, /*!< UART port 0 */UART_NUM_1, /*!< UART port 1 */
#if SOC_UART_HP_NUM > 2UART_NUM_2, /*!< UART port 2 */
#endif
#if SOC_UART_HP_NUM > 3UART_NUM_3, /*!< UART port 3 */
#endif
#if SOC_UART_HP_NUM > 4UART_NUM_4, /*!< UART port 4 */
#endif
#if (SOC_UART_LP_NUM >= 1)LP_UART_NUM_0, /*!< LP UART port 0 */
#endifUART_NUM_MAX, /*!< UART port max */
} uart_port_t;
對于ESP32-S3,一共有3個UART。但是 UART_NUM_0 一般給系統下載和調試用,所以一般用 UART_NUM_1 或 UART_NUM_2 。
2.2 uart_config的設定
第二個參數用來配置UART的工作參數。結構體 **uart_config_t ** 的定義如下:
typedef struct {int baud_rate; /*!< UART baud rate*/uart_word_length_t data_bits; /*!< UART byte size*/uart_parity_t parity; /*!< UART parity mode*/uart_stop_bits_t stop_bits; /*!< UART stop bits*/uart_hw_flowcontrol_t flow_ctrl; /*!< UART HW flow control mode (cts/rts)*/uint8_t rx_flow_ctrl_thresh; /*!< UART HW RTS threshold*/union {uart_sclk_t source_clk; /*!< UART source clock selection */
#if (SOC_UART_LP_NUM >= 1)lp_uart_sclk_t lp_source_clk; /*!< LP_UART source clock selection */
#endif};struct {uint32_t backup_before_sleep: 1; /*!< If set, the driver will backup/restore the HP UART registers before entering/after exiting sleep mode.By this approach, the system can power off HP UART's power domain.This can save power, but at the expense of more RAM being consumed */} flags; /*!< Configuration flags */
} uart_config_t;
2.2.1 baud_rate/波特率設置
用于設定UART的波特率。直接填入數據即可。例如115200。但是最大不超過5000000。
2.2.2 data_bits/數據位數設置
設定數據位。可用的選項有:
typedef enum {UART_DATA_5_BITS = 0x0, /*!< word length: 5bits*/UART_DATA_6_BITS = 0x1, /*!< word length: 6bits*/UART_DATA_7_BITS = 0x2, /*!< word length: 7bits*/UART_DATA_8_BITS = 0x3, /*!< word length: 8bits*/UART_DATA_BITS_MAX = 0x4,
} uart_word_length_t;
最常見是8bit傳輸,即 UART_DATA_8_BITS 。
2.2.3 parity/奇偶校驗位設置
設定奇偶校驗位。可用的選項有:
typedef enum {UART_PARITY_DISABLE = 0x0, /*!< Disable UART parity*/UART_PARITY_EVEN = 0x2, /*!< Enable UART even parity*/UART_PARITY_ODD = 0x3 /*!< Enable UART odd parity*/
} uart_parity_t;
大多數時候都設置為 UART_PARITY_DISABLE ,即不使用奇偶校驗位。不過根據實際使用要求選擇。
2.2.4 stop_bits/停止位設置
設定停止位長度。可用的選項有:
typedef enum {UART_STOP_BITS_1 = 0x1, /*!< stop bit: 1bit*/UART_STOP_BITS_1_5 = 0x2, /*!< stop bit: 1.5bits*/UART_STOP_BITS_2 = 0x3, /*!< stop bit: 2bits*/UART_STOP_BITS_MAX = 0x4,
} uart_stop_bits_t;
停止位可以是1位、1.5位、2位。常見的是使用1位。
2.2.5 flow_ctrl/流控位設置
設定是否使用硬件流控。可用的選項有:
typedef enum {UART_HW_FLOWCTRL_DISABLE = 0x0, /*!< disable hardware flow control*/UART_HW_FLOWCTRL_RTS = 0x1, /*!< enable RX hardware flow control (rts)*/UART_HW_FLOWCTRL_CTS = 0x2, /*!< enable TX hardware flow control (cts)*/UART_HW_FLOWCTRL_CTS_RTS = 0x3, /*!< enable hardware flow control*/UART_HW_FLOWCTRL_MAX = 0x4,
} uart_hw_flowcontrol_t;
根據需要選擇。一般2線UART應用,設置為 UART_HW_FLOWCTRL_DISABLE 。
2.2.6 rx_flow_ctrl_thresh/接收流控門限設置
ESP32-S3有3個UART,同時內置1KB的FIFO。這個FIFO由所有的3個UART分享。由于3個UART有6個通道(3發3收),所以默認情況下,每個UART分得128B的FIFO空間(需要注意,這個FIFO空間是可調的,但是一般情況下無需調整)。
rx_flow_ctrl_thresh 用于設置接收流控門限。因為接收緩存默認128B,rx_flow_ctrl_thresh 設置為比128B略小的數據即可,比如120。也就是接收FIFO內容超過120字節,產生接收流控。
這個僅在使能了硬件流控(flow_ctrl = UART_HW_FLOWCTRL_RTS 或者flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS)時候有效。
2.2.6 lp_source_clk/指定時鐘源
該參數指定UART時鐘源。有如下選項:
typedef enum {UART_SCLK_APB = SOC_MOD_CLK_APB, /*!< UART source clock is APB CLK */UART_SCLK_RTC = SOC_MOD_CLK_RC_FAST, /*!< UART source clock is RC_FAST */UART_SCLK_XTAL = SOC_MOD_CLK_XTAL, /*!< UART source clock is XTAL */UART_SCLK_DEFAULT = SOC_MOD_CLK_APB, /*!< UART source clock default choice is APB */
} soc_periph_uart_clk_src_legacy_t;
缺省使用 SOC_MOD_CLK_APB 即可。
3. UART使用的GPIO的配置
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:同上,指定哪一個UART。
- tx_io_num:指定UART-TX GPIO。
- rx_io_num:指定UART-RX GPIO。
- rts_io_num:指定UART-RTS GPIO。
- cts_io_num:指定UART-CTS GPIO。
一般情況下,使用2線UART,則不需要使用CTS引腳和RTS引腳。則后兩個參數設置為 UART_PIN_NO_CHANGE 。還有一些場合,只需要使用接收或發送,則另一個不用的發送或接收引腳也設置為 UART_PIN_NO_CHANGE 。
4. UART驅動的加載
使用如下函數加載驅動。
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:指定使用哪一個UART外設。
- rx_buffer_size:指定接收緩存大小。
- tx_buffer_size:指定發送緩存大小。這兩個緩存大小,不是指UART外設中FIFO的大小,而是由驅動開辟的位于內存中的緩存大小。接收緩沖大小 rx_buffer_size 必需大于分配給UART外設的接收FIFO的大小(例如,當接收FIFO是默認值128時,則設置為大于128的值)。發送緩沖大小 tx_buffer_size 必需大于分配給UART外設的發送FIFO的大小,或者設置為0。如果設置為0,則發送是阻塞的,發送函數會在數據完全發送后返回(個人理解應該是發送數據全部填入到發送FIFO后就返回)。
- queue_size:事件隊列大小。所謂事件隊列,是UART操作(如發送或接收)觸發了某個事件,如發送完成或接收到數據、超時之類的,則產生一個事件,給用戶處理。不需要,則設置為0。
- uart_queue:這是一個出參,不使用消息隊列時,設置為NULL即可。
- intr_alloc_flags:指定一些標記,如中斷優先級等。定義在 esp_intr_alloc.h 文件中。注意不可使用 ESP_INTR_FLAG_IRAM ,因為驅動的ISR程序沒有定義在內部指令RAM中。
5. 獲取緩沖中的數據量
在從驅動讀取數據之前,一般要先獲取緩沖中有多少數據可讀;在向驅動寫入數據之前,一般要先獲取緩沖中有多少空閑空間可寫。如下兩個函數可實現這兩項功能。
esp_err_t uart_get_buffered_data_len(uart_port_t uart_num, size_t *size) ;esp_err_t uart_get_tx_buffer_free_size(uart_port_t uart_num, size_t *size) ;
6. 讀取和寫入數據
int uart_read_bytes(uart_port_t uart_num, void *buf, uint32_t length, TickType_t ticks_to_wait) ;int uart_write_bytes(uart_port_t uart_num, const void *src, size_t size) ;
對于讀取數據,可以通過參數 ticks_to_wait 指定等待超時時間,以FreeRTOS中的systick計數為單位。
7. 示例
以下程序示例中,配置一個UART接口,然后安裝驅動,循環從驅動中讀取數據并發送回去,從而實現上位機發送數據的loopback。
test_uart.h文件:
#define TEST_UART_UART_GPIO_TX (GPIO_NUM_4)
#define TEST_UART_UART_GPIO_RX (GPIO_NUM_5)
#define TEST_UART_UART_NUM (UART_NUM_1)void TEST_UART_UARTConfig(void) ;
void TEST_UART_UARTRecv2Send(void) ;
test_uart.c文件:
#include "driver/gpio.h"
#include "hal/gpio_types.h"
#include "driver/uart.h"
#include "esp_err.h"#include "test_uart.h"void TEST_UART_UARTConfig(void)
{esp_err_t iRetVal ;const uart_config_t stUARTConfig ={.baud_rate = 115200 ,.data_bits = UART_DATA_8_BITS ,.parity = UART_PARITY_DISABLE ,.stop_bits = UART_STOP_BITS_1 ,.flow_ctrl = UART_HW_FLOWCTRL_DISABLE ,.rx_flow_ctrl_thresh = 64 ,.source_clk = UART_SCLK_APB } ;/* config UART */iRetVal = uart_param_config(TEST_UART_UART_NUM, &stUARTConfig) ;ESP_ERROR_CHECK(iRetVal) ;/* set UART TX & RX GPIO */iRetVal = uart_set_pin(TEST_UART_UART_NUM, TEST_UART_UART_GPIO_TX, TEST_UART_UART_GPIO_RX, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE) ;ESP_ERROR_CHECK(iRetVal) ;/* install driver */iRetVal = uart_driver_install(TEST_UART_UART_NUM, 128 * 4, 128 * 4, 0, NULL, 0);ESP_ERROR_CHECK(iRetVal) ;return ;
}void TEST_UART_UARTRecv2Send(void)
{size_t szSize = 0 ;unsigned char ucBuffer[128] ;esp_err_t iRetVal ;int iReadSize ;/* get rx data size */iRetVal = uart_get_buffered_data_len(TEST_UART_UART_NUM, &szSize) ;ESP_ERROR_CHECK(iRetVal) ;if(0 != szSize){iReadSize = uart_read_bytes(TEST_UART_UART_NUM, (void *)ucBuffer, (szSize > sizeof(ucBuffer)) ? sizeof(ucBuffer) : szSize, 10) ;if(0 < iReadSize){uart_write_bytes(TEST_UART_UART_NUM, (void *)ucBuffer, iReadSize) ;}}
}
main.c文件:
#include <stdint.h>
#include <stdio.h>
#include <stdbool.h>
#include <unistd.h>#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "freertos/semphr.h"#include "test_uart.h"void app_main(void)
{TEST_UART_UARTConfig() ;while (true){TEST_UART_UARTRecv2Send() ;vTaskDelay(50) ;}
}