FreeRTOS 基础系列文章
基本对象
FreeRTOS——任务
FreeRTOS——队列
FreeRTOS——信号量
FreeRTOS——互斥量
FreeRTOS——任务通知
FreeRTOS——流和消息缓冲区
FreeRTOS——软件定时器
FreeRTOS——事件组
内存管理
FreeRTOS——静态与动态内存分配
FreeRTOS——堆内存管理
FreeRTOS——栈溢出保护
代码组织
FreeRTOS——源代码组织
FreeRTOS——创建新的项目
FreeRTOS——配置文件
二进制信号量
提示:在许多情况下,“任务通知”可以提供二进制信号量的轻量级替代方案 |
二进制信号量用于互斥和同步目的。
二进制信号量和互斥量非常相似,但有一些细微的区别:互斥量包括优先级继承机制,二进制信号量没有。这使得二进制信号量成为实现同步(任务之间或任务与中断之间)的更好选择,而互斥体成为实现简单互斥的更好选择。互斥量如何被用作互斥机制的描述同样适用于二进制信号量。本小节仅描述使用二进制信号量进行同步。
信号量 API 函数允许指定阻塞时间。阻塞时间表示在尝试“获取”信号量时,如果信号量不是立即可用的,任务应进入阻塞状态的最大“滴答”数。如果多个任务阻塞在同一个信号量上,那么具有最高优先级的任务将是下一次信号量可用时解除阻塞的任务。
将二进制信号量视为只能容纳一项的队列。因此队列只能为空或已满(因此是二进制的)。使用队列的任务和中断不关心队列包含什么——他们只想知道队列是空的还是满的。可以利用这种机制来同步(例如)任务与中断。
考虑使用任务为外围设备提供服务的情况。轮询外设会浪费 CPU 资源,并阻止其他任务执行。因此,任务最好将大部分时间都花在阻塞状态(允许其他任务执行)并且仅在实际有事情要做时才执行它。这是通过使用一个二进制信号量来实现的,在尝试“获取”信号量时使用任务阻塞。然后为外设编写一个中断程序,当外设需要服务时,它只“释放”信号量。任务总是“获取”信号量(从队列中读取使其为空),但从不“释放”。中断总是“释放”信号量(写入队列使其满),但从不获取它。另请参阅FreeRTOS——任务通知,在某些情况下,它可以用作更快、更轻量级的二进制信号量替代方案。
任务优先级可用于确保外设及时获得服务 —— 有效地生成“延迟中断”方案。(注意 FreeRTOS 也有一个内置的延迟中断机制)。另一种方法是使用队列代替信号量。完成此操作后,中断程序可以捕获与外设事件相关的数据,并将其发送到任务队列中。当队列中的数据可用时,任务会解除阻塞,从队列中检索数据,然后执行所需的任何数据处理。第二种方案允许中断保持尽可能短的时间,所有的后处理都发生在一个任务中。
请注意,中断不得使用不以“FromISR
”结尾的 API 函数。
计数信号量
提示:在许多情况下,“任务通知”可以提供计数信号量的轻量级替代方案 |
正如二进制信号量可以被认为是长度为 1 的队列一样,计数信号量可以被认为是长度大于 1 的队列。同样,信号量的使用者对存储在队列中的数据不感兴趣——只关心队列是否为空。
计数信号量通常用于两件事:
-
计数事件。
在这种使用场景中,事件处理程序将在每次事件发生时“释放”一个信号量(增加信号量计数值),并且处理任务每次处理事件时将“获取”一个信号量(减少信号量计数值)。因此,计数值是已发生事件数与已处理事件数之差。在这种情况下,希望在创建信号量时计数值为零。
-
资源管理。
在此使用场景中,计数值指示可用资源的数量。要获得资源的控制权,任务必须首先获得信号量 —— 递减信号量计数值。当计数值达到零时,没有可用资源。当任务使用资源完成时,它会“释放”信号量 —— 增加信号量计数值。在这种情况下,希望在创建信号量时计数值等于最大计数值。