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

📄 mcohwcc01.c

📁 1开放源码的CanOpen(C)
💻 C
字号:
/**************************************************************************
MODULE:    MCOHWCC01
CONTAINS:  Preliminary, limited hardware driver implementation for
           Atmel 89C51CC01 - tested using the Atmel CANopen Demo Board
		   using a 20Mhz clock (CANgine board: www.cangine.com)
           This version was tested with the Keil compiler system.
           www.keil.com
COPYRIGHT: Embedded Systems Academy, Inc. 2002-2003.
           All rights reserved. www.microcanopen.com
           This software was written in accordance to the guidelines at
		   www.esacademy.com/software/softwarestyleguide.pdf
DISCLAIM:  Read and understand our disclaimer before using this code!
           www.esacademy.com/disclaim.htm
LICENSE:   Users that have purchased a license for PCANopenMagic
           (www.esacademy.com/software/pcanopenmagic)
           may use this code in commercial projects.
           Otherwise only educational use is acceptable.
VERSION:   1.20, Pf/Aa/Ck 27-MAY-03
---------------------------------------------------------------------------
HISTORY:   1.20, Pf 27-MAY-03, Adapted for 20MHz Atmel CANopen Demo Board
                 added support for CANopen ERR and RUN LED
           1.00, Ck 07-OCT-02, First Published Version
---------------------------------------------------------------------------
Known Shortcomings:
Only supports a transmit queue of length "1"
If queue occupied, waits until it is clear
***************************************************************************/ 

#include <Reg51cc01.h>
#include "mcohw.h"

#ifdef USE_LED
BYTE data m200cnt = 0;
#endif // USE_LED

// Global timer/conter variable, incremented every millisecond
WORD data gTimCnt = 0;

// Global conter for number of receive filters used
BYTE gCANFilter = 0;


#ifdef USE_LED
/**************************************************************************
Variables for LED management
**************************************************************************/
BYTE data mLEDtoggle = 0;
BYTE data mLEDcnt = 0;
BYTE data gRLED = LED_OFF; // Current pattern on run led
BYTE data gELED = LED_OFF; // Current pattern on error led


/**************************************************************************
DOES: This function switches the CANopen Err and Run LEDs
as specified by DR-303-3
It must be called once every 200ms
**************************************************************************/
void MCO_SwitchLEDs
  (
  void
  )
{
  mLEDtoggle = ~mLEDtoggle;
  mLEDcnt++;
  if (mLEDcnt >= 6)
  {
    mLEDcnt = 0;
  }

  switch(gRLED) // Run LED
  {
    case LED_OFF:
	  LED_RUN = 1;
	  break;
	case LED_ON:
	  LED_RUN = 0;
	  break;
	case LED_BLINK:
	  LED_RUN = mLEDtoggle;
	  break;
	case LED_FLASH1:
	  if (mLEDcnt == 0)
	  {
	    LED_RUN = 0;
	  }
	  else
	  {
	    LED_RUN = 1;
	  }
	  break;
	default:
	  break;
  }

  switch(gELED) // Error LED
  {
    case LED_OFF:
	  LED_ERR = 1;
	  break;
	case LED_ON:
	  LED_ERR = 0;
	  break;
	case LED_BLINK:
	  LED_ERR = mLEDtoggle;
	  break;
	case LED_FLASH1:
	  if (mLEDcnt == 1)
	  {
	    LED_ERR = 0;
	  }
	  else
	  {
	    LED_ERR = 1;
	  }
	  break;
	default:
	  break;
  }

}
#endif // USE_LED


