基于ESP32的uart通讯

本文详细介绍ESP32上的UART通讯接口配置与使用方法,包括UART0和UART1的配置函数编写,通过实例展示了如何利用ESP32进行异步通讯及硬件流控制通讯。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  本文源码地址为:http://download.youkuaiyun.com/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直接连接即可),发送数据,可以得到如下结果。说明串口数据发送成功。

 

 

 

相关知识:UART相关API接口








转载于:https://www.cnblogs.com/noticeable/p/7465726.html

### ESP32 UART 半双工通信配置与使用 对于ESP32设备,在UART接口上实现半双工通信涉及特定的硬件和软件设置。通常情况下,全双工模式允许数据的同时发送和接收;然而,在某些应用场景下,可能更倾向于采用半双工方式工作。 #### 配置GPIO引脚用于半双工操作 为了使能UART处于半双公状态,需指定一个额外的控制信号线来切换传输方向。此功能可通过编程设定相应的GPIO作为RTS(Request to Send)或DTR(Data Terminal Ready),并将其连接到收发共享的数据线上[^1]。 ```c #include "driver/uart.h" #include "esp_log.h" #define TX_PIN GPIO_NUM_17 // 定义TX使用的GPIO编号 #define RX_PIN GPIO_NUM_16 // 定义RX使用的GPIO编号 #define RTS_PIN GPIO_NUM_4 // 定义RTS使用的GPIO编号, 控制半双工模式下的数据流向 void setup_uart_half_duplex(void){ const 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_RTS, // 启用硬件流控中的RTS部分 }; // 设置UART参数 uart_param_config(UART_NUM_2, &uart_config); // 设置UART管脚映射 uart_set_pin(UART_NUM_2, TX_PIN, RX_PIN, RTS_PIN, UART_PIN_NO_CHANGE); // 初始化UART队列缓冲区大小为128字节 uart_driver_install(UART_NUM_2, 128*2, 0, 0, NULL, 0); } ``` 上述代码片段展示了如何初始化UART端口以支持基于RTS引脚管理的半双工通讯机制。通过调用`uart_param_config()`函数定义波特率及其他串行通信属性,并利用`uart_set_pin()`指派实际物理引脚给逻辑上的Tx/Rx以及RTS线路。 当启用硬件流控制时,可以通过改变RTS电平高低来指示当前是否可以接受新数据输入还是准备发送消息出去。具体来说: - 当RTS被拉低表示请求对方停止传送更多字符直到本地完成处理; - 反之则意味着准备好接收新的信息包。 值得注意的是,虽然这里描述的方法适用于大多数情况,但在特殊场合下也可能需要调整具体的实施细节以便更好地适应目标平台特性或是满足应用需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值