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

📄 can2.c

📁 这是c8051f040的CAN应用程序
💻 C
📖 第 1 页 / 共 2 页
字号:
                                // system clock is 22.1 MHz / 2 = 11.05 MHz
  for (n=0;n<255;n++);          // delay about 1ms
  while ((OSCXCN & 0x80) == 0); // wait for oscillator to stabilize
  CLKSEL |= 0x01;               // switch to external oscillator
}

void config_IO (void)
{
  SFRPAGE  = CONFIG_PAGE;        //Port SFR's on Configuration page
  XBR3     = 0x80;     // Configure CAN TX pin (CTX) as push-pull digital output
  P1MDOUT |= 0x40;     // Configure P1.6 as push-pull to drive LED
  XBR2     = 0x40;     // Enable Crossbar/low ports
}

////////////////////////////////////////////////////////////////////////////////
//CAN Functions
////////////////////////////////////////////////////////////////////////////////


//Clear Message Objects
void clear_msg_objects (void)
{
  SFRPAGE  = CAN0_PAGE;
  CAN0ADR  = IF1CMDMSK;    // Point to Command Mask Register 1
  CAN0DATL = 0xFF;         // Set direction to WRITE all IF registers to Msg Obj
  for (i=1;i<33;i++)
    {
      CAN0ADR = IF1CMDRQST; // Write blank (reset) IF registers to each msg obj
      CAN0DATL = i;
    }
}

//Initialize Message Object for RX
void init_msg_object_RX (char MsgNum)
{
  SFRPAGE  = CAN0_PAGE;
  CAN0ADR  = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT  = 0x00B8;     // Set to WRITE, and alter all Msg Obj except ID MASK
                         // and data bits
  CAN0ADR  = IF1ARB1;    // Point to arbitration1 register
  CAN0DAT  = 0x0000;     // Set arbitration1 ID to "0"
  CAN0DAT  = 0x8000;     // Arb2 high byte:Set MsgVal bit, no extended ID,
                         // Dir = RECEIVE
  CAN0DAT  = 0x0480;     // Msg Cntrl: set RXIE, remote frame function disabled
  CAN0ADR  = IF1CMDRQST; // Point to Command Request reg.
  CAN0DATL = MsgNum;     // Select Msg Obj passed into function parameter list
                         // --initiates write to Msg Obj
  // 3-6 CAN clock cycles to move IF register contents to the Msg Obj in CAN RAM
}

//Initialize Message Object for TX
void init_msg_object_TX (char MsgNum)
{
  SFRPAGE = CAN0_PAGE;
  CAN0ADR = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT = 0x00B2;     // Set to WRITE, & alter all Msg Obj except ID MASK bits
  CAN0ADR = IF1ARB1;    // Point to arbitration1 register
  CAN0DAT = 0x0000;     // Set arbitration1 ID to highest priority
  CAN0DAT = 0xA004;     // Autoincrement to Arb2 high byte:
                        // Set MsgVal bit, no extended ID, Dir = WRITE
  CAN0DAT = 0x0081;     // Msg Cntrl: DLC = 1, remote frame function not enabled
  CAN0ADR = IF1CMDRQST; // Point to Command Request reg.
  CAN0DAT = MsgNum;     // Select Msg Obj passed into function parameter list
                        // --initiates write to Msg Obj
  // 3-6 CAN clock cycles to move IF reg contents to the Msg Obj in CAN RAM.
}

