FreeRTOS学习---“补充知识点”篇

总目录

《FreeRTOS学习—“任务”篇》
《FreeRTOS学习—“消息队列”篇》
《FreeRTOS学习—“信号量”篇》
《FreeRTOS学习—“事件组”篇》
《FreeRTOS学习—“定时器”篇》

FreeRTOS系统的基础函数基本都介绍完了,这里补充一些知识点,其实这些知识点,在其他的操作系统中,也会有不同外观的体现,但是含义上大同小异。

在这里插入图片描述

任务状态

首先上一张图,状态分为两大类,左边的非运行态和右边的运行态。
在这里插入图片描述
非运行态又分为三种

  • 阻塞状态

如果一个任务正在等待某个事件,则称这个任务处于”阻塞态(blocked)”。阻塞态是非运行态的一个子状态。感觉这个状态是最常见的,CPU执行动作快的话,任务才感觉自己是唯一的存在,否则大家都忙着执行,肯定就CPU不够切换了。在这里插入图片描述
任务可以进入阻塞态以等待以下两种不同类型的事件:

类型意义例子
定时(时间相关)事件这类事件可以是延迟到期或是绝对时间到点。比如说某个任务可以进入阻塞态以延迟 10ms。延迟函数
同步事件源于其它任务或中断的事件。比如说,某个任务可以进入阻塞态以等待队列中有数据到来。同步事件囊括了所有板级范围内的事件类型。队列,二值信号量,计数信号量,互斥信号量(recursive semaphore,递归信号量,本文一律称为互斥信号量,因为其主要用于实现互斥访问)和互斥量

任务可以在进入阻塞态以等待同步事件时指定一个等待超时时间,这样可以有效地实现阻塞状态下同时等待两种类型的事件。比如说,某个任务可以等待队列中有数据到来,但最多只等
10ms。如果 10ms 内有数据到来,或是 10ms 过去了还没有数据到来,这两种情况下该任务都将退出阻塞态。

  • 挂起状态

“挂起(suspended)”也是非运行状态的子状态。处于挂起状态的任务对调度器而言是不可见的。让一个任务进入挂起状态的唯一办法就是调用 vTaskSuspend() API 函数;而把一个挂起状态的任务唤 醒的唯一途径就是调用 vTaskResume() 或vTaskResumeFromISR() API 函数。

这个是很少用到的状态,除非调用了前面的挂起函数,大多数应用程序中都不会用到挂起状态。
在这里插入图片描述

  • 就绪状态

如果任务处于非运行状态,但既没有阻塞也没有挂起,则这个任务处于就绪(ready,准备或就绪)状态。处于就绪态的任务能够被运行,但只是”准备(ready)”运行,而当前尚未运行。
此时任务就处在一个等待调度器的状态,不过下一个是不是他,还不确定,需要看看优先级再决定
在这里插入图片描述

任务切换

推荐FreeRTOS使用优先级抢占式调度

  • 每个任务都赋予了一个优先级。
  • 每个任务都可以存在于一个或多个状态。
  • 在任何时候都只有一个任务可以处于运行状态。
  • 调度器总是在所有处于就绪态的任务中选择具有最高优先级的任务来执行。

结合上图,那就是调度器,总是在Ready状态的任务列表中,选择优先级最高的,使其进入运行态。

在这里插入图片描述
要是不抢占,那还要优先级有啥用,优先级才是硬道理
在这里插入图片描述

临界区

多任务系统中存在一种潜在的风险。当一个任务在使用某个资源的过程中,即还没有完全结束对资源的访问时,便被切出运行态,使得资源处于非一致,不完整的状态。如果这个时候有另一个任务或者中断来访问这个资源,则会导致数据损坏或是其它相似的错误。

所以访问一个被多任务共享,或是被任务与中断共享的资源时,需要采用“互斥”技术以保证数据在任何时候都保持一致性。这样做的目的是要确保任务从开始访问资源就具有排它性,直至这个资源又恢复到完整状态。

例如我们去访问LCD显示屏,IIC总线,UART线,等,我们都不会希望传输的内容被别人打断对吧。
在这里插入图片描述

  • 基本临界区方式

通过将代码放在下面两个函数之间。

taskENTER_CRITICAL()
/*
保护内容
*/
taskEXIT_CRITICAL()

