CAN Library
mikroBasic PRO for PIC provides a library (driver) for working with the CAN module.
The CAN is a very robust protocol that has error detection and signalization, self–checking and fault confinement. Faulty CAN data and remote frames are re-transmitted automatically, similar to the Ethernet.
Data transfer rates depends on the distance. For example, 1 Mbit/s can be achieved at network lengths below 40m while 250 Kbit/s can be achieved at network lengths below 250m. The greater distance the lower maximum bitrate that can be achieved. The lowest bitrate defined by the standard is 200Kbit/s. Cables used are shielded twisted pairs.
CAN supports two message formats:
- Standard format, with 11 identifier bits, and
- Extended format, with 29 identifier bits

- Consult the CAN standard about CAN bus termination resistance.
Library Routines
- CANSetOperationMode
- CANGetOperationMode
- CANInitialize
- CANSetBaudRate
- CANSetMask
- CANSetFilter
- CANRead
- CANWrite
- CANSetTxIdleLevel
CANSetOperationMode
Prototype |
sub procedure CANSetOperationMode(dim mode, wait_flag as byte) |
---|---|
Returns |
Nothing. |
Description |
Sets CAN to requested mode, i.e. copies Parameter
|
Requires |
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
CANSetOperationMode(_CAN_MODE_CONFIG, $FF) |
CANGetOperationMode
Prototype |
sub function CANGetOperationMode() as byte |
---|---|
Returns |
Current opmode. |
Description |
Function returns current operational mode of CAN module. |
Requires |
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
if CANGetOperationMode() = _CAN_MODE_NORMAL then ... |
CANInitialize
Prototype |
sub procedure CANInitialize(dim SJW, BRP, PHSEG1, PHSEG2, PROPSEG, CAN_CONFIG_FLAGS as byte) |
---|---|
Returns |
Nothing. |
Description |
Initializes CAN. All pending transmissions are aborted. Sets all mask registers to 0 to allow all messages. Filter registers are set according to flag value: if (CAN_CONFIG_FLAGS and _CAN_CONFIG_VALID_XTD_MSG) <> 0 ' Set all filters to XTD_MSG else if (config and _CAN_CONFIG_VALID_STD_MSG) <> 0 ' Set all filters to STD_MSG else ' Set half of the filters to STD, and the rest to XTD_MSG. Parameters:
|
Requires |
CAN must be in Config mode; otherwise the function will be ignored. Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
init = _CAN_CONFIG_SAMPLE_THRICE and _CAN_CONFIG_PHSEG2_PRG_ON and _CAN_CONFIG_STD_MSG and _CAN_CONFIG_DBL_BUFFER_ON and _CAN_CONFIG_VALID_XTD_MSG and _CAN_CONFIG_LINE_FILTER_OFF ... CANInitialize(1, 1, 3, 3, 1, init) ' Initialize CAN |
CANSetBaudRate
Prototype |
sub procedure CANSetBaudRate(dim SJW, BRP, PHSEG1, PHSEG2, PROPSEG, CAN_CONFIG_FLAGS as byte) |
---|---|
Returns |
Nothing. |
Description |
Sets CAN baud rate. Due to complexity of CAN protocol, you cannot simply force a bps value. Instead, use this function when CAN is in Config mode. Refer to datasheet for details. Parameters:
|
Requires |
CAN must be in Config mode; otherwise the function will be ignored. Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
init = _CAN_CONFIG_SAMPLE_THRICE and _CAN_CONFIG_PHSEG2_PRG_ON and _CAN_CONFIG_STD_MSG and _CAN_CONFIG_DBL_BUFFER_ON and _CAN_CONFIG_VALID_XTD_MSG and _CAN_CONFIG_LINE_FILTER_OFF ... CANSetBaudRate(1, 1, 3, 3, 1, init) |
CANSetMask
Prototype |
sub procedure CANSetMask(dim CAN_MASK as byte, dim value as longint, dim CAN_CONFIG_FLAGS as byte) |
---|---|
Returns |
Nothing. |
Description |
Function sets mask for advanced filtering of messages. Given Parameters:
|
Requires |
CAN must be in Config mode; otherwise the function will be ignored. Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
' Set all mask bits to 1, i.e. all filtered bits are relevant: CANSetMask(_CAN_MASK_B1, -1, _CAN_CONFIG_XTD_MSG) ' Note that -1 is just a cheaper way to write $FFFFFFFF. ' Complement will do the trick and fill it up with ones. |
CANSetFilter
Prototype |
sub procedure CANSetFilter(dim CAN_FILTER as byte, dim value as longint, dim CAN_CONFIG_FLAGS as byte) |
---|---|
Returns |
Nothing. |
Description |
Function sets message filter. Given Parameters:
|
Requires |
CAN must be in Config mode; otherwise the function will be ignored. Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
' Set id of filter B1_F1 to 3: CANSetFilter(_CAN_FILTER_B1_F1, 3, _CAN_CONFIG_XTD_MSG) |
CANRead
Prototype |
sub function CANRead(dim byref id as longint, dim byref data as byte[8], dim byref datalen, CAN_RX_MSG_FLAGS as byte) as byte |
---|---|
Returns |
Message from receive buffer or zero if no message found. |
Description |
Function reads message from receive buffer. If at least one full receive buffer is found, it is extracted and returned. If none found, function returns zero. Parameters:
|
Requires |
CAN must be in mode in which receiving is possible. Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
dim len, rcv, rx as byte dim id as longint dim data as byte[8] ' ... rx = 0 ' ... rcv = CANRead(id, data, len, rx) |
CANWrite
Prototype |
sub function CANWrite(dim id as longint, dim byref data as byte[8], dim datalen, CAN_TX_MSG_FLAGS as byte) as byte |
---|---|
Returns |
Returns zero if message cannot be queued (buffer full). |
Description |
If at least one empty transmit buffer is found, function sends message on queue for transmission. If buffer is full, function returns 0. Parameters:
|
Requires |
CAN must be in Normal mode. Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
Example |
dim id as longint dim tx, data as byte ' ... tx = _CAN_TX_PRIORITY_0 and _CAN_TX_XTD_FRAME ' ... CANWrite(id, data, 2, tx) |
CANSetTxIdleLevel
Prototype |
sub procedrue CANSetTxIdleLevel(dim driveHighState as byte) |
||||||
---|---|---|---|---|---|---|---|
Returns |
Nothing. |
||||||
Description |
This function sets the state of CANTX pin when recessive. Parameters:
|
||||||
Requires |
Microcontroller must be connected to CAN transceiver (MCP2551 or similar) which is connected to CAN bus. |
||||||
Example |
CANSetTxIdleLevel(_CAN_DRIVE_HIGH_STATE_ENABLE) |
CAN Constants
There is a number of constants predefined in CAN library. To be able to use the library effectively, you need to be familiar with these. You might want to check the example at the end of the chapter.
CAN_OP_MODE
CAN_OP_MODE
constants define CAN operation mode. Function CANSetOperationMode
expects one of these as its argument:
const _CAN_MODE_BITS = $E0 ' Use it to access mode bits const _CAN_MODE_NORMAL = 0 const _CAN_MODE_SLEEP = $20 const _CAN_MODE_LOOP = $40 const _CAN_MODE_LISTEN = $60 const _CAN_MODE_CONFIG = $80
CAN_CONFIG_FLAGS
CAN_CONFIG_FLAGS
constants define flags related to CAN module configuration. Functions CANInitialize
and CANSetBaudRate
expect one of these (or a bitwise combination) as their argument:
const _CAN_CONFIG_DEFAULT = $FF ' 11111111 const _CAN_CONFIG_PHSEG2_PRG_BIT = $01 const _CAN_CONFIG_PHSEG2_PRG_ON = $FF ' XXXXXXX1 const _CAN_CONFIG_PHSEG2_PRG_OFF = $FE ' XXXXXXX0 const _CAN_CONFIG_LINE_FILTER_BIT = $02 const _CAN_CONFIG_LINE_FILTER_ON = $FF ' XXXXXX1X const _CAN_CONFIG_LINE_FILTER_OFF = $FD ' XXXXXX0X const _CAN_CONFIG_SAMPLE_BIT = $04 const _CAN_CONFIG_SAMPLE_ONCE = $FF ' XXXXX1XX const _CAN_CONFIG_SAMPLE_THRICE = $FB ' XXXXX0XX const _CAN_CONFIG_MSG_TYPE_BIT = $08 const _CAN_CONFIG_STD_MSG = $FF ' XXXX1XXX const _CAN_CONFIG_XTD_MSG = $F7 ' XXXX0XXX const _CAN_CONFIG_DBL_BUFFER_BIT = $10 const _CAN_CONFIG_DBL_BUFFER_ON = $FF ' XXX1XXXX const _CAN_CONFIG_DBL_BUFFER_OFF = $EF ' XXX0XXXX const _CAN_CONFIG_MSG_BITS = $60 const _CAN_CONFIG_ALL_MSG = $FF ' X11XXXXX const _CAN_CONFIG_VALID_XTD_MSG = $DF ' X10XXXXX const _CAN_CONFIG_VALID_STD_MSG = $BF ' X01XXXXX const _CAN_CONFIG_ALL_VALID_MSG = $9F ' X00XXXXX
You may use bitwise and
to form config byte out of these values. For example:
init = _CAN_CONFIG_SAMPLE_THRICE and _CAN_CONFIG_PHSEG2_PRG_ON and _CAN_CONFIG_STD_MSG and _CAN_CONFIG_DBL_BUFFER_ON and _CAN_CONFIG_VALID_XTD_MSG and _CAN_CONFIG_LINE_FILTER_OFF ... CANInitialize(1, 1, 3, 3, 1, init) ' Initialize CAN
CAN_TX_MSG_FLAGS
CAN_TX_MSG_FLAGS
are flags related to transmission of a CAN message:
const _CAN_TX_PRIORITY_BITS = $03 const _CAN_TX_PRIORITY_0 = $FC ' XXXXXX00 const _CAN_TX_PRIORITY_1 = $FD ' XXXXXX01 const _CAN_TX_PRIORITY_2 = $FE ' XXXXXX10 const _CAN_TX_PRIORITY_3 = $FF ' XXXXXX11 const _CAN_TX_FRAME_BIT = $08 const _CAN_TX_STD_FRAME = $FF ' XXXXX1XX const _CAN_TX_XTD_FRAME = $F7 ' XXXXX0XX const _CAN_TX_RTR_BIT = $40 const _CAN_TX_NO_RTR_FRAME = $FF ' X1XXXXXX const _CAN_TX_RTR_FRAME = $BF ' X0XXXXXX
You may use bitwise and
to adjust the appropriate flags. For example:
' form value to be used with CANSendMessage: send_config = _CAN_TX_PRIORITY_0 and _CAN_TX_XTD_FRAME and _CAN_TX_NO_RTR_FRAME; ... CANSendMessage(id, data, 1, send_config)
CAN_RX_MSG_FLAGS
CAN_RX_MSG_FLAGS
are flags related to reception of CAN message. If a particular bit is set; corresponding meaning is TRUE or else it will be FALSE.
const _CAN_RX_FILTER_BITS = $07 ' Use it to access filter bits const _CAN_RX_FILTER_1 = $00 const _CAN_RX_FILTER_2 = $01 const _CAN_RX_FILTER_3 = $02 const _CAN_RX_FILTER_4 = $03 const _CAN_RX_FILTER_5 = $04 const _CAN_RX_FILTER_6 = $05 const _CAN_RX_OVERFLOW = $08 ' Set if Overflowed; else clear const _CAN_RX_INVALID_MSG = $10 ' Set if invalid; else clear const _CAN_RX_XTD_FRAME = $20 ' Set if XTD message; else clear const _CAN_RX_RTR_FRAME = $40 ' Set if RTR message; else clear const _CAN_RX_DBL_BUFFERED = $80 ' Set if message was ' hardware double-buffered
You may use bitwise and
to adjust the appropriate flags. For example:
if (MsgFlag and CAN_RX_OVERFLOW) = 0 then ... ' Receiver overflow has occurred. ' We have lost our previous message.
CAN_MASK
CAN_MASK
constants define mask codes. Function CANSetMask
expects one of these as its argument:
const CAN_MASK_B1 = 0 const CAN_MASK_B2 = 1
CAN_FILTER
CAN_FILTER
constants define filter codes. Function CANSetFilter
expects one of these as its argument:
const _CAN_FILTER_B1_F1 = 0 const _CAN_FILTER_B1_F2 = 1 const _CAN_FILTER_B2_F1 = 2 const _CAN_FILTER_B2_F2 = 3 const _CAN_FILTER_B2_F3 = 4 const _CAN_FILTER_B2_F4 = 5
Library Example
This is a simple demonstration of CAN Library routines usage. First node initiates the communication with the second node by sending some data to its address. The second node responds by sending back the data incremented by 1. First node then does the same and sends incremented data back to second node, etc.
Code for the first CANSPI node:
program CAN_1st dim Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags as byte ' can flags Rx_Data_Len as byte ' received data length in bytes RxTx_Data as byte[8] ' can rx/tx data buffer Msg_Rcvd as byte ' reception flag ID_1st, ID_2nd as longint ' node IDs Rx_ID as longint main: PORTC = 0 ' clear PORTC TRISC = 0 ' set PORTC as output Can_Init_Flags = 0 ' Can_Send_Flags = 0 ' clear flags Can_Rcv_Flags = 0 ' Can_Send_Flags = _CAN_TX_PRIORITY_0 and ' form value to be used _CAN_TX_XTD_FRAME and ' with CANWrite _CAN_TX_NO_RTR_FRAME Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE and ' form value to be used _CAN_CONFIG_PHSEG2_PRG_ON and ' with CANInit _CAN_CONFIG_XTD_MSG and _CAN_CONFIG_DBL_BUFFER_ON and _CAN_CONFIG_VALID_XTD_MSG ID_1st = 12111 ID_2nd = 3 RxTx_Data[0] = 9 ' set initial data to be sent CANInitialize(1,3,3,3,1,Can_Init_Flags) ' Initialize CAN module CANSetOperationMode(_CAN_MODE_CONFIG,0xFF) ' set CONFIGURATION mode CANSetMask(_CAN_MASK_B1,-1,_CAN_CONFIG_XTD_MSG) ' set all mask1 bits to ones CANSetMask(_CAN_MASK_B2,-1,_CAN_CONFIG_XTD_MSG) ' set all mask2 bits to ones CANSetFilter(_CAN_FILTER_B2_F4,ID_2nd,_CAN_CONFIG_XTD_MSG) ' set id of filter B2_F4 to 2nd node ID CANSetOperationMode(_CAN_MODE_NORMAL,0xFF) ' set NORMAL mode CANWrite(ID_1st, RxTx_Data, 1, Can_Send_Flags) ' send initial message while TRUE Msg_Rcvd = CANRead(Rx_ID , RxTx_Data , Rx_Data_Len, Can_Rcv_Flags) if ((Rx_ID = ID_2nd) and (Msg_Rcvd <> 0)) <> 0 then PORTC = RxTx_Data[0] ' output data at PORTC RxTx_Data[0] = RxTx_Data[0] + 1 Delay_ms(10) CANWrite(ID_1st, RxTx_Data, 1, Can_Send_Flags) ' send incremented data back end if wend end.
Code for the second CANSPI node:
program CAN_2nd dim Can_Init_Flags, Can_Send_Flags, Can_Rcv_Flags as byte ' CAN flags Rx_Data_Len as byte ' received data length in bytes RxTx_Data as byte[8] ' can rx/tx data buffer Msg_Rcvd as byte ' reception flag ID_1st, ID_2nd as longint ' node IDs Rx_ID as longint main: PORTC = 0 ' clear PORTC TRISC = 0 ' set PORTC as output Can_Init_Flags = 0 ' Can_Send_Flags = 0 ' clear flags Can_Rcv_Flags = 0 ' Can_Send_Flags = _CAN_TX_PRIORITY_0 and ' form value to be used _CAN_TX_XTD_FRAME and ' with CANWrite _CAN_TX_NO_RTR_FRAME Can_Init_Flags = _CAN_CONFIG_SAMPLE_THRICE and ' form value to be used _CAN_CONFIG_PHSEG2_PRG_ON and ' with CANInit _CAN_CONFIG_XTD_MSG and _CAN_CONFIG_DBL_BUFFER_ON and _CAN_CONFIG_VALID_XTD_MSG and _CAN_CONFIG_LINE_FILTER_OFF ID_1st = 12111 ID_2nd = 3 RxTx_Data[0] = 9 ' set initial data to be sent CANInitialize(1,3,3,3,1,Can_Init_Flags) ' initialize external CAN module CANSetOperationMode(_CAN_MODE_CONFIG,0xFF) ' set CONFIGURATION mode CANSetMask(_CAN_MASK_B1,-1,_CAN_CONFIG_XTD_MSG) ' set all mask1 bits to ones CANSetMask(_CAN_MASK_B2,-1,_CAN_CONFIG_XTD_MSG) ' set all mask2 bits to ones CANSetFilter(_CAN_FILTER_B2_F3,ID_1st,_CAN_CONFIG_XTD_MSG) ' set id of filter B2_F3 to 1st node ID CANSetOperationMode(_CAN_MODE_NORMAL,0xFF) ' set NORMAL mode while true ' endless loop Msg_Rcvd = CANRead(Rx_ID , RxTx_Data , Rx_Data_Len, Can_Rcv_Flags) ' receive message if ((Rx_ID = ID_1st) and (Msg_Rcvd <> 0)) <> 0 then ' if message received check id PORTC = RxTx_Data[0] ' id correct, output data at PORTC Inc(RxTx_Data[0]) ' increment received data CANWrite(ID_2nd, RxTx_Data, 1, Can_Send_Flags) ' send incremented data back end if wend end.
HW Connection
Example of interfacing CAN transceiver with MCU and bus
What do you think about this topic ? Send us feedback!