基于 esp-idf 的 UART 应用例程解读

1 UART Echo 应用例程解读

此示例演示了“ESP32 如何通过 UART 接口将接收到的数据回传给对端设备”。主要突出 uart_write_bytes()uart_read_bytes() 这两个 API 用法。

#include <stdio.h>         //C 语言头文件
#include "freertos/FreeRTOS.h"   //FreeRTOS 系统文件
#include "freertos/task.h"     //创建任务
#include "driver/uart.h"      //UART 驱动
#include "driver/gpio.h"        //GPIO 配置
#include "sdkconfig.h"       //Sdkconfig 配置选项

/**
 * This is an example which echos any data it receives on configured UART back to the sender,
 * with hardware flow control turned off. It does not use UART driver event queue.
 *
 * - Port: configured UART
 * - Receive (Rx) buffer: on
 * - Transmit (Tx) buffer: off
 * - Flow control: off
 * - Event queue: off
 * - Pin assignment: see defines below (See Kconfig)
 */
// 在 menuconfig 中定义 UART 管脚配置
#define ECHO_TEST_TXD (CONFIG_EXAMPLE_UART_TXD)
#define ECHO_TEST_RXD (CONFIG_EXAMPLE_UART_RXD)
#define ECHO_TEST_RTS (CONFIG_EXAMPLE_UART_RTS)
#define ECHO_TEST_CTS (CONFIG_EXAMPLE_UART_CTS)

#define ECHO_UART_PORT_NUM      (CONFIG_EXAMPLE_UART_PORT_NUM)  //定义 UART 端口(控制器)
#define ECHO_UART_BAUD_RATE     (CONFIG_EXAMPLE_UART_BAUD_RATE)         //定义 UART 波特率
#define ECHO_TASK_STACK_SIZE    (CONFIG_EXAMPLE_TASK_STACK_SIZE)         //任务堆栈大小的设置,设置范围:1K ~ 16 K 。定义 UART Echo 示例的堆栈大小,堆栈大小不足会导致 Crash 碰撞。默认设置是 2 K 。此空间从 DRAM 里分配

#define BUF_SIZE (1024)      //定义 UART Ring Buffer 缓冲区大小,        范围是 0~2048,默认是 1 K;此空间从 DRAM 里分配


static void echo_task(void *arg)
{
    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    uart_config_t uart_config = {
        .baud_rate = ECHO_UART_BAUD_RATE,      //设置 UART 波特率
        .data_bits = UART_DATA_8_BITS,   //UART 数据位,可选 5\6\7 位
        .parity    = UART_PARITY_DISABLE,            //UART 奇偶校验 不使能
        .stop_bits = UART_STOP_BITS_1,   //停止位,可选1.5 \ 2 位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE,   //硬件流控 不使能
        .source_clk = UART_SCLK_APB,      //UART 时钟源设置,默认 APB 时钟(80MHz),可选 8K RTC 和 32.768K   XTAL  外部时钟
    };
    int intr_alloc_flags =0;        // UART 中断优先级设置标志   
    //对应 menuconfig  中的 Place UART ISR function into IRAM 配置选项。0 表示未使能,1 表示使能。
  //如果不选择此选项,UART 中断将长时间禁用并且在进行 SPI FLASH  操作时可能会导致数据丢失。
#if CONFIG_UART_ISR_IN_IRAM
    intr_alloc_flags = ESP_INTR_FLAG_IRAM;
#endif

    ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));     //安装 UART 驱动程序并将 UART 设置为默认配置
    ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));                         //设置 UART 配置参数
    ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));

    // Configure a temporary buffer for the incoming data
    uint8_t *data = (uint8_t *) malloc(BUF_SIZE);

    while (1) {
        // Read data from the UART
        int len = uart_read_bytes(ECHO_UART_PORT_NUM, data, BUF_SIZE, 20 / portTICK_RATE_MS);
        // Write data back to the UART
        uart_write_bytes(ECHO_UART_PORT_NUM, (const char *) data, len);
    }
}

