Code:
'****************************************************************
'* Name : RGV CANBUS TEST *
'* Author : Bobby Garrett *
'* Notice : Copyright (c) 2005 Bobby Garrett *
'* : All Rights Reserved *
'* Date : 22/12/2005 *
'* Version : 3 million And 1.0 *
'* : *
'* Notes : CAN bus Set For 125 kb/s *
'* : Uses Philips PCA82C250 transcievers for CANBUS *
'* : Display is 4x20 LCD on port D *
'* : Three jumpers on PORTA for node address *
'****************************************************************
Device = 18F448
XTAL = 20
'Set up PIC registers
@CONFIG_REQ
@__CONFIG config1h, OSCS_OFF_1 & HS_OSC_1 & CP_OFF_1L
@__CONFIG config2l, BOR_ON_2 & BORV_42_2 & PWRT_ON_2
@__CONFIG config2h, WDT_OFF_2
@__CONFIG config4l, STVR_ON_4 & LVP_OFF_4 & DEBUG_OFF_4
'***********************************************
'* Variable definitions *
'***********************************************
' Some of the variables will not be used as the code is generic.
' EG, if this module node is set to 1 by the jumpers then NODE_1_DATA_xx
' variables are not used as they are for received messages and the
' identifier for the TRANSMIT_DATA_xx will be 1.
Dim TRANSMIT_DATA_0 As Byte
Dim TRANSMIT_DATA_1 As Byte
Dim TRANSMIT_DATA_2 As Byte
Dim TRANSMIT_DATA_3 As Byte
Dim TRANSMIT_DATA_4 As Byte
Dim TRANSMIT_DATA_5 As Byte
Dim TRANSMIT_DATA_6 As Byte
Dim TRANSMIT_DATA_7 As Byte
Dim NODE_1_DATA_0 As Byte
Dim NODE_1_DATA_1 As Byte
Dim NODE_1_DATA_2 As Byte
Dim NODE_1_DATA_3 As Byte
Dim NODE_1_DATA_4 As Byte
Dim NODE_1_DATA_5 As Byte
Dim NODE_1_DATA_6 As Byte
Dim NODE_1_DATA_7 As Byte
Dim NODE_2_DATA_0 As Byte
Dim NODE_2_DATA_1 As Byte
Dim NODE_2_DATA_2 As Byte
Dim NODE_2_DATA_3 As Byte
Dim NODE_2_DATA_4 As Byte
Dim NODE_2_DATA_5 As Byte
Dim NODE_2_DATA_6 As Byte
Dim NODE_2_DATA_7 As Byte
Dim NODE_3_DATA_0 As Byte
Dim NODE_3_DATA_1 As Byte
Dim NODE_3_DATA_2 As Byte
Dim NODE_3_DATA_3 As Byte
Dim NODE_3_DATA_4 As Byte
Dim NODE_3_DATA_5 As Byte
Dim NODE_3_DATA_6 As Byte
Dim NODE_3_DATA_7 As Byte
Dim NODE_4_DATA_0 As Byte
Dim NODE_4_DATA_1 As Byte
Dim NODE_4_DATA_2 As Byte
Dim NODE_4_DATA_3 As Byte
Dim NODE_4_DATA_4 As Byte
Dim NODE_4_DATA_5 As Byte
Dim NODE_4_DATA_6 As Byte
Dim NODE_4_DATA_7 As Byte
Dim NODE_5_DATA_0 As Byte
Dim NODE_5_DATA_1 As Byte
Dim NODE_5_DATA_2 As Byte
Dim NODE_5_DATA_3 As Byte
Dim NODE_5_DATA_4 As Byte
Dim NODE_5_DATA_5 As Byte
Dim NODE_5_DATA_6 As Byte
Dim NODE_5_DATA_7 As Byte
Dim NODE_6_DATA_0 As Byte
Dim NODE_6_DATA_1 As Byte
Dim NODE_6_DATA_2 As Byte
Dim NODE_6_DATA_3 As Byte
Dim NODE_6_DATA_4 As Byte
Dim NODE_6_DATA_5 As Byte
Dim NODE_6_DATA_6 As Byte
Dim NODE_6_DATA_7 As Byte
Dim NODE_7_DATA_0 As Byte
Dim NODE_7_DATA_1 As Byte
Dim NODE_7_DATA_2 As Byte
Dim NODE_7_DATA_3 As Byte
Dim NODE_7_DATA_4 As Byte
Dim NODE_7_DATA_5 As Byte
Dim NODE_7_DATA_6 As Byte
Dim NODE_7_DATA_7 As Byte
Dim RX_NODE_NR As Byte 'Temp store for Identifier of received message
Dim TX_NODE_NR As Byte 'This modules address as set by jumpers on PORTA.
Dim NEW_MESSAGE As Bit
Dim TIMER1 As TMR1L.Word
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
GoTo INIT
'***********************************************
'* Interrupt service vector initialization *
'***********************************************
ON_INTERRUPT GoTo INTERRUPT_ROUTINE 'Point to the Interrupt handler
GoTo START 'Jump over the Interrupt routine
'****************************************************************
'* 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 *
'****************************************************************
INTERRUPT_ROUTINE:
If PIR1.0 = 0 Then GoTo CAN_MODULE_INTERRUPT
Clear T1CON.0 'Stop timer
TIMED_TRANSMIT_ROUTINE: 'If it wasn't the CAN module it must have been the timer Interrupt
Toggle PORTC.6 'Flash RED LED just to let me know it is doing something
'This is just to generate data for testing
'Normally data wil be written to TRANSMIT_DATA_xx from elsewhere in the program.
TRANSMIT_DATA_0 = TRANSMIT_DATA_0 + 1
If TRANSMIT_DATA_0 = 100 Then TRANSMIT_DATA_0 = 0
TRANSMIT_DATA_1 = TRANSMIT_DATA_1 + 1
If TRANSMIT_DATA_1 = 100 Then TRANSMIT_DATA_1 = 0
'Down to here !!!
TXB0D0 = TRANSMIT_DATA_0'Move data into transmit buffer 0
TXB0D1 = TRANSMIT_DATA_1
TXB0D2 = TRANSMIT_DATA_2
TXB0D3 = TRANSMIT_DATA_3
TXB0D4 = TRANSMIT_DATA_4
TXB0D5 = TRANSMIT_DATA_5
TXB0D6 = TRANSMIT_DATA_6
TXB0D7 = TRANSMIT_DATA_7
CANCON = %00001000 'Normal mode, transmit buffer 0
TXERRCNT = 0 'Clear TX error counter
TXB0CON = %00001001 'Start transmition, priority level 1
WAIT_TX0_OK: If TXB0CON.3 = 1 Then WAIT_TX0_OK 'Loop until TX succesfull
CANCON = %00000000 'Select CAN normal mode after transmission
PIR1.0 = 0 'Clear Timer 1 overflow interrupt bit
TIMER1 = 0 'Re-set timer to zero
Set T1CON.0 'Re-start timer
Context Restore 'Exit ISR and re-enable interrupts
CAN_MODULE_INTERRUPT:
If PIR3.0 = 1 Then GoTo RECEIVE_MSG
If PIR3.5 = 1 Then GoTo CAN_ERROR
'**********************************************************************
'* CAN Msg Received Routine *
'* This routine is called when a message has been received into RXB0. *
'* The routine reads the Low identifier Byte And Then shifts the bits *
'* right x 5 to get the number of the node transmitting the message. *
'**********************************************************************
'It could probably be done better with indirect addressing but I only need 6 nodes !
'It also makes the code more readable and understandable when I look at it in 6 months time.
RECEIVE_MSG:
Toggle PORTC.7 'Flash GREEN LED to let me know something is happening
RX_NODE_NR = RXB0SIDL >> 5 'Shift bits right x 5 to determine which node sent
'current message.
If RX_NODE_NR = 1 Then GoTo MESSAGE_FROM_NODE_1 'go to routine for that message.
If RX_NODE_NR = 2 Then GoTo MESSAGE_FROM_NODE_2
If RX_NODE_NR = 3 Then GoTo MESSAGE_FROM_NODE_3
If RX_NODE_NR = 4 Then GoTo MESSAGE_FROM_NODE_4
If RX_NODE_NR = 5 Then GoTo MESSAGE_FROM_NODE_5
If RX_NODE_NR = 6 Then GoTo MESSAGE_FROM_NODE_6
If RX_NODE_NR = 7 Then GoTo MESSAGE_FROM_NODE_7
MESSAGE_FROM_NODE_1:
NODE_1_DATA_0 = RXB0D0 'Copy data in receive buffer as it will be
NODE_1_DATA_1 = RXB0D1 'overwritten by Next message
NODE_1_DATA_2 = RXB0D2
NODE_1_DATA_3 = RXB0D3
NODE_1_DATA_4 = RXB0D4
NODE_1_DATA_5 = RXB0D5
NODE_1_DATA_6 = RXB0D6
NODE_1_DATA_7 = RXB0D7
NEW_MESSAGE = 1 'Set flag to update display
GoTo DONE
MESSAGE_FROM_NODE_2:
NODE_2_DATA_0 = RXB0D0 'Copy data in receive buffer as it will be
NODE_2_DATA_1 = RXB0D1 'overwritten by Next message
NODE_2_DATA_2 = RXB0D2
NODE_2_DATA_3 = RXB0D3
NODE_2_DATA_4 = RXB0D4
NODE_2_DATA_5 = RXB0D5
NODE_2_DATA_6 = RXB0D6
NODE_2_DATA_7 = RXB0D7
NEW_MESSAGE = 1 'Set flag to update display
GoTo DONE
MESSAGE_FROM_NODE_3:
NODE_3_DATA_0 = RXB0D0 'Copy data in receive buffer as it will be
NODE_3_DATA_1 = RXB0D1 'overwritten by Next message
NODE_3_DATA_2 = RXB0D2
NODE_3_DATA_3 = RXB0D3
NODE_3_DATA_4 = RXB0D4
NODE_3_DATA_5 = RXB0D5
NODE_3_DATA_6 = RXB0D6
NODE_3_DATA_7 = RXB0D7
NEW_MESSAGE = 1 'Set flag to update display
GoTo DONE
MESSAGE_FROM_NODE_4:
NODE_4_DATA_0 = RXB0D0 'Copy data in receive buffer as it will be
NODE_4_DATA_1 = RXB0D1 'overwritten by Next message
NODE_4_DATA_2 = RXB0D2
NODE_4_DATA_3 = RXB0D3
NODE_4_DATA_4 = RXB0D4
NODE_4_DATA_5 = RXB0D5
NODE_4_DATA_6 = RXB0D6
NODE_4_DATA_7 = RXB0D7
NEW_MESSAGE = 1 'Set flag to update display
GoTo DONE
MESSAGE_FROM_NODE_5:
NODE_5_DATA_0 = RXB0D0 'Copy data in receive buffer as it will be
NODE_5_DATA_1 = RXB0D1 'overwritten by Next message
NODE_5_DATA_2 = RXB0D2
NODE_5_DATA_3 = RXB0D3
NODE_5_DATA_4 = RXB0D4
NODE_5_DATA_5 = RXB0D5
NODE_5_DATA_6 = RXB0D6
NODE_5_DATA_7 = RXB0D7
NEW_MESSAGE = 1 'Set flag to update display
GoTo DONE
MESSAGE_FROM_NODE_6:
NODE_6_DATA_0 = RXB0D0 'Copy data in receive buffer as it will be
NODE_6_DATA_1 = RXB0D1 'overwritten by Next message
NODE_6_DATA_2 = RXB0D2
NODE_6_DATA_3 = RXB0D3
NODE_6_DATA_4 = RXB0D4
NODE_6_DATA_5 = RXB0D5
NODE_6_DATA_6 = RXB0D6
NODE_6_DATA_7 = RXB0D7
NEW_MESSAGE = 1 'Set flag to update display
GoTo DONE
MESSAGE_FROM_NODE_7:
NODE_7_DATA_0 = RXB0D0 'Copy data in receive buffer as it will be
NODE_7_DATA_1 = RXB0D1 'overwritten by Next message
NODE_7_DATA_2 = RXB0D2
NODE_7_DATA_3 = RXB0D3
NODE_7_DATA_4 = RXB0D4
NODE_7_DATA_5 = RXB0D5
NODE_7_DATA_6 = RXB0D6
NODE_7_DATA_7 = RXB0D7
NEW_MESSAGE = 1 'Set flag to update display
GoTo DONE
DONE:
COMSTAT = 0 'Clear CAN comminication status register
RXB0CON = %00100000 'Set RXB0CON for next message
PIR3 = 0 'Clear CAN bus error interrupt bits
Context Restore 'Exit ISR and re-enable interrupts
'*******************************************************************
'* CAN Error routine *
'* At present this routine only places some registers on the LCD *
'* turns on LED and halts program for diagnosing problem. *
'*******************************************************************
CAN_ERROR:
Cls 'Clear screen
PORTD.1 = 1 'Turn on RED LED for CAN error
Print At 1,1, "CAN error"
Print At 2,1, Dec TXERRCNT
Print At 2,11, Dec RXERRCNT
Print At 1,21, Dec COMSTAT
Print At 1,31, Dec PIR3
Stop
'***********************************************
'* Start of Main Code *
'***********************************************
START:
'Set up priority interrupts.
IPEN = 1 ' Enable priority interrupts.
TMR1IP = 1 ' Set Timer1 as a high priority interrupt source
TMR1IF = 0 ' Clear the Timer1 interrupt flag
TMR1IE = 1 ' Enable Timer1 interrupts
GIEH = 1 ' Set the global interrupt enable bits
'Send start up message to LCD
Cls 'Clear screen
DelayMS 100 ' Wait for LCD to start
Print At 1,1, " Bobby Garrett's" 'Show start up message
Print At 2,1, " RGV250"
Print At 1,21," CAN BUS TEST"
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 = %10110000 'Timer1 - 1:8 prescaler and act as timer
TIMER1 = 0 'Zero Timer
T1CON.0 = 1 'Start Timer running
PIR1.0 = 0 'Clear timer 1 overflow bit
PIE1 = 1 'Enable Timer1 interrupt
'***********************************************
'* Main program LOOP *
'***********************************************
LOOP:
COMSTAT = 0 'Clear CAN comminication status register.
INTCON = %00000000 'Turn off interrupts
'Normal code routines go between here
'Probably try using "Include" here so the CAN code never needs changeing.
If NEW_MESSAGE = 1 Then GoSub DISPLAY 'Only write to display if new message
'And here
INTCON = %11000000 'Turn interrupts back on
GoTo LOOP
DISPLAY:
Print At 1,1, "1<", Dec NODE_1_DATA_0," "
Print At 2,1, "1<", Dec NODE_1_DATA_1," "
Print At 1,7, "2<", Dec NODE_2_DATA_0," "
Print At 2,7, "2<", Dec NODE_2_DATA_1," "
Print At 1,13, "3<", Dec NODE_3_DATA_0," "
Print At 2,13, "3<", Dec NODE_3_DATA_1," "
Print At 1,21, "4<", Dec NODE_4_DATA_0," "
Print At 2,21, "4<", Dec NODE_4_DATA_1," "
Print At 1,27, "5<", Dec NODE_5_DATA_0," "
Print At 2,27, "5<", Dec NODE_5_DATA_1," "
' Print At 1,29, "6<", Dec NODE_6_DATA_0," " 'Not used due to screen size
' Print At 2,29, "6<", Dec NODE_6_DATA_1," " 'also I do not have the nodes
' Print At 1,31, "7<", Dec NODE_7_DATA_0," " 'attached at present
' Print At 2,31, "7<", Dec NODE_7_DATA_1," "
Print At 1,33, "T>", Dec TRANSMIT_DATA_0," "
Print At 2,33, "T>", Dec TRANSMIT_DATA_1," "
NEW_MESSAGE = 0
Return
'******************************************************
'* PIC Initialization *
'* Most of the CAN module registers are here Whether *
'* used Or Not so I don't have to type them in again. *
'******************************************************
INIT:
ALL_DIGITAL = True 'Set all I/O to digital
'Set port direction On power up Or after reset
TRISA.0 = 1 'Set port direction - NODE address bit 0
TRISA.1 = 1 'Set port direction - NODE address bit 1
TRISA.2 = 1 'Set port direction - NODE address bit 2
'Set port direction for CAN I/O
'This is important, Proton does not set the port direction of the CAN I/O pins !!
TRISB.2 = 0 'Set port direction - CANTx pin as output
TRISB.3 = 1 'Set port direction - CANRx pin as input
'Set port direction On power up Or after reset
TRISC.6 = 0 'Set port direction - LED for diagnostics
TRISC.7 = 0 'Set port direction - LED for diagnostics
TRISD.1 = 0 'Set port direction - LED for diagnostics
'Set state of port on power up or after reset
PORTC.6 = 0 'Initialise output as off
PORTC.7 = 0 'Initialise output as off
PORTD.1 = 0 'Initialise output as off
'Determine node address
PORTA = 0 'Clear PORTA
TX_NODE_NR = PORTA & %00000111 '"AND" to filter out unwanted bits
'CAN MODULE
'Set up the CAN module
CANCON = %10000000 'Select CAN config mode
TXB0CON = 0 'Clear transmit buffer 0 control register
'set up CAN hardware
BRGCON1 = %00000011 'SJW = 1 Tq, Tq = 4/Fosc
BRGCON2 = %11101100 'Phase seg 1 = 6 x Tq, Prop = 5 x tq, Sample 3 times
BRGCON3 = %00000111 'Phase seg 2 = 8 x Tq
Clear CIOCON.5 'ENDRHI 'recessive drives Tx to Vdd (required if using MCP 2551)
TXB0DLC = %00001000 'RTR bit cleared, 8 byte data length
RXB0DLC = %00001000 '8 byte data length
'Set low identifier bits to node address set by jumpers on PORTA
'Only low byte used
TXB0SIDH = %00000000 'Set Identifier bits
TX_NODE_NR = TX_NODE_NR << 5 'Shift left before AND ing
TXB0SIDL = TX_NODE_NR & %11100000 'Set Identifier bits
TX_NODE_NR = TX_NODE_NR >> 5 'Shift back for start up message
RXM0SIDH = %00000000 'Set Receive mask 0 bits
RXM0SIDL = %00000000 'Set Receive mask 0 bits
RXM1SIDH = %00000000 'Set Receive mask 1 bits
RXM1SIDL = %00000000 'Set Receive mask 1 bits
RXF0SIDH = %00000000 'Set Receive filter 0 bits
RXF0SIDL = %00000000 'Set Receive filter 0 bits
RXF1SIDH = %00000000 'Set Receive filter 1 bits
RXF1SIDL = %00000000 'Set Receive filter 1 bits
COMSTAT = 0 'Clear CAN comminication status register.
CANCON = %00000000 'Select CAN normal mode
RXB0CON = %00100000 'Receive only valid messages with standard identifier
PIR3 = 0 'Clear Peripheral interrupt register 3
PIE3 = %00100001 'Enable selected Peripheral interrupts
TXERRCNT = 0 'Clear Transmit error counter
RXERRCNT = 0 'Clear Receive error counter
TXB0D0 = 0 'Clear Transmit buffer 0 bytes
TXB0D1 = 0
TXB0D2 = 0
TXB0D3 = 0
TXB0D4 = 0
TXB0D5 = 0
TXB0D6 = 0
TXB0D7 = 0
TXB1D0 = 0 'Clear Transmit buffer 1 bytes
TXB1D1 = 0
TXB1D2 = 0
TXB1D3 = 0
TXB1D4 = 0
TXB1D5 = 0
TXB1D6 = 0
TXB1D7 = 0
TXB2D0 = 0 'Clear Transmit buffer 2 bytes
TXB2D1 = 0
TXB2D2 = 0
TXB2D3 = 0
TXB2D4 = 0
TXB2D5 = 0
TXB2D6 = 0
TXB2D7 = 0
RXB0D0 = 0 'Clear Receive buffer 0 bytes
RXB0D1 = 0
RXB0D2 = 0
RXB0D3 = 0
RXB0D4 = 0
RXB0D5 = 0
RXB0D6 = 0
RXB0D7 = 0
RXB1D0 = 0 'Clear Receive buffer 1 bytes
RXB1D1 = 0
RXB1D2 = 0
RXB1D3 = 0
RXB1D4 = 0
RXB1D5 = 0
RXB1D6 = 0
RXB1D7 = 0
TRANSMIT_DATA_0 = 0 'Clear Variables
TRANSMIT_DATA_1 = 0
TRANSMIT_DATA_2 = 0
TRANSMIT_DATA_3 = 0
TRANSMIT_DATA_4 = 0
TRANSMIT_DATA_5 = 0
TRANSMIT_DATA_6 = 0
TRANSMIT_DATA_7 = 0
NODE_1_DATA_0 = 0 'Clear Variables
NODE_1_DATA_1 = 0
NODE_1_DATA_2 = 0
NODE_1_DATA_3 = 0
NODE_1_DATA_4 = 0
NODE_1_DATA_5 = 0
NODE_1_DATA_6 = 0
NODE_1_DATA_7 = 0
NODE_2_DATA_0 = 0 'Clear Variables
NODE_2_DATA_1 = 0
NODE_2_DATA_2 = 0
NODE_2_DATA_3 = 0
NODE_2_DATA_4 = 0
NODE_2_DATA_5 = 0
NODE_2_DATA_6 = 0
NODE_2_DATA_7 = 0
NODE_3_DATA_0 = 0 'Clear Variables
NODE_3_DATA_1 = 0
NODE_3_DATA_2 = 0
NODE_3_DATA_3 = 0
NODE_3_DATA_4 = 0
NODE_3_DATA_5 = 0
NODE_3_DATA_6 = 0
NODE_3_DATA_7 = 0
NODE_4_DATA_0 = 0 'Clear Variables
NODE_4_DATA_1 = 0
NODE_4_DATA_2 = 0
NODE_4_DATA_3 = 0
NODE_4_DATA_4 = 0
NODE_4_DATA_5 = 0
NODE_4_DATA_6 = 0
NODE_4_DATA_7 = 0
NODE_5_DATA_0 = 0 'Clear Variables
NODE_5_DATA_1 = 0
NODE_5_DATA_2 = 0
NODE_5_DATA_3 = 0
NODE_5_DATA_4 = 0
NODE_5_DATA_5 = 0
NODE_5_DATA_6 = 0
NODE_5_DATA_7 = 0
NODE_6_DATA_0 = 0 'Clear Variables
NODE_6_DATA_1 = 0
NODE_6_DATA_2 = 0
NODE_6_DATA_3 = 0
NODE_6_DATA_4 = 0
NODE_6_DATA_5 = 0
NODE_6_DATA_6 = 0
NODE_6_DATA_7 = 0
NODE_7_DATA_0 = 0 'Clear Variables
NODE_7_DATA_1 = 0
NODE_7_DATA_2 = 0
NODE_7_DATA_3 = 0
NODE_7_DATA_4 = 0
NODE_7_DATA_5 = 0
NODE_7_DATA_6 = 0
NODE_7_DATA_7 = 0
RX_NODE_NR = 0
'Set Diplay up
Declare LCD_TYPE 0
Declare LCD_INTERFACE 4
Declare LCD_LINES 2
LCD_DTPIN = PORTD.4
LCD_ENPIN = PORTD.2
LCD_RSPIN = PORTD.3
If TX_NODE_NR > 0 And TX_NODE_NR < 8 Then GoTo START 'Check node address is set
'If the program has got to here then the node address has not been read properly (1 - 7)
'Put message on screen and Flash LED, halt program.
Cls 'Clear screen
Print At 1,1, "NODE ERROR - ",Dec TX_NODE_NR
NODE_ERROR:
Toggle PORTD.1 'Flash RED LED for Node address error
DelayMS 1000
GoTo NODE_ERROR
Stop