ESP32+FreeRTOS


前言:

跟着B站“孤独的二进制”老师粗略学习了下ESP32上FreeRTOS的使用,为了加深理解,对所学习的API进行归纳整理。

与其临渊羡鱼,不如退而结网


一、内存管理

1.用途

任务内存管理优化(提高分配内存的效率避免堆栈溢出等问题)

2.相关API

ESP.getHeapSize() //获取Heap(堆)内存的总大小
ESP.getFreeHeap() //当前可用堆内存的总大小
uxTaskGetStackHighWaterMark(taskHandle) //用于获取指定任务的堆栈高水位标记,即任务执行过程中堆栈的最大利用率

3.注意事项

分配给任务栈的大小一般为最大使用量的两倍。


二、任务管理

1、任务创建

TaskHandle_t TaskHandle = NULL; //创建任务句柄(任务控制块指针)

xTaskCreate(
TaskFunction_t pvTaskCode, //任务函数
const char * const pcName, //任务名
configSTACK_DEPTH_TYPE usStackDepth,//任务栈大小
void *pvParameters, //传参指针
UBaseType_t uxPriority, //任务优先级
TaskHandle_t *pxCreatedTask //任务句柄
);
返回值 pdPass 表示任务创建成功

xTaskCreatePinnedToCore(task1,“task”,1024*4,NULL,1,NULL,0 or 1);//将任务放在核心0或核心1上(在双核主控上使用)
Serial.println(xPortGetCoreID());//打印当前任务是工作在哪个核心上

2、任务暂停

void vTaskSuspend( TaskHandle_t xTaskToSuspend );
该函数会将任务句柄指定的任务从就绪队列中移除,并将其状态设置为暂停状态。

3、任务恢复

void vTaskResume( TaskHandle_t xTaskToResume );
该函数会将任务句柄指示的之前被暂停的任务重新放入就绪队列,使其可以被调度器调度并继续执行。

4、任务删除

void vTaskDelete( TaskHandle_t xTask );
使用此函数会将任务句柄所指示的任务删除

5、任务优先级

void vTaskPrioritySet( TaskHandle_t xTask,UBaseType_t uxNewPriority );//设置优先级
UBaseType_t uxTaskPriorityGet( TaskHandle_t xTask );//获取TaskHandle任务优先级
BaseType_t uxTaskPriorityGet(NULL);//获取当前任务优先级
taskYIELD(); //资源退让给同等级或者更高级的任务

6、获取任务状态

xTaskGetSchedulerState()

6、看门狗

概况:
看门狗是针对Task任务的
Arduion-ESP32 默认在 Core 0 的 IDLE 任务开启了看门狗 时间为 5000 ticks = 5秒
Core 0 和 Core 1 都运行了 FreeRTOS的IDLE任务,优先级为 0
IDLE(空闲)任务是用于清理被删除任务的内存
Core 1 loopBack任务就是Arduino的 setup 和 loop 优先级为 1

//手动关闭CPU上的TWDT - 慎重操作
disableCore0WDT();
disableCore1WDT();

esp_task_wdt_add(NULL);//给本任务添加看门狗(NULL代表本任务)
esp_task_wdt_delete(NULL)//移除本任务的看门狗(NULL代表本任务)


二、互斥量Mutex

1、作用/特点

使用Mutex相互排斥来解决多个任务同时对共享资源访问造成的问题
有多任务同时写入,或者数据大小超过cpu内存通道时,或者对共享资源的访问时候,需要有防范机制
MUTEX的工作原理可以想象成
共享的资源被锁在了一个箱子里,只有一把钥匙,有钥匙的任务才能对该资源进行访问

2、相关API

SemaphoreHandle_t xHandler; 创建Handler
xHandler = xSemaphoreCreateMutex(); 创建一个MUTEX 返回NULL,或者handler
xSemaphoreGive(xHandler); 释放
xSemaphoreTake(xHanlder, timeout); 指定时间内获取信号量 返回pdPASS, 或者pdFAIL

三、队列Queue

1.作用/特点

队列(queue)可以用于"任务到任务"、“任务到中断”、“中断到任务"直接传输信息。
队列可以包含若干个数据:队列中有若干项,这被称为"长度”(length)
每个数据大小固定
创建队列时就要指定长度、数据大小
数据的操作采用先进先出的方法(FIFO,First In First Out):写数据时放到尾部,读数据时从头部读

2.相关API

//创建消息队列
QueueHandle_t xQueueCreate(
UBaseType_t uxQueueLength,//长度,数据个数
UBaseType_t uxItemSize ); //数据大小

发送数据到队列中
BaseType_t xQueueSend(
QueueHandle_t xQueue, //消息队列句柄
const void * pvItemToQueue, //待发送数据的地址
TickType_t xTicksToWait //等待时间
);

从队列中往外读取数据
BaseType_t xQueueReceive(
QueueHandle_t xQueue, //消息队列句柄
void *pvBuffer, //存储接收到数据的地址
TickType_t xTicksToWait //等待时间
);

四、信号量

1、作用/特点

一个任务(生产者)发出信号。另外一个任务(消费者)接受信号
二进制信号量可以想成就是一个整数 0 或者 1
计数信号量是0-max
Give就是+1
Take就是-1
Take的时候如果这个整数是0的话,就等待一直到timeout

2、相关API