void app_main(void)
{
    xTaskCreate(echo_task, "uart_echo_task", ECHO_TASK_STACK_SIZE, NULL, 10, NULL);
}

uart_driver_install() 函数对应的参数:

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端口号,最大端口号为(UART_NUM_MAX -1)。

  • rx_buffer_size:UART RX 环形(ring buffer size)缓冲区大小,应大于 UART FIFO(128 字节) 的大小。

  • tx_buffer_size:UART TX 环形缓冲区大小。如果设置为零,驱动程序将不使用 TX 缓冲区,TX 功能将阻塞任务,直到所有数据都发送出去。

  • queue_size:UART 事件队列大小/深度。

  • uart_queue:UART 事件队列句柄(输出参数)。成功后,将在此处写入新的队列句柄以提供对 UART 事件的访问。如果设置为 NULL,驱动程序将不使用事件队列。

  • intr_alloc_flags: 用于分配中断的标志。一个或多个(ORred)ESP_INTR_FLAG_* 值。有关更多信息,请参阅 esp_intr_alloc.h。不要在此处设置 ESP_INTR_FLAG_IRAM(驱动程序的 ISR 处理程序不在 IRAM 中)


uart_param_config() 函数对应的参数:

设置 UART 配置参数

uart_param_config(uart_port_t uart_num, constuart_config_t *uart_config)
  • uart_num:UART端口号,最大端口号为(UART_NUM_MAX -1)。

  • uart_config:UART参数设置


uart_set_pin() 函数对应的参数:

将 UART 外设的信号分配给 GPIO 引脚。

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端口号,最大端口号为(UART_NUM_MAX -1)。

  • tx_io_num:UART TX 引脚 GPIO 编号。

  • rx_io_num:UART RX 引脚 GPIO 编号。

  • rts_io_num:UART RTS 引脚 GPIO 编号。

  • cts_io_num:UART CTS 引脚 GPIO 编号。

uart_write_bytes() 函数对应的参数

从给定的缓冲区的长度向 UART 端口发送数据。 如果 UART 驱动程序的参数 ‘tx_buffer_size’ 设置为零:该函数将在所有数据发送出去或至少被推送到 TX FIFO 之前返回。 否则,如果 ‘tx_buffer_size’ > 0,该函数将在将所有数据复制到 tx ring buffer 后返回,UART ISR 将逐渐将数据从 ring buffer 移动到 TX FIFO。

uart_write_bytes(uart_port_t uart_num, const void *src, size_t size)

返回 :

  • (-1) 参数错误

  • OTHERS (>=0) 推送到 TX FIFO 的字节数

  • uart_num:UART端口号,最大端口号为(UART_NUM_MAX -1)。

  • src: 数据缓冲区地址

  • size: 发送的数据长度

uart_read_bytes() 函数对应的参数

UART 从 UART 缓冲区读取字节。

uart_read_bytes(uart_port_t uart_num, void *buf, uint32_t length, TickType_t ticks_to_wait)

返回:

  • (-1) Error

  • OTHERS (>=0) 从 UART FIFO 读取的字节数

  • uart_num:UART端口号,最大端口号为(UART_NUM_MAX -1)。

  • buf: 指向缓冲区的指针。

  • length: 数据长度

  • ticks_to_wait: sTimeout,以 RTOS 滴答计数

  • 测试步骤如下:

1、使用 “串口调试工具”的 TXD & RXD 分别与 ESP32 的 RXD(GPIO5) 和 TXD(GPIO4) 连接。

2、在 PC 端通过“串口调试工具”发送数据给 ESP32

3、ESP32 通过 RXD(GPIO5) 去接收 “串口调试工具”发送过来的数据。目前例程对于这一过程,在 ESP32 端没有打印读取到的数据,可以自行加一个打印。每次接收到数据后就打印一下。

4、然后 ESP32 再将接收到的串口数据通过 TXD 回传给“串口调试工具”

5、“串口调试工具” 的 RXD 接收到 ESP32 回传的数据后,在 PC 端的串口调试助手上可以看到接收到的数据。
在这里插入图片描述

  • 例程测试结果:

