上图是官方的说明,系统通过定时器0设定1ms的时间作为各个任务的调度基准时钟,在任务的组件数组里面定义每个任务的的状态、计数器、周期、执行函数。
首先咱们看第一句话,定时器0作为任务调度的基准时钟。定时器0是在系统初始化的时候就开启了一个1ms一次的中断。
第二句话任务组件数组里定义里面定义每个任务的的状态、计数器、周期、执行函数。这句话告诉我们Task_Comps[]是一个任务组件数组。查看TASK_COMPONENTS的定义是一个结构体,实际上Task_Comps[]就是一个结构体数组。
typedef struct
{
u8 Run; //任务状态:Run/Stop
u16 TIMCount; //定时计数器
u16 TRITime; //重载计数器
void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;
通过typedef struct 方式声明结构体TASK_COMPONENTS,然后用TASK_COMPONENTS创建 Task_Comps[]结构体数组并赋值。注意通过typedef struct 方式声明的结构体TASK_COMPONENTS使用时相当于struct TASK_COMPONENTS。结构体里面的void (*TaskHook) (void)是一个函数指针,需要传一个无参无返回值的函数地址进去,因为函数名本身就是指针,所以直接传进去函数名就可以了。
static TASK_COMPONENTS Task_Comps[]=
{
//状态 计数 周期 函数
{0, 250, 250, Sample_Lamp}, /* task 1 Period: 250ms */
{0, 500, 500, Sample_ADtoUART}, /* task 2 Period: 500ms */
/* Add new task here */
};
下面这句话是算出有几个任务
u8 Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps[0]);
然后看下一句, 计数器每ms减1,为0时设置状态位,并将周期时间重载到计数器里。我们看一下是怎么实现的,首先计数器每ms减1上面说了是通过定时器0中断实现的,我们看一下定时器0的中断函数。
void Timer0_ISR_Handler (void) interrupt TIMER0_VECTOR //进中断时已经清除标志
{
Task_Marks_Handler_Callback(); //任务标记回调函数
}
定时器0调用了Task_Marks_Handler_Callback()任务标记回调函数,因为定时器0 1ms产生一次中断,所以这个任务标记回调函数就是1ms运行一次。下面看一下任务回调函数:
void Task_Marks_Handler_Callback(void)
{
u8 i;
for(i=0; i<Tasks_Max; i++)
{
if(Task_Comps[i].TIMCount) /* If the time is not 0 */
{
Task_Comps[i].TIMCount--; /* Time counter decrement */
if(Task_Comps[i].TIMCount == 0) /* If time arrives */
{
/*Resume the timer value and try again */
Task_Comps[i].TIMCount = Task_Comps[i].TRITime;
Task_Comps[i].Run = 1; /* The task can be run */
}
}
}
}
任务回调函数每次运行,通过for(i=0; i<Tasks_Max; i++)循环每个任务结构体,如果这个任务的定时计数器不是0,定时计数器减1,如果定时计数器为0了,那就把重载计数器的值赋给定时计数器,然后把任务状态置1,表示这个任务需要运行一下了。
最后一句话,任务处理函数检查每个任务的状态,如果置位的话执行对应函数。需要运行的任务在任务处理回调函数void Task_Pro_Handler_Callback(void)中处理,我们先看一下主函数
void main(void)
{
SYS_Init();
while (1)
{
Task_Pro_Handler_Callback();
}
}
进入主函数后,先运行系统初始化SYS_Init()来初始化定时器0,开启1ms一次的定时器中断和总中断,然后进入while循环调用任务处理回调函数。也就是说这个任务处理函数是只要任务状态置1了,就可以马上去处理这个任务,下面看一下任务处理函数:
void Task_Pro_Handler_Callback(void)
{
u8 i;
for(i=0; i<Tasks_Max; i++)
{
if(Task_Comps[i].Run) /* If task can be run */
{
Task_Comps[i].Run = 0; /* Flag clear 0 */
Task_Comps[i].TaskHook(); /* Run task */
}
}
}
任务处理函数很好理解,每个人任务循环一边,只要任务状态 Task_Comps[i].Run为1,清零状态位Task_Comps[i].Run = 0,然后运行任务Task_Comps[i].TaskHook()。