结构体数组的周期性调度
本节知识点还是挺多的,而且不是那么容易理解。
1.首先创建了task.c和task.h的文件
在task.c文件中,定义一个结构体:
static TASK_COMPONENTS Task_Comps[]=
{
//状态 计数 周期 函数
{0, 300, 300, Led0_Blink}, /* 300ms执行一次 */
{0, 600, 600, Led1_Blink}, /* 600ms执行一次 */
{0, 900, 900, Led2_Blink}, /* 900ms执行一次 */
{0, 10, 10, key_task}, /* 10ms执行一次 */
/* Add new task here */
};
任务标记回调函数:void Task_Marks_Handler_Callback(void),此函数的作用是对结构体中的每一组元素根据计数值进行倒数,当倒数到0时,计数重置为计数周期,并且第一位run置1,从而调用相应的任务执行函数。
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 */
}
}
}
}
任务处理回调函数:void Task_Marks_Handler_Callback(void),此函数的作用是当run置一后,执行相应的函数。
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.c
#include "task.h"
#include "io.h"
static TASK_COMPONENTS Task_Comps[]=
{
//状态 计数 周期 函数
{0, 300, 300, Led0_Blink}, /* 300ms执行一次 */
{0, 600, 600, Led1_Blink}, /* 600ms执行一次 */
{0, 900, 900, Led2_Blink}, /* 900ms执行一次 */
{0, 10, 10, key_task}, /* 10ms执行一次 */
/* Add new task here */
};
u8 Tasks_Max = sizeof(Task_Comps)/sizeof(Task_Comps[0]);
//========================================================================
// 函数: Task_Handler_Callback
// 描述: 任务标记回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2012-10-22
//========================================================================
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 */
}
}
}
}
//========================================================================
// 函数: Task_Pro_Handler_Callback
// 描述: 任务处理回调函数.
// 参数: None.
// 返回: None.
// 版本: V1.0, 2012-10-22
//========================================================================
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.h文件中,有结构体声明及回调函数的声明
#ifndef __TASK_H
#define __TASK_H
#include "config.h"
typedef struct
{
u8 Run; //任务状态:Run/Stop
u16 TIMCount; //定时计数器
u16 TRITime; //重载计数器
void (*TaskHook) (void); //任务函数
} TASK_COMPONENTS;
void Task_Marks_Handler_Callback(void);
void Task_Pro_Handler_Callback(void);
#endif
那之前p00每300ms闪烁一次,p01每600ms闪烁一次,p02每900ms闪烁一次为例
增加了io.c和io.h文件,将io口的配置转移到这里。
io.c文件
#include "io.h"
u16 key_vol=0;
void Led0_Blink(void){
P00=!P00;
}
void Led1_Blink(void){
P01=!P01;
}
void Led2_Blink(void){
P02=!P02;
}
void key_task(void){
if(P32==0){
key_vol++;
if(key_vol==5){
//按键按下的任务
printf("按键单机\r\n");
}
}
else{
key_vol=0;
}
}
io.h文件
#ifndef __IO_H
#define __IO_H
#include "config.h"
void Led0_Blink(void);
void Led1_Blink(void);
void Led2_Blink(void);
void key_task(void);
#endif
main.c
#include "config.h"
#include "task.h"
char *USER_DEVICEDESC = NULL;
char *USER_PRODUCTDESC = NULL;
char *USER_STCISPCMD = "@STCISP#";
void main(void)
{
sys_init();
usb_init(); //USB CDC 接口配置
IE2 |= 0x80; //使能USB中断
Timer0_Init(); //定时器初始化
EA = 1; //IE |= 0X80;
P40=0;
while (DeviceState != DEVSTATE_CONFIGURED); //等待USB完成配置
while(1)
{
if (bUsbOutReady) //如果接收到了数据
{
//USB_SendData(UsbOutBuffer,OutNumber); //发送数据缓冲区,长度(接收数据原样返回, 用于测试)
usb_OUT_done(); //
}
Task_Pro_Handler_Callback(); //执行函数
}
}
void Timer0_Isr(void) interrupt 1
{
Task_Marks_Handler_Callback(); //系统计时
}