在这里插入图片描述

  • 修改后的程序:
    在这里插入图片描述

  • 打印结果:

在这里插入图片描述
在这里插入图片描述


2 uart async rxtxtasks 例程解读

  • 此例程的 UART 设置 与 UART Echo 例程基本一致,主要突出使用 ESP32 的 UART 的 TX 和 RX 同时创建 TX Task 和 RX Task 两个任务并行运行的用法
  • TX Task 以每 2 秒发送一次 “Hello World”的字符串。
  • RX Task 可接收其他设备通过 TX 发送过来的数据。
/* UART asynchronous example, that uses separate RX and TX tasks

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "string.h"
#include "driver/gpio.h"

static const int RX_BUF_SIZE = 1024;

#define TXD_PIN (GPIO_NUM_4)
#define RXD_PIN (GPIO_NUM_5)

void init(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_DISABLE,
        .source_clk = UART_SCLK_APB,返回:
    };
    // We won't use a buffer for sending data.
    uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
    uart_param_config(UART_NUM_1, &uart_config);
    uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}

int sendData(const char* logName, const char* data)
{
    const int len = strlen(data);
    const int txBytes = uart_write_bytes(UART_NUM_1, data, len);
    ESP_LOGI(logName, "Wrote %d bytes", txBytes);
    return txBytes;
}

static void tx_task(void *arg)
{
    static const char *TX_TASK_TAG = "TX_TASK";
    esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO);
    while (1) {
        sendData(TX_TASK_TAG, "Hello world");
        vTaskDelay(2000 / portTICK_PERIOD_MS);
    }
}

static void rx_task(void *arg)
{
    static const char *RX_TASK_TAG = "RX_TASK";
    esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO);
    uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE+1);
    while (1) {
        const int rxBytes = uart_read_bytes(UART_NUM_1, data, RX_BUF_SIZE, 1000 / portTICK_RATE_MS);
        if (rxBytes > 0) {
            data[rxBytes] = 0;
            ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
            ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
        }
    }
    free(data);
}

void app_main(void)
{
    init();
    xTaskCreate(rx_task, "uart_rx_task", 1024*2, NULL, configMAX_PRIORITIES, NULL);
    xTaskCreate(tx_task, "uart_tx_task", 1024*2, NULL, configMAX_PRIORITIES-1, NULL);
}

测试方式:

  • 例程默认使用 UART1 来进行测试,TXD 为 GPIO4 ;RXD 为 GPIO5 。
  • 测试时,为了方便查看测试结果,可将 TXD(GPIO4) 与 RXD(GPIO5) 连接。

测试结果如下:

I (0) TX_TASK: Wrote 11 bytes
I (2324) RX_TASK: Read 11 bytes: 'Hello world'
I (2324) RX_TASK: 0x3ffb4da0   48 65 6c 6c 6f 20 77 6f  72 6c 64                 |Hello world|

在这里插入图片描述

  • 也可将 ESP32 的 TXD(GPIO4)和 RXD(GPIO5)分别与串口调试工具的 RXD 和 TXD 连接,通过 PC 端的串口调试助手向 ESP32 发送数据。

测试结果如下:

在这里插入图片描述

在这里插入图片描述


3 uart echo rs485 例程测试:

此例程的实现与 uart echo 基本一致。主要是通过 RS 485 发送数据给 ESP32 ,ESP32 再讲接收到的数据回传给 RS485

/* Uart Events Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "nvs_flash.h"
#include "driver/uart.h"
#include "freertos/queue.h"
#include "esp_log.h"
#include "sdkconfig.h"

/**
 * This is a example which echos any data it receives on UART back to the sender using RS485 interface in half duplex mode.
*/
#define TAG "RS485_ECHO_APP"

// Note: Some pins on target chip cannot be assigned for UART communication.
// Please refer to documentation for selected board and target to configure pins using Kconfig.
#define ECHO_TEST_TXD   (CONFIG_ECHO_UART_TXD)
#define ECHO_TEST_RXD   (CONFIG_ECHO_UART_RXD)