SemaphoreHandle_t xHandler; 创建信号量Handler
xHandler = xSemaphoreCreateBinary(); 创建一个二进制信号量 返回NULL,或者handler
xHandler=xSemaphoreCreateCounting(3, 0);//创建计数信号量
xSemaphoreGive(xHandler); 生产者+1
xSemaphoreTake(xHanlder, timeout); 消费者-1 返回pdPASS, 或者pdFAIL
void vSemaphoreDelete( SemaphoreHandle_t xSemaphore );//删除信号量

五、事件标志组

1.作用/特点

// 3 Bytes 24bit 每一位表示一个事件
可以实现等待和同步的操作

2.相关API

EventGroupHandle_t xEventPurchase = NULL; //创建事件组 handler
xEventGroupCreate //用于创建一个事件标志组,并返回一个事件标志组句柄
xEventGroupSetBits //用于设置事件标志组的位
xEventGroupWaitBits //用于等待指定的事件标志位被设置
xEventGroupGetBits //用于获取当前事件标志组的位状态
xEventGroupClearBits //用于清除指定的事件标志位

用于同步多个任务或事件组的状态,并返回已设置的事件位(bit)
xEventGroupSync( EventGroupHandle_t xEventGroup, //事件组句柄
const EventBits_t uxBitsToSet, //将哪些位设置为1,然后等待
const EventBits_t uxBitsToWaitFor, //等待这些bit被设置为一
TickType_t xTicksToWait ); //等待时间

七、流媒体缓存

程序: 使用Stream Buffer 对流媒体数据,在任务间进行传输
流媒体,读和写的大小都没有任何的限制
读和写的大小可以不一致, 比如写入100 bytes, 可以分成两次每次50 bytes读取出来
注意: 适合于一个任务写,另外一个任务读
不适合多任务读写
如果必须要用在多任务的读写,请将内容放入CRITICAL SECTION
可以使用 MUTEX 或者 TASK Notification

八、消息缓存

Message Buffer基于Stream Buffer上实现的, 在传输的时候用4个字节记录了sent的内容大小
这样子读取的话,也可以一次读取对应大小的数据
所以很适合 串口 接收和发送数据,每次的大小不定,但是接受和发送的数据量需要相同

八、直接任务通知

1.作用/特点

每个任务都有一个结构体:TCB(Task Control Block),包括两个成员。
一个是uint32_t类型,用来表示通知值。
一个是uint8_t类型,用来表示通知状态。
通知状态有3种取值:
taskNOT_WAITING_NOTIFICATION:任务没有在等待通知
taskWAITING_NOTIFICATION:任务在等待通知
taskNOTIFICATION_RECEIVED:任务接收到了通知,也被称为pending(有数据了,待处理)
我们不能对通知状态进行直接的读写操作,是系统自动的。只能对通知值进行操作。

2.相关API

使用直接任务通知(Task Notification)来取代二进制信号量(Binary Semaphore)
xTaskNotifyGive // 相当于精简化的 xTaskNotify() + eIncrement
ulTaskNotifyTake // 等待通知,然后重置为0

专业版本
BaseType_t xTaskNotify(
TaskHandle_t xTaskToNotify, //被通知任务的句柄
uint32_t ulValue, //怎么使用ulValue,由eAction 参数决定
eNotifyAction eAction );//见下表
返回值 pdPASS/pdFAIL

eNotifyAction取值说明
eNoAction仅仅是更新通知状态为"pending",未使用ulValue。 这个选项相当于轻量级的、更高效的二进制信号量。
eSetBits通知值 = 原来的通知值 按位或 ulValue。 相当于轻量级的、更高效的事件组。
eIncrement通知值 = 原来的通知值 + 1,未使用ulValue。 相当于轻量级的、更高效的二进制信号量、计数型信号量。 相当于**xTaskNotifyGive()**函数。
eSetValueWithoutOverwrite不覆盖。 如果通知状态为"pending"(表示有数据未读), 则此次调用xTaskNotify不做任何事,返回pdFAIL。 如果通知状态不是"pending"(表示没有新数据), 则:通知值 = ulValue。
eSetValueWithOverwrite覆盖。 无论如何,不管通知状态是否为"pendng", 通知值 = ulValue。

BaseType_t xTaskNotifyWait(
uint32_t ulBitsToClearOnEntry, //在通知到达前,将对应位清零
uint32_t ulBitsToClearOnExit, //在得到数据后退出时,将对应位清零。
uint32_t *pulNotificationValue, //将通知值赋给变量
TickType_t xTicksToWait );//任务进入阻塞态的超时时间

九、软件定时器

1.作用/特点

在FreeRTOS中,我们可以设置无数个软件定时器,他们都是基于系统滴答中断的
软件定时器有一次性周期性两种。他们会在定时时间到达时执行回调函数。

要想使用软件定时器,要先指定周期,类型,回调函数。

2.相关API

TimerHandle_t lockHandle, checkHandle;//定义软件定时器句柄

创建定时器
lockHandle=xTimerCreate(
const char * const pcTimerName, //定时器的名字
const TickType_t xTimerPeriodInTicks, //周期
const UBaseType_t uxAutoReload, //类型,pdTRUE,自动加载 pdFAIL,一次性
void * const pvTimerID, /回调函数可以使用此参数, 比如分辨是哪个定时器
TimerCallbackFunction_t pxCallbackFunction);//回调函数
//创建成功则返回 TimerHandle_t ,否则返回NULL

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值