FreeRTOS——信号量,互斥锁,临界区,延时
目录
- 一、FreeRTOS的时间管理
- 二、FreeRTOS资源管理
一、FreeRTOS的时间管理
在FreeRTOS中每个任务都是独立的,并且每个任务都是不会返回的,而FreeRTOS内核一般采用抢占式调度算法调度任务,如果某个任务的优先级是最高的,而该任务又没有实现阻塞,则会出现其他任务无法运行的现象,所以必须要求任务可以阻塞,才可以把CPU资源让给其他任务。
基于这样的需求,FreeRTOS提供了两个函数,一个是相对延时函数vTaskDelay(),另一个是绝对延时函数vTaskDelayUntil()。
相对延时函数
vTaskDelay()函数用于阻塞延时,调用该函数之后,任务就会进入阻塞态,然后就可以把CPU资源让给其他任务,但是需要注意,该函数属于相对延时函数,就是说任务从调用该函数之后开始延时,经过指定的延时时间之后结束,延时时间取决于系统Systick时钟节拍的周期,该函数并不适合用于周期性执行任务。
绝对延时函数
通过刚才的分析,可以知道相对延时函数可能会受到外界因素的干扰导致时间出现偏差,基于这样的考虑,FreeRTOS提供了一个绝对延时函数vTaskDelayUntil(),该函数也可以实现周期性的延时,但是不同的是,该函数的延时时间是精准的。
自定义延时函数
通过刚才的学习,已经知道FreeRTOS实时操作系统中设置的Sysytick嘀嗒定时器的tick的时钟节拍(嘀嗒中断的频率)设置的频率为1000HZ,也就是说不管相对延时函数还是绝对延时函数,延时时间都是以毫秒为单位,并且FreeRTOS并没有提供以微秒为单位的延时函数,所以用户就可以自行优化之前的delay_us()和delay_ms()函数。
之前设计的延时函数是直接控制Systick定时器的寄存器实现的,但是现在Systick必须交给FreeRTOS,所以用户需要修改自己的延时函数。
二、FreeRTOS资源管理
FreeRTOS是一个多任务的操作系统,但是在多任务系统中可能会存在一种潜在的风险,就是当一个任务在使用某个资源的过程中,可能会出现优先级更高的任务打断该任务对资源的访问的情况,这样会导致资源变得不完整,也就是会导致数据丢失或者损坏。
所以在访问一个被多任务共享或是被任务与中断共享的资源时,需要采用”互斥”技术以保证数据在任何时候都保持一致性。这样做的目的是要确保任务从开始访问资源就具有排它性,直至这个资源又恢复到完整状态。
FreeRTOS提供了多种方案来实现互斥,最常用的方案是使用临界区、挂起调度器、使用信号量、使用互斥型信号量,具体采用哪种方案取决于访问共享资源的速度,但是最好的互斥方法(如果可能的话,任何时候都当如此)还是通过精心设计应用程序,尽量不要共享资源,或者是每个资源都通过单任务访问。
使用临界区
临界区也被称为临界段,其实就是指一段程序在运行的过程中不能被打断,思考:什么情况下程序运行时会被打断? 回答:任务切换 and 触发中断。
系统调度的本质也是产生一个PendSV中断,所以两者可以理解为都是由于触发中断导致程序运行时被打断,而临界区的实现机制就是通过简单的禁用中断来实现。
所以该方案适用于访问共享资源速度很快的场合(比如任务和中断服务函数共享的全局变量、执行喂狗操作、读写少量数据、对Flash进行读取等)。
挂起调度器
可以发现临界区的使用可能会影响系统中断延时,为了解决这个影响FreeRTOS提供了另一种方案,那就是在任务中可以对系统调度器进行挂起,由于FreeRTOS的任务都是通过调度器进行调度,所以当某个任务执行过程中把调度器挂起之后,其他的任务就无法切换,此时也就意味着挂起调度器的这个任务的优先级就变为了最高,只有当该任务恢复调度器,才会进行任务上下文的切换。
当然,任务在挂起调度器之后虽然不会进行任务上下文的切换,但是系统的中断还是可以正常工作的,思考:当调度器被挂起后能否在中断程序中恢复调度器?? 回答:是不可以!
该方案适合在访问比如缓冲区数据、变量自加自减等某些共享资源时使用,或者可以用在某些不能被拆分的程序中,比如某些硬件的初始化中会使用很多延时函数,此时又不能被其他任务抢占,就可以采用该方案。
使用信号量
对于信号量而言,大家并不陌生,在学习linux系统进程与线程时就已经了解过了,使用信号量可以实现任务之间的同步以及临界资源的互斥访问,其实信号量的本质就是一个非负整数,用这个数字表示资源的数量,任务可以申请信号量(P操作),当某任务申请一次,则该值减一,表示资源较少,当该值为零就表示无可用资源,则其他等待信号量的任务就会进入阻塞态,所以任务申请信号量并且使用完成后应该主动释放信号量(V操作)。
FreeRTOS中提供了多种类型的信号量,比如有二进制信号量、计数型信号量、互斥型信号量等,每种信号量都提供了对应的API函数接口,可以参考FreeRTOS的官网文档资料。
使用互斥锁