Send data via CAN BUS

02 Dec 2011

Hello,

I'm starting a new project but don't have to much experience in C, and my goal is to measure the Volts that are available in the port 20 (DigitalIn). Currently I'm only sending the integer part, but I want to know how I can send the complete measure (e.g. I read 2.55V in MBED1 and I want to send via CAN BUS to receive in the MBED2 the 2.55V).

For this project I'm using the following material:

  • 2x MBEDs
  • 2x CAN MCP2551
  • 1x 120 Ohm resistor

In MBED1 I'm using the following code:

#include "mbed.h"
#include "CAN.h"

AnalogIn ain(p19);

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

CAN can1(p30, p29);

Serial pc(USBTX,USBRX); //tx. rx

int main() {

    char value = 0;
    float measure = 0;
    
    pc.baud(9600);
    
    can1.frequency(125000);
    
    /*********Program Starts Here***************/
    while(1) {
        measure = (0.707631 * ain) / 0.211966;
        value = (int) measure;
    
        if(can1.write(CANMessage(0x42, &value, 2))) {
            led1 = 1;
            pc.printf("> %u volts ", value);
            pc.printf("-- %f volts \n", measure);
        }
                
        wait(2.0);
        led1 = 0;
        
        measure = 0;
    }
}

And in MBED2 I'm using this code to print out the values:

#include "mbed.h"
#include "CAN.h"

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

CAN can2(p30, p29);

Serial pc(USBTX,USBRX); //tx. rx

int main() {

    CANMessage msg;
    float measure = 0;
    
    pc.baud(9600);
    
    can2.frequency(125000);
    
    /*********Program Starts Here***************/
    
    while(1) {
    
        wait(0.5);
        
        if(can2.read(msg)) { 
            led2=1;
            pc.printf("Received value: %02X volts",msg.data[0]);
            
            measure = (int) msg.data[0];
            
            pc.printf(" ---  Value in Volts >> %4.2f V\n", measure);
        } 
        
        led2 = 0;
        wait(0.2);
        led4 = !led4;
        
        measure = 0;
    }
}

Regards

02 Dec 2011

Not 100% sure, but is MBED 1 actualy reading voltage correctly ? (Printf ....)

I would sudjest reading ADC as 16 bit number, then sending it as 2 bytes,

..

Re-constituting it on MBED 2, and then sompthing like this:

float MyResult = ((msg.data[0]) + (msg.data[2] * 256)) * (1/2^16);

printf ("Real nunber recived = $2.5f \r\n" MyResult);

OR:

just use non float/real numbers.

Hope this is usefull

Ceri

04 Dec 2011

Hi,

To convert back and forth you can use a union like:

typedef struct bytes_32 {
    unsigned char b0;
    unsigned char b1;
    unsigned char b2;
    unsigned char b3;
} bytes_32;

typedef union {
    unsigned long l;
    bytes_32 b;
} packed_long;

You just copy either the long (or int) in the l packed_long member and can read the bytes in the b.b0..b.b3 members or the other way round. SO if you copy msg[0]..msg[3] into b.b0..b.b3 you can read the integer back.

The format (ie byte order) is also correct for CANOpen (I verified it against samples). If you want to be a bit more CANOpen compatible request the free CIA301 standard at CANOpen.org.

wvd_vegt

20 Aug 2017

See J1939 automotive protocol.

22 Aug 2017

Start with One micro and put the CAN module in Loopback mode so it sends data to itself. Use this to test write and reading data without worrying about transceivers, termination resistors, wiring, a second micro etc.

can.mode(CAN::LocalTest);

The CAN module must see the CAN bus voltage in order to initialize. For the loopback test, I believe you have to short the CAN TX and CAN RX pins or the module will fail to initialize.

Be sure you are watching your mbed default debug console messages. It can report on various problems it sees.