//Start CAN
void start_CAN (void)
{
  /* Calculation of the CAN bit timing :

  System clock        f_sys = 22.1184 MHz/2 = 11.0592 MHz.
  System clock period t_sys = 1/f_sys = 90.422454 ns.
  CAN time quantum       tq = t_sys (at BRP = 0)

  Desired bit rate is 1 MBit/s, desired bit time is 1000 ns.
  Actual bit time = 11 tq = 996.65ns ~ 1000 ns
  Actual bit rate is 1.005381818 MBit/s = Desired bit rate+0.5381%

  CAN bus length = 10 m, with 5 ns/m signal delay time.
  Propagation delay time : 2*(transceiver loop delay + bus line delay) = 400 ns
  (maximum loop delay between CAN nodes)

  Prop_Seg = 5 tq = 452 ns ( >= 400 ns).
  Sync_Seg = 1 tq

  Phase_seg1 + Phase_Seg2 = (11-6) tq = 5 tq
  Phase_seg1 <= Phase_Seg2,  =>  Phase_seg1 = 2 tq and Phase_Seg2 = 3 tq
  SJW = (min(Phase_Seg1, 4) tq = 2 tq

  TSEG1 = (Prop_Seg + Phase_Seg1 - 1) = 6
  TSEG2 = (Phase_Seg2 - 1)            = 2
  SJW_p = (SJW - 1)                   = 1

  Bit Timing Register = BRP + SJW_p*0x0040 = TSEG1*0x0100 + TSEG2*0x1000 = 2640

  Clock tolerance df :

  A: df < min(Phase_Seg1, Phase_Seg2) / (2 * (13*bit_time - Phase_Seg2))
  B: df < SJW / (20 * bit_time)

  A: df < 2/(2*(13*11-3)) = 1/(141-3) = 1/138 = 0.7246%
  B: df < 2/(20*11)                   = 1/110 = 0.9091%

  Actual clock tolerance is 0.7246% - 0.5381% = 0.1865% (no problem for quartz)
  */

  SFRPAGE  = CAN0_PAGE;
  CAN0CN  |= 0x41;       // Configuration Change Enable CCE and INIT
  CAN0ADR  = BITREG   ;  // Point to Bit Timing register
  CAN0DAT  = 0x2640;     // see above

  CAN0ADR  = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT  = 0x0087;     // Config for TX : WRITE to CAN RAM, write data bytes,
                         // set TXrqst/NewDat, clr IntPnd

  // RX-IF2 operation may interrupt TX-IF1 operation
  CAN0ADR  = IF2CMDMSK;  // Point to Command Mask 2
  CAN0DATL = 0x1F;       // Config for RX : READ CAN RAM, read data bytes,
                         // clr NewDat and IntPnd
  CAN0CN  |= 0x06;       // Global Int. Enable IE and SIE
  CAN0CN  &= ~0x41;      // Clear CCE and INIT bits, starts CAN state machine
}

//Transmit CAN frame to turn other node's LED ON
void transmit_turn_LED_ON (char MsgNum)
{
  SFRPAGE  = CAN0_PAGE;  // IF1 already set up for TX
  CAN0ADR  = IF1CMDMSK;  // Point to Command Mask 1
  CAN0DAT  = 0x0087;     // Config to WRITE to CAN RAM, write data bytes,
                         // set TXrqst/NewDat, Clr IntPnd
  CAN0ADR  = IF1DATA1;   // Point to 1st byte of Data Field
  CAN0DATL = 0x11;       // Ones signals to turn LED's light ON in data A1 field
  CAN0ADR  = IF1CMDRQST; // Point to Command Request Reg.
  CAN0DATL = MsgNum;     // Move new data for TX to Msg Obj "MsgNum"
}

//Transmit CAN Frame to turn other node's LED OFF
void transmit_turn_LED_OFF (char MsgNum)
{
  SFRPAGE  = CAN0_PAGE;  // IF1 already set up for TX
  CAN0ADR  = IF1DATA1;   // Point to 1st byte of Data Field
  CAN0DATL = 0x00;       // Zero signals to turn LED's light ON in Data A1 field
  CAN0ADR  = IF1CMDRQST; // Point to Command Request Reg.
  CAN0DATL = MsgNum;     // Move new data for TX to Msg Obj "MsgNum"
}


// Receive Data from the IF2 buffer
void receive_data (char MsgNum)
{
  char virtual_button;
  SFRPAGE  = CAN0_PAGE; // IF1 already set up for RX
  CAN0ADR  = IF2CMDRQST;// Point to Command Request Reg.
  CAN0DATL = MsgNum;    // Move new data for RX from Msg Obj "MsgNum"
                        // Move new data to a
  CAN0ADR  = IF2DATA1;  // Point to 1st byte of Data Field

  virtual_button = CAN0DATL;
  if (virtual_button == 0x11)   //Ones is signal from other node to turn LED ON
    LED = 1;
  else  LED = 0;                //Otherwise turn LED OFF (message was one's)
}

////////////////////////////////////////////////////////////////////////////////
//Interrupt Service Routine
////////////////////////////////////////////////////////////////////////////////
void ISRname (void) interrupt 19
{
  status = CAN0STA;
  if ((status&0x10) != 0)
    {                            // RxOk is set, interrupt caused by reception
      CAN0STA = (CAN0STA&0xEF)|0x07;         // Reset RxOk, set LEC to NoChange
      /* read message number from CAN INTREG */
      receive_data (0x01);             // Up to now, we have only one RX message
    }
  if ((status&0x08) != 0)
    {                            // TxOk is set, interrupt caused by transmision
      CAN0STA = (CAN0STA&0xF7)|0x07;        // Reset TxOk, set LEC to NoChange
    }
  if (((status&0x07) != 0)&&((status&0x07) != 7))
    {                           // Error interrupt, LEC changed
      /* error handling ? */
      CAN0STA = CAN0STA|0x07;              // Set LEC to NoChange
    }
}

⌨️ 快捷键说明

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