基于51的任务调度--合作式任务调度器(部分源代码)

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

声明:此代码来自《时间触发嵌入式系统设计模式》







/*---------------------main.c-----------------------------------------------
*
* -------------------------------------------------------------------------
* 硬件要求:T2 16位自动重装调度器
* 采用12Mhz 的振荡器
* ------------------------------------------------------------------------*/


#include

void main (void )
{
//设置调度器
SCH_Init_T2 () ;
//为任务做准备
//task_init ();
//add code here .....
SCH_Add_Task ( pTask , delay , period ) ;
//调度器启动
SCH_Start ();
while (1)
{
SCH_Dispatch_Tasks();
}

}

/*----------------------------------------------------------------------
* ------------------文件结束-------------------------------------------
* --------------------------------------------------------------------*/







/*-------------------------------------------------------
-----------------main.h----------------------------------
-------------------------------------------------------*/

#ifndef _MAIN_H
#define _MAIN_H
//-------------------------------------------------------------------------------------------------------------------------------
//every project should change this value
//-------------------------------------------------------------------------------------------------------------------------------
//
//target mcu
#include
//-------------------------------------------------------
//
//cystal fz
#define OSC_FREQ (11059200ul)
//-------------------------------------------------------
//
//instuction
#define OSC_PRE_INST (12)
//-------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------
//below is some code you may not need to change -------------------------------------------------------------------------------
//------------------------------------------------------------------------------------------------------------------------------
typedef unsigned char tByte ;
typedef unsigned int tword ;
typedef unsigned long tlong ;


//some other mecro
#ifndef TRUE
#define FALSE 0
#define TRUE (!FALSE)
#endif
#define RETURN_NORMAL (bit) 0
#define RETURN_ERROR (bit) 1


//interrupt
#define INTERRUPT_timer0_Overflow 1
#define INTERRUPT_timer1_Overflow 3
#define INTERRUPT_timer2_Overflow 5


//-----------------------------------------------------
#define INTERRUPT_RART_RX_TX 4
#define INTERRUPT_CAN_c515 17


//-----------------------------------------------------
//error code


#define ERROR_SCH_TOO_MANY_TASK (1)
#define ERROR_SCH_CAN_NOT_DELETE_TASK (2)

#define ERROR_SCH_WAITINT_FOR_SLAVE_TO_ACK (0XAA)
#define ERROR_SCH_WAITING_FOR_START_COMMAND_FROM_MASTER (0xAA)

#define ERROR_SCH_ONE_OR_MORE_SLAVE_DIT_

NOT_START (OXAO)
#define ERROR_SCH_LOST_SLAVE (0x08)

#define ERROR_I2C_WAIT_BYTE_AT24C64 (11)
#define ERROR_I2C_READ_BYTE_AT24C64 (12)
#define ERROR_I2C_WRITE_BYTE (13)
#define ERROR_I2C_READ_BYTE (14)
#define ERROR_USART_T1 (21)
#define ERROR_USART_WRITE_CHAR (22)

#endif





/*-------------------------------------------------------------
* -----------------------SCH51.C------------------------------
* ---------------------------------------------------------*/

//****这里是调度器的内核函数*****---------------
//这些函数可以用与所用的51单片机
//SCH_Max_Task必须由用户设置,参见SCH51.H
//省电模式:省电模式必须被修改以适合不同的单片机
//---------------------------------------------------------------------------------------------------------
#include"sch51.h"
#include"main.h"
#include"port.h"
//公用变量定义---------------------------------------------------------------------------------------------
//任务队列
sTask SCH_task_G[SCH_Max_Task];
//用来显示错误代码
//错误代码的详细资料见Main.h
//错误显示端口详细信息见port.h
tByte Error_code_G = 0 ;
//------------------私有函数原型---------------------------------------------------------------------------
static SCH_Go_To_Sleep (void );
//-----------------------私有变量--------------------------------------------------------------------------
//跟踪自上一次错误报告以来的时间
static tWord SCH_tick_count_G ;
//上一次的错误代码
static tByte Last_Error_code_G ;
//*---------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------
//---------------------------------------------------------------------------------------------------------
/*这是调度函数,当一个任务需要运行时,SCH_Dispatch_Tasks()将运行它,这个函数必须被主循环(重复)调用。*/
void SCH_Dispatch_Task(void)
{
tByte Index ;
//调度(运行)下一个任务
for(Index=0 ; Index < SCH_Max_Task ; Index++)
{
if(SCH_task_G[Index].run>0)
{
*SCH_task_G[Index].pTask(); //运行任务
SCH_task_G[Index].run-=1; //复位运行run状态标识
//周期性的将任务自动运行
//如果这是一个单次任务则将其从任务列队里删除
if (SCH_tack_G[Index].period==0)
{
SCH_Delete_Task(Index);
}
}
}
//报告系统状态
SCH_Report_Status();
//进入系统空闲模式
SCH_Go_To_Sleep();

}