/*======================================================================*/
/* FUNCTION:   init_can_125_20                                          */
/* DESCRIPTION:Initializes the CAN interface. Bus operates at 125kBit,  */
/*             if processor clock is 20MHz.                             */
/* CAUTION:    Does not initialize filters - nothing will be received   */
/*             unless screeners are set using set_screener_std          */
/* INPUT:      none                                                     */
/* OUTPUT:     none                                                     */
/*======================================================================*/
void init_can_125_20 ( void )
{
BYTE i;

/* Enable X2 mode */
   CKCON = 0x01;

/* timing for X2 mode, 20MHz, 125kbps */
   CANBT1 = 7 << 1;
   CANBT2 = (1 << 5) | (7 << 1); // SJW << 5, PRS << 1
   CANBT3 = (2 << 4) | (7 << 1); // PHS2 << 4, PHS << 1

/* Clear all acceptance filters and masks, receive nothing */
   for (i=0; i<15; i++)
   {
      CANPAGE  = i << 4;            /* select msg object i */
      CANIDT1  = 0xFF;              /* msg id bits 3-10 */
      CANIDT2  = 0xE0;              /* msg id bits 0-2 */
      CANIDT4  = 0x00;              /* no remote request */
      CANIDM1  = 0xFF;              /* mask bits 3-10 */
      CANIDM2  = 0xE0;              /* mask bits 0-2 */
      CANIDM4  = 0x05;              /* only accept that msg id */
      if (i!=0)
         CANSTCH = 0x00;            /* clear receive ok (and all other) flags */
      else
         CANSTCH = 0x40;            /* for transmit buffer we need to set TX for first transmit */
/* disable msg object */
      CANCONCH = 0x00;              /* msg object is disabled */
   }
  
   CANGCON = 0x02;                 /* enable CAN controller */
   while (!(CANGSTA & 0x04));      /* wait for can controller to be enabled */

   // Initialize Timer interrupt here. 
   // MCOHW_TimerISR must be executed once every millisecond.
   TR0     =  0;                   /* timer 0: stop */
   TMOD    |= 1;                   /* mode 1 */
   TH0     =  0xFF;
   TL0     =  0xFF;
   TR0     =  1;                   /* timer 0: start */
   ET0     =  1;                   /* enable timer 0 int */
}


/*======================================================================*/
/* FUNCTION:   set_screener_std                                         */
/* DESCRIPTION:Sets one of the four screeners (acceptance filters) of   */
/*             the CAN controller.                                      */
/* CAUTION:    For the AT89C51CC01 from Atmel the screeners translate   */
/*             to individual message buffers 1-14. The parameters       */
/*             x_Mask and Bx_Match are ignored.                         */
/* INPUT:      Screener - 1 to 4, one of the four screeners             */
/*             ID_Match - Match/Code value for ID                       */
/* OUTPUT:     none                                                     */
/*======================================================================*/
void set_screener_std ( BYTE Screener, WORD ID_Match )
{
   CANPAGE  = Screener << 4;        /* select msg object */
   CANIDT1  = (ID_Match & 0x07F8) >> 3; /* msg id bits 3-10 */
   CANIDT2  = (ID_Match & 0x0007) << 5; /* msg id bits 0-2 */
   CANIDT4  = 0x00;                 /* no remote request */
   CANIDM1  = 0xFF;                 /* mask bits 3-10: must match */
   CANIDM2  = 0xE0;                 /* mask bits 0-2: must match */
   CANIDM4  = 0x05;                 /* only accept that msg id */
/* clear receive ok (and all other) flags */
   CANSTCH  = 0x00;                /* initialize */
/* enable msg object */
   CANCONCH = 0x88;                /* msg object is enabled for receive, expected 8 bytes */
}



BYTE MCOHW_PullMessage (CAN_MSG *pReceiveBuf)
{
DWORD Identifier;                   /* Definition of vars */
BYTE  Length;
BYTE  i,j;

   for (j=1; j<=gCANFilter; j++)   /* Find msg object that has received something */
   {
      CANPAGE = j << 4;    // select msg object

/* Check the CAN status register for received message                */
      if (CANSTCH & 0x20)
      {                                       /* Message received!   */
         /* Copy message to application message buffer.              */
         Identifier = (unsigned int)(CANIDT1 << 3) | (CANIDT2 >> 5);
         Length     = CANCONCH & 0x0F;
 
         pReceiveBuf->ID  = Identifier;
         pReceiveBuf->LEN = Length;

         /* Read data bytes and write to buffer                      */
         for (i=0; i < Length; i++)
    	      *(BYTE *)(pReceiveBuf->BUF+i) = CANMSG;  /* copy bytes   */
 
         // clear receive ok flag
         CANSTCH &= 0xDF;
         // re-enable msg object
         CANCONCH = 0x88;      /* msg object receives and is enabled */
                               /* 8 bytes excpected                  */

         return (1);                /* Return TRUE, msg rcvd    */
     }
  }

  return (0);                      /* Return False, no msg rcvd */
}

