在单片机编程中,时间片轮询法是鉴于裸机编程与RTOS编程之间的。如果你熟练使用时间片轮询发的话,RTOS可以肯定也使用很6。
时间片轮询使用
在使用时间片轮询法的话,我们需要创建一个任务结构体:
struct TaskStruct
{
u16 TaskTickNow;//用于计时
u16 TaskTickMax;//设置计时时间
u8 TaskStatus;//任务运行标志位
void (*FC)();//任务函数指针
};
struct TaskStruct taskStruct[] = {
{ 0, 5000, 0, OLED_Task},
{ 0, 2000, 0, LED_Task},
{ 0, 20, 0, Hx711_Task},
{ 0, 20, 0, key3_Task},
{ 0, 20, 0, key2_Task},
{ 0, 20, 0, key1_Task},
{ 0, 20, 0, key0_Task},
{ 0, 1000, 0, debug_Task},
};
我们需要一个定时器触发中断函数,进行累加。给单片机赋予一个时间概念,时间片一般为1ms。
//定时器中断
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update) != RESET)
{
OS_Run();
TIM_ClearITPendingBit(TIM2,TIM_IT_Update);
}
}
void OS_Run(void)
{
u8 i;
for(i=0;i<TaskCount;i++)
{
if(!taskStruct[i].TaskStatus)
{
if(++taskStruct[i].TaskTickNow >= taskStruct[i].TaskTickMax)
{
taskStruct[i].TaskTickNow = 0;
taskStruct[i].TaskStatus = 1;
}
}
}
}
在while循环中添加:
int main()
{
while(1)
{
if(taskStruct[i].TaskStatus)
{
taskStruct[i].FC();
taskStruct[i].TaskStatus = 0;
}
if(++i>=TaskCount)
i = 0;
}
}
时间片轮询法注意事项
1.由于时间片轮询法延时不是绝对准确,例如,任务A周期100ms,当时间线来到100ms那个节点,现在应该去执行任务A,但如果当前有之前任务还没执行完,将会让任务A执行周期变得不准确,并不是100ms,可能是103ms。
这样也引出Freertos里面一些任务需要用绝对延时vTaskDelayUntil()与vTaskDelay()
2.时间片轮询里面不能使用delay_ms(),将CPU卡死。可以使用
//task任务执行周期是100ms
void task()
{
static u8 u8cnt1 = 0;
if(u8cnt1++ >= 2) // 200ms执行里面
{
}
}
3.裸机时间片轮询编程中有些任务不能太长,需要切开step1,step2,step3比较好