Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Does any one have any example code on how to use CAN?

Status
Not open for further replies.

kennethone

Newbie level 1
Joined
Jan 20, 2010
Messages
1
Helped
0
Reputation
0
Reaction score
0
Trophy points
1,281
Activity points
1,290
DISPic30f4013 Can help

Hi Does nay one have any example code on how to use CAN, I looked at the code at the bottom of post, but I don't understand how to pass teh message pointer. I used

int main(void)
{
int i;
_TRISB8 = 0;

CANMSG testmsg;
/* SENDER
for (i=0;i<8;i++){
testmsg.data=1;
}
while(1){
CanSendMessage(&testmsg);
for(i=0; i<10000; i++){;}
}/**/
//* RECEIVER
while(1){
//TRISB = 0x0000;

//CanReceiveMessage(&testmsg);
if(testmsg.data[1]==1){
_RB8=1; // Turn on pin RB8 if message received data[1] == 1
}

}
/**/
}


but I don't have any idea on how to manipulate the SID or the length fields or even if they need to be manipulated. My code doesn't work.
 

Re: DISPic30f4013 Can help

You first have to set up the can module, read the 'CanLib.h' file for init sequence.

Code:
/*--- Set up can module ---*/ 

void setup_can(void) 
  { 
  CanInit(); 
  CanSetMask(0, 0x00); 
  CanSetFilter(0, 0x123); 
  CanConfig(); 
  }

CanConfig sets baud rate to 500Kbps with 20Tq for a clock of 10MHz.
You will have to modify CanConfig function in 'CanLib.c' if you need different settings

The sid is the address that the node will respond too, which you put into a receive filter.
The mask is used to set a range of valid addresses. Clearing a mask bit to 0 allows the bit through. If the mask bit is set to 1, then the filter bit and the sid bit must match to be valid.
This allows for a range of addresses to be accepted.
You need to look at the data sheet, there are two receive buffers with different masks and filters.

A message can be 0 to 8 bytes long, which you put into the length variable.
You put the address of the node into the sid variable.
Sample message:

Code:
/*--- Transmit can message --*/ 

void transmit_canMessage(void) 
  { 
  CANMSG message; 
  uint16_t speed, temperature; 

  speed = revsPerMinute / 10; 
  temperature = pcb_temperature(); 

  message.sid = 0x123; 
  message.length = 8;  

  message.data[0] = temperature >> 8; 
  message.data[1] = temperature; 
  message.data[2] = 0; 
  message.data[3] = 0; 
  message.data[4] = 0; 
  message.data[5] = speed >> 8; 
  message.data[6] = speed; 
  message.data[7] = 0; 

  CanSendMessage(&message); 
  }

Can messages are periodic, normally sent every XmS, typically 100mS.
You can set up a circular buffer to receive the messages.

Code:
/*--- can message circular buffer ---*/

#define BUFFERSIZE 12

CANMSG canMsg[BUFFERSIZE];
uint8_t writePtr; 
uint8_t readPtr;

You need to keep track of errors

Code:
/*--- Can errorflags data structure ---*/

typedef struct
  {
  unsigned Rx0_OVERFLOW:1;  /* Receive buffer 0 has overflowed */
  unsigned Rx1_OVERFLOW:1;  /* Receive buffer 1 has overflowed */
  unsigned RxBUSPASSIVE:1;  /* Receiver in error state, bus passive */
  unsigned RxWARNING:1;     /* Receiver in error state, warning */ 
  unsigned LOSTCOMMS:1;			/* */
  }CANERROR;

volatile CANERROR CANERRORbits;

intialise the can receive interrupts

Code:
IPC6bits.C1IP = 4U;     /* Set can interrupt priority */

  C1INTFbits.RX0IF = 0U;  /* Clear Receive buffer interrupt flags */    
  C1INTFbits.RX1IF = 0U;
  C1INTEbits.RX0IE = 1U;  /* Enable Receive buffer interrupts */ 
  C1INTEbits.RX1IE = 1U;

  C1INTFbits.RX0OVR = 0U; /* Clear Receive error interrupt flags */
  C1INTFbits.RX1OVR = 0U; 
  C1INTFbits.ERRIF = 0U;
  C1INTEbits.ERRIE = 1U;  /* Enable Receive error interrupts */ 
  
  IFS1bits.C1IF = 0U;     /* Clear can interrupt flag */
  IEC1bits.C1IE = 1U;     /* Enable can interrupts */

  writePtr = 0U;
  readPtr = 0U;           /* Clear message buffer pointers */

Then you write a can receive interrupt routine