// RTS for RS485 Half-Duplex Mode manages DE/~RE
#define ECHO_TEST_RTS   (CONFIG_ECHO_UART_RTS)

// CTS is not used in RS485 Half-Duplex Mode
#define ECHO_TEST_CTS   (UART_PIN_NO_CHANGE)

#define BUF_SIZE        (127)                      //Buffer Size 默认是 127 当超过 127 时 ,会分两包进行接收(读)和发送(写)。
#define BAUD_RATE       (CONFIG_ECHO_UART_BAUD_RATE)

// Read packet timeout
#define PACKET_READ_TICS        (100 / portTICK_RATE_MS)
#define ECHO_TASK_STACK_SIZE    (2048)
#define ECHO_TASK_PRIO          (10)
#define ECHO_UART_PORT          (CONFIG_ECHO_UART_PORT_NUM)

// Timeout threshold for UART = number of symbols (~10 tics) with unchanged state on receive pin
#define ECHO_READ_TOUT          (3) // 3.5T * 8 = 28 ticks, TOUT=3 -> ~24..33 ticks

static void echo_send(const int port, const char* str, uint8_t length)
{
    if (uart_write_bytes(port, str, length) != length) {
        ESP_LOGE(TAG, "Send data critical failure.");
        // add your code to handle sending failure here
        abort();
    }
}

// An example of echo test with hardware flow control on UART
static void echo_task(void *arg)
{
    const int uart_num = ECHO_UART_PORT;
    uart_config_t uart_config = {
        .baud_rate = BAUD_RATE,
        .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 = 122,
        .source_clk = UART_SCLK_APB,
    };

    // Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);

    ESP_LOGI(TAG, "Start RS485 application test and configure UART.");

    // Install UART driver (we don't need an event queue here)
    // In this example we don't even use a buffer for sending data.
    ESP_ERROR_CHECK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0));

    // Configure UART parameters
    ESP_ERROR_CHECK(uart_param_config(uart_num, &uart_config));

    ESP_LOGI(TAG, "UART set pins, mode and install driver.");

    // Set UART pins as per KConfig settings
    ESP_ERROR_CHECK(uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));

    // Set RS485 half duplex mode
    ESP_ERROR_CHECK(uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX));

    // Set read timeout of UART TOUT feature
    ESP_ERROR_CHECK(uart_set_rx_timeout(uart_num, ECHO_READ_TOUT));

    // Allocate buffers for UART
    uint8_t* data = (uint8_t*) malloc(BUF_SIZE);

    ESP_LOGI(TAG, "UART start recieve loop.\r\n");
    echo_send(uart_num, "Start RS485 UART test.\r\n", 24);

    while(1) {
        //Read data from UART
        int len = uart_read_bytes(uart_num, data, BUF_SIZE, PACKET_READ_TICS);

        //Write data back to UART
        if (len > 0) {
            echo_send(uart_num, "\r\n", 2);
            char prefix[] = "RS485 Received: [";
            echo_send(uart_num, prefix, (sizeof(prefix) - 1));
            ESP_LOGI(TAG, "Received %u bytes:", len);
            printf("[ ");
            for (int i = 0; i < len; i++) {
                printf("0x%.2X ", (uint8_t)data[i]);
                echo_send(uart_num, (const char*)&data[i], 1);
                // Add a Newline character if you get a return charater from paste (Paste tests multibyte receipt/buffer)
                if (data[i] == '\r') {
                    echo_send(uart_num, "\n", 1);
                }
            }
            printf("] \n");
            echo_send(uart_num, "]\r\n", 3);
        } else {
            // Echo a "." to show we are alive while we wait for input
            echo_send(uart_num, ".", 1);
            ESP_ERROR_CHECK(uart_wait_tx_done(uart_num, 10));
        }
    }
    vTaskDelete(NULL);
}

void app_main(void)
{
    //A uart read/write example without event queue;
    xTaskCreate(echo_task, "uart_echo_task", ECHO_TASK_STACK_SIZE, NULL, ECHO_TASK_PRIO, NULL);
}

