1. 程式人生 > >Universal Asynchronous Receiver/Transmitter

Universal Asynchronous Receiver/Transmitter

UART

概述

嵌入式應用通常要求一個簡單的並且佔用系統資源少的方法來傳輸資料.通用非同步收發傳輸器(UART) 即可以滿足這些要求,它能夠靈活地與外部裝置進行全雙工資料交換.ESP32 晶片中有 3 個UART 控制器可供使用,並且相容不同的 UART 裝置.另外,UART 還可以用作紅外資料交換(IrDA) 或 RS-485 調變解調器.

3 個 UART 控制器有一組功能相同的暫存器.本文以 UARTn 指代 3 個 UART 控制器,n 為0、1、2.

主要特性

  • 可程式設計收發波特率
  • 3 個 UART 的傳送 FIFO 以及接收 FIFO 共享1024 x 8-bit RAM
  • 全雙工非同步通訊
  • 支援輸入訊號波特率自檢功能
  • 支援 5/6/7/8 位資料長度
  • 支援 1/1.5/2/3/4 個停止位
  • 支援奇偶校驗位
  • 支援 RS485 協議
  • 支援 IrDA 協議
  • 支援 DMA 高速資料通訊
  • 支援 UART 喚醒模式

功能描述

UART 是一種以字元為導向的通用資料鏈,可以實現裝置間的通訊.非同步傳輸的意思是不需要在傳送資料上新增時鐘資訊.這也要求傳送端和接收端的速率、停止位、奇偶校驗位等都要相同,通訊才能成功.

一個典型的 UART 幀開始於一個起始位,緊接著是有效資料,然後是奇偶校驗位(可有可無),最後是停止位.ESP32 上的 UART 控制器支援多種字元長度和停止位.另外,控制器還支援軟硬體流控和 DMA,可以實現無縫高速的資料傳輸.開發者可以使用多個 UART 埠,同時又能保證很少的軟體開銷.

UART 基本架構圖

圖1 UART 基本架構圖

UART 有兩個時鐘源:80-MHz APB_CLK 以及參考時鐘 REF_TICK (詳情請參考章節復位和時鐘).可以通過配置 UART_TICK_REF_ALWAYS_ON 來選擇時鐘源.時鐘中的分頻器用於對時鐘源進行分頻,然後產生時鐘訊號來驅動 UART 模組.ART_CLKDIV_REG 將分頻係數分成兩個部分:UART_CLKDIV 用於配置整數部分,UART_CLKDIV_FRAG 用於配置小數部分.

UART 控制器可以分為兩個功能塊:傳送塊和接收塊.

傳送塊包含一個傳送 FIFO 用於快取待發送的資料.軟體可以通過 APB 匯流排寫 Tx_FIFO,也可以通過 DMA 將資料搬入 Tx_FIFO.Tx_FIFO_Ctrl 用於控制 Tx_FIFO 的讀寫過程,當 Tx_FIFO 非空時,Tx_FSM 通過 Tx_FIFO_Ctrl讀取資料,並將資料按照配置的幀格式轉化成位元流.位元流輸出訊號 txd_out 可以通過配置 UART_TXD_INV 暫存器實現取反功能.

接收塊包含一個接收 FIFO 用於快取待處理的資料.輸入位元流 rxd_in 可以輸入到 UART 控制器.可以通過 UART_RXD_INV 暫存器實現取反.Baudrate_Detect 通過檢測最小位元流輸入訊號的脈寬來測量輸入訊號的波特率.Start_Detect 用於檢測資料的 START 位,當檢測到 START 位之後,RX_FSM 通過 Rx_FIFO_Ctrl 將幀解析後的資料存入 Rx_FIFO 中.

軟體可以通過 APB 匯流排讀取 Rx_FIFO 中的資料.為了提高資料傳輸效率,可以使用 DMA 方式進行資料傳送或接收.

