接前一篇文章:ESP32-C3第二路串口(非调试)串口打通(1)
本文内容参考:
ESP32爬坑之旅②——初识FreeRTOS_esp32 xtaskcreate-CSDN博客
特此致谢!
上一回讲解了ESP32-C3系列芯片UART引脚复用的细节,本回开始详细讲解添加第二路串口功能的软硬件细节。
2. 新建项目工程
实际上,乐鑫提供的例程中已经有了添加第二路串口的代码。在VSCode中选择
选择“New Project Wizard”,新建工程,之后通过“Choose Template” -> “ESP-IDF”,来到以下界面:
选择其中(红色框中)的“uart_echo”:
详细阅读一下其说明:
根据以上描述,官方例程“uart_echo”中使用的是GPIO4和GPIO5。GPIO4用作UART1的TxD,GPIO5用作UART1的RxD。
创建工程后,整体工程如下图所示:
3. 工程代码详解
(1)main\uart_echo_example_main.c
/* UART Echo 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 "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "driver/uart.h"
#include "driver/gpio.h"
#include "sdkconfig.h"
#include "esp_log.h"
/**
* 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)
*/
#define ECHO_TEST_TXD (CONFIG_EXAMPLE_UART_TXD)
#define ECHO_TEST_RXD (CONFIG_EXAMPLE_UART_RXD)
#define ECHO_TEST_RTS (UART_PIN_NO_CHANGE)
#define ECHO_TEST_CTS (UART_PIN_NO_CHANGE)
#define ECHO_UART_PORT_NUM (CONFIG_EXAMPLE_UART_PORT_NUM)
#define ECHO_UART_BAUD_RATE (CONFIG_EXAMPLE_UART_BAUD_RATE)
#define ECHO_TASK_STACK_SIZE (CONFIG_EXAMPLE_TASK_STACK_SIZE)
static const char *TAG = "UART TEST";
#define BUF_SIZE (1024)
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_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));
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 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 - 1), 20 / portTICK_PERIOD_MS);
// Write data back to the UART
uart_write_bytes(ECHO_UART_PORT_NUM, (const char *) data, len);
if (len) {
data[len] = '\0';
ESP_LOGI(TAG, "Recv str: %s", (char *) data);
}
}
}
void app_main(void)
{
xTaskCreate(echo_task, "uart_echo_task", ECHO_TASK_STACK_SIZE, NULL, 10, NULL);
}
在笔者前述文章中已提到,
main目录是一个必须存在的特殊组件。一个工程有且仅有一个main目录,该目录包含了项目本身的源代码和用户程序的入口app_main,用户程序默认从此处开始执行。main组件的特殊之处还有,它默认依赖于所有搜索路径中的组件,因此不必再自己的CMakeLists.txt中使用REQUIRES或PRIV_REQUIRES指明依赖关系。
- app_main函数
ESP32(准确地说是ESP-IDF)开发程序中有且只能有一个app_main函数,该函数是用户程序的入口,相当于其它系统中的main函数。
本例程代码中,在app_main函数中只调用了一句代码,如下:
void app_main(void)
{
xTaskCreate(echo_task, "uart_echo_task", ECHO_TASK_STACK_SIZE, NULL, 10, NULL);
}
由此引出了xTaskCreate函数。
- xTaskCreate函数
从单片机学过来的朋友应该知道,一般都是在主函数中添加while循环,在while循环即主循环中实现相应的功能。而在此处,主函数app_main中却见不到执行主while循环,这是怎么回事呢?想必一切的奥秘都在xTaskCreate函数中。要了解xTaskCreate函数的具体细节,得先从FreeRTOS说起。
知识补强 —— FreeRTOS介绍
1. 简介
FreeRTOS是一个迷你的实时操作系统内核。作为一个轻量级的操作系统,功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能、软件定时器、协程等,可基本满足较小系统的需要。
2. 功能和特点
- 用户可配置内核功能
- 多平台的支持
- 提供一个高层次的信任代码的完整性
- 目标代码小,简单易用
- 遵循MISRA-C标准的编程规范
- 强大的执行跟踪功能
- 堆栈溢出检测
- 没有限制的任务数量
- 没有限制的任务优先级
- 多个任务可以分配相同的优先权
- 队列、二进制信号量、计数信号灯和递归通信和同步的任务
- 优先级继承
- 免费开源的源代码
3. 系统功能
作为一个轻量级的操作系统,FreeRTOS提供的功能包括:任务管理、时间管理、信号量、消息队列、内存管理、记录功能等,可基本满足较小系统的需要。FreeRTOS内核支持优先级调度算法,每个任务可根据重要程度的不同被赋予一定的优先级,CPU总是让处于就绪态的、优先级最高的任务先运行。FreeRTOS内核同时支持轮换调度算法,系统允许不同的任务使用相同的优先级,在没有更高优先级任务就绪的情况下,同一优先级的任务共享CPU的使用时间。
FreeRTOS的内核可根据用户需要设置为可剥夺型内核或不可剥夺型内核。当FreeRTOS被设置为可剥夺型内核时,处于就绪态的高优先级任务能剥夺低优先级任务的CPU使用权,这样可保证系统满足实时性的要求;当FreeRTOS被设置为不可剥夺型内核时,处于就绪态的高优先级任务只有等当前运行任务主动释放CPU的使用权后才能获得运行,这样可提高CPU的运行效率。
ESP32的ESP-IDF中集成了FreeRTOS的代码。
下一回对于FreeRTOS的核心函数(xTaskCreate函数等)进行介绍。