/********************************************************************************/
/******************************数据结构******************************************/
typedef tWord unsigned int;
typedef tByte unsigned char;
//可能的话,存储在DATA区,以供快速存取
//每个任务的存储总和是7个字节
typedef data struct
{
//指向任务的指针,必须是一个void(void)函数
void (code *pTask)(void);
//延迟(时标)直到函数将(下一次)运行
tWord Delay;
//连续运行之间的间隔(时标)
tWord Period;
//当任务需要运行时(由调度器)加1
tByte RunMe;
}sTask;
#define SCH_MAX_TASKS (3)
//定义创建任务队列
sTask SCH_tasks_G[SCH_MAX_TASKS];
/***************************初始化函数*******************************************/
/********************************************************************************/
/*SCH_Init_T2()。调度器初始化函数,准备调度器数据结构并且设置定时器以所需的频率 */
/*中断,必须在使用调度器之前调用这个函数,定时溢出初始化时标间隔为1ms */
/********************************************************************************/
void SCH_Init_T2(void)
{
TBYTE i;
for (i = 0; i < SCH_MAX_TASKS; i++)
{
SCH_Delete_Task(i);
}
//复位全局错误变量,SCH_Delete_Task将产生一个错误代码(因为任务队列是空的)
Error_Code_G = 0;
//设置定时器2,自动重装、16位定时功能。
//晶振假定为12MHz,定时器2的精度是1us,要求的定时器2溢出为1ms
//需要1000个定时器时标,重装值为65536-1000 = 64536 = 0xFC18
//代码略....
}
/***************************刷新函数*********************************************/
/********************************************************************************/
/*SCH_Updata()这是调度器的中断服务程序,初始化函数中的定时器决定了它的调用频率 */
/*这个版本由定时器2中断触发,定时器自动重装 */
/********************************************************************************/
void SCH_Update(void) interrupt INTERRUPT_Timer_2_Overflow
{
tByte Index;
TF2 = 0;//必须手工清除
//注意计算单位为"时标"(不是毫秒)
for (Index = 0; Index < SCH_MAX_TASKS; Index++)
{
//检测这里是否有任务
if (SCH_tasks_G[Index].pTask)
{
if (SCH_tasks_G[Index].Delay == 0)
{
//任务需要运行
SCH_tasks_G[Index].RunMe += 1;//RunMe标志加1
if (SCH_tasks_G[Index].Period)
{
//调度周期性的任务再次运行
SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Period;
}
else
{
//还没准备好运行,延迟减1
SCH_tasks_G[Index].Delay -= 1;
}
}
}
}
}
/***************************添加任务函数*****************************************/
/********************************************************************************/
/*SCH_Add_Task()使任务(函数)每隔一定间隔或在用户定义的延迟之后执行 */
/*参数:pFunction需要调度的函数名称 */
/* Delay任务第一次执行前的延迟,设置为0任务立即执行 */
/* Period任务重复运行的时标间隔,如果为0任务只执行一次 */
/********************************************************************************/
tByte SCH_Add_Task(void (code * pFunciton)[], const tWord Delay, const tWord PERIDO)
{
tByte Index = 0;
//首先在队列中找到一个空隙(如果有的话)
while ((SCH_tasks_G[Index].pTask != 0) && (Index < SCH_MAX_TASKS))
{
Index++;
}
//是否已经到达队列的结尾?
if (Index == SCH_MAX_TASKS)
{
//任务队列已满
//设置全局错误变量
Error_code_G = ERROR_SCH_TOO_MANY_TASKS;
//同时返回错误代码
return SCH_MAX_TASKS;
}
//如果能脑诵说这里说明任务队列有空间
SCH_tasks_G[Index].pTask = pFunciton;
SCH_tasks_G[Index].Delay = Delay;
SCH_tasks_G[Index].Period = PERIDO;
SCH_tasks_G[Index].RunMe = 0;
return Index;//返回任务的位置(以便以后删除)
}
/***************************"调度"程序函数***************************************/
/********************************************************************************/
/*SCH_Dispatch_Task()这是"调度程序",当任务(函数需要运行时)SCH_Dispatch_Task()*/
/*将运行它。这个函数必须被主循环(重复)调用 */
/********************************************************************************/
void SCH_Dispatch_Task(void)
{
tByte Index;
//调度运行下一个任务(如果有任务就绪)
for (Index = 0; Index < SCH_MAX_TASKS; Index++)
{
if (SCH_tasks_G[Index].RunMe > 0)
{
*SCH_tasks_G[Index].pTask(); //执行任务
SCH_tasks_G[Index].RunMe -= 1; //复位/减小RunMe标志
//周期性的任务将自动再次运行,如果是单次任务,则将它从队列中删除
if (SCH_tasks_G[Index].Period == 0)
{
SCH_Delete_Task(Index);
}
}
}
//报告系统状况
SCH_Report_Status();
//这里调度器进入空闲模式
SCH_Go_To_Sleep();
}
/***************************删除任务函数*****************************************/
/********************************************************************************/
/*SCH_Delete_Task()删除任务函数 */
/********************************************************************************/
bit SCH_Delete_Task(const tByte TASK_INDEX)
{
bit Return_code;
if (SCH_tasks_G[Index].pTask == 0)
{
//这里没有任务
//设置全局变量错误
Error_code_G = ERROR_SCH_CANNOT_DELETE_TASK;
Return_code = RETURN_ERROR;
}
else
{
Return_code = RETURN_NORMAL;
}
SCH_tasks_G[Index].pTask 0;
SCH_tasks_G[Index].Delay = 0;
SCH_tasks_G[Index].Period = 0;
SCH_tasks_G[Index].RunMe = 0;
return Return_code;
}
/***************************降低功耗函数*****************************************/
/********************************************************************************/
/*软件控制进入空闲模式,而当微处理器收到任何中断时返回正常运行模式 */
/********************************************************************************/
void SCH_Go_To_Sleep()
{
PCON |= 0X01; //进入空闲模式
}
/***************************报告错误函数*****************************************/
/********************************************************************************/
/*此函数由刷新函数调用,用来报告这些错误代码 */
/********************************************************************************/
void SCH_Report_Status(void)
{
#if SCH_REPORT_ERRORS
//只在需要报告错误时适用
//检查新的错误代码
//代码略
#endif
}
/***************************开始函数*********************************************/
/********************************************************************************/
/*在所有的任务都被添加之后,将调用这个函数来开始调度过程 */
/********************************************************************************/
void SCH_Start(void)
{
EA = 1;
}
int main(int argc, char* argv[])
{
//设置调度器
SCH_Init_T2();
//为Flash_LED任务做准备
LED_Flash_Init();
//增加FLash LED任务(1000ms亮,1000ms灭)
//定时单位为时标(1ms间隔)
SCH_Add_Task(LED_Flash_Update, 0, 1000);
//开始调度器
SCH_Start();
while (1)
{
SCH_Dispatch_Task();
}
}
时间触发调度器
最新推荐文章于 2023-03-13 01:03:22 发布