Code:
/*********************************************************************************************
  Function: void __attribute__((__interrupt__)) _C1Interrupt(void)       

  PreCondition: Can1 receive interrups are enabled     
 
  Input: none.            

  Output: none.          

  Side Effects: ERRORflags and CANERRORbits may be set or cleared.    

  Overview: Can receive interrupt routine is entered on receipt of a can message.
            The error flags are checked and used to set or clear flags in the CANERROR
            stucture. If an overflow has occured and a message lost, receive buffers are cleared 
            else the received message is read and stored in the message buffer and the  
            buffer pointer incremented.  
                        
  Note 1: RX0OVR, RX1OVR must be cleared in order to clear ERRIF.  
          RXEP and EWARN are set and cleared by hardware.              
**********************************************************************************************/

void __attribute__((__interrupt__)) _C1Interrupt(void)
  {
  IFS1bits.C1IF = 0;        /* Clear can interrupt flag */

  if(C1INTFbits.ERRIF)      /* Check for receive errors */
    {
    ERRORflags.CANERR = 1;  /* Set Can error flag */

    if(C1INTFbits.RX0OVR)   /* Rx0 has overflowed, message has been lost */
      {
      CANERRORbits.Rx0_OVERFLOW = 1;  /* Set CANERRORbits */
      C1RX0CONbits.RXFUL = 0;         /* Clear Rx0 buffer */
      C1INTFbits.RX0OVR = 0;          /* Clear interrupt flag */
      }
    else{
      CANERRORbits.Rx0_OVERFLOW = 0;  /* clear CANERRORbits */
      }

    if(C1INTFbits.RX1OVR)   /* Rx1 has overflowed, message has been lost */
      {
      CANERRORbits.Rx1_OVERFLOW = 1;  /* Set CANERRORbits */
      C1RX1CONbits.RXFUL = 0;         /* Clear Rx1 buffer */
      C1INTFbits.RX1OVR = 0;          /* Clear interrupt flag */
      }
    else{
      CANERRORbits.Rx1_OVERFLOW = 0;  /* clear CANERRORbits */
      }
      
    C1INTFbits.ERRIF = 0;   /* Clear can error flag, must be done last */  
    }
  else                      /* no can errors */
    {
    ERRORflags.CANERR = 0;  
    CanReceiveMessage(&canMsg[writePtr]);
    if(++writePtr >= BUFFERSIZE){
      writePtr = 0;
      }
    }
  
  if(C1INTFbits.RX0IF){       /* Message received in buffer 0 (only clear one flag at a time) */
    C1INTFbits.RX0IF = 0;
    }
  else if(C1INTFbits.RX1IF){  /* Message received in buffer 1 */
    C1INTFbits.RX1IF = 0;
    }

  CANERRORbits.RxBUSPASSIVE = C1INTFbits.RXEP;  /* Can bus error state counters */
  CANERRORbits.RxWARNING = C1INTFbits.EWARN;    /* Set or clear CANERRORbits */
  if(C1INTFbits.EWARN){                         /* Set CANERR bit if error count warning set */
    ERRORflags.CANERR = 1;
    } 
  }

Now your program periodically reads the can message circular buffer.

Code:
/*********************************************************************************************
  Function: void serviceCan(void)        

  PreCondition: The Can module has been initialised.   
 
  Input: none.            

  Output: none          

  Side Effects: The variable 'PUMP.targetSpeed' may be changed.   

  Overview: This function is called from the main program loop at 100mS intervals to service the
            can bus. If can messages are pending, the function calls readMessages().
            The function calls canTxStatus() to report pump status over can.  
            The function also increments and tests the counter canTimeout.         
  Note 1:                       
**********************************************************************************************/

void serviceCan(void)
  {
  static uint8_t canTimeout;

  if(readPtr != writePtr)
    {
    canTimeout = 0;
    ERRORflags.LOSTCOMMS = 0;
    readMessages();
    }
  else if(++canTimeout > CANCOMMS_LOST){
    ERRORflags.LOSTCOMMS = 1;
    }
  
  canTxStatus();
  }

You then write a readMessages function to do whatever the messages mean to the program?

Code:
/*--- Decode message ---*/

static void readMessages(void)
  {
  while(readPtr != writePtr)
    {
    switch(canMsg[readPtr].sid)
      {
      case PUMP_COMMAND:  ERRORflags.ONOFF = canMsg[readPtr].data[0]; 
                          PUMP.speedDemand = canMsg[readPtr].data[1];

                          if(ERRORflags.ONOFF == 1){
                            PUMP.speedDemand *= 58;
                            }
                          else{
                            PUMP.speedDemand = 0;
                            }
                          break;

      case REQUEST: etc, etc  
                         break;
      }

    if(++readPtr >= BUFFERSIZE){
      readPtr = 0;
      }
    }
  }


The above functions are extracts from a larger can comms module to control a pump.
You might need to juggle a few bits to make it compile.
 

    V

    Points: 2
    Helpful Answer Positive Rating
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top