接前一篇文章:ESP32-C3第二路串口(非调试)串口打通(3)
本文内容参考:
基于 esp-idf 的 UART 应用例程解读_uart asynchronous example with separate receive an-CSDN博客
特此致谢!
上一回对于FreeRTOS中的“创建和删除任务类”函数进行了讲解,并最终讲到了app_main主函数中通过xTaskCreate函数创建的任务函数echo_task。本回对于该函数进行详细解析。
3. 工程代码详解
(1)main\uart_echo_example_main.c
- echo_task函数
再次贴出echo_task函数源码:
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,.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_DEFAULT,};int intr_alloc_flags = 0;#if CONFIG_UART_ISR_IN_IRAMintr_alloc_flags = ESP_INTR_FLAG_IRAM;
#endifESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));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 datauint8_t *data = (uint8_t *) malloc(BUF_SIZE);while (1) {// Read data from the UARTint len = uart_read_bytes(ECHO_UART_PORT_NUM, data, (BUF_SIZE - 1), 20 / portTICK_PERIOD_MS);// Write data back to the UARTuart_write_bytes(ECHO_UART_PORT_NUM, (const char *) data, len);if (len) {data[len] = '\0';ESP_LOGI(TAG, "Recv str: %s", (char *) data);}}
}
一段一段来解析。
1)代码片段1
先来看第1段代码:
/* Configure parameters of an UART driver,* communication pins and install the driver */uart_config_t uart_config = {.baud_rate = ECHO_UART_BAUD_RATE,.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_DEFAULT,};
uart_config_t的定义在C:\Espressif\frameworks\esp-idf-v5.2.1\components\driver\uart\include\driver\uart.h中,代码如下:
/*** @brief UART configuration parameters for uart_param_config function*/
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};
} uart_config_t;
其实不外乎就是串口那点事儿:波特率是多少、几位数据位、几位停止位、是否带奇偶校验、是否有流控等。经常使用串口的人应该对于这些设置项很熟悉了。
这里:
波特率为ECHO_UART_BAUD_RATE,其定义在同文件(main\uart_echo_example_main.c)中,如下:
#define ECHO_UART_BAUD_RATE (CONFIG_EXAMPLE_UART_BAUD_RATE)
而CONFIG_EXAMPLE_UART_BAUD_RATE的定义在build\config\sdkconfig.h中,(当前配置)如下:
#define CONFIG_EXAMPLE_UART_BAUD_RATE 115200
即波特率为115200。
数据位为UART_DATA_8_BITS,即8位数据位。UART_DATA_8_BITS的定义在C:\Espressif\frameworks\esp-idf-v5.2.1\components\hal\include\hal\uart_types.h中,如下:
/*** @brief UART word length constants*/
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;
停止位为UART_STOP_BITS_1,即1位停止位。UART_STOP_BITS_1的定义在C:\Espressif\frameworks\esp-idf-v5.2.1\components\hal\include\hal\uart_types.h中,如下:
/*** @brief UART stop bits number*/
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;
奇偶校验方式为UART_PARITY_DISABLE,即不使能奇偶校验。UART_PARITY_DISABLE的定义在C:\Espressif\frameworks\esp-idf-v5.2.1\components\hal\include\hal\uart_types.h中,如下:
/*** @brief UART parity constants*/
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_HW_FLOWCTRL_DISABLE,即不使用流控。UART_HW_FLOWCTRL_DISABLE的定义在C:\Espressif\frameworks\esp-idf-v5.2.1\components\hal\include\hal\uart_types.h中,如下:
/*** @brief UART hardware flow control modes*/
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;
时钟源为UART_SCLK_DEFAULT。UART_SCLK_DEFAULT的定义在C:\Espressif\frameworks\esp-idf-v5.2.1\components\soc\esp32c3\include\soc\clk_tree_defs.h中,
/*** @brief Type of UART clock source, reserved for the legacy UART driver*/
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;
即UART(串口)的时钟源来自于APB总线,这也是默认的设置。
总体上,进行以上设置后,就相当于在串口调试助手中进行以下设置:
2)代码片段2
接下来是与intr_alloc_flags相关的代码片段:
int intr_alloc_flags = 0;#if CONFIG_UART_ISR_IN_IRAMintr_alloc_flags = ESP_INTR_FLAG_IRAM;
#endif
intr_alloc_flagsUART中断优先级设置标志。对应于menuconfig中的“Place UART ISR function into IRAM”配置选项,0表示未使能,1表示使能。
如果不选择此选项,UART中断将长时间禁用并且在进行SPI FLASH操作时可能会导致数据丢失。
3)代码片段3
接下来是与UART配置和设置相关的代码片段:
ESP_ERROR_CHECK(uart_driver_install(ECHO_UART_PORT_NUM, BUF_SIZE * 2, 0, 0, NULL, intr_alloc_flags));ESP_ERROR_CHECK(uart_param_config(ECHO_UART_PORT_NUM, &uart_config));ESP_ERROR_CHECK(uart_set_pin(ECHO_UART_PORT_NUM, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS));
这一段代码涉及到的内容较多,因此对于这一段代码的详细解析,放在下一回中。