⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 sch51.c

📁 《时间触发嵌入式系统设计模式》一书中的合作式调度器的算法
💻 C
字号:
/*--------------------------------------------------------------------*-

	SCH51.C (V1.00)

	这里是调度器的内核函数,这个函数可以用于所有的8051芯片.
	
    --- SCH_MAX_TASKS必须由用户设置 ----
	 
-*---------------------------------------------------------------------*/

/*
 * Copyright (c) 2006
 * All rights reserved
 * 
 * 文件名称: SCH51.C 
 * 文件标识: 
 * 摘	 要: 内核函数
 * 
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期:
 ************************************************************************/

#include"main.H"
#include"Port.H"
#include"SCH51.H"
#include "MMI.h"
#include"Uart.h"
#include"LedDisp.h"
#include"key.h"


/*私有函数*/
static void SCH_Updata(void);
static void SCH_Report_Status(void);
//---------------公用常数-------------------------------
// 在任一时刻要求的任务最大数目
// 每个新建项目都必须调整
#define SCH_MAX_TASKS (8)
//-------公用变量定义-----------------------------------------------------
// 任务队列
sTask SCH_tasks_G[SCH_MAX_TASKS];



#define RETURN_NORMAL (bit)0
#define RETURN_ERROR (bit)1
// 错误代码
#define ERROR_SCH_TOO_MANY_TASKS (1)
#define ERROR_SCH_CANNOT_DELETE_TASK (2)
// 用来显示错误代码
static unsigned char Error_code_G = 0;
static unsigned char RTCCounter = 0;


/*---------------------------------------------------------*-
 * 函数名称: SCH_Update_Server()
 * 入	 口: 
 * 出	 口:
 * 函数功能: 调度器的中断服务程序
 * 
 * 说	 明: "刷新"函数,确定某个任务需要运行时,将这个任务的
 * 			 RunMe标志加1,然后该任务将由调度程序执行.
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期:
-*---------------------------------------------------------*/
void SCH_Update_Server(void)interrupt 5 
{
	static unsigned char KeytimeRunCnt;
	TF2 = 0; // 必须手工清除
	
	if( (++RTCCounter == 200) )
	{	
		RTCCounter = 0;
		RTC_Soft_clock();			/*定时器例行程序*/
		/*每秒钟查询一次是否有闹铃时间到*/
		if (RingIDRegister > 0)
		{	/*响铃*/
			Ring_server();
		}
	}

	if (++KeytimeRunCnt == 2)
	{
		KeytimeRunCnt = 0;
		KeyPad();		/*每10毫秒扫描一次键盘*/
	}
	FlashFreq();
	SCH_Updata();
}


/*---------------------------------------------------------*-
 * 函数名称: SCH_Dispatch_Tasks()
 * 入	 口: 
 * 出	 口:
 * 函数功能: 调度函数,当一个任务()需要运行时,此函数将运行它,
 * 
 * 说	 明: 这个函数必须被主循环(重复)调用 
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期:
-*---------------------------------------------------------*/
void SCH_Dispatch_Tasks(void)
{
	unsigned char Index;

	// 调度(运行)下一个任务(如果有任务就绪)
	for (Index=0; Index<SCH_MAX_TASKS; Index++)
	{
		if (SCH_tasks_G[Index].RunMe > 0)
		{
			// 运行任务
			(*SCH_tasks_G[Index].pTask)();
			// 复位 / 降低RunMe标志
			SCH_tasks_G[Index].RunMe -= 1;

			// 周期性的任务将自动地再次运行
			// 如果这个是'单次'任务,将它从队列中删除
			if (SCH_tasks_G[Index].Period == 0)
			{
				SCH_Delete_Task(Index);
			}
		}
	}
	
	// 报告系统状况
	SCH_Report_Status();
}

/*---------------------------------------------------------*-
 * 函数名称: SCH_Report_Status()
 * 入	 口: 
 * 出	 口:
 * 函数功能: 用来显示错误代码
 * 
 * 说	 明: 错误只在有限的时间内显示,此后错误代码被复位为0.
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期: 
-*---------------------------------------------------------*/
void SCH_Report_Status(void)
{
	// 只在需要报告错误时适用
	// 检查新的错误代码
	if (Error_code_G != 0)
	{
		switch (Error_code_G)
		{
			case 1:	uart_send_string("Tasks Full\n", 0);	break;	// 任务队列已满
			case 2:	uart_send_string("No Tasks\n", 0);	break;	// 这里没有任务
			default: break;
		}
	}
	
	Error_code_G = 0; // 复位错误代码
}


