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

📄 can.c

📁 AVR平台下的CanOpen协议桟源码包括应用
💻 C
📖 第 1 页 / 共 3 页
字号:
/* ------------------------------------------------------------------------
File   : can.c

Descr  : Functions for serial operation of an 81C91 CAN-controller.

History: 19JAN.00; Henk B&B; Definition.
         31JAN.00; Henk B&B; Beware!: start reading/writing message
	                     with most-significant byte (7) and end
			     with data byte 0.
	 21JUL.00; Henk B&B; Enable the use of all 16 message objects
	                     (up to now just the first 8 were considered).
	 22FEB.01; Henk B&B; Keep some variables in EEPROM (optionally).
	 17JUL.01; Henk B&B; Go to sleep for a while at bus-off, before
	                     reinitialising.
	 17OCT.01; Henk B&B; Implement CAN descriptor register refresh.
	 27FEB.03; Henk B&B; Add a CAN configuration parameters datablock
	                     (in EEPROM);
			     add possibility to disable Remote Frames,
	                     through the Object Dictionary, but keep
			     Nodeguarding possible (through automatic replies).
	   MAY.03; Henk B&B; Added receive message buffering under interrupt.
	 02JUN.03; Henk B&B; Add to CAN configuration parameters datablock:
			     - add CANopenOpStateInit bool, to automatically
			       go to state Operational at startup
			     - add Bus-off max counter value
	 26SEP.03; Henk B&B; Added can_recv_descriptor_refresh();
	                     call it in can_read() as well as can_write(),
			     to refresh descriptors of all receiving buffers.
	 23OCT.03; Henk B&B; Enable the 81c91's Transmit Check feature.
	 25FEB.04; Henk B&B; Added toggle bit to Emergency message.
	 31MAR.04; Henk B&B; remove can_recv_descriptor_refresh() from
	                     can_write(): message loss is possible.
--------------------------------------------------------------------------- */

#include "general.h"
#include "can.h"
#include "guarding.h"
#include "jumpers.h"
#include "pdo.h"
#include "spi.h"
#include "store.h"
#include "timer103.h"

#ifdef __VARS_IN_EEPROM__
#include "eeprom.h"
#endif

/* CANopen state of this node (declared in ELMBmain.c) */
extern BYTE NodeState;

/* ------------------------------------------------------------------------ */
/* CAN message buffering in RAM */

/* Number of message buffers (here must be a power of 2!) */
#define CAN_BUFS        64
#define CAN_BUFS_MASK   CAN_BUFS-1
/* Size of message buffer */
#define CAN_BUF_SIZE    11

/* Indices into the individual buffers */
#define MSG_DATA_I      0
#define MSG_DLC_I       8
#define MSG_OBJECT_I    9
#define MSG_VALID_I     10

/* Buffer values:
   'message-present' byte in location MSG_VALID_I:
   0x00 means 'message present', 0xFF means 'no message present'.
   To tolerate up to 2 bitflips:
   bits-in-byte <= 2: message
   bits-in-byte >= 6: no message */
#define BUF_EMPTY       0xFF
#define BUF_NOT_EMPTY   0x00

/* Array of CAN message buffers */
static BYTE CanMsgBuf[CAN_BUFS][CAN_BUF_SIZE];

static BOOL CanBufFull;

/* Parameters which are being used according to a majority voting mechanism:
   MsgOutIndex_ : index of the first-to-be-handled CAN-message buffer,
   MsgCounter_: number of unhandled CAN-messages in buffers */
static BYTE MsgOutIndex1, MsgOutIndex2, MsgOutIndex3;
static BYTE MsgCounter1,  MsgCounter2,  MsgCounter3;

/* NB: make sure to disable the CAN INT interrupt before writing or reading
   anything to/from the CAN-controller in the main program loop !
   (and also when updating the buffer counter in the main loop) */

/* ------------------------------------------------------------------------ */
/* CAN-controller message object descriptors */

