UART的使用
Uart串口是最常用的通信方式,一般用于单片机与单片机之间的通信,或者单片机与电脑之间的通信。ESP32-C3的Uart接口有2个,分别是Uart0和Uart1,其中Uart0的TX和RX引脚默认是固定的,而Uart1的TX和RX引脚是可配置的。
一.简单使用方法
1.UART的初始化
- 初始化Uart0的配置参数
- uart驱动的安装
- uart引脚的指定
void usart_init(void)
{
const uart_config_t uart_config = {
.baud_rate = 9600,
.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,
};
// 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);
}2.UART的发送数据
使用函数: uart_write_bytes(UART_NUM_1, (const char *)data, len);
3.UART的接收数据
使用函数: uart_read_bytes(UART_NUM_1, (uint8_t *)data, len, 1000 / portTICK_RATE_MS);说明
- 由于uart_read_bytes函数是阻塞的,所以如果接收的数据量比较大,可能会导致程序卡死。
- 硬件串口接收到数据后会将数据保存在接收缓冲区中,只有当执行了uart_read_bytes函数后才会从接收缓冲区中读取数据。
- 接收缓冲区的大小由uart_driver_install函数的第二个参数决定。
- 读取数据后,接收缓冲区中的数据会被清空,所以如果需要多次读取数据,需要再次调用uart_read_bytes函数。
二.UART的实际使用方法
1.发送后等待接收数据
void usart_send_recv_data(uint8_t len, uint8_t *data, uint8_t *fb_data, RX_Feedback feedback)
{
uart_write_bytes(UART_NUM_1, data, len);
vTaskDelay(100 / portTICK_PERIOD_MS);
uint8_t cnt = 2; // 等待2秒
while (cnt--)
{
const int rxBytes = uart_read_bytes(UART_NUM_1, fb_data, RX_BUF_SIZE, 1000 / portTICK_PERIOD_MS);
if (rxBytes > 0)
{
fb_data[rxBytes] = 0;
feedback(0, rxBytes, fb_data); // 函数返回时
break;
}
}
}2.只发送数据
这个比较简单,直接调用uart_write_bytes函数即可。
void usart_send_data(uint8_t len, uint8_t *data)
{
uart_write_bytes(UART_NUM_1, data, len);
}2.只接收数据.
void usart_recv_data(uint8_t *data, RX_Feedback feedback, uint8_t delay)
{
uint8_t cnt = delay < 2 ? 2 : delay; // 等待2秒
while (cnt--)
{
const int rxBytes = uart_read_bytes(UART_NUM_1, data, RX_BUF_SIZE, 1000 / portTICK_PERIOD_MS);
if (rxBytes > 0)
{
data[rxBytes] = 0;
feedback(1, rxBytes, data); // 函数返回时
break;
}
}
}三.使用事件通知的方式接收数据
示例程序: ESP_IDF 框架的Example项目uart_events
1.安装串口驱动的改动
如果要使用事件通知的方式来进行接收数据,需要使用uart_driver_install函数的参数中,指定队列queue及队列queue的大小. 在初始串口时,需要修改并添加以下代码:
// 安装串口驱动
uart_driver_install(EX_UART_NUM, BUF_SIZE * 2, BUF_SIZE * 2, 20, &uart0_queue, 0);
// 清空队列,并设置队列大小为20
uart_pattern_queue_reset(EX_UART_NUM, 20);说明
esp_err_t 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 驱动程序并将 UART 设置为默认配置。 UART 中断服务例程处理程序将连接到该函数运行的同一 CPU 核心。
参数:uart_num – UART 端口号,最大端口号为 (UART_NUM_MAX -1)。rx_buffer_size – UART RX 环形缓冲区大小。如果设置为零,驱动程序将不会使用 RX 缓冲区,RX 函数将阻塞,直到所有数据都已接收。tx_buffer_size – UART TX 环形缓冲区大小。如果设置为 0,驱动程序将不使用 TX 缓冲区,TX 功能将阻塞任务,直到所有数据都已发送出去。queue_size – UART 事件队列大小/深度。uart_queue – UART 事件队列句柄(输出参数)。成功时,在此处写入新的队列句柄以提供访问 UART 事件。如果设置为 NULL,驱动程序将不使用事件队列。intr_alloc_flags – 中断分配使用的标志。一个或多个(按位或)ESP_INTR_FLAG_*值。有关更多信息,请参阅 esp_intr_alloc.h。在此处不要设置 ESP_INTR_FLAG_IRAM(驱动程序的 ISR 处理程序不在 IRAM 中)。
返回:
ESP_OK 成功 - ESP_FAIL 参数错误.
备注:
Rx_buffer_size 应大于 UART_HW_FIFO_LEN(uart_num)。Tx_buffer_size 应为零或大于 UART_HW_FIFO_LEN(uart_num)。
通过 uart_driver_install 函数安装串口驱动后,会自动创建一个队列,用于接收串口事件。uart_queue 参数的作用是:UART事件队列句柄(输出参数):这个参数是一个指向UART事件队列句柄的指针,函数执行后,新的队列句柄会被写入这个指针所指向的位置。这个句柄用于访问和管理UART事件。成功时,一个新的队列句柄会被写入这里以提供对UART事件的访问:当函数执行成功时,它会创建一个新的队列句柄,并将这个句柄的值写入到这个参数所指向的位置。这样,调用者就可以使用这个句柄来访问和处理UART事件。如果设置为NULL,驱动程序将不会使用事件队列:如果调用者在调用函数时将这个参数设置为NULL,那么驱动程序将不会使用事件队列。这意味着UART事件不会被放入队列中,调用者需要通过其他方式来处理这些事件。
2. 串口事件处理函数
串口的事件处理一般是设计一个任务来处理,当串口接收到数据时,会触发一个事件,这个事件会被放入队列中,然后任务会从队列中取出事件,并进行处理。
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, (TickType_t)portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
switch(event.type) {
// UART 接收数据事件
// 我们最好快速处理数据事件,因为数据事件会比其他类型的事件多得多。如果我们花费太多时间在数据事件上,队列可能会满。
// 如果我们花费太多时间在数据事件上,队列可能会满。所以,我们需要尽快处理数据事件,并将数据写入到缓冲区中,然后立即返回。
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;
//检测到硬件 FIFO 溢出事件
case UART_FIFO_OVF:
ESP_LOGI(TAG, "hw fifo overflow");
// 如果发生 FIFO 溢出,您应该考虑为您的应用程序添加流量控制。
// 中断服务例程(ISR)已经重置了接收 FIFO。
// 例如,我们在这里直接清除接收缓冲区,以便读取更多数据。
uart_flush_input(EX_UART_NUM);
xQueueReset(uart0_queue);
break;
//UART 环形缓冲区已满事件
case UART_BUFFER_FULL:
ESP_LOGI(TAG, "ring buffer full");
// If buffer full happened, you should consider increasing 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;
//检测到 UART RX 中断事件
case UART_BREAK:
ESP_LOGI(TAG, "uart rx break");
break;
//UART 奇偶校验错误的通风
case UART_PARITY_ERR:
ESP_LOGI(TAG, "uart parity error");
break;
//EUART 帧错误事件
case UART_FRAME_ERR:
ESP_LOGI(TAG, "uart frame error");
break;
//串口模式检测
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) {
// 之前有一个 UART_PATTERN_DET 事件,但由于模式位置队列已满,无法记录位置。我们应该设置更大的队列大小。
// 例如,我们在这里直接刷新接收缓冲区。
// 作为例子,我们在这里直接清空接收缓冲区。
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);
}四. 串口传输的模式匹配方式
串口传输的模式匹配方式,就是在串口传输的过程中,通过模式匹配的方式,来识别出数据包的起始和结束位置,从而实现数据的解析。在一些应用场景中,需要接收特殊格式的数据包,这些数据包有着固定的格式,在这种情况下,可以使用模式匹配的方式,来识别出数据包的起始和结束位置,从而实现数据的解析。
1. 串口模式匹配的设设置
串口模式匹配的设置,一般需要通过uart_pattern_config()函数来设置。这个函数的参数包括串口编号、模式匹配的字符串、模式匹配的字符串的长度、模式匹配的字符串的起始位置、模式匹配的字符串的结束位置。一般这个设置在串口初始化的时候进行。例如,下面的代码就是设置串口模式匹配的例子:
//Set uart pattern detect function.
uart_enable_pattern_det_baud_intr(EX_UART_NUM, '+', PATTERN_CHR_NUM, 9, 0, 0);这样设置后,当收到串口数据时,就会自动进行模式匹配,如果匹配成功,就会触发模式匹配中断,从而实现数据的解析。 参数分析:
- EX_UART_NUM: UART端口号,这里是UART_NUM_1
- '+': 模式字符,即要匹配的字符
- PATTERN_CHR_NUM: 模式字符的数量,假如:PATTERN_CHR_NUM设置为3
- 9: 这应该是超时或其他配置参数
- 0, 0: 其他配置参数 根据这些参数,特别是'+'和PATTERN_CHR_NUM为3,这个函数设置了UART检测连续3个+字符的模式。在代码中,当检测到模式时,会触发UART_PATTERN_DET事件,然后读取
模式前的数据和模式本身。所以,一个可以匹配的字符串例子应该是包含连续3个加号的字符串,比如"hello+++"或"+++world"。
2. 串口模式匹配的处理方式
当匹配发生后,会产生一个模式匹配中断,中断处理函数如下:
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, (TickType_t)portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
switch(event.type) {
//................................
//UART_模式匹配中断
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;
//................................
}
}
}
free(dtmp);
dtmp = NULL;
vTaskDelete(NULL);
}首先,当UART接收到"hello+++world"时,由于其中包含了连续的3个加号"+++",会触发UART_PATTERN_DET事件。在uart_event_task函数中,会处理这个事件
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) {
// 处理错误情况
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;在这段代码中:
- pos = 5 表示模式"+++"在接收缓冲区中的位置是5(从0开始计数,所以是第6个字符的位置)
- buffered_size = 8 表示接收缓冲区中总共有8个字符("hello+++")
- 代码读取了模式前的数据("hello")和模式本身("+++")
但是,这段代码并没有读取模式后的数据("world")。这意味着"world"仍然留在UART接收缓冲区中。
然后,当下一个UART_DATA事件发生时(因为缓冲区中还有数据),会执行以下代码:
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;这段代码会读取剩余的数据("world"),然后通过uart_write_bytes函数将其发送回UART,这就是为什么用户在串口中收到了"world"。
所以,"world"是通过uart_write_bytes(EX_UART_NUM, (const char*) dtmp, event.size);这行代码发送的,这是一个回显功能,将接收到的数据发送回去。
总结:
当你发送"hello+++world"字符串到ESP32时,代码的执行流程如下:
- 首先,UART接收到整个字符串"hello+++world"
- 由于设置了模式检测(连续3个+),当检测到"+++"时,触发了UART_PATTERN_DET事件
- 在UART_PATTERN_DET事件处理中:
- 获取模式位置:pos = 5("hello"的长度)
- 读取模式前的数据:"hello"
- 读取模式本身:"+++"
- 但是,这段代码没有读取模式后的数据"world"
- 由于"world"仍然留在UART接收缓冲区中,它会触发一个新的UART_DATA事件
五. 串口如何与RS485芯片配合传输数据
示例代码: ESP_IDF 框架的Example项目 UART_ECHO_RS485
VCC ---------------+ +--------------- VCC
| |
+-------x-------+ +-------x-------+
RXD <------| RO | | RO|-----> RXD
| B|---------------|B |
TXD ------>| DI MAX483 | \ / | MAX483 DI|<----- TXD
ESP32 BOARD | | RS-485 side | | SERIAL ADAPTER SIDE
RTS --+--->| DE | / \ | DE|---+
| | A|---------------|A | |
+----| /RE | | /RE|---+-- RTS
+-------x-------+ +-------x-------+
| |
--- ---在驱动rs485芯片时,需要使用RTS信号来控制芯片的发送和接收模式.当RTS信号为低电平时,芯片处于接收模式,当RTS信号为高电平时,芯片处于发送模式.这样就可以实现串口与rs485芯片的配合传输数据了.
1. 如何配置RTS信号
RTS引脚可以直接在esp-idf框架中配置即可. 只需要一行代码:
uart_set_pin(uart_num, ECHO_TEST_TXD, ECHO_TEST_RXD, ECHO_TEST_RTS, ECHO_TEST_CTS)其中参数: ECHO_TEST_RTS 就是RTS引脚.只需要在这里配置即可.此时RTS引脚就可以直接使用.不需要其它配置.
2. 需要配置RTS引脚为输出模式吗?
答: 不需要. 在ESP32中,RTS引脚默认是作为GPIO引脚使用的.当配置为UART引脚时,RTS引脚会自动配置为UART引脚.
3. 设置RS485为半双工模式?
uart_set_mode(uart_num, UART_MODE_RS485_HALF_DUPLEX);4. 设置串口的接收数据时的超时时间
uart_set_rx_timeout(uart_num, 100);在这个项目中,这行代码设置了 RS485 通信的接收超时时间为 10 个比特位的时间。这意味着如果在接收数据过程中,超过这个时间没有新的数据到达,UART 会认为当前帧已经接收完毕,并触发相应的中断或回调函数。
六. 使用UART0进行数据传输
由于ESP-IDF中串口0通常用作调试输出,因此我们只使用串口1进行数据传输.但是在一些应用中,我们需要2个串口,这时候就需要使用UART0进行数据传输了. 串口0的使用方法与串口1完全一样,只是我们需要将调试输出的方向从串口0中改到其它接口中.修改的方法是使用 idf.py menuconfig 配置调试输出的方向.Component config → ESP System Settings → Channel for console output
在这个选项可以选择其它的串口或是直接选择 none,这样就不会输出调试信息了.当使用了USB的JTAG进行调试时,就会有"USB JTAG/serial"选项. 也可以选择 选择"USB JTAG/serial"
除此之外,在配置串口的引脚时,串口0的引脚也可以指定其它引脚进行,但是芯片的原来的GPIO20和GPIO21引脚不能使用.因为这两个引脚是作为串口0的专用引脚.如果要使用这两个引脚的话,需要在串口初始化时,这样编写代码:
uart_set_pin(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);这里的 UART_PIN_NO_CHANGE 表示不修改引脚的配置. 这样串口的引脚就还是默认的gpio20和gpio21引脚了.
七. UART的示例代码
/* 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, (TickType_t)portMAX_DELAY)) {
bzero(dtmp, RD_BUF_SIZE);
ESP_LOGI(TAG, "uart[%d] event:", EX_UART_NUM);
switch(event.type) {
// UART 接收数据事件
// 我们最好快速处理数据事件,因为数据事件会比其他类型的事件多得多。如果我们花费太多时间在数据事件上,队列可能会满。
// 如果我们花费太多时间在数据事件上,队列可能会满。所以,我们需要尽快处理数据事件,并将数据写入到缓冲区中,然后立即返回。
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;
//检测到硬件 FIFO 溢出事件
case UART_FIFO_OVF:
ESP_LOGI(TAG, "hw fifo overflow");
// 如果发生 FIFO 溢出,您应该考虑为您的应用程序添加流量控制。
// 中断服务例程(ISR)已经重置了接收 FIFO。
// 例如,我们在这里直接清除接收缓冲区,以便读取更多数据。
uart_flush_input(EX_UART_NUM);
xQueueReset(uart0_queue);
break;
//UART 环形缓冲区已满事件
case UART_BUFFER_FULL:
ESP_LOGI(TAG, "ring buffer full");
// If buffer full happened, you should consider increasing 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;
//检测到 UART RX 中断事件
case UART_BREAK:
ESP_LOGI(TAG, "uart rx break");
break;
//UART 奇偶校验错误的通风
case UART_PARITY_ERR:
ESP_LOGI(TAG, "uart parity error");
break;
//EUART 帧错误事件
case UART_FRAME_ERR:
ESP_LOGI(TAG, "uart frame error");
break;
//串口模式检测
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) {
// 之前有一个 UART_PATTERN_DET 事件,但由于模式位置队列已满,无法记录位置。我们应该设置更大的队列大小。
// 例如,我们在这里直接刷新接收缓冲区。
// 作为例子,我们在这里直接清空接收缓冲区。
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_DEFAULT,
};
//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);
//Create a task to handler UART event from ISR
xTaskCreate(uart_event_task, "uart_event_task", 2048, NULL, 12, NULL);
}