进行临界区保护。 在taskENTER_CRITICAL() 与 taskEXIT_CRITICAL()之间的操作不会切换到其它任务。 中断可以执行,也允许嵌套,但只是针对优先级高于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断 – 而且这些中断不允许访问FreeRTOS API 函数。

临界区是提供互斥功能的一种非常原始的实现方法。临界区的工作仅仅是简单地把中断全部关掉,或是关掉优先级在
configMAX_SYSCAL_INTERRUPT_PRIORITY 及以下的中断——依赖于具体使用的 FreeRTOS
移植。抢占式上下文切换只可能在某个中断中完成,所以调用
taskENTER_CRITICAL()的任务可以在中断关闭的时段一直保持运行态,直到退出临界区。
临界区必须只具有很短的时间,否则会反过来影响中断响应时间。在每次调用taskENTER_CRITICAL()之后,必须尽快地配套调用一个
taskEXIT_CRITICAL()。从这个角度来看,对标准输出的保护不应当采用临界区,因为写终端在时间上会是一个相对较长的操作。
临界区嵌套是安全的,因为内核有维护一个嵌套深度计数。临界区只会在嵌套深度为 0 时才会真正退出——即在为每个之前调用的
taskENTER_CRITICAL()都配套调用了 taskEXIT_CRITICAL()之后。

  • 挂起(锁定)调度器

也可以通过挂起调度器来创建临界区。挂起调度器有些时候也被称为锁定调度器。
通过将代码放在下面两个函数之间。

void vTaskSuspendAll( void );
portBASE_TYPE xTaskResumeAll( void );

基本临界区保护一段代码区间不被其它任务或中断打断。由挂起调度器实现的临界区只可以保护一段代码区间不被其它任务打断,因为这种方式下,中断是使能的。
如果一个临界区太长而不适合简单地关中断来实现,可以考虑采用挂起调度器的方式。但是唤醒(resuming or unsuspending)调度器却是一个相对较长的操作。所以评估哪种是最佳方式需要结合实际情况。
嵌套调用 vTaskSuspendAll()和 xTaskResumeAll()是安全的,因为内核有维护一个嵌套深度计数。调度器只会在嵌套深度计数为 0 时才会被唤醒——即在为每个之前调用的 vTaskSuspendAll()都配套调用了 xTaskResumAll()之后。

  • 互斥量

通过使用互斥量或者二值信号量,也可以达到保护临界资源的目的。

互斥量是一种特殊的二值信号量,用于控制在两个或多个任务间访问共享资源。单词MUTEX(互斥量)源于”MUTual EXclusion”。
在用于互斥的场合,互斥量从概念上可看作是与共享资源关联的令牌。一个任务想要合法地访问资源,其必须先成功地得到(Take)该资源对应的令牌(成为令牌持有者)。
当令牌持有者完成资源使用,其必须马上归还(Give)令牌。只有归还了令牌,其它任务才可能成功持有,也才可能安全地访问该共享资源。一个任务除非持有了令牌,否则不允许访问共享资源。

  • 守护进程

前面的方法只是告诉不让别人动你的蛋糕,万一碰上不守规矩的,还是会出事情
在这里插入图片描述
所以守护任务才是最好的方式。
守护任务提供了一种干净利落的方法来实现互斥功能,而不用担心会发生优先级反转和死锁。
守护任务是对某个资源具有唯一所有权的任务。只有守护任务才可以直接访问其守护的资源——其它任务要访问该资源只能间接地通过守护任务提供的服务。
例如,我们访问LCD,可以建立一个消息队列来管理要显示的内容,有一个守护任务来控制显示,只有它才能操作LCD,这样就不会有问题了。
在这里插入图片描述

FreeRTOS 提供了多种特性用以实现互斥,但是最好的互斥方法(如果可能的话,任何时候都当如此)还是通过精心设计应用程序,尽量不要共享资源,或者是每个资源都通过单任务访问。

结束语

没事看看各大公司的招聘信息,就大概能知道学什么东西是有价值的,有市场的,这和搞研发是一个性质,市场需要什么,就做什么,而不是做一个东西,去找市场。操作系统这些知识点,还是比较具备通用性的。
在这里插入图片描述
今年得减肥了,一颗星的健康怕是有点扛不住。减了肥容易婚外情吗?
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

胖哥王老师

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值