/* Description Registers settings for NMT, SDO-tx/SDO-rx, Emergency,
   Bootup/Nodeguard, SYNC, PDOs, etc.
   (according to the CANopen Predefined Connection Set);
   in the following array is space for all available message buffers;
   NB: to simplify refreshing the descriptor registers the CAN_DESCRIPTOR
       array contains the values in order of message buffer number to
       write to; make absolutely sure this list matches the message/buffer
       numbering in can.h !! */

const BYTE CAN_DESCRIPTOR[C91_MSG_BUFFERS][2] =
{
  /* Buffer 0 must be used if we want to filter out RTRs for this node
     (and to let them be handled by the microcontroller!) */
  { 0xFF,		0xE0 },

  /* NMT */
  { NMT_OBJ,		C91_NMT_LEN },

  /* SYNC */
  { SYNC_OBJ,		C91_SYNC_LEN },

  /* EMERGENCY */
  { EMERGENCY_OBJ,	C91_EMERGENCY_LEN },

  /* SDO-Transmit */
  { SDOTX_OBJ,		C91_SDOTX_LEN },

  /* SDO-Receive */
  { SDORX_OBJ,		C91_SDORX_LEN },

  /* Bootup/Nodeguard */
  { NODEGUARD_OBJ,	C91_NODEGUARD_LEN },

  /* Transmit-PDO2 */
  { TPDO2_OBJ,		C91_TPDO2_LEN },

  /* Transmit-PDO1 */
  { TPDO1_OBJ,		C91_TPDO1_LEN },

  /* Receive-PDO1 */
  { RPDO1_OBJ,		C91_RPDO1_LEN },

  /* Receive-PDO2 */
  { RPDO2_OBJ,		C91_RPDO2_LEN },

  /* Transmit-PDO3 */
  { TPDO3_OBJ,		C91_TPDO3_LEN },

  /* ---- object available ---- */
  { 0xFF,		0xE0 },

  /* ---- object available ---- */
  { 0xFF,		0xE0 },

  /* ---- object available ---- */
  { 0xFF,		0xE0 },

  /* ---- object available ---- */
  { 0xFF,		0xE0 }
};

/* This array of BOOLs indicates which CAN-controller buffers
   are receiving buffers; their descriptors are refreshed
   (if __CAN_REFRESH__ is defined) in can_read() and can_write()
   Make sure this array matches CAN_DESCRIPTOR[] !
   Do not refresh RTR buffer like this: RTR may get lost */
const BOOL CANBUF_IS_RECV[C91_MSG_BUFFERS] =
{
  FALSE, TRUE,  TRUE,  FALSE,
  FALSE, TRUE,  FALSE, FALSE,
  FALSE, TRUE,  TRUE,  FALSE,
  FALSE, FALSE, FALSE, FALSE
};

/* Index for CANBUF_IS_RECV[] */
static BYTE CanRefreshIndex;

/* CAN-controller register settings for baudrate configuration */
const BYTE CAN_BAUDRATE_CONFIGS[4][3] =
{
  { C91_BRP_50K,	C91_BL1_50K,	C91_BL2_50K },
  { C91_BRP_500K,	C91_BL1_500K,	C91_BL2_500K },
  { C91_BRP_250K,	C91_BL1_250K,	C91_BL2_250K },
  { C91_BRP_125K,	C91_BL1_125K,	C91_BL2_125K }
};

/* ------------------------------------------------------------------------ */
/* Globals */

BYTE        NodeID;      /* (stored in EEPROM) */

BYTE        CANopenErrorReg;

/* Counter for errors in the CAN communication */
static BYTE CanErrorCntr;

BOOL        RtrDisabled; /* (stored in EEPROM) */

/* Boolean to enable 'autostart' (automatically goto Operational mode) */
static BOOL CANopenOpStateInit; /* (copy in EEPROM) */

/* Max counter value for bus access retries after Bus-off events */
static BYTE CanBusOffMaxCnt;    /* (copy in EEPROM) */

/* Bus-off events counter */
BYTE        CanBusOffCnt = 0;

/* Help variables for RTR reception */
static BYTE RtrIdHi;     /* (stored in EEPROM) */
static BYTE RtrIdLo;     /* (stored in EEPROM) */

/* Help variables for CAN message reception */
static BYTE ObjectMask1;
static BYTE ObjectMask2;

