PS:刚开始接触FreeRTOS,先在esp32里面试试水。
本文不做过多的理论解释,只做自己一些初学感悟,如有错误望指出。(后续还会补上stm32里面的RTOS)
学习网站:【ESP32,ESP8266】教程汇总 - DF创客社区 - 分享创造的喜悦 (dfrobot.com.cn)
之前做项目的时候,发现esp32竟然有两个内核,那就比较强大了喔,可以把函数分在不同的内核里面,这样的话就互相不干扰了。理论上来讲,应该也可以实现两种不同频率的呼吸灯了,但是我的开发板上面没有呼吸灯,所以就不实践了。只能自己写一些简单代码来看看情况了。
1.创建任务,以及删除任务
先来看看代码
void setup()
{
Serial.begin(115200);
xTaskCreatePinnedToCore(task1, "task1", 1000, NULL, 1, NULL,0);
xTaskCreatePinnedToCore(task2, "task2", 1000, NULL, 2, NULL,1);
}
void loop()
{
}
void task1(void *parameter)
{
while(1)
{
Serial.println("task1:hello!");
vTaskDelay(pdMS_TO_TICKS(1000));
}
}
void task2(void *parameter)
{
while(1)
{
Serial.println("task2:hello!");
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
我们创建了两个任务,分别在两个核上面 运行,其中1是大核,程序默认在1核上面运行的,下面是运行结果
有意思的是,有一个时间段任务1和任务2会同时打印。
我们来看看xTaskCreatePinnedToCore函数的参数
task1:函数指针,指向要运行的任务函数。
"task1":这是任务的名称,是一个字符串,用于标识任务
10000 :这是任务的栈深度,即任务栈的大小,以字为单位
NULL:这是传递给任务函数的参数,可以是一个指针,用于在任务中传递数据,我们这边是空,所以没有参数。
1:标志任务优先级
NULL:这是一个指向 TaskHandle_t类型的指针,用于接收任务句柄。任务句柄可以用于后续操作,如删除任务或挂起任务。待会我们来是一下
0:指在内核0里面运行。
我们来创建一个结构体指针,待会用来作为删除任务的句柄,代码如下。
TaskHandle_t taskHandle;
void setup()
{
Serial.begin(115200);
xTaskCreatePinnedToCore(task1, "task1", 1000, NULL, 1, &taskHandle,0);
xTaskCreatePinnedToCore(task2, "task2", 1000, NULL, 2, NULL,1);
}
void loop()
{
delay(10000);
}
void task1(void *parameter)
{
for(int i=0;i<20;i++)
{
Serial.println("task1:hello!");
vTaskDelay(pdMS_TO_TICKS(1000));
}
vTaskDelete(taskHandle);
}
void task2(void *parameter)
{
while(1)
{
Serial.println("task2:hello!");
vTaskDelay(pdMS_TO_TICKS(5000));
}
}
我们设置在打印20次之后,删除任务1,果然,在20个hello之后task1就不再出现了
除了这种方式删除任务,还可以直接 vTaskDelete(NULL);可以把本任务函数给删除掉。
void task1(void *parameter)
{
for(int i=0;i<20;i++)
{
Serial.println("task1:hello!");
vTaskDelay(pdMS_TO_TICKS(1000));
}
vTaskDelete(NULL);
}
2.从消息队列里面提取数据
下面是代码和运行结果
QueueHandle_t myQueue;
typedef struct
{
unsigned int drain_total_count_p; // 排放总次数
unsigned int drain_total_pulse_p; // 排放总脉冲
float last_drain_time_p; // 前次排水时间
float drain_total_flow_p;
} jsondata_struct;
jsondata_struct jsondata;
jsondata_struct jsondata_receive;
void setup()
{
Serial.begin(115200);
myQueue = xQueueCreate(1, sizeof(jsondata_struct)); // 创建队列
jsondata.drain_total_count_p = 1;
jsondata.drain_total_pulse_p = 2;
jsondata.last_drain_time_p = 3.1;
jsondata.drain_total_flow_p = 3.2;
xQueueSend(myQueue, &jsondata, portMAX_DELAY); // 发送数据到队列
}
void loop()
{
BaseType_t messagesWaiting = uxQueueMessagesWaiting(myQueue);
if(messagesWaiting>0)
{
if (xQueueReceive(myQueue, &jsondata_receive, portMAX_DELAY) == pdPASS)
{
Serial.printf("数据:%d,%d,%f,%f\n", jsondata_receive.drain_total_count_p, jsondata_receive.drain_total_pulse_p, jsondata_receive.last_drain_time_p, jsondata_receive.drain_total_flow_p);
}
}
else
{
Serial.println("无数据");
}
delay(2000);
}
这段代码创建队列,发送数据到队列,然后读取队列里面的数据,需要注意的事,队列的数据只能被读取一次,读完之后就没有数据了。