'**************************************************************** '* Name : CAN SIMPLE DEMO * '* Author : Bobby Garrett * '* Notice : Copyright (c) 2008 Bobby Garrett * '* : All Rights Reserved * '* Date : 1/12/2008 * '* Version : 1 * '* Library : CAN_LIBRARY_1_4 * '* Node : 1 * '* Notes : CAN BUS Set For 125 kb/s * '* : A simple demo to demonstrate CAN communication * '* : between 2 PIC's * '* : DATA output is via serial and 4x20 LCD * '**************************************************************** '**************************************************************** '* Select the PIC configuration, only Select one Device * '**************************************************************** 'If 18F448/458 is used the serial settings will need to be changed 'as they do not have a EUSART 'Path will have to be changed to your requirements ' Include "C:\BOBBYS_STUFF\PIC PROJ\CAN NODES\18F448_CONFIG.INC" Include "18F458_CONFIG.INC" ' Include "CAN_MACROS.pbp" Include "CAN_LIBRARY_1_4.pbp" ' Include "C:\BOBBYS_STUFF\PIC PROJ\CAN NODES\18F4680_CONFIG.INC" 'If you alter the xtal you will also have to change the settings for the 'CAN module and the hardware serial comms. ' Xtal = 20 'Define clock All_Digital = True 'Set all I/O to digital Clear 'Clear all RAM DelayMS 100 'Let PIC start up '**************************************************************** '* Set serial comms parameters * '**************************************************************** Declare Hserial_Baud = 115200 'Set baud rate to 115200 for 20MHz XTAL Declare Hserial_RCSTA = %10010000 'Enable serial port and continuous receive Declare Hserial_TXSTA = %00100100 'Enable transmit and asynchronous mode 'USART settings 18f448/458 etc ' SPBRG = 10 ' 115200 Baud @ 20MHz, -1.36% 'EUSART settings 18F4680 etc ' BAUDCON.3 = 1 ' Enable 16 bit baudrate generator SPBRG = 42 ' 115200 Baud @ 20MHz, 0.94% ' SPBRGH = 0 ' Hserial_Clear = On 'Enable Error clearing on received characters Dim IN_CHR As Byte 'Character in input buffer '**************************************************************** '* Display pins and declares * '**************************************************************** Declare LCD_Type 0 Declare LCD_Interface 4 Declare LCD_Lines 2 ' LCD_DTPin = PORTD.4 ' LCD_ENPin = PORTD.2 ' LCD_RSPin = PORTD.3 '**************************************************************** '* Variables for CAN TX * '**************************************************************** Dim TX_DATA[8] As Byte Dim TX_NODE_NR As Word 'Used for - Start up delay ' - Start up message ' - Duplicate node ID check Dim TIMED_TX_DATA[8] As Byte'Array for the Timed TX data '**************************************************************** '* Variables for CAN RX * '**************************************************************** Dim RX_NODE_NR As Word Dim RX_NODE_ID[4] As Byte Dim RX_MSG_ID As Byte Dim RX_DATA[8] As Byte Dim RX_MSG_LEN[1] As Byte 'Created array of 1 byte so I can pass 'data back out of CANReceiveMessage routine Dim RX_FLAGS As Byte Dim MAX_DATA As Byte 'No of data bytes in RX message '**************************************************************** '* Variables for Timer1 * '**************************************************************** Dim TIMER1 As TMR1L.Word Dim TIMER_1_BITS As Byte Dim TIMER_1_OFFSET As Word '**************************************************************** '* Symbols for Interrupts etc * '**************************************************************** Symbol IPEN = RCON.7 Symbol TMR1IP = IPR1.0 Symbol TMR1IF = PIR1.0 Symbol TMR1IE = PIE1.0 Symbol GIEH = INTCON.7 Symbol GIEL = INTCON.6 Symbol TMR1ON = T1CON.0 '**************************************************************** '* Diagnostic LED's * '**************************************************************** Symbol LOOP_LED = PORTA.0 'Alias the GREEN LED (LOOP) Symbol TX_LED = PORTA.1 'Alias the AMBER LED (TX) Symbol CAN_ERROR_LED = PORTA.2 'Alias the RED LED (CAN error)(not used in this example) Symbol RX_LED = PORTA.3 'Alias the AMBER LED (RX) 'Set port direction On power up Or after reset TRISA.0 = 0 'Set port direction - LED for diagnostics TRISA.1 = 0 'Set port direction - LED for diagnostics TRISA.2 = 0 'Set port direction - LED for diagnostics TRISA.3 = 0 'Set port direction - LED for diagnostics 'Set state of port on power up or after reset PORTA.0 = 0 'Initialise output as off PORTA.1 = 0 'Initialise output as off PORTA.2 = 0 'Initialise output as off PORTA.3 = 0 'Initialise output as off '**************************************************************** '* Variables for CAN TX Method * '**************************************************************** '* This function is not part of the CAN module, it is used to * '* determine how the user requires the data to be transmitted. * '* Normally CAN is EVENT driven but there are timed methods as * '* well. * '**************************************************************** Dim TX_COUNT As Word 'Counter for TIMED TX routine TX_COUNT = 1 Dim TX_TIME As Word 'Value used for TIMED TX '**************************************************************** '* Variables for NON critical subroutine updates * '* Values are set in INIT routine at end of program * '**************************************************************** Dim SIM_DATA_SUB_UPDATE_TIME As Byte Dim SIM_DATA_SUB_REQ_COUNTER As Byte Dim DISPLAY_SUB_UPDATE_TIME As Byte Dim DISPLAY_SUB_REQ_COUNTER As Byte 'Stagger update times so they do not all occur at once SIM_DATA_SUB_REQ_COUNTER = 1 DISPLAY_SUB_REQ_COUNTER = 2 '**************************************************************** '* Set non critical update times in multiples of 10mS set in * '* TX_TIME (Max 250) * '* If TX_TIME = 1 and UPDATE_TIME = 10 then update will be * '* 1 x 10 x 10 = 100mS * '**************************************************************** SIM_DATA_SUB_UPDATE_TIME = 10 DISPLAY_SUB_UPDATE_TIME = 10 '**************************************************************** '* End of variable / symbols definitions * '**************************************************************** '**************************************************************** 'CAN configuration settings * '**************************************************************** 'Set configuration mode, no confirmation. CANSetOperationMode [CAN_OP_MODE_CONFIG,NO] 'CAN configuration - accept valid standard messages. CANInitialise [CAN_CONFIG_VALID_STD_MSG] 'Set CAN node ID. (This must be unique to the network) ' (Can be set by dipswitches if preferred) CANSetNodeID [1] 'Set CAN message ID. CANSetMsgID [0,STD] '**************************************************************** '* Set ALL masks and filters to 0. * '* This means that all messages from all nodes are accepted * '**************************************************************** 'Set CAN mask bits. CANSetMask [CAN_MASK_B0,0,0,0,0,STD] CANSetMask [CAN_MASK_B1,0,0,0,0,STD] 'Set CAN filter bits. CANSetFilter [CAN_FILTER_B0_F1,0,0,0,0,STD] CANSetFilter [CAN_FILTER_B0_F2,0,0,0,0,STD] CANSetFilter [CAN_FILTER_B1_F1,0,0,0,0,STD] CANSetFilter [CAN_FILTER_B1_F2,0,0,0,0,STD] CANSetFilter [CAN_FILTER_B1_F3,0,0,0,0,STD] CANSetFilter [CAN_FILTER_B1_F4,0,0,0,0,STD] '**************************************************************** '* Set CAN BAUD rate. * '* The nodes can have different Xtal speeds but the BUS * '* bitrate MUST be the same for all nodes. * '* * '* These settings are for 20Mhz xtal - 125k BUS. * '* BRGCON1 'SJW = 1 Tq, Tq = 4/Fosc * '* BRGCON2 'Phase seg 1 = 6 x Tq, Prop = 5 x tq,Seg 2 freely prog, Sample 3 times '* BRGCON3 'Phase seg 2 = 8 x Tq, Line filter off * '**************************************************************** '20Mhz / 125k BUS CANSetBaudRate [1,4,6,8,5,CAN_CONFIG_PHSEG2_PRG_ON & CAN_CONFIG_SAMPLE_THRICE & CAN_CONFIG_LINE_FILTER_OFF] 'Use CAN node ID for pre determined delay before setting NORMAL mode 'This ensures that all nodes will not attempt to start transmitting at 'the same time - Lowest ID will start first 'Only for STD message ID. TX_NODE_NR.HighByte = TXB0SIDH TX_NODE_NR.LowByte = TXB0SIDL TX_NODE_NR = TX_NODE_NR >> 5 'Shift right to get correct ID TX_NODE_NR = TX_NODE_NR & %0000000000011111 'Mask higher 11 bits DelayMS TX_NODE_NR 'Change back to normal operation mode, no confirmation. CANSetOperationMode [CAN_OP_MODE_NORMAL,NO] '**************************************************************** '* End of CAN configuration settings * '**************************************************************** '**************************************************************** '* Settings for CAN TX frequency * '**************************************************************** TX_TIME = 10 'No of INT's for TX if CAN_TX_TYPE = TIMED 'MIN = 1(10mS) / MAX = 6000(1 minute) '**************************************************************** '* Set up Timer 1 * '**************************************************************** TIMER_1_BITS = %10000000 'Timer 1 configuration bits 'Timer 1 - 1:1 prescaler and act as timer TIMER_1_OFFSET = 15539 'Timer 1 offset for (10mS Interrupts) 'Configured for 20 Mhz xtal PIE1 = %00000001 PIR1 = %00000001 '**************************************************************** '* Interrupt service vector initialization * '* There isn't a low int routine * '**************************************************************** ' On_Hardware_Interrupt GoTo HIGH_INTERRUPT_ROUTINE GoTo OVER_INT '**************************************************************** '* Interrupt Service Routine * '**************************************************************** '* Determine if it is a timed interrupt or CAN module interrupt * '* Also the ISR determines whether a Valid message or CAN error * '* interrupt has occured and then proceeds accordingly * '**************************************************************** 'High_Int_Sub_Start 'HIGH_INTERRUPT_ROUTINE: Context Save If PIR1.0 = 0 Then GoTo CAN_MODULE_INTERRUPT Clear T1CON.0 'Stop timer TX_COUNT = TX_COUNT + 1 If TX_COUNT >= 6000 Then TX_COUNT = 1 '1 per minute max If TX_COUNT >= TX_TIME Then GoTo TX_ON_TIME 'Increment counters for non critical update subroutines SIM_DATA_SUB_REQ_COUNTER = SIM_DATA_SUB_REQ_COUNTER + 1 DISPLAY_SUB_REQ_COUNTER = DISPLAY_SUB_REQ_COUNTER + 1 'If TX_TIME is not complete then return from interrupt. 'Set / clear relevant bits before returning from interupt PIR1.0 = 0 'Clear Timer 1 overflow interrupt bit TIMER1 = TIMER_1_OFFSET 'Re-load timer Set T1CON.0 'Re-start timer Context Restore 'Exit ISR and re-enable interrupts 'This routine is called at intervals set by value in TX_TIME 'It always uses message 0 'Values in TIMED_TX_DATA array are loaded elsewhere TX_ON_TIME: CANSetMsgID [0,STD] 'Timed data is always message zero 'Move data in to the TX register array TX_DATA#0 = TIMED_TX_DATA#0 TX_DATA#1 = TIMED_TX_DATA#1 TX_DATA#2 = TIMED_TX_DATA#2 TX_DATA#3 = TIMED_TX_DATA#3 TX_DATA#4 = TIMED_TX_DATA#4 TX_DATA#5 = TIMED_TX_DATA#5 TX_DATA#6 = TIMED_TX_DATA#6 TX_DATA#7 = TIMED_TX_DATA#7 TX_COUNT = 1 'Reset timer TX_ROUTINE: Toggle TX_LED 'Flash LED - let me know it is transmitting 'Message will be transmitted with the Node address as set in CANSetNodeID ' and the message ID as set in CANSetMsgID CANSendMessage [TX_DATA,8,CAN_TX_PRIORITY_0 & CAN_TX_NO_RTR_FRAME,CAN_TX_OK] 'Set / clear relevant bits before returning from interupt PIR1.0 = 0 'Clear Timer 1 overflow interrupt bit TIMER1 = TIMER_1_OFFSET 'Re-load timer Set T1CON.0 'Re-start timer ' Context Restore 'Exit ISR and re-enable interrupts CAN_MODULE_INTERRUPT: If PIR3.0 = 1 Then GoTo CAN_RECEIVE If PIR3.1 = 1 Then GoTo CAN_RECEIVE '**************************************************************** '* CAN_RECEIVE * '* The interrupt directs the program to here so there must be a * '* message in one of the receive buffers. * '* After the CANReceiveMessage routine returns the message the * '* sending Node ID and message ID is determined. * '* !!!! Only standard identifiers used - 5 bits for Node ID and * '* 6 bits for the Message ID (32 Node ID's and 64 Messages). * '**************************************************************** CAN_RECEIVE: Toggle RX_LED 'Flash LED - let me know it is receiving CANReceiveMessage [RX_NODE_ID,RX_DATA,RX_MSG_LEN,RX_FLAGS] 'Determine Node ID 'Only STD message ID is used in this example 'RX_NODE_ID#0/#1 = RXBxSIDH/L RX_NODE_NR.HighByte = RX_NODE_ID#0 RX_NODE_NR.LowByte = RX_NODE_ID#1 RX_NODE_NR = RX_NODE_NR >> 5 RX_NODE_NR = RX_NODE_NR & %0000000000011111 'Mask higher 11 bits 'Determine Message ID 'Only STD message ID is used in this example 'RX_NODE_ID#0 = RXBxSIDH RX_MSG_ID = RX_NODE_ID#0 RX_MSG_ID = RX_MSG_ID >> 2 MAX_DATA = RX_MSG_LEN#0 & %00001111 'strip RTR bit '**************************************************************** 'Send data out to serial port * 'Node - Message - Data length * 'Data byte 0,1,2,3,4,5,6,7 * '**************************************************************** HSerOut ["Node ",Dec RX_NODE_NR," - ","Msg ",Dec RX_MSG_ID," - ","Len ",Dec MAX_DATA,10,13] HSerOut [Dec RX_DATA#0," ",Dec RX_DATA#1," ",Dec RX_DATA#2," ",Dec RX_DATA#3," ",Dec RX_DATA#4," ",Dec RX_DATA#5," ",Dec RX_DATA#6," ",Dec RX_DATA#7,10,13] HSerOut [" ",10,13] 'If a message is still in one of the receive buffers then do it again If RXB0CON.7 = 1 Then GoTo CAN_RECEIVE If RXB1CON.7 = 1 Then GoTo CAN_RECEIVE PIR3 = 0 'Clear CAN Interrupt bits ' Context Restore 'Exit ISR and re-enable interrupts ' High_Int_Sub_End '**************************************************************** '* End of Interrupt routines * '**************************************************************** OVER_INT: '**************************************************************** '* Start of Main Code * '**************************************************************** START: 'Send start up message and Node number to serial port HSerOut ["Bobby Garrett's CAN BUS DEMO Node ",Dec TX_NODE_NR,10,13] 'Send start up message and Node number to LCD Cls 'Clear screen DelayMS 200 'Wait for LCD to start Print At 1,1, " Bobby Garrett's" 'Show start up message Print At 2,1, " CAN BUS DEMO" Print At 2,21," NODE ",Dec TX_NODE_NR 'Show node number DelayMS 2000 'Show message for 2 seconds Cls 'Clear screen 'Set up TIMER1 T1CON = TIMER_1_BITS TIMER1 = TIMER_1_OFFSET 'Load timer 1 T1CON.0 = 1 'Start Timer running PIR1.0 = 0 'Clear timer 1 overflow bit PIE1 = 1 'Enable Timer1 interrupt INTCON = %11000000 'Turn interrupts on GoSub SIM_DATA GoSub DISPLAY '**************************************************************** '* Main program LOOP * '**************************************************************** LOOP: If SIM_DATA_SUB_REQ_COUNTER > SIM_DATA_SUB_UPDATE_TIME Then GoSub SIM_DATA If DISPLAY_SUB_REQ_COUNTER > DISPLAY_SUB_UPDATE_TIME Then GoSub DISPLAY GoTo LOOP '**************************************************************** '* End of Main program LOOP * '**************************************************************** '**************************************************************** '* Subroutines * '**************************************************************** '**************************************************************** '* Simulate data - used for testing * '**************************************************************** SIM_DATA: Toggle LOOP_LED 'Flash LED - let me know program is running 'This is just to generate data for testing 'TIMED_TX_DATA is transferred to TX_DATA[X] in the TX routine. TIMED_TX_DATA#0 = TIMED_TX_DATA#0 + 1 If TIMED_TX_DATA#0 > 20 Then TIMED_TX_DATA#0 = 0 TIMED_TX_DATA#1 = TIMED_TX_DATA#1 + 1 If TIMED_TX_DATA#1 > 30 Then TIMED_TX_DATA#1 = 0 TIMED_TX_DATA#2 = TIMED_TX_DATA#2 + 1 If TIMED_TX_DATA#2 > 40 Then TIMED_TX_DATA#2 = 0 TIMED_TX_DATA#3 = TIMED_TX_DATA#3 + 1 If TIMED_TX_DATA#3 > 50 Then TIMED_TX_DATA#3 = 0 TIMED_TX_DATA#4 = TIMED_TX_DATA#4 + 1 If TIMED_TX_DATA#4 > 60 Then TIMED_TX_DATA#4 = 0 TIMED_TX_DATA#5 = TIMED_TX_DATA#5 + 1 If TIMED_TX_DATA#5 > 70 Then TIMED_TX_DATA#5 = 0 TIMED_TX_DATA#6 = TIMED_TX_DATA#6 + 1 If TIMED_TX_DATA#6 > 80 Then TIMED_TX_DATA#6 = 0 TIMED_TX_DATA#7 = TIMED_TX_DATA#7 + 1 If TIMED_TX_DATA#7 > 90 Then TIMED_TX_DATA#7 = 0 Clear SIM_DATA_SUB_REQ_COUNTER Return '**************************************************************** '* Display update subroutine * '**************************************************************** DISPLAY: INTCON = %00000000 'Turn off interrupts Print At 1,1, "Node ", Dec RX_NODE_NR," " Print At 1,8, "Msg ", Dec RX_MSG_ID," " Print At 1,14, "Len ", Dec MAX_DATA," " Print At 2,1, Dec RX_DATA#0," " Print At 2,5, Dec RX_DATA#1," " Print At 2,9, Dec RX_DATA#2," " Print At 2,13, Dec RX_DATA#3," " Print At 1,21, Dec RX_DATA#4," " Print At 1,25, Dec RX_DATA#5," " Print At 1,29, Dec RX_DATA#6," " Print At 1,33, Dec RX_DATA#7," " INTCON = %11000000 'Turn interrupts back on Clear DISPLAY_SUB_REQ_COUNTER Return