本文源碼地址為:http://download.csdn.net/download/noticeable/9961054
ESP32上有三個UART通訊接口,設備號,從0~2,即UART0,UART1,UART2。支持異步通訊,ESP32開發板上micro USB 連接的即使UART0接口,通常使用該串口作為日志輸出,用於調試,另外兩個串口作為工作串口,可用來輸出和接收數據。
對於uart通訊,主要可以分為以下幾個部分:
PART1:
定義引腳
1 #ifndef size_t 2 #define size_t unsigned int 3 #endif 4 #define BUF_SIZE (1024) 5 #define ECHO_TEST_TXD (4) 6 #define ECHO_TEST_RXD (5) 7 #define ECHO_TEST_RTS (18) 8 #define ECHO_TEST_CTS (19)
9 QueueHandle_t uart0_queue;
定義引腳,這里TXD、RXD是串口輸出通常用到數據寫出和讀入的引腳,關於RTS和CTS引腳 (注意:由於UART0已經的引腳配置已經固定默認在BootLoader中了,不能更改,所以不能配置引腳也無需定義)
RTS(Request To Send 請求發送):用於傳輸PC機發往串口Modem等設備的信號,該信號表示PC機是否允許Modem發數據。
CTS:Clear to send,在計算機UART引腳中定義表示為允許發送。
在與計算機通訊過程中常與RTS( request to send, 請求發送信號 )一起被提到,是UART通訊過程中flow control的兩個引腳,是成對出現的。
下面說一下這兩個引腳的作用;
(1) 隱藏終端問題被減輕了,因為長data幀只有在信道預約后才能被發送;
(2)因為rts幀和cts幀較短,涉及rts幀和cts幀的碰撞將僅持續很短的rts幀或cts幀持續期。一旦rts幀和cts幀被正確傳輸,后續的data幀和ack幀應當能無碰撞的發送。
PART2:編寫uart處理任務
1 void uart_task(void *pvParameters) 2 { 3 int uart_num = (int) pvParameters; 4 uart_event_t event; 5 size_t buffered_size; 6 uint8_t* dtmp = (uint8_t*) malloc(BUF_SIZE); 7 for(;;) { 8 //Waiting for UART event. 9 if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) { 10 ESP_LOGI(TAG, "uart[%d] event:", uart_num); 11 switch(event.type) { 12 //Event of UART receving data 13 /*We'd better handler data event fast, there would be much more data events than 14 other types of events. If we take too much time on data event, the queue might 15 be full. 16 in this example, we don't process data in event, but read data outside.*/ 17 case UART_DATA: 18 uart_get_buffered_data_len(uart_num, &buffered_size); 19 ESP_LOGI(TAG, "data, len: %d; buffered len: %d", event.size, buffered_size); 20 break; 21 //Event of HW FIFO overflow detected 22 case UART_FIFO_OVF: 23 ESP_LOGI(TAG, "hw fifo overflow\n"); 24 //If fifo overflow happened, you should consider adding flow control for your application. 25 //We can read data out out the buffer, or directly flush the rx buffer. 26 uart_flush(uart_num); 27 break; 28 //Event of UART ring buffer full 29 case UART_BUFFER_FULL: 30 ESP_LOGI(TAG, "ring buffer full\n"); 31 //If buffer full happened, you should consider encreasing your buffer size 32 //We can read data out out the buffer, or directly flush the rx buffer. 33 uart_flush(uart_num); 34 break; 35 //Event of UART RX break detected 36 case UART_BREAK: 37 ESP_LOGI(TAG, "uart rx break\n"); 38 break; 39 //Event of UART parity check error 40 case UART_PARITY_ERR: 41 ESP_LOGI(TAG, "uart parity error\n"); 42 break; 43 //Event of UART frame error 44 case UART_FRAME_ERR: 45 ESP_LOGI(TAG, "uart frame error\n"); 46 break; 47 //UART_PATTERN_DET 48 case UART_PATTERN_DET: 49 ESP_LOGI(TAG, "uart pattern detected\n"); 50 break; 51 //Others 52 default: 53 ESP_LOGI(TAG, "uart event type: %d\n", event.type); 54 break; 55 } 56 } 57 } 58 free(dtmp); 59 dtmp = NULL; 60 vTaskDelete(NULL); 61 }
uart_task任務的作用為對接收到的數據進行處理,並將結果通過日志的形式打印到串口調試助手上,最后在任務結束時,將處理任務刪除掉。
PART3:
編寫uart0 配置函數
1 void uart_evt_test() 2 { 3 int uart_num = UART_NUM_0; 4 uart_config_t uart_config = { 5 .baud_rate = 115200, 6 .data_bits = UART_DATA_8_BITS, 7 .parity = UART_PARITY_DISABLE, 8 .stop_bits = UART_STOP_BITS_1, 9 .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, 10 .rx_flow_ctrl_thresh = 122, 11 }; 12 //Set UART parameters 13 uart_param_config(uart_num, &uart_config); 14 //Set UART log level 15 esp_log_level_set(TAG, ESP_LOG_INFO); 16 //Install UART driver, and get the queue. 17 uart_driver_install(uart_num, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart0_queue, 0); 18 //Set UART pins,(-1: default pin, no change.) 19 //For UART0, we can just use the default pins. 20 //uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); 21 //Set uart pattern detect function. 22 uart_enable_pattern_det_intr(uart_num, '+', 3, 10000, 10, 10); 23 //Create a task to handler UART event from ISR 24 xTaskCreate(uart_task, "uart_task", 2048, (void*)uart_num, 12, NULL); 25 //process data 26 uint8_t* data = (uint8_t*) malloc(BUF_SIZE); 27 do { 28 int len = uart_read_bytes(uart_num, data, BUF_SIZE, 100 / portTICK_RATE_MS); 29 if(len > 0) { 30 ESP_LOGI(TAG, "uart read : %d", len); 31 uart_write_bytes(uart_num, (const char*)data, len); 32 } 33 } while(1); 34 }
uart_event_test函數,用來對uart進行配置其中
uart_num 設置UART外設號碼,可選位UART_NUM_0、UART_NUM_1、UART_NUM_2
baud_rate 設置波特率 可選為:
data_bits 設置數據位寬
parity 是否校驗 UART_PARITY_DISABLE禁用UART奇偶校驗,UART_PARITY_EVEN啟用UART偶校驗,UART_PARITY_ODD啟用UART奇校驗
stop_bits 停止位位數
flow_ctrl UART硬件流控制模式 UART_HW_FLOWCTRL_DISABLE 禁用硬件流控制,UART_HW_FLOWCTRL_RTS啟用RX硬件流控制(rts),UART_HW_FLOWCTRL_CTS啟用TX硬件流控制,UART_HW_FLOWCTRL_CTS_RTS 啟用硬件流控制。
rx_flow_ctrl_thresh 硬件流控制的閾值。
最后調用 uart_param_config(uart_num, &uart_config);對uart參數進行設定
esp_log_level_set(TAG, ESP_LOG_INFO);對esp32的輸出日志設置級別,這里將uart example設置為正常的流和事件作為日志輸出。
uart_driver_install(uart_num, BUF_SIZE * 2, BUF_SIZE * 2, 10, &uart0_queue, 0);安裝UART驅動程序。UART ISR處理程序將附加到該功能正在運行的同一CPU內核。
uart_enable_pattern_det_intr(uart_num, '+', 3, 10000, 10, 10); UART使能模式檢測功能。專為“AT命令”等應用程序而設計。當硬件檢測到一系列相同的字符時,中斷將被觸發。
xTaskCreate(uart_task, "uart_task", 2048, (void*)uart_num, 12, NULL); 調用uart_task 任務,對接收到的數據相關的長度等信息進行打印。
其后的任務即為處理接收到的數據,並將數據打印出來,並等待。
函數的作用是配置了uart0的工作模式,並通過聲明了的uart0_queue消息隊列接收信息,並在調用uart_driver_install注冊串口時將消息隊列傳遞到層,當有串口消息來時,串口消息隊列會發送消息到該消息隊列,然后通過uart_task接收串口數據,如果檢測到入伍中有消息隊列則讀串口。
可以看出,uart0的通訊方式是有消息來了才接收,所以其為異步通訊方式。
PART4:
編寫uart1配置函數
1 void uart_echo_test() 2 { 3 int uart_num = UART_NUM_1; 4 uart_config_t uart_config = { 5 .baud_rate = 115200, 6 .data_bits = UART_DATA_8_BITS, 7 .parity = UART_PARITY_DISABLE, 8 .stop_bits = UART_STOP_BITS_1, 9 .flow_ctrl = UART_HW_FLOWCTRL_CTS_RTS, 10 .rx_flow_ctrl_thresh = 122, 11 }; 12 //Configure UART1 parameters 13 uart_param_config(uart_num, &uart_config); 14 //Set UART1 pins(TX: IO4, RX: I05, RTS: IO18, CTS: IO19) 15 uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS); 16 //Install UART driver( We don't need an event queue here) 17 //In this example we don't even use a buffer for sending data. 18 uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0); 19 20 uint8_t* data = (uint8_t*) malloc(BUF_SIZE); 21 while(1) { 22 //Read data from UART 23 int len = uart_read_bytes(uart_num, data, BUF_SIZE, 20 / portTICK_RATE_MS); 24 //Write data back to UART 25 uart_write_bytes(uart_num, (const char*) data, len); 26 } 27 }
對於uart1,其大致過程與uart0函數是相似的,但是不同點在與其通訊模式與uart0是不同的,第9行可以看出它是通過硬件流進行通訊的。
PART5:
app_main函數
1 void app_main() 2 { 3 //A uart read/write example without event queue; 4 xTaskCreate(uart_echo_test, "uart_echo_test", 1024, NULL, 10, NULL); 5 6 //A uart example with event queue. 7 uart_evt_test(); 8 }
通過app_main對兩個函數進行調用。
實驗現象:
由於本人手上沒有硬件流相關的串口調試器,所以對於uart1的驗證無法進行了,這里只對uart0的結果進行實驗。
打開串口調試助手,連接esp32(通過usb直接連接即可),發送數據,可以得到如下結果。說明串口數據發送成功。

