📄 hsch51.c
字号:
/*------------------------------------------------------------------*-
hSCH51.C (v1.00)
------------------------------------------------------------------
系统核心模块.
任务调用模块.
/// HYBRID SCHEDULER CORE ///
*** THESE ARE THE CORE SCHEDULER FUNCTIONS ***
--- These functions may be used with all 8051 devices ---
*** hSCH_MAX_TASKS *must* be set by the user ***
--- see "Sch51.h" ---
*** Includes power-saving mode ***
--- You *MUST* confirm that the power-down mode is adapted ---
--- to match your chosen device (usually only necessary with
--- Extended 8051s, such as c515c, c509, etc ---
COPYRIGHT
---------
This code is from the book:
PATTERNS FOR TIME-TRIGGERED EMBEDDED SYSTEMS by Michael J. Pont
[Pearson Education, 2001; ISBN: 0-201-33138-1].
This code is copyright (c) 2001 by Michael J. Pont.
See book for copyright details and other information.
-*------------------------------------------------------------------*/
#include "../a/main/main.h"
#include "OS_cfg.h"
#include "hSch51.h"
// ------ Public variable definitions ------------------------------
// The array of tasks
sTaskH hSCH_tasks_G[hSCH_MAX_TASKS];
// Used to display the error code
// See Main.H for details of error codes
// See Port.H for details of the error port
// ------ Private function prototypes ------------------------------
static void hSCH_Go_To_Sleep(void);
// ------ Private variables ----------------------------------------
// Keeps track of time since last error was recorded (see below)
static tWord Error_tick_count_G;
// The code of the last error (reset after ~1 minute)
static tByte Last_error_code_G;
#if _OS_DISPATCH_TASK > 0
/*------------------------------------------------------------------*-
hSCH_Dispatch_Tasks()
This is the 'dispatcher' function. When a task (function)
is due to run, hSCH_Dispatch_Tasks() will run it.
This function must be called (repeatedly) from the main loop.
-*------------------------------------------------------------------*/
void hSCH_Dispatch_Tasks(void)
{
tByte tAutoData Index;
// Dispatches (runs) the next task (if one is ready)
for (Index = 0; Index < hSCH_MAX_TASKS; Index++)
{
// Only dispatching co-operative tasks
if ((hSCH_tasks_G[Index].Co_op) && (hSCH_tasks_G[Index].RunMe > 0))
{
// Run the task
(*hSCH_tasks_G[Index].pTask)();
// Reset / reduce RunMe flag
hSCH_tasks_G[Index].RunMe --;
// Periodic tasks will automatically run again
// - if this is a 'one shot' task, remove it from the array
if (hSCH_tasks_G[Index].Period == 0)
{
// Faster than call to delete task
hSCH_tasks_G[Index].pTask = 0;
}
}
}
#if _OS_REPORT_ERRORS > 0
// Report system status
hSCH_Report_Status();
#endif
}
#endif
#if _OS_ADD_TASK > 0
/*------------------------------------------------------------------*-
hSCH_Add_Task()
Causes a task (function) to be executed at regular intervals
or after a user-defined delay
Index - Task ID nunber 0-hSCH_MAX_TASKS
Fn_P - The name of the function which is to be scheduled.
NOTE: All scheduled functions must be 'void, void' -
that is, they must take no parameters, and have
a void return type.
Del - The interval (TICKS) before the task is first executed
Rep - If 'Rep' is 0, the function is only called once,
at the time determined by 'Del'. If Rep is non-zero,
then the function is called repeatedly at an interval
determined by the vakue of Rep (see below for examples
that should help clarify this).
Co-op - Set to 1 if it a co-op task; 0 if pre-emptive
RETN: The position in the task array at which the task has been added.
If the return value is hSCH_MAX_TASKS then the task could not be
added to the array (there was insufficient space). If the
return value is < hSCH_MAX_TASKS, then the task was added
successfully.
Note: this return value may be required, if a task is
to be subsequently deleted - see hSCH_Delete_Task().
EXAMPLES:
Task_ID = hSCH_Add_Task(Do_X,1000,0,0);
Causes the function Do_X() to be executed once after 1000 ticks.
(Pre-emptive task)
Task_ID = hSCH_Add_Task(Do_X,0,1000,1);
Causes the function Do_X() to be executed regularly, every 1000 ticks.
(co-operative task)
Task_ID = hSCH_Add_Task(Do_X,300,1000,0);
Causes the function Do_X() to be executed regularly, every 1000 ticks.
Task will be first executed at T = 300 ticks, then 1300, 2300, etc.
(Pre-emptive task)
-*------------------------------------------------------------------*/
tByte hSCH_Add_Task(tByte Index, // Task ID
void (code* Fn_p)(), // Task function pointer
tWord Del, // Num ticks 'til task first runs
tWord Per, // Num ticks between repeat runs
bit Co_op) // Co_op / pre_emp
{
//tByte Index = 0;
// First find a gap in the array (if there is one)
//while ((hSCH_tasks_G[Index].pTask != 0) && (Index < hSCH_MAX_TASKS))
//{
// Index++;
//}
// Have we reached the end of the list?
if (Index == hSCH_MAX_TASKS)
{
// Task list is full
//
// Set the global error variable
#if _OS_REPORT_ERRORS > 0
Error_code_G = ERROR_SCH_TOO_MANY_TASKS;
#endif
// Also return an error code
return(hSCH_MAX_TASKS);
}
// If we're here, there is a space in the task array
hSCH_tasks_G[Index].pTask = Fn_p;
hSCH_tasks_G[Index].Delay = Del;
hSCH_tasks_G[Index].Period = Per;
hSCH_tasks_G[Index].Co_op = Co_op;
hSCH_tasks_G[Index].RunMe = 0;
return(Index); // return position of task (to allow later deletion)
}
#endif
#if _OS_DELETE_TASK > 0
/*------------------------------------------------------------------*-
hSCH_Delete_Task()
Removes a task from the scheduler. Note that this does
*not* delete the associated function from memory:
it simply means that it is no longer called by the scheduler.
PARAMS: Task_index - The task index. Provided by hSCH_Add_Task().
RETURNS: RETURN_ERROR or RETURN_NORMAL
-*------------------------------------------------------------------*/
tBOOL hSCH_Delete_Task(tByte Task_index)
{
tBOOL Return_code;
if (hSCH_tasks_G[Task_index].pTask == 0)
{
// No task at this location...
//
// Set the global error variable
#if _OS_REPORT_ERRORS > 0
Error_code_G = ERROR_SCH_CANNOT_DELETE_TASK;
#endif
// ...also return an error code
Return_code = RETURN_ERROR;
}
else
{
Return_code = RETURN_NORMAL;
}
hSCH_tasks_G[Task_index].pTask = 0;
hSCH_tasks_G[Task_index].Delay = 0;
hSCH_tasks_G[Task_index].Period = 0;
hSCH_tasks_G[Task_index].RunMe = 0;
return(Return_code); // return status
}
#endif
#if _OS_REPORT_ERRORS > 0
/*------------------------------------------------------------------*-
hSCH_Report_Status()
Simple function to display error codes.
This version displays code on a port with attached LEDs:
adapt, if required, to report errors over serial link, etc.
Errors are only displayed for a limited period
(60000 ticks = 1 minute at 1ms tick interval).
After this the the error code is reset to 0.
This code may be easily adapted to display the last
error 'for ever': this may be appropriate in your
application.
See Chapter 14 for further information.
-*------------------------------------------------------------------*/
void hSCH_Report_Status(void)
{
// ONLY APPLIES IF WE ARE REPORTING ERRORS
// Check for a new error code
if (Error_code_G != Last_error_code_G)
{
// Negative logic on LEDs assumed
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_tick_count_G != 0)
{
if (--Error_tick_count_G == 0)
{
Error_code_G = 0; // Reset error code
}
}
}
}
#endif
#if _OS_CHANGE_REP_TASK > 0
/*------------------------------------------------------------------*-
hSCH_Change_rep()
Change task repeat timer.
-*------------------------------------------------------------------*/
void hSCH_Change_rep(tByte Task_index, tWord uiRep)
{
hSCH_tasks_G[Task_index].Period = uiRep;
}
#endif
#if _OS_CTXSW_TASK > 0
/*------------------------------------------------------------------*-
hSCH_CtxSw()
This is the scheduler ISR. It is called at a rate
determined by the timer settings in the 'init' function.
This version is triggered by Timer 2 interrupts:
timer is automatically reloaded.
-*------------------------------------------------------------------*/
void hSCH_CtxSw(void)
{
tByte tAutoData Index;
// NOTE: calculations are in *TICKS* (not milliseconds)
for (Index = 0; Index < hSCH_MAX_TASKS; Index++)
{
// Check if there is a task at this location
if (hSCH_tasks_G[Index].pTask)
{
if (hSCH_tasks_G[Index].Delay == 0)
{
// The task is due to run
//
if (hSCH_tasks_G[Index].Co_op)
{
// If it is a co-operative task, increment the RunMe flag
hSCH_tasks_G[Index].RunMe ++;
}
else
{
// If it is a pre-emptive task, run it IMMEDIATELY
(*hSCH_tasks_G[Index].pTask)(); // Run the task
//hSCH_tasks_G[Index].RunMe --; // Reset / reduce RunMe flag jinys05-07-07
// Periodic tasks will be scheduled again (see below)
// - if this is a 'one shot' task, remove it from the array
if (hSCH_tasks_G[Index].Period == 0)
{
hSCH_tasks_G[Index].pTask = 0;
}
}
if (hSCH_tasks_G[Index].Period)
{
// Schedule this periodic task to run again
hSCH_tasks_G[Index].Delay = hSCH_tasks_G[Index].Period;
}
}
//else // jinys 05-07-07 不去掉的话,任务延时会比设定值多一次
//{
// Not yet ready to run: just decrement the delay
hSCH_tasks_G[Index].Delay --;
//}
}
}
}
#endif
/*------------------------------------------------------------------*-
---- END OF FILE -------------------------------------------------
-*------------------------------------------------------------------*/
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -