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

📄 scu_am.c

📁 PATTERNS FOR TIME-TRIGGERED EMBEDDED SYSTEMS by Michael J. Pont This code is copyright (c) 200
💻 C
📖 第 1 页 / 共 2 页
字号:

  This is the scheduler ISR.  It is called at a rate determined by 
  the timer settings in SCU_A_MASTER_Init_T2().  This version is 
  triggered by Timer 2 interrupts: timer is automatically reloaded.

-*------------------------------------------------------------------*/
void SCU_A_MASTER_Update_T2(void) interrupt INTERRUPT_Timer_2_Overflow  
   {
   tByte Task_index;
   tByte Previous_slave_index;

   TF2 = 0; // Must manually clear this. 

   // Refresh the watchdog
   SCU_A_MASTER_Watchdog_Refresh();

   // Default
   Network_error_pin = NO_NETWORK_ERROR;

   // Keep track of the current slave
   // FIRST VALUE IS 0
   Previous_slave_index = Current_slave_index_G;   

   // Assume 2-byte messages sent and received
   // - it takes two ticks to deliver each message
   if (Message_byte_G == 0)
      {
      Message_byte_G = 1;  
      }
   else
      {
      Message_byte_G = 0;

      if (++Current_slave_index_G >= NUMBER_OF_SLAVES)
         {
         Current_slave_index_G = 0;
         }
      }

   // Check that the appropriate slave responded to the previous message:
   // (if it did, store the data sent by this slave)
   if (SCU_A_MASTER_Process_Ack(Previous_slave_index) == RETURN_ERROR)
      {
      Network_error_pin = NETWORK_ERROR;
      Error_code_G = ERROR_SCH_LOST_SLAVE;

      // If we have lost contact with a slave, we attempt to
      // switch to a backup device (if one is available) as we reset the network
      //
      // NOTE: We don't do this every tick (or the the network will be constantly reset)
      //
      // Choose a value of SLAVE_RESET_INTERVAL to allow resets (say) every 5 seconds
      if (++Slave_reset_attempts_G[Previous_slave_index] >= SLAVE_RESET_INTERVAL)
         {
         SCU_A_MASTER_Reset_the_Network();
         }
      }
   else
      {
      // Reset this counter
      Slave_reset_attempts_G[Previous_slave_index] = 0;
      }

   // Send 'tick' message to all connected slaves
   // (sends one data byte to the current slave)
   SCU_A_MASTER_Send_Tick_Message(Current_slave_index_G);

   // NOTE: calculations are in *TICKS* (not milliseconds)
   for (Task_index = 0; Task_index < SCH_MAX_TASKS; Task_index++)
      {
      // Check if there is a task at this location
      if (SCH_tasks_G[Task_index].pTask)
         {
         if (SCH_tasks_G[Task_index].Delay == 0)
            {
            // The task is due to run
            SCH_tasks_G[Task_index].RunMe += 1;  // Increment the run flag

            if (SCH_tasks_G[Task_index].Period)
               {
               // Schedule periodic tasks to run again
               SCH_tasks_G[Task_index].Delay = SCH_tasks_G[Task_index].Period;
               }
            }
         else
            {
            // Not yet ready to run: just decrement the delay 
            SCH_tasks_G[Task_index].Delay -= 1;
            }
         }         
      }
   }   

/*------------------------------------------------------------------*-

  SCU_A_MASTER_Send_Tick_Message()

  This function sends a tick message, over the USART network.
  The receipt of this message will cause an interrupt to be generated
  in the slave(s): this invoke the scheduler 'update' function
  in the slave(s).

-*------------------------------------------------------------------*/
void SCU_A_MASTER_Send_Tick_Message(const tByte SLAVE_INDEX) 
   {
   tLong Timeout;

   // Find the slave ID for this slave 
   tByte Slave_ID = (tByte) Current_Slave_IDs_G[SLAVE_INDEX];

   // Sending one byte of data at a time, depending on index value
   // If Message_byte_G is 0, send first byte (the slave ID)
   if (Message_byte_G == 0)
      {
      Timeout = 0;
      while ((++Timeout) && (TI == 0));  

      if (Timeout == 0)
         {
         // UART did not respond - error
         Error_code_G = ERROR_USART_TI; 
         return;
         } 

      TI = 0;                                            
      TB8 = 1;  // Set 'Command' bit
      SBUF = Slave_ID;
      }
   else
      {
      // Message_byte_G is 1, send the data byte 
      Timeout = 0;
      while ((++Timeout) && (TI == 0));  

      if (Timeout == 0)
         {
         // usart did not respond - error
         Error_code_G = ERROR_USART_TI; 
         return;
         } 

      TI = 0;
      TB8 = 0;
      SBUF = Tick_message_data_G[SLAVE_INDEX];
      }
 
   // Data sent - return
   }


