简单的本节略过,详细的可以看视频:单片机ESP32上的FREERTOS这个作者讲的挺好的,通俗易懂
任务的状态
FreeRTOS中的任务有运行态、就绪态、阻塞态、挂起态四种状态,在任何时候都只处于其中一种状态。任务状态之间的转换如下图所示:
任务的优先级
每一个任务都会有一个任务优先级,其范围为 0 (configMAX_PRIORITIES - 1),0优先级最低,(configMAX_PRIORITIES - 1)优先级最大,通常空闲任务的优先级最低,为0。
创建任务
使用动态的方法创建一个任务:
void setup() {
xTaskCreate(task1, //任务函数
"task1", //任务名字
4096, //任务堆栈大小
NULL, //传递给任务函数的参数
5, //任务优先级
NULL); //任务句柄
}
void task1(void *pvParameters)
{
//任务初始化程序
while(1)
{
//任务的循环任务
vTaskDelay(1); //任务延时调度
}
vTaskDelete(NULL); //删除自身函数
}
更多的任务创建和FreeRTOS函数说明看这里:
ESP32之FreeRTOS–任务的创建和运行
传递给任务函数的参数
/*
程序: FREERTOS - 单个参数传递
大家在看本程序的时候,需要对指针非常的了解
知道 * -> &的作用
作业: 添加LED3_PIN 15
公众号:孤独的二进制
*/
byte LED1_PIN = 23;
byte LED2_PIN = 21;
void task1(void *pt) {
byte * pbLEDPIN;
pbLEDPIN = (byte *)pt;
byte LEDPIN;
LEDPIN = *pbLEDPIN;
pinMode(LEDPIN, OUTPUT);
while (1) {
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
vTaskDelay(1000);
}
}
void task2(void *pt) {
byte LEDPIN = *(byte *)pt;
pinMode(LEDPIN, OUTPUT);
while (1) {
digitalWrite(LEDPIN, !digitalRead(LEDPIN));
vTaskDelay(3000);
}
}
void setup() {
Serial.begin(9600);
byte * pbLED1PIN;
pbLED1PIN = &LED1_PIN;
void * pvLED1PIN;
pvLED1PIN = (void *)pbLED1PIN;
if (xTaskCreate(task1,
"Blink 23",
1024,
pvLED1PIN,
1,
NULL) == pdPASS)
Serial.println("Task1 Created.");
if (xTaskCreate(task2,
"Blink 21",
1024,
(void *)&LED2_PIN,
1,
NULL) == pdPASS)
Serial.println("Task2 Created.");
}
void loop() {
}
程序出处
该程序task1创建一个字节指针 byte * pbLED1PIN,通过 pbLED1PIN =&LED1_PIN来指向LED1_PIN的地址,再创建pvLED1PIN这个void类型的指针来存储pbLED1PIN转换成void的值。
函数传递的是void类型的指针,所以参数需要转换成void类型的指针才能在任务函数传递。
task2则简单粗暴一点,(void *)&LED2_PIN,直接取地址,然后用空指针去指向,也一样完成传递。
结构体多参数传递
程序出处
typedef struct {
byte pin;
int delayTime;
} LEDFLASH;
LEDFLASH led1, led2;
if (xTaskCreate(ledFlash,
"FLASH LED",
1024,
(void *)&led1,
1,
NULL) == pdPASS)
Serial.println("led1 flash task Created.");
void ledFlash(void *pt) {
LEDFLASH * ptLedFlash = (LEDFLASH *)pt;
byte pin = ptLedFlash->pin;
int delayTime = ptLedFlash->delayTime;
pinMode(pin,OUTPUT);
while (1) {
digitalWrite(pin, !digitalRead(pin));
vTaskDelay(delayTime);
}
}
实例化结构体led1,然后传入结构体的指针地址,再创建结构体指针(类型为LEDFLASH )使其等于pt(类型转换为LEDFLASH *),这样子就可以获取到结构体led1的地址了。
互斥量Mutex
程序
多个任务一起用同一个变量就会出问题了,所以就要引入互斥量的概念,简单来说,就是互斥锁锁住一个变量之后,只有等这个锁解了,其他任务才能使用这个变量。
/*
程序: Tasks之间数据传递
有多任务同时写入,或者数据大小超过cpu内存通道时,或者对共享资源的访问时候,需要有防范机制
使用MUTEX对数据对Cirtical Section的内容进行保护
可以想象成MUTEX就是一把锁
公众号:孤独的二进制
语法:
SemaphoreHandle_t xHandler; 创建Handler
xHandler = xSemaphoreCreateMutex(); 创建一个MUTEX 返回NULL,或者handler
xSemaphoreGive(xHandler); 释放
xSemaphoreTake(xHanlder, timeout); 指定时间内获取信号量 返回pdPASS, 或者pdFAIL
理解方法:
MUTEX的工作原理可以想象成
共享的资源被锁在了一个箱子里,只有一把钥匙,有钥匙的任务才能对改资源进行访问
*/
SemaphoreHandle_t xMutexInventory = NULL; //创建信号量Handler
void retailTask(void *pvParam) {
while (1) {
// 在timeout的时间内如果能够获取就继续
// 通俗一些:获取钥匙
if (xSemaphoreTake(xMutexInventory, timeOut) == pdPASS) {
//被MUTEX保护的内容叫做 Critical Section
for (int i; i < random(10, 100); i++)
vTaskDelay(pdMS_TO_TICKS(i));
//释放钥匙
xSemaphoreGive(xMutexInventory);
} else {
//无法获取钥匙
}
};
vTaskDelay(100); //老板要求慢一些,客户升级后,可以再加快速度
}
}
if (xSemaphoreTake(xMutexInventory, timeOut) == pdPASS)
如果没有获取到互斥量,则执行以下内容,超时时间是timeOut
xSemaphoreGive(xMutexInventory);
ESP32的双核心
ESP32是具有两个核心的芯片(可以对应一下你手中的型号作对比),是一个40nm的芯片。
核心0主要负责WiFi和蓝牙,如果不是操作这两个,十分不建议将代码放在核心0中运行
/*
程序: 多核多任务
API:
xPortGetCoreID() 获取当前任务运行的核心
xTaskCreate() 有系统选择运行核心,优先选择0
xTaskCreatePinnedToCore() 指派任何给指定核心
公众号:孤独的二进制
*/
void taskA(void *ptParam) {
while (1) {
Serial.println(xPortGetCoreID()); //获取当前任务在哪个核心运行
}
}
void setup() {
// put your setup code here, to run once:
Serial.begin(115200);
xTaskCreatePinnedToCore(taskA, "Task A", 1024 * 4, NULL, 1, NULL,1);
}
void loop() {
Serial.println(xPortGetCoreID());
}
主要是这一句,修改最后一个参数0或1即可修改核心数,使用Arduino环境对esp进行开发时建议使用Application CPU(id=1),否则可能有bug,不建议使用xTaskCreate
xTaskCreatePinnedToCore(taskA, "Task A", 1024 * 4, NULL, 1, NULL,1);
固定频率运行任务
以固定频率运行任务,不多也不少文章来源:https://www.toymoban.com/news/detail-414269.html
TickType_t xLastWakeTime = xTaskGetTickCount();
vTaskDelayUntil(&xLastWakeTime, xFrequency);
vTaskDelayUntil(上一次唤醒的时间的结构体地址, 下一次运行的时间);
软件定时器
FreeRTOS中只要内存允许,想要多少个Timer 就有多少个Timer文章来源地址https://www.toymoban.com/news/detail-414269.html
lockHandle = xTimerCreate("Lock Car",
2000, //两秒钟唤醒一次
pdFALSE,
(void *)0,
lockCarCallback);
到了这里,关于【ESP32】arduino中的ESP32实时系统FreeRTOS使用教程(一)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!