直接使用 IDFV4.33的SDK直接在Arduino中开发,以下代码测试成功。通过FreeRTOS创建多任务,RX和TX分别在两个任务中互不影响。同时测试了ESP_LOG相关函数和设置 代码如下。
#include <stdint.h>
#include <string.h>
#include <stdbool.h>
#include <inttypes.h>
#include <functional>
//#include "HardwareSerial.h"
#include "soc/rtc_wdt.h"
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_system.h"
#include "esp_adc_cal.h"
#include "esp_task_wdt.h" //设置看门狗用
#include "esp_err.h"
#include "esp_system.h"
#include "esp_log.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#define BTN_STOP_ALARM 0
#define LED_D4 12
#define LED_D5 13
#define TXD1 0
#define RXD1 1
#define ToggleOutput(out) do { digitalWrite(out, !digitalRead(out)); } while(0)
#define ToggleOutBlink(out,interval) do {static uint32_t estp=0;if( (millis()-estp)>=interval ){ estp=millis();digitalWrite(out, !digitalRead(out));} } while(0)
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE//要在文件或组件范围内覆盖默认的详细级别,请定义LOG_LOCAL_LEVEL宏。
//串口环形缓冲区大小, 可修改
static const int RX_BUF_SIZE = 1024;
//uart tx和rx, 可以修改
#define TXD_PIN (GPIO_NUM_0)
#define RXD_PIN (GPIO_NUM_1)
//vTaskDelay(pdMS_TO_TICKS(100));//等待系统初始化
static const char *RX_TASK_TAG = "RX_TASK";
static const char *TX_TASK_TAG = "TX_TASK";
//串口初始化
void uart_init(void) {
//uart配置参数
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,
};
//安装uart驱动, 配置UART RX 环形缓冲区大小, 不设置TX 环形缓冲区, 不设置UART 事件队列, 不设置中断
uart_driver_install(UART_NUM_1, RX_BUF_SIZE * 2, 0, 0, NULL, 0);
//配置uart参数
uart_param_config(UART_NUM_1, &uart_config);
//配置uart引脚
uart_set_pin(UART_NUM_1, TXD_PIN, RXD_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
}
//uart 发送线程 测试OK
static void tx_task(void *arg)
{
while (1) {
//往UART_NUM_1发送"Hello world"
uart_write_bytes(UART_NUM_1, "Hello world!\n", strlen("Hello world!\n"));
ESP_LOGI(TX_TASK_TAG, "Send %d bytes: '%s'", strlen("Hello world!\n"), "");
//延时2000ms
vTaskDelay(2000 / portTICK_PERIOD_MS);
//ToggleOutput(LED_D4);
}
}
//uart 接收线程
/*
如果不再需要Rx FIFO缓冲区中的数据,则可以通过调用清除缓冲区uart_flush()。
在读取数据之前,您可以调用来检查Rx FIFO缓冲区中可用的字节数uart_get_buffered_data_len(),然后再读取相应的内容,这样就不会造成不必要的阻塞。下面给出了使用这些功能的示例。
// Read data from UART.
const int uart_num = UART_NUM_2;
uint8_t data[128];
int length = 0;
ESP_ERROR_CHECK(uart_get_buffered_data_len(uart_num, (size_t*)&length));
length = uart_read_bytes(uart_num, data, length, 100);
*/
static void rx_task(void *arg){
//动态分配内存data
uint8_t* data = (uint8_t*) malloc(RX_BUF_SIZE+1);
int Alength = 0;
ESP_LOGE(RX_TASK_TAG, "RX Loop Start..........'");
while (1) {//任务线程创建后就在循环内等待字节接收
//从UART_NUM_1接收数据到data, 最大接收RX_BUF_SIZE个数据, 超时时长1000ms
ESP_ERROR_CHECK(uart_get_buffered_data_len(UART_NUM_1, (size_t*)&Alength));
ESP_LOGI(RX_TASK_TAG, "uart_get_buffered_data_len %d bytes\n", Alength);
if (Alength>0) {
ToggleOutput(LED_D5);
const int rxBytes = uart_read_bytes(UART_NUM_1, data, RX_BUF_SIZE, 100 / portTICK_RATE_MS);
if (rxBytes > 0) {
//字符串结束符0
data[rxBytes] = 0;
//字符串打印接收数据
ESP_LOGI(RX_TASK_TAG, "Read %d bytes: '%s'", rxBytes, data);
//16进制打印接收数据
ESP_LOG_BUFFER_HEXDUMP(RX_TASK_TAG, data, rxBytes, ESP_LOG_INFO);
}
}else vTaskDelay(0);// 1/portTICK_RATE_MS 去掉将阻塞loop!loop内的函数无法运行(ilde 没有空余时间了!)!但是其他Task线程会照常运行!但是实时性增强了!
}
//动态释放内存data
free(data);
ESP_LOGE(RX_TASK_TAG, "RX Loop Exit..........'");
}
void setup() {
pinMode(LED_D4, OUTPUT);
pinMode(LED_D5, OUTPUT);
esp_log_level_set(RX_TASK_TAG, ESP_LOG_INFO); // enable INFO logs from DHCP client
esp_log_level_set(TX_TASK_TAG, ESP_LOG_INFO); // enable INFO logs from DHCP client
//串口初始化
uart_init();
//创建并启动串口接收线程rx_task
xTaskCreate(rx_task, "uart_rx_task", 1024*2, NULL, configMAX_PRIORITIES, NULL);
//创建并启动串口发送线程tx_task
xTaskCreate(tx_task, "uart_tx_task", 1024*2, NULL, configMAX_PRIORITIES-1, NULL);
}
void loop() {
ToggleOutBlink(LED_D4,1000);
}