/* Toggle bit for the Emergency CAN-message */
static BYTE CanEmgToggle = 0x80;

/* ------------------------------------------------------------------------ */
/* Local prototypes */

static BYTE can_check_for_msgs( void );
static BYTE get_buf_index     ( void );
static BYTE get_buf_cntr      ( void );
static BYTE bits_in_byte      ( BYTE val );

static void can_load_config   ( void );

#ifdef __CAN_REFRESH__
static void can_descriptor_refresh( BYTE object_no );
static void can_recv_descriptor_refresh( void );
#endif /* __CAN_REFRESH__ */

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

BYTE can_read_reg( BYTE regaddr )
{
  BYTE byt;

  /* Select CAN-controller and read-mode */
  CAN_SELECT();
  CAN_READ_ENABLE();

  spi_write( regaddr );
  byt = spi_read();

  /* Deselect CAN-controller */
  CAN_DESELECT();

  return byt;
}

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

void can_write_reg( BYTE regaddr, BYTE byt )
{
  /* Select CAN-controller and write-mode */
  CAN_SELECT();
  CAN_WRITE_ENABLE();

  spi_write( regaddr );
  spi_write( byt );

  /* Deselect CAN-controller */
  CAN_DESELECT();
}

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

void can_init( BOOL init_msg_buffer )
{
  BYTE baudrate;
  BYTE i, canaddr;
  BYTE id_hi, id_lo;
  BYTE bufno;

  /* Disable interrupt */
  CAN_INT_DISABLE();

  /* Initialise configuration parameters */
  can_load_config();

  /* Reset error counter */
  if( init_msg_buffer ) CanErrorCntr = 0;

  /* Initialize CANopen Error Register Object (Object 0x1001) */
  CANopenErrorReg = 0x00;

  /* Prepare PORTB for jumper read-out */
  DDRB  = PORTB_DDR_FOR_JUMPERS;
  PORTB = PORTB_DATA_FOR_JUMPERS;

  /* Read the jumper settings */
  NodeID   = read_nodeid();
  baudrate = read_baudrate();

  /* Set PORTB back to 'operational' setting */
  DDRB  = PORTB_DDR_OPERATIONAL;
  PORTB = PORTB_DATA_OPERATIONAL;

  /* Set CAN-controller in configuration mode */
  can_write_reg( C91_MODE_STATUS_I, C91_RES | C91_IM );

  /* Initialise registers 0 to 0x0A to zero */
  for( i=0; i<0x0B; ++i ) can_write_reg( i, 0x00 );

  /* Enable Monitor Mode to enable reception of RTRs (by CPU!) ?
     ###BEWARE: all messages not received by any of the other
                buffers are now accepted in buffer 0...
		could be a bit much if there are many nodes
		(many messages) on the bus... */
  can_write_reg( C91_CONTROL_I, 0x00 ); /* Do not enable Monitor Mode */

  /* Enable the 81C91 controller's Transmit Check feature */
  can_write_reg( C91_CONTROL_I, can_read_reg(C91_CONTROL_I) |
		 C91_TRANSMIT_CHECK_ENABLE );

  /* Reset bits in Interrupt Register */
  can_write_reg( C91_INTERRUPT_I, 0x00 );

  /* Output Control */
  can_write_reg( C91_OUTPUTCONTROL_I, 0x18 );

  /* Clock Control */
  can_write_reg( C91_CLOCKCONTROL_I, 0x80 );
  can_write_reg( C91_CLOCKCONTROL_I, 0x01 );

  /* Write the settings for the required CAN-bus baudrate */
  can_write_reg( C91_BRP_I, CAN_BAUDRATE_CONFIGS[baudrate][0] );
  can_write_reg( C91_BL1_I, CAN_BAUDRATE_CONFIGS[baudrate][1] );
  can_write_reg( C91_BL2_I, CAN_BAUDRATE_CONFIGS[baudrate][2] );

  /* Node-ID for Description Register is split over 2 bytes */
  id_hi = NodeID >> 3;
  id_lo = NodeID << 5;

  /* Initialise the Object Descriptor Registers */
  canaddr = C91_DR00_I;
  for( bufno=0; bufno<C91_MSG_BUFFERS; ++bufno )
    {
      BYTE desc_hi, desc_lo;

      /* Use the corresponding descriptor bytes */
      desc_hi = CAN_DESCRIPTOR[bufno][0];
      desc_lo = CAN_DESCRIPTOR[bufno][1];

      /* NMT and SYNC are broadcast messages: Node-ID is not in */
      if( bufno != C91_NMT && bufno != C91_SYNC )
	{
	  /* Node-ID is included in COB-ID */
	  desc_hi |= id_hi;
	  desc_lo |= id_lo;
	}

      /* Write the CAN-controller's Descriptor Registers */
      can_write_reg( canaddr, desc_hi );
      ++canaddr;
      can_write_reg( canaddr, desc_lo );
      ++canaddr;
    }

  /* Receive-Interrupt Mask Registers
     (in combination with the Interrupt Mask setting below) */
  can_write_reg( C91_RECV_INTERRUPT_MASK1_I, 0xFF );
  can_write_reg( C91_RECV_INTERRUPT_MASK2_I, 0xFF );

  /* Enable INT pin interrupt for received messages only */
  can_write_reg( C91_INTERRUPT_MASK_I, C91_RECV_INT ); 

  /* If Remote Frames are not required adjust
     the CAN-controller's configuration: disable Monitor Mode for buffer 0
     and enable automatic RTR for NODEGUARD messages */
  can_rtr_enable( pdo_rtr_required() );

  /* Set CAN-controller to operational mode */
  can_write_reg( C91_MODE_STATUS_I, 0x00 );

  /* Bit masks for objects received */
  ObjectMask1 = 0;
  ObjectMask2 = 0;

  /* Help variables for RTR reception */
  RtrIdHi = id_hi;
  RtrIdLo = id_lo | C91_DR_RTR_MASK;

#ifdef __VARS_IN_EEPROM__
  /* Create working copies of configuration globals in EEPROM */
  if( eeprom_read( EE_NODEID ) != NodeID )
    eeprom_write( EE_NODEID, NodeID );
  if( eeprom_read( EE_RTRIDHI ) != RtrIdHi )
    eeprom_write( EE_RTRIDHI, RtrIdHi );
  if( eeprom_read( EE_RTRIDLO ) != RtrIdLo )
    eeprom_write( EE_RTRIDLO, RtrIdLo );
#endif /* __VARS_IN_EEPROM__ */

  if( init_msg_buffer )
    {
      /* Initialize the CAN-message buffer and management stuff */
      for( bufno=0; bufno<CAN_BUFS; ++bufno )
	CanMsgBuf[bufno][MSG_VALID_I] = BUF_EMPTY;
      CanBufFull = FALSE;
      MsgOutIndex1 = 0; MsgOutIndex2 = 0; MsgOutIndex3 = 0;
      MsgCounter1  = 0; MsgCounter2  = 0; MsgCounter3  = 0;
    }

  /* Enable interrupt */
#ifndef __ELMB103__
  /* Low level of INT1 generates an interrupt
     (= default and unchangeable on ATmega103) */
  EICRA &= ~(BIT(ISC11) | BIT(ISC10));
#endif
  CAN_INT_ENABLE(); /* Enable interrupt from CAN-controller */

  CanRefreshIndex = C91_MSG_BUFFERS-1;
}

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

BOOL can_msg_available( void )
{
  BOOL available;

  /* Need undisturbed access to buffer management variables !
     (because even the get_buf_xxx() functions may alter variables,
     due to the (self-correcting) majority voting mechanism) */
  CAN_INT_DISABLE();

  /* CAN-message available in buffer ? */
  available = (get_buf_cntr() > 0);

  CAN_INT_ENABLE();

#ifdef __VARS_IN_EEPROM__
  /* EEPROM access removed from CAN interrupt handling, do it here instead ! */
  if( !available )
    {
      NodeID  = eeprom_read( EE_NODEID );
      RtrIdLo = eeprom_read( EE_RTRIDLO );
      RtrIdHi = eeprom_read( EE_RTRIDHI );
    }
#endif /* __VARS_IN_EEPROM__ */

  return available;
}

⌨️ 快捷键说明

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