/*使任务(函数)每隔一定时间或在用户定义的延迟之后运行
* Fn_p被调用函数名,被调用的函数一定是void fn (void)类型的
* DELAY在任务第一次被运行之前的时标(时间间隔)
* PERIOD如果PERIOD 的为0 ,则在在DELAY确定的时间之后运行一次
如果PERIOD

不为0则每隔PERIOD 确定的时间运行一次
* ------------------------------------------------------------------------------------------------------*/
tByte SCH_Add_Task(void (code * pFuction)() , const tWord DELAY , const tWord PERIOD )
{
tByte Index = 0 ;
//在任务列队中找一个空隙,如果有的话
while ((SCH_task_G[Index].pTask !=0) && (Index{
Index++;
}
//是否已到达任务队列末尾
if(Index == SCH_MAX_TASK)
{
//任务列队已满
//无法添加任务
//设置全局错误变量
Error_code_G = ERROR_TOO_MANY_TASK;
//返回错误代码
return SCH_MAX_TASKS;
}

//如果能运行到这,则以说明任务队列有空隙

SCH_task_G[Index].pTask = pFuction ;
SCH_task_G[Index].delay = DELAY ;
SCH_task_G[Index].period = PERIOD ;
SCH_task_G[Index].run = 0 ;
return Index ; //返回任务位置以便删除


}


/*-----------------SCH_Delete_Task()------------------------------------
* 从任务调度器中删除某个任务。并不从存储器中删除某个任务,而仅仅是不由调度器调度这个函数了
* TASK_INDEX任务索引,由SCH_Add_Task()提供,返回值RETURN_NOMAL 或RETURN_ERROR
* -----------------------------------------------------------------*/
bit SCH_Delete_Task(const tbyte TASK_INDEX)
{
bit Return_code ;
if (SCH_task_G[TASK_INDEX].pTask == 0)
{
//没有任务
//
//设置全局错误代码
Error_code_G = ERROR_SCH_CANNOT_DELETE_TASK;
//返回错误代码
Return_code = RETURN_ERROR ;
}
else
{
Return_code = RETURN_NOMAL ;
}
SCH_task_G[TASK_INDEX].pTask == 0 ;
SCH_task_G[TASK_INDEX].Delay == 0 ;
SCH_task_G[TASK_INDEX].period == 0 ;
SCH_task_G[TASK_INDEX].run == 0 ;
return Return_code ; //返回状态
}


/*------------------------------------------------------------------------------------
* --------------------------SCH_report_status----------------------------------------
* 用来显示错误代码的简单函数
* 这个版本将用连接到端口上的LED来显示状态代码
* 如果需要的话可以修改为通过串行连接等方式来报告错误
* Error are only displayed for a limited period
* (60000 ticks = 1 minute at 1ms tick interval)
* 错误代码只在有限的时间内显示,此后显示被复位。
* 这些代码可以容易的被修改为“永远”显示最近的错误代码,这在系统中可能更加合理
*-----------------------------------------------------------------------------------*/
void SCH_Report_status(void)
{
#ifdef SCH_REPORT_ERRORS
//只在需要报告错误时适用
//检查新的错误代码
if(Error_code_G != Last_error_code_G)
{
//假定LED采用负逻辑
Error_port = 255 - Error_code_G ;
Last_error_code_G = Error_code_G ;

if(Error_code_G != 0)
{
Error_tick_count_G = 60000 ;
}
else
{
Error_tick_count_G = 0 ;
}

}
else


{
if(Error_code_G != 0 )
{
if(--Error_tick_count_G == 0 )
{
Error_code_G = 0 ; //复位错误代码
}
}
}
#endif
}


/*---------------------------------------------------------------------------------------
-------------------------------Go_to_sleep()--------------------------------------------
-----------------------------------------------------------------------------------------
本调度器在时钟时标之间将进入睡眠状态,以节省功耗,下一个时标将使处理器返回到正常的操作状态
注意此处的的这个函数如果由宏来实现,或简单的将这里的代码粘贴到“调度”函数中,可以带来少量的
性能改善,然而,采用调用函数的方式来实现,可以在开发期间更容易的用keil硬件模拟器中的性能分析器
来估计调度器的性能
*******如果使用看门狗,可能需要将此功能禁止**********
*******根据硬件来修改次函数**************************
--------------------------------------------------------------------------------------*/

SCH_Go_To_Sleep ()
{
PCON |= 0X01 ;
//PCON |= 0X01 ;
}

/*-------------------------------------------------------------------------------------------
* -------------------------------------SCH_Init ()------------------------------------------
* ----------------------------------------------------------------------------------------
* 调度器初始化函数。准备调度器数据结构,并且设置定时器以所需的频率中断
* 必须在使用调度器之前调用这个函数。-------------------------------------------------------
* ----------------------------------------------------------------------------------------*/
void SCH_Init(void)
{
tByte i ;
for (i=0 ; i< SCH_MAX_TASKS ; i++ )
{
SCH_Delete_Task(i ) ;
}
//复位全局变量
Error_code_G = 0 ;
//设置定时器2
//自动重装的16位定时器函数
//晶振假定为12MHZ
//定时器的精度为1us
//定时器溢出为1ms
//需要1000个定时器时标
//重装值为65536-1000 = 64536 (0xfc18)
T2CON = 0x04 ;
T2MOD = 0X00 ;
TH2 = 0XFC ;
RCAP2H = 0XFC ;
TL2 = 0X18 ;
RCAP2L = 0X18 ;
ET2 = 1 ;
TR2 = 1 ;

}

/*-----------------------------------------------------------------------------
* ----------------------------SCH_Start()-------------------------------------
* --------------------------------------------------------------------------
* 通过允许中断来启动调度器
* 通常在添加了所有任务之后启动调度器,保证任务同步
* 应该只使能调度器中断
* --------------------------------------------------------------------------*/
void SCH_Start (void)
{
EA =1 ; //开总中断
}



/*----------------------------------------------------------------------------
* ---------------------------SCH_Updata()------------------------------------
* -------

-------------------------------------------------------------------
* 这是定时器中断的服务程序,初始化函数中的定时器的设置决定了它的调用频率
* 此更新函数是根据定时器2来进行中断触发的:定时器自动重装。
* ------------------------------------------------------------------------*/
void SCH_Updata () interrupt INTERRUPT_Timer_2_Overflow
{
tByte Index ;
TF2 = 0 ; //定时器2的中断触发位,手动清零。
for(Index ; Index < SCH_max_Tasks ; Index++)
{
//检测是否有任务
if(SCH_tasks_G[Index].pTask)
{
if(SCH_tasks_G[Index].delay == 0 )
{
SCH_tasks_G[Index].run += 1 ;
if(SCH_tasks_G[Index].period)
{
SCH_Task_G[Index].delay = SCH_Task_G[Index].period ;
}
else
{
SCH_Delete_Tasks (Index);
}
}
else
{
SCH_Tasks_G[Index].delay -=1 ; //还没有到时间,延迟减1
}


}
}
}

/*--------------------------------------------------------------------------------------------------------------------------------------------------
* ------------------------------------------------文件结束-----------------------------------------------------------------------------------------
* -----------------------------------------------------------------------------------------------------------------------------------------------*/

















/*---------------------------------------------------------------------------
* -------------------------------sch51.h------------------------------------
* -----------------------------------------------------------------------*/
ifndef _SCH_51_H
#define _SCH_51_H
#include
//公用数据声明
//可能的话把数据放在data区加快存取速度
//每一个任务的存储器总和为7个字节
//----------------------------------
typedef data struct
{
//指向任务的指针 *void (void)
void (code * pTask) (void);
//延时时标,到下一次运行的时间
//详情参见SCH_Add_Task()
tWord delay;
//连续运行间隔的时标
tWord period;
//当程序需要运行时加1
tByte run;
}
//----------------------------------
//------------公用的函数原型--------
void SCH_Dispatch_Task(void);
tByte SCH_Add_Task(void (code *)(void), const tWord ,const tWord );
bit SCH_Delete_Task(const tByte );
void SCH_Report_Status(void);
void SCH_Init (void ) ;
void SCH_Start (void) ;

//公用常数--------------------------
#define SCH_Max_Task (1)

#endif

相关文档
最新文档