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

📄 scc_m515.c

📁 基于8051共享时钟调度器的can总线通讯
💻 C
📖 第 1 页 / 共 2 页
字号:
/*------------------------------------------------------------------*-

   SCC_M515.c (v1.01)

  ------------------------------------------------------------------

   *** THIS IS A SHARED-CLOCK (CAN) SCHEDULER (MASTER) ***
   *** FOR 80C515C (etc.) ***

   *** Uses T2 for timing, 16-bit auto reload ***

   *** This version assumes 10 MHz crystal on 515c ***
   *** 6 ms (precise) tick interval ***

   *** Both Master and Slave(s) share the same tick rate ***


   -----------------------------------------------------------
   --- NOTE: 'Idle mode' must be disabled (in Sch51.C)     ---
   --- or the on-chip watchdog will not function correctly ---
   -----------------------------------------------------------


   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 "Main.h"
#include "Port.h"

#include "Delay_T0.h"
#include "TLight_B.h"
#include "SCC_M515.h"

// ------ Public variable definitions ------------------------------

// Four bytes of data (plus ID information) are sent 
tByte Tick_message_data_G[NUMBER_OF_SLAVES][4] = {'M'};  
tByte Ack_message_data_G[NUMBER_OF_SLAVES][4];

// ------ Public variable declarations -----------------------------

// The array of tasks (see Sch51.c)
extern sTask SCH_tasks_G[SCH_MAX_TASKS];

// The error code variable (see Sch51.c)
extern tByte Error_code_G;

// ------ Private variable definitions -----------------------------

static tByte Slave_index_G = 0;
static bit First_ack_G = 1;

// ------ Private function prototypes ------------------------------

static void SCC_A_MASTER_Send_Tick_Message(const tByte);
static bit  SCC_A_MASTER_Process_Ack(const tByte);

static void SCC_A_MASTER_Shut_Down_the_Network(void);

static void SCC_A_MASTER_Enter_Safe_State(void);

static void SCC_A_MASTER_Watchdog_Init(void);
static void SCC_A_MASTER_Watchdog_Refresh(void) reentrant;

static tByte  SCC_A_MASTER_Start_Slave(const tByte)  reentrant;


// ------ Private constants ----------------------------------------

// Do not use ID 0x00 (used to start slaves)
static const tByte MAIN_SLAVE_IDs[NUMBER_OF_SLAVES] = {0x01};
static const tByte BACKUP_SLAVE_IDs[NUMBER_OF_SLAVES] = {0x02};

#define NO_NETWORK_ERROR (1) 
#define NETWORK_ERROR (0)

// ------ Private variables ----------------------------------------

static tWord Slave_reset_attempts_G[NUMBER_OF_SLAVES];

// Slave IDs may be any non-zero tByte value (but all must be different)
static tByte Current_Slave_IDs_G[NUMBER_OF_SLAVES] = {0};


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

  SCC_A_MASTER_Init_T2_CAN()

  Scheduler initialisation function.  Prepares scheduler data 
  structures and sets up timer interrupts at required rate.
  Must call this function before using the scheduler.  

-*------------------------------------------------------------------*/
void SCC_A_MASTER_Init_T2_CAN(void) 
   {
   tByte i;
   tByte Message;
   tByte Slave_index;

   // No interrupts (yet)
   EAL = 0;

   // Start the watchdog
   SCC_A_MASTER_Watchdog_Init();

   Network_error_pin = NO_NETWORK_ERROR;

   // ------ Set up the scheduler ----------------------------------
   // Sort out the tasks
   for (i = 0; i < SCH_MAX_TASKS; i++) 
      {
      SCH_Delete_Task(i);
      }

   // Reset the global error variable
   // - SCH_Delete_Task() will generate an error code, 
   //   (because the task array is empty)
   Error_code_G = 0;

   // We allow any combination of ID numbers in slaves
   for (Slave_index = 0; Slave_index < NUMBER_OF_SLAVES; Slave_index++)
      {
      Slave_reset_attempts_G[Slave_index] = 0;
      Current_Slave_IDs_G[Slave_index] = MAIN_SLAVE_IDs[Slave_index];
      }

   // Get ready to send first tick message
   First_ack_G = 1;
   Slave_index_G = 0;

   // ------ Set up the CAN link (begin) ------------------------

   // ---------------- SYSCON Register --------------
   // The access to XRAM and CAN controller is enabled.
   // The signals !RD and !WR are not activated during accesses
   // to the XRAM/CAN controller.
   // ALE generation is enabled.
   SYSCON = 0x20;  

   //  ------------ CAN Control/Status Register --------------
   //  Start to init the CAN module
   CAN_cr  = 0x41;  // INIT and CCE

   //  ------------ Bit Timing Register ---------------------
   // Baudrate = 333.333 kbaud 
   // - Need 308+ kbaud plus for 1ms ticks, 8 data bytes
   // - See text for details  
   //
   // There are 5 time quanta before sample point
   // There are 4 time quanta after sample point
   // The (re)synchronization jump width is 2 time quanta
   CAN_btr1  = 0x34;      // Bit Timing Register
   CAN_btr0  = 0x42; 

   CAN_gms1  = 0xFF;  // Global Mask Short Register 1
   CAN_gms0  = 0xFF;  // Global Mask Short Register 0

   CAN_ugml1 = 0xFF;  // Upper Global Mask Long Register 1
   CAN_ugml0 = 0xFF;  // Upper Global Mask Long Register 0

   CAN_lgml1 = 0xF8;  // Lower Global Mask Long Register 1
   CAN_lgml0 = 0xFF;  // Lower Global Mask Long Register 0

   // --- Configure the 'Tick' Message Object ---
   // 'Message Object 1' is valid
   CAN_messages[0].MCR1  = 0x55;    // Message Control Register 1
   CAN_messages[0].MCR0  = 0x95;    // Message Control Register 0

   // Message direction is transmit
   // Extended 29-bit identifier 
   // These have ID 0x000000 and 5 valid data bytes
   CAN_messages[0].MCFG = 0x5C;      // Message Configuration Register

   CAN_messages[0].UAR1  = 0x00;    // Upper Arbit. Reg. 1
   CAN_messages[0].UAR0  = 0x00;    // Upper Arbit. Reg. 0
   CAN_messages[0].LAR1  = 0x00;    // Lower Arbit. Reg. 1
   CAN_messages[0].LAR0  = 0x00;    // Lower Arbit. Reg. 0

   CAN_messages[0].Data[0] = 0x00;   // data byte 0
   CAN_messages[0].Data[1] = 0x00;   // data byte 1
   CAN_messages[0].Data[2] = 0x00;   // data byte 2
   CAN_messages[0].Data[3] = 0x00;   // data byte 3
   CAN_messages[0].Data[4] = 0x00;   // data byte 4

   // --- Configure the 'Ack' Message Object ---
   
   // 'Message Object 2' is valid
   // NOTE: Object 2 receives *ALL* ack messages
   CAN_messages[1].MCR1  = 0x55;    // Message Control Register 1
   CAN_messages[1].MCR0  = 0x95;    // Message Control Register 0

   // Message direction is receive
   // Extended 29-bit identifier
   // These all have ID: 0x000000FF (5 valid data bytes)
   CAN_messages[1].MCFG = 0x04;      // Message Configuration Register

   CAN_messages[1].UAR1  = 0x00;    // Upper Arbit. Reg. 1
   CAN_messages[1].UAR0  = 0x00;    // Upper Arbit. Reg. 0
   CAN_messages[1].LAR1  = 0xF8;    // Lower Arbit. Reg. 1
   CAN_messages[1].LAR0  = 0x07;    // Lower Arbit. Reg. 0

   // Configure remaining message objects - none are valid
   for (Message = 2; Message <= 14; ++Message)
      {                                 
      CAN_messages[Message].MCR1  = 0x55;  // Message Control Register 1
      CAN_messages[Message].MCR0  = 0x55;  // Message Control Register 0
      }

   // ------------ CAN Control Register ---------------------
   //  reset CCE and INIT
   CAN_cr = 0x00;

   // ------ Set up the CAN link (end) --------------------------

   // ------ Set up Timer 2 (begin) --------------------------------
   // 80c515c, 10 MHz
   // Timer 2 is set to overflow every 6 ms - see text
   // Mode 1 = Timerfunction

   // Prescaler: Fcpu/12
   T2PS = 1;

   // Mode 0 = auto-reload upon timer overflow
   // Preset the timer register with autoreload value
   // NOTE: Timing is same as standard (8052) T2 timing
   // - if T2PS = 1 (otherwise twice as fast as 8052)
   TL2 = 0x78;
   TH2 = 0xEC;
     
   //  Mode 0 for all channels
   T2CON |= 0x11;

   //  timer 2 overflow interrupt is enabled
   ET2 = 1;
   //  timer 2 external reload interrupt is disabled
   EXEN2 = 0;

   // Compare/capture Channel 0 
   // Disabled
   // Compare Register CRC on: 0x0000;
   CRCL = 0x78;
   CRCH = 0xEC;
  
   //  CC0/ext3 interrupt is disabled
   EX3 = 0;
  
   // Compare/capture Channel 1-3 
   // Disabled
   CCL1 = 0x00;
   CCH1 = 0x00;
   CCL2 = 0x00;
   CCH2 = 0x00;
   CCL3 = 0x00;
   CCH3 = 0x00;
  
   // Interrupts Channel 1-3 
   // Disabled
   EX4 = 0;
   EX5 = 0;
   EX6 = 0;
  
   // all above mentioned modes for Channel 0 to Channel 3 
   CCEN = 0x00;
   // ------ Set up Timer 2 (end) ----------------------------------
   }

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

  SCC_A_MASTER_Start()

  Starts the scheduler, by enabling interrupts.

  NOTE: Usually called after all regular tasks are added,
  to keep the tasks synchronised.

  NOTE: ONLY THE SCHEDULER INTERRUPT SHOULD BE ENABLED!!! 

