时间触发调度器

/********************************************************************************/
/******************************数据结构******************************************/
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();
	}

}

  • 1
    点赞
  • 13
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值