/*------------------------------------------------------------------*-

  SCU_A_MASTER_Process_Ack()

  Make sure the slave (SLAVE_ID) has acknowledged the previous
  message that was sent.  If it has, extract the message data
  from the USART hardware: if not, call the appropriate error
  handler.

  Slave_index - The index of the slave. 

  RETURNS:  RETURN_NORMAL - Ack received (data in Ack_message_data_G)
            RETURN_ERROR  - No ack received (-> no data)

-*------------------------------------------------------------------*/

bit SCU_A_MASTER_Process_Ack(const tByte Slave_index) 
   {
   tByte Message_contents;
   tByte Slave_ID;

   // First time this is called there is no ack tick to check 
   // - we simply return 'OK'
   if (First_ack_G)
      {
      First_ack_G = 0;
      return RETURN_NORMAL;
      }

   // Find the slave ID for this slave 
   Slave_ID = (tByte) Current_Slave_IDs_G[Slave_index];

   // Data should already be in the buffer
   if (RI == 0)
      {
      // Slave has not replied to last tick message

      // Set error LED
      Network_error_pin = NETWORK_ERROR;

      return RETURN_ERROR;
      } 

   // There is data - get it
   Message_contents = (tByte) SBUF;
   RI = 0;

   // This is the reply to the last message 
   // - reverse the message byte interpretation 
   if (Message_byte_G == 1)
      {
      // Check the 'command bit' is set
      if (RB8 == 1)
         {
         // Check that the ID is correct
         if (Slave_ID == (tByte) Message_contents)
            {
            // Required Ack message was received
            return RETURN_NORMAL;
            }
         }

       // Something is wrong...

       // Set error LED
       Network_error_pin = NETWORK_ERROR;

       return RETURN_ERROR;
       }
    else
       {  
       // There *ARE* data available 
       // Extract the data from the slave message
       //
       // NOTE: We *assume* these data are OK
       // - you may wish to send crucial data twice, etc.
       Ack_message_data_G[Slave_index] = Message_contents;
  
       return RETURN_NORMAL;  // return the slave data
       }
   }

/*------------------------------------------------------------------*-

  SCU_A_MASTER_Reset_the_Network()

  This function resets (that is, restarts) the whole network.

-*------------------------------------------------------------------*/
void SCU_A_MASTER_Reset_the_Network(void)
   {
   EA = 0;   // Disable interrupts
   while(1); // Watchdog will time out
   }

/*------------------------------------------------------------------*-

  SCU_A_MASTER_Shut_Down_the_Network()

  This function shuts down the whole network.

-*------------------------------------------------------------------*/
void SCU_A_MASTER_Shut_Down_the_Network(void)
   {
   EA = 0; // Disable interrupts

   Network_error_pin = NETWORK_ERROR;
   SCH_Report_Status(); // Sch not running - do this manually

   while(1)
      {
      SCU_A_MASTER_Watchdog_Refresh();
      }
   }


/*------------------------------------------------------------------*-

  SCU_A_MASTER_Enter_Safe_State()

  This is the state enterted by the system when:
  (1) The node is powered up or reset
  (2) The Master node cannot detect a slave
  (3) The network has an error

  Try to ensure that the system is in a 'safe' state in these 
  circumstances.

-*------------------------------------------------------------------*/
void SCU_A_MASTER_Enter_Safe_State(void)
   {
   // USER DEFINED - Edit as required
   TRAFFIC_LIGHTS_Display_Safe_Output();
   } 

/*------------------------------------------------------------------*-

  SCU_A_MASTER_Watchdog_Init()

  This function sets up the watchdog timer.

  If the Master fails (or other error develop), 
  no tick messages will arrive, and the scheduler
  will stop.  

  To detect this situation, we have a (hardware) watchdog
  running in the slave.  This watchdog - which should be set to
  overflow at around 100ms - is used to set the system into a
  known (safe) state.  The slave will then wait (indefinitely)
  for the problem to be resolved.

  NOTE: The slave will not be generating Ack messages in these 
  circumstances.  The Master (if running) will therefore be aware
  that there is a problem.  

-*------------------------------------------------------------------*/
void SCU_A_MASTER_Watchdog_Init(void)   
   {
   // INIT NOT REQUIRED FOR 1232 EXTERNAL WATCHDOG
   // - May be required wwith different watchdog hardware
   //
   // Edit as required
   }


/*------------------------------------------------------------------*-

  SCU_A_MASTER_Watchdog_Refresh()

  Feed the external (1232) watchdog.

  Timeout is between ~60 and 250 ms (hardware dependent)

  Assumes external 1232 watchdog

-*------------------------------------------------------------------*/
void SCU_A_MASTER_Watchdog_Refresh(void) reentrant
   {
   // Change the state of the watchdog pin
   if (WATCHDOG_state_G == 1)
      {
      WATCHDOG_state_G = 0;
      WATCHDOG_pin = 0;
      }
   else
      {
      WATCHDOG_state_G = 1;
      WATCHDOG_pin = 1;
      } 
   }    


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

⌨️ 快捷键说明

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