硬件准备:

  • 1 个 RS485 转 USB 适配器;
  • 1 个 RS485 转 UART 适配器;
  • 1 个 ESP32 开发板

硬件连接:

  • 将 RS485 转 USB 适配器连接到 PC 电脑;
  • 将 RS485 转 USB 适配器的 D+、D- 、输出和 GND 线分别连接到 RS485 转 UART 适配器的 D+、D- 输出和 GND 线。
  • 将 RS485 转 UART 的 TXD 、RXD、GND、VDD 分别与 ESP32 的 RXD(GPIO22)、TXD(GPIO23)、GND、VDD 线连接。

如下:
在这里插入图片描述

测试结果:

  • 通过 PC 端串口调试助手发送数据:
    在这里插入图片描述

  • ESP32 接收数据:
    在这里插入图片描述


4 uart events 例程解读

此例程是通过 ESP32 的 UART0 检测接收到的不同的指令来触发对应的事件,与 AT 应用类似。

/* UART Events Example

   This example code is in the Public Domain (or CC0 licensed, at your option.)

   Unless required by applicable law or agreed to in writing, this
   software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
   CONDITIONS OF ANY KIND, either express or implied.
*/
#include <stdio.h>
#include <string.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "freertos/queue.h"
#include "driver/uart.h"
#include "esp_log.h"

static const char *TAG = "uart_events";

/**
 * This example shows how to use the UART driver to handle special UART events.
 *
 * It also reads data from UART0 directly, and echoes it to console.
 *
 * - Port: UART0
 * - Receive (Rx) buffer: on
 * - Transmit (Tx) buffer: off
 * - Flow control: off
 * - Event queue: on
 * - Pin assignment: TxD (default), RxD (default)
 */

#define EX_UART_NUM UART_NUM_0
#define PATTERN_CHR_NUM    (3)         /*!< Set the number of consecutive and identical characters received by receiver which defines a UART pattern*/

#define BUF_SIZE (1024)
#define RD_BUF_SIZE (BUF_SIZE)
static QueueHandle_t uart0_queue;

static void uart_event_task(void *pvParameters)
{
    uart_event_t event;
    size_t buffered_size;
    uint8_t* dtmp = (uint8_t*) malloc(RD_BUF_SIZE);
    for(;;) {
        //Waiting for UART event.
        if(xQueueReceive(uart0_queue, (void * )&event, (portTickType)portMAX_DELAY)) {
            bzero(dtmp, RD_BUF_SIZE);
            ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
            switch(event.type) {
                //Event of UART receving data
                /*We'd better handler data event fast, there would be much more data events than
                other types of events. If we take too much time on data event, the queue might
                be full.*/
                case UART_DATA:                                              //普通数据
                    ESP_LOGI(TAG, "[UART DATA]: %d", event.size);
                    uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
                    ESP_LOGI(TAG, "[DATA EVT]:");
                    uart_write_bytes(EX_UART_NUM, (const char*) dtmp, event.size);
                    break;
                //Event of HW FIFO overflow detected
                case UART_FIFO_OVF:        //没有及时取走 Buffer 里的数据
                    ESP_LOGI(TAG, "hw fifo overflow");
                    // If fifo overflow happened, you should consider adding flow control for your application.
                    // The ISR has already reset the rx FIFO,
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                //Event of UART ring buffer full
                case UART_BUFFER_FULL:   //超过 Buffer Size 的数据
                    ESP_LOGI(TAG, "ring buffer full");
                    // If buffer full happened, you should consider encreasing your buffer size
                    // As an example, we directly flush the rx buffer here in order to read more data.
                    uart_flush_input(EX_UART_NUM);
                    xQueueReset(uart0_queue);
                    break;
                //Event of UART RX break detected
                case UART_BREAK:      
                    ESP_LOGI(TAG, "uart rx break");
                    break;
                //Event of UART parity check error
                case UART_PARITY_ERR:    //奇偶校验位错误  
                    ESP_LOGI(TAG, "uart parity error");
                    break;
                //Event of UART frame error
                case UART_FRAME_ERR:   //帧错误
                    ESP_LOGI(TAG, "uart frame error");
                    break;
                //UART_PATTERN_DET
                case UART_PATTERN_DET:            //范例
                    uart_get_buffered_data_len(EX_UART_NUM, &buffered_size);
                    int pos = uart_pattern_pop_pos(EX_UART_NUM);
                    ESP_LOGI(TAG, "[UART PATTERN DETECTED] pos: %d, buffered size: %d", pos, buffered_size);
                    if (pos == -1) {
                        // There used to be a UART_PATTERN_DET event, but the pattern position queue is full so that it can not
                        // record the position. We should set a larger queue size.
                        // As an example, we directly flush the rx buffer here.
                        uart_flush_input(EX_UART_NUM);
                    } else {
                        uart_read_bytes(EX_UART_NUM, dtmp, pos, 100 / portTICK_PERIOD_MS);
                        uint8_t pat[PATTERN_CHR_NUM + 1];
                        memset(pat, 0, sizeof(pat));
                        uart_read_bytes(EX_UART_NUM, pat, PATTERN_CHR_NUM, 100 / portTICK_PERIOD_MS);
                        ESP_LOGI(TAG, "read data: %s", dtmp);
                        ESP_LOGI(TAG, "read pat : %s", pat);
                    }
                    break;
                //Others
                default:
                    ESP_LOGI(TAG, "uart event type: %d", event.type);
                    break;
            }
        }
    }
    free(dtmp);
    dtmp = NULL;
    vTaskDelete(NULL);
}

void app_main(void)
{
    esp_log_level_set(TAG, ESP_LOG_INFO);

    /* Configure parameters of an UART driver,
     * communication pins and install the driver */
    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_DISABLE,
        .source_clk = UART_SCLK_APB,
    };
    //Install UART driver, and get the queue.
    uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
    uart_param_config(EX_UART_NUM, &uart_config);

    //Set UART log level
    esp_log_level_set(TAG, ESP_LOG_INFO);
    //Set UART pins (using UART0 default pins ie no changes.)
    uart_set_pin(EX_UART_NUM, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);

    //Set uart pattern detect function.
    uart_enable_pattern_det_baud_intr(EX_UART_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0);
    //Reset the pattern queue length to record at most 20 pattern positions.
    uart_pattern_queue_reset(EX_UART_NUM, 20);     //20 是队列长度

    //Create a task to handler UART event from ISR
    xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL);      //12 是任务优先级
}

测试方法:

  • 下载此例程,在 PC 端使用串口调试助手,通过 UART0 发送不同事件的指令,将会触发对应指令的返回信息。

硬件接线:

  • 使用串口调试工具的 TXD、RXD 分别与 ESP32 UART0 的 RXD、TXD 连接。

测试结果:
在这里插入图片描述
在这里插入图片描述


5 uart select 例程解读

此例程用于演示 select() 在 UART 接口上使用同步 I/O 多路复用。。UART0 可作为 Monitor 打印日志,又可读写数据。
请注意,通过使用 uart_read_bytes() 可以获得相同的结果,但使用 select() 将允许 ESP32 与其他虚拟文件系统 (VFS) 驱动程序一起使用,例如 LWIP 套接字。

测试方法:

  • 使用一个 ESP32 开发板下载例程
  • 通过 Monitor 查看日志
  • 任意键入字符,可在 Monitor 端查看打印

测试结果:

I (15321) uart_select_example: Timeout has been reached and nothing has been received
I (20321) uart_select_example: Timeout has been reached and nothing has been received
I (25321) uart_select_example: Timeout has been reached and nothing has been received
I (26811) uart_select_example: Received: a
I (26921) uart_select_example: Received: g
I (27571) uart_select_example: Received: d
I (27801) uart_select_example: Received: f
I (28101) uart_select_example: Received: a
I (28271) uart_select_example: Received: h
I (28461) uart_select_example: Received: d
I (33461) uart_select_example: Timeout has been reached and nothing has been received
I (38461) uart_select_example: Timeout has been reached and nothing has been received

  • 6
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值