-*------------------------------------------------------------------*/
void SCC_A_MASTER_Start(void) 
   {
   tByte Num_active_slaves;
   tByte i;
   bit Slave_replied_correctly;
   tByte Slave_index, Slave_ID;

   // Refresh the watchdog
   SCC_A_MASTER_Watchdog_Refresh();

   // Place system in 'safe state'
   SCC_A_MASTER_Enter_Safe_State();

   // Report error as we wait to start
   Network_error_pin = NETWORK_ERROR;

   Error_code_G = ERROR_SCH_WAITING_FOR_SLAVE_TO_ACK;
   SCH_Report_Status(); // Sch not yet running - do this manually

   // Pause here (300 ms), to time-out all the slaves
   // (This is the means by which we synchronise the network)
   for (i = 0; i < 10; i++)
      {
      Hardware_Delay_T0(30);
      SCC_A_MASTER_Watchdog_Refresh();
      }     

   // Currently disconnected from all slaves
   Num_active_slaves = 0;

   // After the initial (long) delay, all (operational) slaves will have timed out.
   // All operational slaves will now be in the 'READY TO START' state
   // Send them a 'slave id' message to get them started
   Slave_index = 0;
   do {
      // Refresh the watchdog
      SCC_A_MASTER_Watchdog_Refresh();

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

      Slave_replied_correctly = SCC_A_MASTER_Start_Slave(Slave_ID);

      if (Slave_replied_correctly)
         {
         Num_active_slaves++;
         Slave_index++;
         }
      else
         {
         // Slave did not reply correctly 
         // - try to switch to backup device (if available)
         if (Current_Slave_IDs_G[Slave_index] != BACKUP_SLAVE_IDs[Slave_index])
            {
            // There is a backup available: switch to backup and try again
            Current_Slave_IDs_G[Slave_index] = BACKUP_SLAVE_IDs[Slave_index];

⌨️ 快捷键说明

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