I’m encountering some issues with the CAN BUS module on the PIC18F2580. I should probably mention that I’m new to working with CAN, so I may have overlooked something quite simple.
Currently, I’m attempting to send a single CAN message at 250kbps (using ID 0x202 with 8 bytes).
For now, I’ve set the first byte to 0xFF just for testing purposes (I plan to modify it based on an ADC reading later). I'm not interested in receiving messages, so I don't need any specific interrupts and set RX pin.
At the moment, I’m seeing 0V on the CANTX pin (RB2) to the transceiver.
Investigating the problem and debugging with a LED, I noticed that
TXB0CONbits.TXREQ
is never going back to 0 after the fisrt transmit, thus never actually transmitting.
I’m using MPLABX v6.00 and XC8 V3.00.
May I ask if any CAN-PIC expert could explain what is the issue? It wuold be greatly appreciated. Thanks!
Code:
#pragma config [...various...] //ask if you need to see them
#include <xc.h>
#include <stdio.h>
#include <stdlib.h>
#define _XTAL_FREQ 1000000 // INT OSC frequency
// Initialize the ADC module for AN10 (RB0)
void ADC_Init() {
ADCON1 = 0b00000100; // Configure AN10 as an analog input
ADCON2 = 0b10001101; // Right justification, Fosc/16
ADCON0 = 0b00101001; // Select channel AN10
}
// Read the ADC value
unsigned int ADC_Read() {
ADCON0bits.GO = 1;
while (ADCON0bits.GO);
return ((unsigned int)(ADRESH << 8) + ADRESL);
}
// Initialize the CAN module
void CAN_Init() {
// Configure CAN pins
TRISBbits.TRISB2 = 0; // Set CANTX as output
TRISBbits.TRISB3 = 1; // Set CANRX as input
// Set the CAN module to configuration mode
CANCON = 0x80; // Configuration mode
while ((CANSTAT & 0xE0) != 0x80); // Wait until it enters configuration mode
// Set the CAN bus speed (250kbps with Fosc = 1MHz, prescaler Fosc/16)
BRGCON1 = 0x00; // Prescaler (BRP = 0)
BRGCON2 = 0xB8; // Propagation segment
BRGCON3 = 0x05; // Phase segment
// Set the transmission buffer to high priority
TXB0CON = 0x00;
// Set the CAN module to normal mode
CANCON = 0x00;
while ((CANSTAT & 0xE0) != 0x00); // Wait until it enters normal mode
}
// Transmit a CAN message
void CAN_Transmit(unsigned int ID, unsigned char *message, unsigned char length) {
unsigned int timeout = 5000;
// Wait for the buffer to be free
while (TXB0CONbits.TXREQ && timeout--) {
__delay_us(10);
}
if (timeout == 0) return; // Timeout, exit
// Set the message ID
TXB0SIDH = (unsigned char)(ID >> 3); // Upper 8 bits
TXB0SIDL = (unsigned char)(ID << 5); // Lower 3 bits + standard frame
// Set the message length
TXB0DLC = length & 0x0F;
// Copy the data into buffer
TXB0D0 = message[0];
TXB0D1 = message[1];
TXB0D2 = message[2];
TXB0D3 = message[3];
TXB0D4 = message[4];
TXB0D5 = message[5];
TXB0D6 = message[6];
TXB0D7 = message[7];
// Enable transmission
TXB0CONbits.TXREQ = 1;
}
int main() {
unsigned int adc_value;
unsigned char message[8] = {0xFF};
TRISC = 0x00; // Configure PORTC as output
ADC_Init();
CAN_Init();
while (1) {
adc_value = ADC_Read();
adc_value = (adc_value * 0x64) / 1023;
/* --------------FUTURE USE-----------------
//message[0] = (unsigned char)adc_value;
//message[4] = (adc_value < 0x14) ? 0x00 : 0x01;*/
CAN_Transmit(0x202, message, 8);
PORTCbits.RC3 ^= 1;
__delay_ms(100);
}
return (EXIT_SUCCESS);
}
if (timeout == 0) return; // Timeout, exitshould be IN yourwhileloop, not be placed after it.