ESP32freeRTOS(上)
ESP32 freeRTOS(上)
教程来自:https://www.bilibili.com/video/BV1FD4y1c7rA
环境的搭建就不多说了,参考这里:esp32ctf_thu学习
搭建好之后可以找一个例子先试一下,目录在 idf 下面的 examples\get-started,就用那个 hello_world 吧,打开 idf cmd 后切换到那个目录,使用命令 idf.py build 编译,完成之后可以使用 idf.py flash 将程序烧录进去
Task创建与删除
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// 声明一个 task
void myTask(void *pvParam){
while(1){
printf("hello world from myTask \n\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
//vTaskDelete(NULL); //vTaskDelete如果放在task里且句柄为空 则会删除当前task
}
void app_main(void)
{
TaskHandle_t myHandle = NULL;
xTaskCreate(myTask, "myTask1", 1024, NULL, 1, &myHandle);
// 参数:task函数指针,task名字,分配内存,传递的参数,优先级别,句柄地址
// 空闲task优先级是0,我们设置为1表示比空闲task优先级高
vTaskDelay(8000/portTICK_PERIOD_MS);
//根据创建的task的句柄调用vTaskDelete删除task
if(myHandle){
vTaskDelete(myHandle);
}
}
Task输入参数
task 的参数是一个无类型的指针
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// 声明一个 task
void myTask(void *pvParam){
int *pInt;
pInt = (int *)pvParam;
printf("I got a num = %d\n", *pInt);
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL); //vTaskDelete如果放在task里且句柄为空 则会删除当前task
}
int testNum = 1; //要传的值
void app_main(void)
{
xTaskCreate(myTask, "myTask1", 2048, (void *) &testNum, 1, NULL);
}
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
// 声明一个 task
void myTask(void *pvParam){
int *pArrayAddr;
pArrayAddr = (int *)pvParam;
printf("I got a num0 = %d\n", *pArrayAddr);
printf("I got a num1 = %d\n", *(pArrayAddr+1));
printf("I got a num2 = %d\n", *(pArrayAddr+2));
printf("I got a num3 = %d\n", *(pArrayAddr+3));
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL); //vTaskDelete如果放在task里且句柄为空 则会删除当前task
}
int testNum[] = {2,0,2,3};
void app_main(void)
{
xTaskCreate(myTask, "myTask1", 2048, (void *) testNum, 1, NULL);
}
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
typedef struct A_STRUCT{
int num;
char name[];
} xStruct;
xStruct myStruct = {1,"yichen\x00"};
void myTask(void *pvParam){
xStruct *pStruct;
pStruct = (xStruct *)pvParam;
printf("I got a num = %d\n", pStruct->num);
printf("I got a name = %s\n", pStruct->name);
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL); //vTaskDelete如果放在task里且句柄为空 则会删除当前task
}
void app_main(void)
{
xTaskCreate(myTask, "myTask1", 2048, (void *) &myStruct, 1, NULL);
}
Task优先级别
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask(void *pvParam){
vTaskDelay(1000/portTICK_PERIOD_MS);
vTaskDelete(NULL); //vTaskDelete如果放在task里且句柄为空 则会删除当前task
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
UBaseType_t iPriority = 0;
xTaskCreate(myTask, "myTask1", 2048, NULL, 1, &pxTask);
iPriority = uxTaskPriorityGet(pxTask); //使用句柄获取优先级
printf("\niPriority = %d\n",iPriority);
}
相同优先级的 task 会共享处理器时间,基于时间片运行,谁先创建谁先运行,然后就轮换着
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
while(1){
printf("this message from task 1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void myTask2(void *pvParam){
while(1){
printf("this message from task 2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, NULL);
xTaskCreate(myTask2, "myTask2", 2048, NULL, 1, NULL);
}
不同的优先级会先运行优先级更高的
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
while(1){
printf("this message from task 1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void myTask2(void *pvParam){
while(1){
printf("this message from task 2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, NULL);
xTaskCreate(myTask2, "myTask2", 2048, NULL, 2, NULL);
}
这里如果不管用是因为你手上的 esp32 是双核运行,idf.py menuconfig 修改一下配置,选择 Run FreeRTOS only on first core
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
while(1){
printf("this message from task 1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void myTask2(void *pvParam){
while(1){
printf("this message from task 2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
UBaseType_t iPriority = 0;
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, &pxTask);
xTaskCreate(myTask2, "myTask2", 2048, NULL, 2, NULL);
iPriority = uxTaskPriorityGet(pxTask);
printf("\nTask1 iPriority = %d\n",iPriority);
vTaskPrioritySet(pxTask,3);// 根据task句柄修改优先级
iPriority = uxTaskPriorityGet(pxTask);
printf("\nTask1 iPriority = %d\n",iPriority);
}
task挂起和恢复
任务一共有 4 种状态:执行、就绪、阻塞、挂起
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
while(1){
printf("this message from task 1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
//vTaskSuspend(NULL); //挂起当前任务
}
}
void myTask2(void *pvParam){
while(1){
printf("this message from task 2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
UBaseType_t iPriority = 0;
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, &pxTask);
xTaskCreate(myTask2, "myTask2", 2048, NULL, 2, NULL);
vTaskDelay(3000/portTICK_PERIOD_MS);
vTaskSuspend(pxTask); //通过句柄挂起任务
}
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
while(1){
printf("this message from task 1\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
//vTaskSuspend(NULL); //挂起当前任务
}
}
void myTask2(void *pvParam){
while(1){
printf("this message from task 2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
UBaseType_t iPriority = 0;
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, &pxTask);
xTaskCreate(myTask2, "myTask2", 2048, NULL, 2, NULL);
vTaskSuspend(pxTask); //通过句柄挂起任务
vTaskDelay(3000/portTICK_PERIOD_MS);
vTaskResume(pxTask); //通过句柄恢复任务
}
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
printf("Test begin\n");
vTaskSuspendAll(); //挂起调度器,挂起后不能再调用FreeRTOS的API函数
for (int i=0;i<9999;i++){ //这段代码执行期间不会调度其他任务,也就是说不会执行myTask2
for(int j=0;j<5000;j++){
;
}
}
xTaskResumeAll(); //恢复调度器
printf("Test end\n");
vTaskDelete(NULL);
}
void myTask2(void *pvParam){
while(1){
printf("this message from task 2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
// UBaseType_t iPriority = 0;
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, &pxTask);
xTaskCreate(myTask2, "myTask2", 2048, NULL, 1, NULL);
// vTaskSuspend(pxTask); //通过句柄挂起任务
// vTaskDelay(3000/portTICK_PERIOD_MS);
// vTaskResume(pxTask); //通过句柄恢复任务
}
Task系统
使用 tasklist 查看系统中所有任务的状态,需要在 idf.py menuconfig 修改一下配置,把其中的 Enable FreeRTOS trace facility 和 Enable FreeRTOS stats formatting functions 打开
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
printf("Test begin\n");
vTaskSuspendAll(); //挂起调度器,挂起后不能再调用FreeRTOS的API函数
for (int i=0;i<9999;i++){ //这段代码执行期间不会调度其他任务,也就是说不会执行myTask2
for(int j=0;j<5000;j++){
;
}
}
xTaskResumeAll(); //恢复调度器
printf("Test end\n");
vTaskDelete(NULL);
}
void myTask2(void *pvParam){
while(1){
printf("this message from task 2\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, &pxTask);
xTaskCreate(myTask2, "myTask2", 2048, NULL, 1, NULL);
static char taskBuffer[512] = {0}; //声明字符数组用来存储结果
while(1){
vTaskList(taskBuffer);
printf("---------------------------------------------\n");
printf("Name State priority Stack Num\n");
printf("%s\n",taskBuffer);
vTaskDelay(3000/portTICK_PERIOD_MS);
}
}
结果解析:
Name 表示任务的名字,State 表示状态,priority 表示优先级,Stack 表示可用栈空间的大小,Num 表示任务的 id
Name State priority Stack Num
myTask2 R 1 1748 5
main X 1 3712 2
myTask1 R 1 1756 4
IDLE R 0 1244 3
esp_timer S 22 3652 1
其中状态有这么些个:
X 表示正在运行,B 表示阻塞,R 表示就绪,S 表示挂起,D 表示被删除
Task堆栈
在创建任务的时候有个参数是设置堆栈深度,也就是说这个值并不是栈的大小,如果说栈的宽度是 4 个字节,设置的这个值为 100 的话,那么栈的小大就是 400 个字节,可以使用 uxTaskGetStackHighWaterMark 获取
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
while(1){
printf("Task1 begin\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
xTaskCreate(myTask1, "myTask1", 2048, NULL, 1, &pxTask);
UBaseType_t iStack;
while(1){
iStack = uxTaskGetStackHighWaterMark(pxTask); //uxTaskGetStackHighWaterMark取值
printf("task1 iStack = %d\n",iStack);
vTaskDelay(3000/portTICK_PERIOD_MS);
}
}
Task看门狗
有一些 Task 需要周期性运行,每隔一段时间要运行一次,如果一段时间内没有被运行,会触发任务的看门狗,打印出一些信息或者重启系统,看门狗也有 callback 函数可以自定义操作
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
void myTask1(void *pvParam){
while(1){
;
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
xTaskCreate(myTask1, "myTask1", 1024, NULL, 1, &pxTask);
}
回显结果中有这样的信息,触发了看门狗,这是因为 IDLE 这个任务每隔一段时间就需要运行一下,esp32 IDLE 任务里面注册了看门狗且会有喂狗的行为,而我们的 myTask1 优先级比 IDLE 高且没有调用阻塞函数(vTaskDelay 等)导致 IDLE 一直没有被执行,就没法喂狗,狗饿了就叫了🦮:
(15305) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
(15305) task_wdt: - IDLE (CPU 0)
(15305) task_wdt: Tasks currently running:
(15305) task_wdt: CPU 0: myTask1
(15305) task_wdt: Print CPU 0 (current core) backtrace
解决这个问题的一个方法是在 myTask1 调用阻塞或者挂起函数,让他释放资源
还有一个方法就是把 myTask1 的优先级也变成 0,这样就不会因为 myTask1 的优先级高而不调用 IDLE
那怎么给自己的任务养一只看门狗呢?首先要在头文件中引入 #include "esp_task_wdt.h",然后在你的任务中创建看门狗 esp_task_wdt_add(NULL); 参数是任务的句柄,在任务里面用 NULL 就行
然后还要使用 esp_task_wdt_reset() 定期的喂狗
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
void myTask1(void *pvParam){
while(1){
;
}
}
void myTask2(void *pvParam){
esp_task_wdt_add(NULL); //创建看门狗
while(1){
printf("Task2\n");
//esp_task_wdt_reset(); //喂狗
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
TaskHandle_t pxTask = NULL;
xTaskCreate(myTask1, "myTask1", 1024, NULL, 0, &pxTask);
xTaskCreate(myTask2, "myTask2", 1024, NULL, 0, NULL);
}
如果取消喂狗的操作,会触发看门狗
(10335) task_wdt: Task watchdog got triggered. The following tasks did not reset the watchdog in time:
(10335) task_wdt: - myTask2 (CPU 0)
(10335) task_wdt: Tasks currently running:
(10335) task_wdt: CPU 0: myTask1
(10335) task_wdt: Print CPU 0 (current core) backtrace
Queue传递数据
通过队列传递数据,队列是一个先入先出的结果
比如下面这个函数,sendTask 往队列里面放数据,recvTask 从队列里面取数据
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "freertos/queue.h" //队列所需头文件
void sendTask(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察发送队列返回值,判断是否成功
int i = 0; //定义发送的数据
while(1){
xStatus = xQueueSend(QHandle, &i, 0); //参数:队列句柄、发送缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Send Done!\n");
i++;
if (i==8) i=0; //到8归零
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void recvTask(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int j = 0;
while(1){
if(uxQueueMessagesWaiting(QHandle) !=0){ //先判断队列句柄是否为空
xStatus = xQueueReceive(QHandle, &j, 0); //参数:队列句柄、接收缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Recv Fail!\n");
else
printf("Recv j=%d Done!\n", j);
vTaskDelay(1000/portTICK_PERIOD_MS);
}else{
printf("No Data!\n");
}
}
}
void app_main(void)
{
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = xQueueCreate(5, sizeof(int)); //创建队列,参数:队列长度、队列的宽度
if (QHandle != NULL){
printf("Create queue successfully!\n");
xTaskCreate(sendTask, "sendTask", 1024*5, (void *)QHandle, 1, NULL);
xTaskCreate(recvTask, "recvTask", 1024*5, (void *)QHandle, 1, NULL);
}
else{
printf("Can't create queue!\n");
}
}
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "freertos/queue.h" //队列所需头文件
typedef struct A_STRUCT{
char id;
char data;
} xStruct;
void sendTask(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察发送队列返回值,判断是否成功
xStruct myStruct = {1,66}; //定义发送的数据
while(1){
xStatus = xQueueSend(QHandle, &myStruct, 0); //参数:队列句柄、发送缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Send Done!\n");
myStruct.id++;
if (myStruct.id==8) myStruct.id=0; //到8归零
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void recvTask(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
xStruct myStruct = {0,0}; //定义接收的数据
while(1){
if(uxQueueMessagesWaiting(QHandle) !=0){ //先判断队列句柄是否为空
xStatus = xQueueReceive(QHandle, &myStruct, 0); //参数:队列句柄、接收缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Recv Fail!\n");
else
printf("Recv myStruct.id=%d myStruct.data=%d Done!\n", myStruct.id, myStruct.data);
vTaskDelay(1000/portTICK_PERIOD_MS);
}else{
printf("No Data!\n");
}
}
}
void app_main(void)
{
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = xQueueCreate(5, sizeof(int)); //创建队列,参数:队列长度、队列的宽度
if (QHandle != NULL){
printf("Create queue successfully!\n");
xTaskCreate(sendTask, "sendTask", 1024*5, (void *)QHandle, 1, NULL);
xTaskCreate(recvTask, "recvTask", 1024*5, (void *)QHandle, 1, NULL);
}
else{
printf("Can't create queue!\n");
}
}
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "freertos/queue.h" //队列所需头文件
typedef struct A_STRUCT{
char id;
char data;
} xStruct;
void sendTask(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察发送队列返回值,判断是否成功
char *pStrToSend; //定义发送的数据
int i=0;
while(1){
pStrToSend = (char *)malloc(50); //分配内存
snprintf(pStrToSend, 50, "Hello From Queue %d\r\n" ,i);
i++;
xStatus = xQueueSend(QHandle, &pStrToSend, 0); //参数:队列句柄、发送缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Send Done!\n");
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void recvTask(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
char *pStrToRecv; //定义接收的数据
while(1){
if(uxQueueMessagesWaiting(QHandle) !=0){ //先判断队列句柄是否为空
xStatus = xQueueReceive(QHandle, &pStrToRecv, 0); //参数:队列句柄、接收缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Recv Fail!\n");
else
printf("Recv %s Done!\n", pStrToRecv);
free(pStrToRecv);
vTaskDelay(1000/portTICK_PERIOD_MS);
}else{
printf("No Data!\n");
}
}
}
void app_main(void)
{
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = xQueueCreate(5, sizeof(char *)); //创建队列,参数:队列长度、队列的宽度
if (QHandle != NULL){
printf("Create queue successfully!\n");
xTaskCreate(sendTask, "sendTask", 1024*5, (void *)QHandle, 1, NULL);
xTaskCreate(recvTask, "recvTask", 1024*5, (void *)QHandle, 1, NULL);
}
else{
printf("Can't create queue!\n");
}
}
Queue多进单出
多个任务往一个队列里面放数据,一个任务从队列里面取数据,这时候要格外重视任务优先级,在这段代码中,我们设置 recvTask 从队列中取值,他的优先级更高,保证他取完值才会交给其他任务来运行,另外两个任务优先级相同,一次往队列里面放值
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "freertos/queue.h" //队列所需头文件
void sendTask1(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i=111;
while(1){
xStatus = xQueueSend(QHandle, &i, 0); //参数:队列句柄、发送缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Send %d Done!\n", i);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void sendTask2(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i=222;
while(1){
xStatus = xQueueSend(QHandle, &i, 0); //参数:队列句柄、发送缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Send %d Done!\n", i);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void recvTask(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i; //定义接收的数据
while(1){
xStatus = xQueueReceive(QHandle, &i, portMAX_DELAY); //参数:队列句柄、接收缓冲区地址、超时时间
//portMAX_DELAY表示无限等待,阻塞task
if(xStatus != pdPASS)
printf("Recv Fail!\n");
else
printf("Recv %d Done!\n", i);
}
}
void app_main(void)
{
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = xQueueCreate(5, sizeof(char *)); //创建队列,参数:队列长度、队列的宽度
if (QHandle != NULL){
printf("Create queue successfully!\n");
xTaskCreate(sendTask1, "sendTask1", 1024*5, (void *)QHandle, 1, NULL);
xTaskCreate(sendTask2, "sendTask2", 1024*5, (void *)QHandle, 1, NULL);
xTaskCreate(recvTask, "recvTask", 1024*5, (void *)QHandle, 2, NULL);
}
else{
printf("Can't create queue!\n");
}
}
Queue集合
在应用设计中,会出现多个 task 分别写各自的 Queue,然后一个 task 分别从各个队列中读取数据,freertos 提供了一个队列集合的概念,把这些队列全部放在一个集合中,提供一个函数接口(xQueueSelectFromSet)从集合中取有数据的对应的队列的句柄,然后再读取数据
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "freertos/queue.h" //队列所需头文件
void sendTask1(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i=111;
while(1){
xStatus = xQueueSend(QHandle, &i, 0); //参数:队列句柄、发送缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Send %d Done!\n", i);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void sendTask2(void *pvParam){
QueueHandle_t QHandle; //创建一个队列句柄
QHandle = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i=222;
while(1){
xStatus = xQueueSend(QHandle, &i, 0); //参数:队列句柄、发送缓冲区地址、超时时间
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Send %d Done!\n", i);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void recvTask(void *pvParam){
QueueSetHandle_t QueueSet; //创建一个队列句柄
QueueSet = (QueueSetHandle_t) pvParam; //取得队列句柄
QueueSetMemberHandle_t QueueData;
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i; //定义接收的数据
while(1){
QueueData = xQueueSelectFromSet(QueueSet, portMAX_DELAY); //从队列集合中取有数据的队列
xStatus = xQueueReceive(QueueData, &i, portMAX_DELAY); //参数:队列句柄、接收缓冲区地址、超时时间
//portMAX_DELAY表示无限等待,阻塞task
if(xStatus != pdPASS)
printf("Recv Fail!\n");
else
printf("Recv %d Done!\n", i);
}
}
void app_main(void)
{
QueueHandle_t QHandle1; //创建一个队列句柄
QHandle1 = xQueueCreate(5, sizeof(char *)); //创建队列,参数:队列长度、队列的宽度
QueueHandle_t QHandle2; //创建一个队列句柄
QHandle2 = xQueueCreate(5, sizeof(char *)); //创建队列,参数:队列长度、队列的宽度
QueueSetHandle_t QueueSet; //创建队列集合(两个队列长度的和)
QueueSet = xQueueCreateSet(10);
xQueueAddToSet(QHandle1, QueueSet); //把QHandle1加到QueueSet中
xQueueAddToSet(QHandle2, QueueSet); //把QHandle2加到QueueSet中
if ((QHandle1 != NULL) && (QHandle2 != NULL) && (QueueSet != NULL)){
printf("Create queue successfully!\n");
xTaskCreate(sendTask1, "sendTask1", 1024*5, (void *)QHandle1, 1, NULL);
xTaskCreate(sendTask2, "sendTask2", 1024*5, (void *)QHandle2, 1, NULL);
xTaskCreate(recvTask, "recvTask", 1024*5, (void *)QueueSet, 2, NULL);
}
else{
printf("Can't create queue!\n");
}
}
Queue MailBox
队列会把数据从一个 task 发送到另一个 task 或中断,但是 mailbox 会保存数据,被任何 task 或中断读取数据
发送方会覆盖 mailbox 的值,接收方只能读取 mailbox 的值
#include <stdio.h>
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "esp_task_wdt.h"
#include "freertos/queue.h" //队列所需头文件
void writeTask(void *pvParam){
QueueHandle_t MailBox; //创建一个队列句柄
MailBox = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i=1;
while(1){
xStatus = xQueueOverwrite(MailBox, &i); //参数:队列句柄、发送缓冲区地址
if(xStatus != pdPASS)
printf("Send Fail!\n");
else
printf("Write %d Done!\n", i);
i++;
vTaskDelay(6000/portTICK_PERIOD_MS);
}
}
void readTask(void *pvParam){
QueueHandle_t MailBox; //创建一个队列句柄
MailBox = (QueueHandle_t) pvParam; //取得队列句柄
BaseType_t xStatus; //定义一个变量,观察接收队列返回值,判断是否成功
int i;
while(1){
xStatus = xQueuePeek(MailBox, &i, 0); //参数:队列句柄、发送缓冲区地址
if(xStatus != pdPASS)
printf("Read Fail!\n");
else
printf("Read %d Done!\n", i);
vTaskDelay(1000/portTICK_PERIOD_MS);
}
}
void app_main(void)
{
QueueHandle_t MailBox; //创建一个队列句柄
MailBox = xQueueCreate(1, sizeof(int)); //创建队列,参数:队列长度、队列的宽度
if (MailBox != NULL){
printf("Create queue successfully!\n");
xTaskCreate(writeTask, "writeTask", 1024*5, (void *)MailBox, 1, NULL);
xTaskCreate(readTask, "readTask1", 1024*5, (void *)MailBox, 2, NULL); //共用readTask函数体创建三个不同的任务
xTaskCreate(readTask, "readTask2", 1024*5, (void *)MailBox, 2, NULL);
xTaskCreate(readTask, "readTask3", 1024*5, (void *)MailBox, 2, NULL);
}
else{
printf("Can't create queue!\n");
}
}