/*---------------------------------------------------------*-
 * 函数名称: SCH_Add_Task()
 * 入	 口: (*pFunction)任务指针,(DELAY)到第一次运行间隔时标,
 * 			 (PERIOD)每次运行的间隔时标
 *
 * 出	 口: 返回SCH_MAX_TASKS表示任务队列已满
 *			 返回(Index)=任务位置
 *
 * 函数功能: 用来添加任务到任务队列上,以保证它们在需要的时
 * 			 候被调用
 * 
 * 说	 明: 使任务函数每隔一定间隔或在用户的延迟之后执行.
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期:
-*---------------------------------------------------------*/
unsigned char SCH_Add_Task(void (code *pFunction)(),	// 任务指针
							const unsigned int DELAY,	// 延迟Delay个时标后函数将第一次运行
							const unsigned int PERIOD)  // 连续的运行之间的间隔(时标)
{
	unsigned char 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 = pFunction;
	SCH_tasks_G[Index].Delay = DELAY;
	SCH_tasks_G[Index].Period = PERIOD;
	SCH_tasks_G[Index].RunMe = 0;
	// 返回任务的位置(以便以后删除)
	return Index;	
}


/*---------------------------------------------------------*-
 * 函数名称: SCH_Delete_Task()
 * 入	 口: TASK_INDEX -任务索引.由SCH_Add_task()提供
 * 
 * 出	 口: 返回值: RETURN_ERROR(或)RETURN_NORMAL
 *		
 * 函数功能: 从调度器删除任务.
 * 
 * 说	 明: 请注意:并不是从存储器中删除相关的函数,仅仅是不再
 * 			 由调度器调用这个任务.
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期: 
-*---------------------------------------------------------*/
bit SCH_Delete_Task(const unsigned char TASK_INDEX)
{
	bit Return_code;

	if (SCH_tasks_G[TASK_INDEX].pTask == 0)
	{
		// 这里没有任务
		// 设置全局错误变量
		Error_code_G = ERROR_SCH_CANNOT_DELETE_TASK;
		// 同时返回错误代码
		Return_code = RETURN_ERROR;
	}
	else
	{
		Return_code = RETURN_NORMAL;
	}

	// 删除任务
	SCH_tasks_G[TASK_INDEX].pTask = 0x00;
	SCH_tasks_G[TASK_INDEX].Delay = 0;
	SCH_tasks_G[TASK_INDEX].Period = 0;
	SCH_tasks_G[TASK_INDEX].RunMe = 0;

	// 返回状态
	return Return_code;
}

/*---------------------------------------------------------*-
 * 函数名称: SCH_Update()
 * 入	 口: 
 * 出	 口:
 * 函数功能: 在调度器的中断服务程序中运行
 * 
 * 说	 明: "刷新"函数,确定某个任务需要运行时,将这个任务的
 * 			 RunMe标志加1,然后该任务将由调度程序执行.
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期:
-*---------------------------------------------------------*/
void SCH_Updata(void)
{
	unsigned char Index;
	// 注意: 计算单位为"时标" (不是毫秒)
	for (Index=0; Index < SCH_MAX_TASKS; Index++)
	{
		// 检测这里是否有任务?
		if (SCH_tasks_G[Index].pTask != 0)
		{
			if (SCH_tasks_G[Index].Delay == 0)
			{
				// 任务需要运行
				SCH_tasks_G[Index].RunMe += 1;	// RunMer标志加1
				if (SCH_tasks_G[Index].Period != 0)
				{
					// 调度定期的任务再次运行
					SCH_tasks_G[Index].Delay = SCH_tasks_G[Index].Period;	
				}
			}
			else
			{
				// 还没有准备好运行,延迟减1
				SCH_tasks_G[Index].Delay -= 1;		
			}
		}	
	}
}
/*---------------------------------------------------------*-
 * 函数名称: SCH_Init_Timer2()
 * 入	 口: 
 * 出	 口:
 * 函数功能: 准备调度器数据结构并且设置定时器以所需的频率中断
 * 
 * 说	 明: 调度器初始化化函数,必须在使用调度器之前调用它
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期:
-*---------------------------------------------------------*/
void SCH_Init_Timer2(void)
{
	unsigned char i;
	
	for (i=0; i<SCH_MAX_TASKS; i++)
	{
		SCH_Delete_Task(i);
	}

	// 复位全局错误变量
	// - SCH_Delete_Task()将产生一个错误代码
	// (因为任务队列是空的)
//	Error_code_G = 0;

	// 设置定时器2
	// 16位定时自动重装
	T2CON = 0x04;
	
	TH2 = PRELOAD_05mS_H;
	RCAP2H = PRELOAD_05mS_H;
	TL2 = PRELOAD_05mS_L;
	RCAP2L = PRELOAD_05mS_L;
	
	ET2 = 1;	// 使能定时器2中断
	TR2 = 1;	// 启动定时器2	
}


/*---------------------------------------------------------*-
 * 函数名称: SCH_Start()
 * 入	 口: 
 * 出	 口:
 * 函数功能: 通过允许中断来启动调度器
 * 
 * 说	 明: 在添加了所有定期的任务之后调用,从而使任务保持同步.
 *			 注意:应该只使能调度器中断
 *
 * 当前版本: 1.1			 * 取代版本:
 * 作	 者: wsl		 * 原作者  : Michael J.Pont
 * 完成日期: 2006-09-14		 * 完成日期: 
-*---------------------------------------------------------*/
void SCH_Start(void)
{
	EA = 1;
}





//**************END OF FILE*********************************

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -