1.任务管理:

1)任务状态:

运行态可以转换到就绪态,阻塞态,挂起态。

就绪态可以转换到运行态,挂起态。

阻塞态可以转换到就绪态,挂起态。

挂起态可以转换到就绪态。

2)任务控制块TCB:

(1)任务函数的入口地址:任务函数的定义格式

void startTaskA(void* arg)

{

for(;;)

{

//写任务需要执行代码

//通常需要考虑进入到非运行态(释放CPU使用权)

}

vTaskDelete(NULL);

}

(2)任务名

(3)堆栈大小

(4)任务的优先级

3)任务的操作:

(1)任务的创建:xTaskCreate()

  (2)任务的删除:vTaskDelete()

(3)任务挂起与解除挂起:vTaskSuspend(),vTaskResume()

(4)使任务休眠阻塞:vTaskDelay(),参数:表示需要休眠的节拍数

2.任务的通信

1)队列的用途:

实现任务之间的数据传递,队列实现任务间通信的基础。

2)队列的特点:

FIFO,先入先出

任务对队列操作可能引起阻塞;写阻塞,读阻塞

写队列会将数据拷贝写入到队列的末尾

读队列会从队列的头部读取并删除数据

创建时,需要指定队列的深度,以及数据块大小

1.创建队列:

QueueHandle_t xQueueCreate(UBaseType_t uxQueueLength, UBaseType_t uxItemSize);

                        参数依次: 队列的深度,  队列中每个数据块的大小

                     返回值: 队列的句柄

2.发送消息:

BaseType_t xQueueSend(QueueHandle_t xQueue, const void * pvItemToQueue, TickType_t xTicksToWait);

                         参数依次: 队列句柄,  待发送数据的地址,   超时时间(若出现写阻塞)

3.从中断中发送消息

BaseType_t xQueueSendFromISR(QueueHandle_t xQueue, const void * pvItemToQueue, BaseType_t * pxHigherPriorityTaskWoken);

4.接收消息

BaseType_t xQueueReceive(QueueHandle_t xQueue, void * pvBuffer, TickType_t xTicksToWait);

                   参数依次: 队列句柄,  存储接收数据的地址,   超时时间(若出现读阻塞)

 为什么上传数据到队列可能会超时?

A: 因为队列存在“写阻塞”特性,当一个任务对一个已经装满的队列进行写操作,

它就就会进入到阻塞状态,直到队列解除阻塞(通常是队列被读取了数据 或 队列被

删除)那么任务会回到就绪态 或 超时时间达到,写入失败

5.何时必须使用由TIM实现的定时函数?

当实现通信操作时,比如实现IIC通信的开始条件、停止条件、发送数据帧时。必须使用TIM的定时函数,若使用了vTaskDelay()则可能导致延时阻塞的期间执行了其他任务,最终使开始条件或停止条件中的某个时段延长,超出了规定时间,开始或停止条件建立失败。

3)信号量:实现任务之间同步

1.核心操作:

创建这种信号。

信号量P操作。 信号量-1,即公共资源数量减一。任务申请占用一个公共资源

(有两种结果:若当前有资源,成功占用;若当前没有资源,阻塞直到有资源)

信号量V操作。信号量+1,即公共资源数量加一。任务释放一个占用的公共资源。

没有优先级继承机制,不适合用于实现任务间的互斥;错误使用可能会出现“优先级反转问题”。

2.FreeRTOS中的信号量主要有两种类型:计数信号量和二值信号量。

  二值信号量(Binary Semaphore)

概念:二值信号量是一种只有两个值(0和1)的特殊信号量。

作用:用于任务同步或事件通知,以及控制对某个资源的独占访问。例如,某任务等待中断事件触发,中断服务函数通过释放二值信号量通知任务。

特点:

  1. 轻量级:占用内存少,操作简单。
  2. 事件通知:适用于中断触发的事件处理。
  3. 二选一:只有两种状态(已释放/已获取),逻辑清晰。
  4. 功能单一:不能记录多个事件发生的情况。
  5. 没有优先级继承:可能发生优先级翻转问题。

创建信号量:

二值信号量:SemaphoreHandle_t xSemaphoreCreateBinary(void);

计数信号量:SemaphoreHandle_t xSemaphoreCreateCounting(UBaseType_t uxMaxCount, UBaseType_t uxInitialCount);

释放信号量/信号量+1:BaseType_t  xSemaphoreGive(SemaphoreHandle_t xSemaphore);

(信号量的V操作)

从中断中释放信号量:BaseType_t xSemaphoreGiveFromISR(SemaphoreHandle_t xSemaphore, BaseType_t * pxHigherPriorityTaskWoken);

获取信号量/试图信号量-1:BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);

(信号量的P操作)

4)互斥锁:实现任务之间互斥

优先级继承:

(1)触发前提:

两个优先级不同的任务竞争公共资源,低优先级任务先执行P操作抢占到资源,

高优先级任务后执行P操作去抢占资源。

(2)触发时机:

高优先级任务执行P操作,但资源已被低优先级任务占用,高优先级任务阻塞。

(3)效果:

在低优先级任务释放资源之前(V操作之前),低优先级任务会临时被系统自动提升优先级

直到与高优先级的任务一致。

(4)可以用于实现任务间的互斥访问

获取信号量/试图信号量-1:BaseType_t xSemaphoreTake(SemaphoreHandle_t xSemaphore, TickType_t xTicksToWait);

(信号量的P操作)创建互斥信号量

QueueHandle_t  xSemaphoreCreateMutex( void );

返回值:互斥量句柄(队列,因为信号量的底层实现是通过队列完成的);

若返回NULL,则创建失败

申请占用一个互斥量/申请获取访问公共资源的令牌/申请占用一个公共资源/试图让信号量-1/P操作 BaseType_t  xSemaphoreTake ( QueueHandle_t xQueue, TickType_t xTicksToWait )

参数:xQueue       信号量句柄 

     xTicksToWait  超时时间,单位:节拍

返回值:若成功占用,返回pdPASS

若未能成功占用,返回errQUEUE_EMPTY

互斥量中很多数据和队列有关,原因是互斥量底层是基于深度为1的队列实现的!

释放一个互斥量/归还访问公共资源的令牌/释放一个占用的公共资源/使信号量+1/V操作

BaseType_t  xSemaphoreGive( QueueHandle_t xQueue )

参数:xQueue       信号量句柄

返回值:若成功释放,返回pdPASS

若释放前,互斥量已存在(值为1),则返回errQUEUE_FULL

5)事件组:

在 FreeRTOS 中,事件组(Event Group)是一个用于管理和同步任务的机制。它允许任务之间通过事件标志(bits)来通信和同步。事件组中的每一位(bit)代表一个独立的事件,任务可以设置、清除、等待或查询这些事件标志位。

(1)事件组的主要功能:

设置事件标志位:任务或中断服务例程可以设置一个或多个事件标志位,以表示某些事件已经发生。

清除事件标志位:任务可以清除一个或多个事件标志位,以重置或表示某些事件已经处理完毕。

等待事件标志位:任务可以阻塞等待,直到一个或多个特定的事件标志位被设置。这种等待可以是一直等待,直到所有指定的事件都发生,或者只要其中的一个事件发生就退出等待。

查询事件标志位:任务可以查询当前事件组的状态,以检查哪些事件已经发生。

​​​​​​​1.创建事件组

原型:EventGroupHandle_t xEventGroupCreate( void );

功能:创建一个事件组,并返回它的句柄

参数:无

返回值:返回事件组的句柄。如果返回 NULL,表示事件组创建失败。

​​​​​​​2.设置事件标志位

原型:EventBits_t xEventGroupSetBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToSet );

功能:设置事件组中的一个或多个事件标志位,即触发事件。

参数:xEventGroup:事件组句柄。

uxBitsToSet:要设置的事件标志位。

返回值:返回设置前事件组的事件标志位。

备注:每种事件标志位具体对应第几位,以及该标志位的含义,都是由开发者自行规定。

​​​​​​​3.清除事件标志位

原型:EventBits_t  xEventGroupClearBits( EventGroupHandle_t xEventGroup, const EventBits_t uxBitsToClear );

功能:清除事件组中的一个或多个事件标志位。

参数:xEventGroup:事件组句柄。

uxBitsToClear:要清除的事件标志位。

返回值:返回清除前事件组的事件标志位。

​​​​​​​4.等待事件标志位

原型:EventBits_t  xEventGroupWaitBits( EventGroupHandle_t xEventGroup,

                                 const EventBits_t uxBitsToWaitFor,

                                 const BaseType_t xClearOnExit,

                                 const BaseType_t xWaitForAllBits,

                                 TickType_t xTicksToWait );

功能:等待一个或多个事件标志位被设置。

参数:xEventGroup:事件组句柄。

uxBitsToWaitFor:等待的事件标志位。如果等待多种事件,就用按位或 | 连接

xClearOnExit:退出时是否清除事件标志位,pdTRUE 表示清除,pdFALSE 表示不清除。

xWaitForAllBits:等待所有指定的事件标志位都被设置,pdTRUE 表示等待所有,

pdFALSE 表示任意一个。

xTicksToWait:等待的最大时间(以时钟节拍计),如果设置为 portMAX_DELAY,表示无限等待。

返回值:返回清零前的事件组的值。

Logo

openvela 操作系统专为 AIoT 领域量身定制,以轻量化、标准兼容、安全性和高度可扩展性为核心特点。openvela 以其卓越的技术优势,已成为众多物联网设备和 AI 硬件的技术首选,涵盖了智能手表、运动手环、智能音箱、耳机、智能家居设备以及机器人等多个领域。

更多推荐