前言
本片文章记录我学习FreeRTOS中的“临界段”知识点,同时也希望我的分享能给你带来帮助
目录
前言
一、临界段(临界区)
二、任务级临界段代码
三、中断级临界段代码保护
四、结语
一、临界段(临界区)
在FreeRTOS的学习中,涉及中断的内容部分,我们会见到“临界段代码”这种描述。但是具体什么是临界段代码呢?下面记录一下我的学习理解。
临界段代码也叫做临界区,是指那些必须完整运行,不能被打断的代码段!!!
比如有的外设的初始化需要严格的时序,初始化过程中不能被打断。FreeRTOS在进入临界段代码的时候需要关闭中断,当处理完临界段代码以后再打开中断。
FreeRTOS系统本身就有很多的临界段代码,这些代码都加了临界段代码保护,我们在写自己的用户程序的时候有些地方也需要添加临界段代码保护。
FreeRTOS与临界段代码保护有关的函数有4个:
1、taskENTER_CRITICAL()
2、taskEXIT_CRITICAL()
3、taskENTER_CRITICAL_FROM_ISRO
4、taskEXIT_CRITICAL_FROM_ISR()这四个函数其实是宏定义,在 task.h文件中有定义。
这四个函数的区别是前两个是任务级的临界段代码保护,后两个是中断级的临界段代码保护
二、任务级临界段代码
taskENTER_CRITICAL()和 taskEXIT_CRITICAL()是任务级的临界代码保护,一个是进入临界段,一个是退出临界段,这两个函数是成对使用的,这函数的定义如下:
而portENTER_CRITICAL()和portEXIT_CRITICAL()也是宏定义,在文件 portmacro.h 中有定义,如下:
函数vPortEnterCritical()和 vPortExitCritical()在文件 port.c中,函数如下:
可以看出在进入函数vPortEnterCritical()以后会首先关闭中断,然后给变uxCriticalNesting加一,uxCriticalNesting是个全局变量,用来记录临界段嵌套次数的。
函数vPortExitCTitical()是退出临界段调用的,函数每次将uxCriticalNesting减一,只有当uxCriticalNesting为0的时候才会调用函数portENABLE_INTERRUPTS()使能中断。
这样保证了在有多个临界段代码的时候不会因为某一个临界段代码的退出而打乱其他临界段的保护,只有所有的临界段代码都退出以后才会使能中断!任务级临界代码保护使用方法如下:
void taskcritical_test(void) {while(1){taskENTER_CRITICAL(); //(1)进入临界区total_num+=0.01f; printf("total_num 的值为:%.4frln",total_num);taskEXIT_CRITICAL(); //(2)退出临界区vTaskDelay(1000);} }
(1)和(2中间的代码就是临界区代码,注意临界区代码一定要精简!
因为进入临界区会关闭中断,这样会导致优先级低于configMAX_SYSCALL_INTERRUPT_PRIORITY的中断得不到及时的响应!!!!
三、中断级临界段代码保护
函数taskENTER_CRITICAL_FROM_ISR()和 taskEXIT_CRITICAL_FROM_ISR()中断级别临界段代码保护,是用在中断服务程序中的,而且这个中断的优先级一定要低于configMAX_SYSCALL_INTERRUPT_PRIORITY!原因前面已经说了。这两个函数在文件task.h中有如下定义:
接着找portSET_INTERRUPT_MASK_FROM_ISR()和portCLEAR_INTERRUPT_MASK_FROM_ISR(),这两个在文件portmacro.h中有如下定义:
vPortSetBASEPRIO()前面已经说过了,就是给BASEPRI寄存器中写入一个值。函数ulPortRaiseBASEPRI()在文件portmacro.h中定义的,如下:
(1)、先读出BASEPRI的值,保存在ulReturn 中。
(2)、将configMAX_SYSCALL_INTERRUPT_PRIORITY 写入到寄存器BASEPRI 中。(3)、返回ulReturn,退出临界区代码保护的时候要使用到此值!
中断级临界代码保护使用方法如下:
(1)进入临界区
(2)退出临界区
四、结语
关于FreeRTOS临界段的知识就记录至此了,希望我的分享对你有所帮助!