在esp32芯片中接收串口数据有多种方式,默认采用串口轮询读取方式效率低下,
通常像51或stm32基于中断的方式对于esp32这种与rtos深度融合的系统来说会降低系统的
实时性,所以可以采用freertos的事件上报的消息队列方式会提高系统的性能。
使用串口1监听数据到来事件再立即读取缓冲区。
#ifndef __BOARD_UART1_H__
#define __BOARD_UART1_H__
#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"
#include "freertos/queue.h"
static const char *UART1_TAG = "uart1_events";
#define RX_BUF_SIZE (1024)
#define UART_NUM_1 (1)
#define TXD_PIN (GPIO_NUM_17)
#define RXD_PIN (GPIO_NUM_18)
#define EX_UART_NUM UART_NUM_1
#define PATTERN_CHR_NUM (3)
#define RD_BUF_SIZE (RX_BUF_SIZE)
static QueueHandle_t uart1_queue;
#define UART1_QUEUE_SIZE (30)
/**
* 枚举uart_event_type_t 环形缓冲区中使用的UART事件类型。值:
UART_DATA UART数据事件
UART_BREAK UART中断事件
UART_BUFFER_FULL UART RX缓冲区已满事件
UART_FIFO_OVF UART FIFO溢出事件
UART_FRAME_ERR UART RX帧错误事件
UART_PARITY_ERR UART RX奇偶校验事件
UART_DATA_BREAK UART TX数据和中断事件
UART_PATTERN_DET 检测到UART模式
UART_EVENT_MAX UART事件最大索引
*/
static inline void uart1_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_DEFAULT,
};
uart_driver_install(EX_UART_NUM, RX_BUF_SIZE * 2, 0,UART1_QUEUE_SIZE,&uart1_queue, 0);
uart_param_config(EX_UART_NUM, &uart_config);
uart_set_pin(EX_UART_NUM, TXD_PIN, RXD_PIN, 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, UART1_QUEUE_SIZE);
}
static inline void uart1_send(unsigned char*data,int len)
{
int offset = 0;
int txbytes = 0;
while(len > 0)
{
txbytes = uart_write_bytes(EX_UART_NUM, data + offset, len);
offset += txbytes;
len -= txbytes;
}
}
#endif
/
事件队列任务
static void uart1_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(uart1_queue, (void * )&event, (TickType_t)portMAX_DELAY)) {
//bzero(dtmp, RD_BUF_SIZE);
//ESP_LOGI(UART1_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(UART1_TAG, "[UART DATA]: %d", event.size);
uart_read_bytes(EX_UART_NUM, dtmp, event.size, portMAX_DELAY);
//ESP_LOGI(UART1_TAG, "[DATA EVT]:");
//uart_write_bytes(EX_UART_NUM, (const char*) dtmp, event.size);
print0x(dtmp,event.size);
break;
//Event of HW FIFO overflow detected
case UART_FIFO_OVF:
ESP_LOGI(UART1_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(uart1_queue);
break;
//Event of UART ring buffer full
case UART_BUFFER_FULL:
ESP_LOGI(UART1_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(uart1_queue);
break;
//Event of UART RX break detected
case UART_BREAK:
ESP_LOGI(UART1_TAG, "uart rx break");
break;
//Event of UART parity check error
case UART_PARITY_ERR:
ESP_LOGI(UART1_TAG, "uart parity error");
break;
//Event of UART frame error
case UART_FRAME_ERR:
ESP_LOGI(UART1_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(UART1_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(UART1_TAG, "read data: %s", dtmp);
ESP_LOGI(UART1_TAG, "read pat : %s", pat);
}
break;
//Others
default:
ESP_LOGI(UART1_TAG, "uart event type: %d", event.type);
break;
}
}
}
free(dtmp);
dtmp = NULL;
vTaskDelete(NULL);
}
xTaskCreate(uart1_event_task, "uart1_event_task", 4096, NULL, UART1_EVENT_TASK_PRIORITY, NULL);