上次我们使用任务调度器实现了双任务的切换,在任务1和任务2函数中需要对 umTaskSched()函数进行多次调用,针对这个问题,下面提出关于是否可以自动周期调用umTaskSched()函数的方法。提出了一种基于时间片切换的方式,该方式如何触发?由谁来触发?使用定时器定时溢出产生中断来触发,该定时器就是Systick定时器,它是一个24位倒计数定时器,当计数到 0 时,将从RELOAD 寄存器中自动重装载定时初值,开始新一轮计数。只要不把它在 SysTick 控制及状态寄存器中的使能位清除,就永不停息。
初始化Systick定时器,让该定时器在n*ms时触发Systick中断,具体代码如下:
// Systick定时器初始化函数
void SetSysTickperiod(uint32_t ms)
{
SysTick->LOAD = ms*SystemCoreClock/1000-1; //Ô¤×°ÔØÖµ
NVIC_SetPriority(SysTick_IRQn,(1<<__NVIC_PRIO_BITS)-1);
SysTick->VAL = 0;
SysTick->CTRL = SysTick_CTRL_CLKSOURCE_Msk|
SysTick_CTRL_TICKINT_Msk|
SysTick_CTRL_ENABLE_Msk;
}
将任务中umTaskSched()函数转移到Systick中断函数中Systick_Hander() 具体代码如下:
//Systick中断函数
void Systick_Hander()
{
umTaskSched();
}
暂且将Systick定时器初始化函数,放置在第一个任务函数中,且将任务1和任务2函数中的 umTaskSched()函数移除,具体如下
最后需要修改下系统的时钟频率,将SystemCoreClock配置为12M,即是将__XTAL 配置为12000000u 分频系数__SYSTEM_CLOCK设置为1.
趁着媳妇睡着了,撩一下PendSV异常,本人在调试基于这个实验的时候死活进不去Task2中,花了几个小时一直找,一直找,最后发现是这个原因:在FirstTask()中,我之前没有在意,先是触发PendSV异常,然后再设置优先级,这样的操作导致我后面检查了好久才发现是这个原因,所以这里告诫大家,一些设备的初始化我们尽可能按着顺序来,避免不必要的时间浪费在这无休止的检查中。
最后我们来一起看一下效果吧!编译代码,Debug仿真运行,直接全速运行代码,下面是逻辑分析的波形,可以看到任务1和任务2执行的时间是相等的,即是Systick中断触发的时间,本次我们就完成了双任务时间片切换。