HW_Flow_Ctrl 通過標準 UART RTS 和 CTS(rtsn_out 和 ctsn_in)流控訊號來控制 rxd_in 和 txd_out 的資料流.SW_Flow_Ctrl 通過在傳送資料流中插入特殊字元以及在接收資料流中檢測特殊字元來進行資料流的控制.當 UART 處於 Light-sleep(詳情請參考章節低功耗管理)狀態時,Wakeup_Ctrl 開始計算 rxd_in 的脈衝個數,當脈衝個數大於 UART_ACTIVE_THRESHOLD 時產生 wake_up 訊號給 RTC 模組,由 RTC 來喚醒 UART 控制器.

UART 共享RAM 圖

UART 共享 RAM 圖

應用示例

配置 UART 設定並使用 UART1 介面安裝 UART 驅動程式進行讀/寫:peripherals/uart_echo.

設定 UART 驅動程式以半雙工模式通過 RS485 介面進行通訊:peripherals/uart_echo_rs485. 此示例類似於 uart_echo,但通過連線到 ESP32 引腳的 RS485 介面晶片提供通訊.

API Reference

Header File

API 使用

以下概述描述了用於在 ESP32 和某些其他 UART 裝置之間建立通訊的功能和資料型別. 概述反映了程式設計 ESP32 的UART驅動程式時的典型工作流程,並分為以下幾個部分:

  1. 設定通訊引數 - 波特率,資料位,停止位等
  2. 設定通訊引腳 - 連線另一個 UART 的引腳
  3. 驅動程式安裝 - 為 UART 驅動程式分配 ESP32 的資源
  4. 執行 UART 通訊 - 傳送/接收資料
  5. 使用中斷 - 觸發特定通訊事件的中斷
  6. 刪除驅動程式 - 如果不再需要 UART 通訊,則釋放 ESP32 的資源

使 UART 能開始工作是完成前面的四個步驟,後兩個步驟是可選的.

驅動程式由uart_port_t標識,它對應於一個組 UART 控制器. 這種識別存在於以下所有函式呼叫中.

設定通訊引數

有兩種方法可以設定 UART 的通訊引數. 一種是通過呼叫uart_param_config()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,
    .data_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_thresh = 122,
};
// Configure UART parameters
ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));

設定通訊引腳

通過呼叫函式 uart_set_pin()我們可以輸入巨集UART_PIN_NO_CHANGE而不是 GPIO 引腳編號,並且不會更改當前分配的引腳. 如果不使用某個引腳,則應輸入相同的巨集.

// 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()來安裝 UART 驅動. 並分配給 UART 所需的若干資源. 資源的型別/大小被指定為函式引數並需要考慮:

  • 傳送緩衝區的大小
  • 接收緩衝區的大小
  • 事件佇列控制代碼和大小
  • 用於分配中斷的標誌
// 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));

如果上述所有步驟均已完成,我們就可以連線其他 UART 裝置並開始通訊.

執行 UART 通訊

序列通訊的過程受 UART 硬體 FSM 的控制. 要傳送的資料應放入 Tx FIFO 緩衝區, FSM 將序列化併發送出去. 完成類似的過程,但是以相反的順序,接收資料. 傳入的序列流由 FSM 處理並移至 Rx FIFO 緩衝區. 因此, API 的通訊功能的任務僅限於向/從相應緩衝區寫入和讀取資料. 這反映在一些函式名稱中,例如:uart_write_bytes()用於傳輸資料,或uart_read_bytes()用於讀取傳入資料.

使用中斷

報告了 UART 的特定狀態或檢測到的錯誤有 19 箇中斷. ESP32 技術參考手冊(PDF)中介紹了可用中斷的完整列表. 要啟用特定中斷,請呼叫uart_enable_intr_mask(),以禁用呼叫uart_disable_intr_mask(). 所有中斷的掩碼都以UART_INTR_MASK的形式提供. 使用uart_isr_register()完成向服務中斷註冊處理程式,使用uart_isr_free()釋放處理程式. 要在呼叫處理程式後清除中斷狀態位,請使用uart_clear_intr_status().

刪除驅動程式

如果與uart_driver_install()建立通訊一段特定時間,然後不需要,則可以通過呼叫uart_driver_delete()來刪除驅動程式以釋放分配的資源.