软件延时是让CPU空等来达到延时的效果。但是使用RTOS的优势其一就是榨干CPU性能,不让CPU空闲。软件延时违背了这一个初衷。于是便出现了阻塞延时,即任务如果需要延时,任务会放弃CPU的使用权,CPU去干其他事情,当任务延时时间到的时候任务重新获取CPU使用权继续运行,充分利用CPU资源。
而当多有任务都延时,CPU去干嘛?于是便出现了“空闲任务”,当没有其他任务可以运行的时候,CPU就去运行这个空闲任务。该空闲任务是RTOS系统在“启动调度器”的时候创建的一个优先级最低的任务,通常是一些系统内存清理的工作。
(但是为了简单起见,我们本章实现的空闲任务 只是对一个全局变量进行计数。鉴于空闲任务的这种特性,在实际应用中,当系统进入空 闲任务的时候,可在空闲任务中让单片机进入休眠或者低功耗等操作。)
1. 实现空闲任务
1.1 定义空闲任务的栈
通过静态创建任务的方式,定义空闲任务的栈,预先定义好空闲任务的栈空间。
1.2 定义空闲任务的任务控制块
TCB_t是系统定义的任务控制块数据类型,具体看我之前任务的创建与切换那篇。
1.3 创建空闲任务
定义好任务的栈,任务控制块后,加上main.c函数里面的任务函数主体,我们就可以创建空闲任务。其实就是正常的任务创建流程:
(1)获取空闲任务内存,也就是将pxIdleTaskTCBBuffer和pxIdleTaskStackBuffer这两个接下来要作为形参传到函数xTaskCreateStatic()的指针分别指向空闲任务的TCB和栈起始地址。这个操作由vApplicationGetIdleTaskMemory()函数来实现,具体代码如下:
(2)利用xTaskCreateStatic()函数创建空闲任务
(3)将空闲任务插入到就绪列表的开头,空闲任务的优先级是最低的。
2 阻塞延时
2.1 vTaskDelay()函数
阻塞延时函数vTaskDelay()在task.c中实现,在通过任务阻塞来实现任务延时,任务阻塞这段时间CPU可以去做其他任务。
(1)获取当前任务的任务TCB,pxCurrentTCB是task.c中的全局指针。
(2)xTicksToDelay是任务控制块的一个成员,用于记录任务需要延时的时间,单位是SysTick的中断周期。学过内核的应该对系统时钟SysTick有印象(递减到一定次数进入中断,这里记录的是进入中断的次数,比如SysTick的中断周期是10ms,10ms进一次中断,调用vTaskDelay(2)就可以实现2*10ms的延时),xTicksToDelay定义如下,在空闲任务的TCB中:
(3)调用任务切换函数taskYIELD()函数实现阻塞延时(任务切换)。
2.2 vTaskSwitchContext()函数
这个函数在任务的创建与切换那里就有设计,是一个用于任务切换的函数,但在涉及阻塞延时的时候,需要考虑优先级。vTaskSwitchContext()函数本来的作用就是寻找最高优先级的就绪任务,然后更新pxCurrentTCB。
(1)如果当前任务是空闲任务,那么就去尝试任务1或者任务2,看看他们是否在阻塞状态(延时是否结束),如果没有阻塞就切换任务,如果延时还没到期就继续执行空闲任务。【这里的空闲任务没有具体实现】
(2)如果当前任务是任务1或者任务2,就检查下一个任务是否在延时中,不在延时就切换到下一个任务,否则,判断一下当前任务是否应该进入延时,是的话就切到空闲任务,否则不进行任何切换。
3. SysTick中断服务函数
在vTaskToDelay上下文切换函数中,会判断每个任务的TCB中的延时成员xTicksToDelay的值是否为0,为0对应任务就绪,不为0则继续延时。xTicksToDelay在延时过程中不断递减,变为0则延时结束。而xTicksToDelay的递减周期(两次递减相隔多久)就是由SysTick中断提供(也就是系统时钟),SysTick中断服务函数如下:
(1)进入临界段,关中断【因为要操作xTickCount这个在port.c中的全局变量】
(2)更新系统时基,该函数定义在task.c中,其实就是两个事情,第一就是系统时基计数器累加;第二就是扫描所有就绪列表中正在延时的任务,把所有就绪列表中正在延时的任务的xTicksToDelay递减,如下:
(3)退出临界段,开中断。
4. SysTick初始化函数
学过STM32基础的小伙伴们都知道,要想使用系统时钟SysTick,我们首先要初始化它。初始化代码如下:
(1)配置SysTick需要用到的寄存器 和宏定义,可以通过查手册得到。在port.c中实现
(2)-①SysTick初始化函数vPortSetupTimerInterrupt()在启动调度器函数xPortStartScheduler()中被调用,用来设置SysTick。在宏定义中我们可以知道,如果没有定义configSYSTICK_CLOCK_HZ则configSYSTICK_CLOCK_HZ就等于在中FreeRTOSConfig.h的configSYSTICK_CLOCK_HZ,并且在FreeRTOSConfig.h还定义了configTICK_RATE_HZ,如下:
第一行设置了系统时钟,因为这里实验室软件仿真,所有手动设置成与ARMCM3文件中的SYSTEM_CLOCK一样,即25M。
第二行规定了SysTick每秒中断多少次,这里设置100次,就是1/100s=10ms一次中断。
(2)-②设置系统定时器的时钟等于内核时钟,使能SysTick定时器中断,使能SysTick定时器。(寄存器操作,可以查手册详细了解)
5. 实验
创建两个任务,实验类似于任务创建和切换,不重复了。
主要修改就是把任务一和任务二的软件延时函数换成了上面实现的阻塞延时函数vTaskDelay,在阻塞延时的过程中完成任务切换而不是通过protYIELD函数进行任务切换。
同时,还需要为空闲任务定义任务栈和TCB。
————————————————
版权声明:本文为CSDN博主「Crazyong」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/weixin_58754097/article/details/158769887
|
本帖子中包含更多资源
您需要 登录 才可以下载或查看,没有账号?注册
×
|