BYTE MCOHW_PushMessage (CAN_MSG *pTransmitBuf)
{
DWORD Identifier;                   /* CAN message identifier */
BYTE  Length;                       /* length of data frame */
BYTE  i;                            /* local loop counter */

/* Prepare length code and identifier.                                  */
   Length     = pTransmitBuf->LEN;
   Identifier = pTransmitBuf->ID;

   CANPAGE  = 0 << 4;               /* select msg object 0 */

/* Check if write access to CAN controller buffer is allowed          */
   while (!(CANSTCH & 0x40)) 
   {
   }
   if (!(CANSTCH & 0x40))
   {
     return 0;
   }

   CANCONCH &=  0x3F;              /* disable object */
   CANSTCH  &= ~0x40;              /* clear TXOK bit */

   CANIDT1  = (Identifier & 0x07F8) >> 3;  /* msg id bits 3-10 */
   CANIDT2  = (Identifier & 0x0007) << 5;  /* msg id bits 0-2 */
   CANIDT4  = 0x00;                /* no remote request */

/* Write message to transmit buffer                                     */
   for (i=0; i < Length; i++)        /* write data bytes */
      CANMSG = pTransmitBuf->BUF[i]; /* copy data byte  */

/* set length and enable msg object => send */
   CANCONCH = 0x40 | (Length & 0x0F);
   
   return 1;
}


/**************************************************************************
DOES: Reads and returns the value of the current 1 millisecond system
      timer tick.
**************************************************************************/
WORD MCOHW_GetTime (void)
{
WORD tmp;

  EA = 0; // Disable Interrupts
  tmp = gTimCnt;
  EA = 1; // Enable Interrupts
  return tmp;
}


BYTE MCOHW_IsTimeExpired(WORD timestamp)
{
WORD time_now;

  EA = 0; // Disable Interrupts
  time_now = gTimCnt;
  EA = 1; // Enable Interrupts
  timestamp++; // To ensure the minimum runtime
  if (time_now > timestamp)
  {
    if ((time_now - timestamp) < 0x8000)
      return 1;
    else
      return 0;
  }
  else
  {
    if ((timestamp - time_now) > 0x8000)
      return 1;
    else
      return 0;
  }
}

/**************************************************************************
DOES: Timer Interrupt Service Routine. 
      Increments the global millisecond counter tick.
      This function needs to be executed once every millisecond!
**************************************************************************/
#define T0_RELOAD 62210 
// Time reload to achieve 1 millisecond at 20MHz, 6-clock

void MCOHW_TimerISR (void) interrupt 1
{

  TR0 = 0; // Stop Timer 0
  TH0 = T0_RELOAD / 256;
  TL0 = T0_RELOAD % 256; // Timer reload value
  TR0 = 1; // Start Timer 0

  gTimCnt++; // Increment global counter

#ifdef USE_LED
  m200cnt++;
  if (m200cnt >= 200)
  {
    MCO_SwitchLEDs(); // Call all 200ms
    m200cnt = 0;
  }
#endif // USE_LED
}

BYTE MCOHW_Init (WORD BaudRate)
{
// This version only supports 125kbit at 20MHz
  if (BaudRate == 125)
  {
    init_can_125_20();
    gCANFilter = 0;
	return 1;
  }
  else
  {
    return 0;
  }
}

BYTE MCOHW_SetCANFilter (WORD CANID)
{
  gCANFilter++;
  if (gCANFilter > 14)  // Kl, 10/9/02 Modified for CC01
  {
    return 0;
  }
  else
  {
    set_screener_std(gCANFilter, CANID); 
    return 1;
  }
}


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






⌨️ 快捷键说明

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