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

📄 hsch51.c

📁 时间触发式51单片机嵌入式多任务系统
💻 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 + -