Code to Parse ASCII data over CAN

Hi,

I want to send a TLV data received from Serial read to CAN format.

if a received TLV string is = 0A04060708090B03010203

i need to format it has
Tag = 0A
length = 04
value = 06070809
Tag = 0B
length = 03
value = 010203

Please help to decode the received TLV in this format and send it on CAN bus.

Thanks,
Vani

what Arduino and CAN shield are you using?
what is the CAN receiver?

using the Library Manager (click Sketch>Include Library>Manage Libraries) instal the mcp-can library
have a look at sample project Examples>mcp_can>CAN_send which transmits a CAN message

how is the TVL data received over Serial, e.g. as ASCII text or in binary?
the maximum CAN message size is 8 bytes so you will have to split the TLV data into at least two messages

I find it useful to have a USB-CAN dongle for a PC to help viewing CAN data and debugging problems

Hi Horace,

Currently I am sending ASCII data via serial monitor using USB UART.
And I am using Canable pro as CAN receiver.

Sending the data to CAN using the below method
CAN.sendMsgBuf(0x18FF1100, 1, 8, dta);

receiver code

#include <mcp_can.h>
#include <SPI.h>

#define SPI_CS_PIN 9

String inputString = "";

MCP_CAN CAN(SPI_CS_PIN);

void setup() {
// initialize serial:
Serial.begin(115200);
while(!Serial);

while (CAN_OK != CAN.begin(CAN_500KBPS))    // init can bus : baudrate = 500k
{
    Serial.println("CAN BUS FAIL!");
    delay(100);
}
Serial.println("CAN BUS OK!");

// reserve 200 bytes for the inputString:
inputString.reserve(200);

}

void loop(){

serialEvent()

}

void serialEvent() {
while (Serial.available()) {
// get the new byte:
char inChar = (char)Serial.read();
// add it to the inputString:
inputString += inChar;

}

}
}

Can you please guide me on how to split the TLV data into two messages and send it over CAN .

Thanks,
Vanishree

consider

Output:

  0a 04 06 07 08 09
  0b 03 01 02 03


byte buf [] =  {
    0x0A, 0x04, 0x06, 0x07, 0x08, 0x09, 0x0B, 0x03, 0x01, 0x02, 0x03 };

char s [80];

// -----------------------------------------------------------------------------
void
decode (
    byte *buf,
    int   nByte )
{
    while (nByte)  {
        byte tag = *buf++;
        byte len = *buf++;

        sprintf (s, "  %02x %02x", tag, len);
        Serial.print (s);

        for (int n = len; n > 0; n--)  {
            sprintf (s, " %02x", *buf++);
            Serial.print (s);
        }
        Serial.println ();

        nByte -= 2 + len;
    }
}

// -----------------------------------------------------------------------------
void setup ()
{
    Serial.begin (9600);

    decode (buf, sizeof(buf));
}

void loop ()
{
}

Hi ,

Can you please suggest me how to send these data over CAN.

Thanks

if your TVL data is input as a ASCII string you need to convert it into a byte array for transmission over canbus, e.g.

// convert TVL ASCII string to byte array
//      e.g. "0A04060708090B03010203"
// return length for data read OK  0 for fail
int toBytes(byte *d) {
  char data[20] = {0};
  while (!Serial.available()) ;  // wait
  // get tag and length
  Serial.readBytesUntil('\n', data, 4);
  Serial.print("\n\ndata read = "); Serial.println(data);
  int tag=0, length=0;
  if(sscanf(data, "%02x%02x", &tag, &length) != 2)return 0;
  d[0]=tag;
  d[1]=length;
  // read values
  for (int i = 0; i < length; i++) {
     char data[20] = {0};
     Serial.readBytesUntil('\n', data, 2);
     Serial.print("data read = "); Serial.println(data);
     int value=0;
     sscanf(data, "%02x", &value);
     d[2+i]=value;
  }
 return d[1];
}

void setup() {
  Serial.begin(115200);
}

void loop() {
  byte d[11] = {0};
  int l=toBytes(d);
  if(l<=0) return;
  Serial.print("data length = ");
  Serial.println(l);
  Serial.print(" byte data to transmit over canbus ");
  for (int i = 0; i < l+2; i++)
  {
    Serial.print(" ");
    Serial.print(d[i], HEX);
  }
}

a run with "0A04060708090B03010203" input to the serial monitor gives

data read = 0A04
data read = 06
data read = 07
data read = 08
data read = 09
data length = 4
 byte data to transmit over canbus  A 4 6 7 8 9

data read = 0B03
data read = 01
data read = 02
data read = 03
data length = 3
 byte data to transmit over canbus  B 3 1 2 3

I assume your TVL data will never be longer than 8 bytes?
when you transmit the can data will the tag be the CanID?
what is the receiver?

try this code

// canbus transmit TVL data

#include <mcp_can.h>
#include <SPI.h>

MCP_CAN CAN0(10);//9);     // Set CS pin <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<

// convert TVL ASCII string to byte array
//      e.g. "0A04060708090B03010203"
// return length for data read OK  0 for fail
int TVLtoBytes(byte *d) {
  char data[20] = {0};
  while (!Serial.available()) ;  // wait
  // get tag and length
  Serial.readBytesUntil('\n', data, 4);
  Serial.print("\n\ndata read = "); Serial.println(data);
  int tag = 0, length = 0;
  if (sscanf(data, "%02x%02x", &tag, &length) != 2)return 0;
  d[0] = tag;
  d[1] = length;
  // read values
  for (int i = 0; i < length; i++) {
    char data[20] = {0};
    Serial.readBytesUntil('\n', data, 2);
    Serial.print("data read = "); Serial.println(data);
    int value = 0;
    sscanf(data, "%02x", &value);
    d[2 + i] = value;
  }
  return d[1];
}

void setup()
{
  Serial.begin(115200);
  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  while (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) != CAN_OK) // for Canbus shield V1
  //while(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) != CAN_OK)  // for Can MCP2515 board
    Serial.println("MCP2515 not initialized!");
  Serial.println("Initialized MCP2515");
  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
}

void loop() {
  byte d[11] = {0};
  int l = TVLtoBytes(d);
  if (l <= 0) return;
  Serial.print("data length = ");
  Serial.println(l);
  Serial.print(" byte data to transmit over canbus ");
  for (int i = 0; i < l + 2; i++)
  {
    Serial.print(" ");
    Serial.print(d[i], HEX);
  }
  // send data:  ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
  byte sndStat = CAN0.sendMsgBuf(d[0], 0, d[1], &d[2]);
  if (sndStat == CAN_OK)  Serial.println("Message Sent Successfully!");
  else                    Serial.println("Error Sending Message...");
}

when run on a Mega using Canbus shield V1

Entering Configuration Mode Successful!
Setting Baudrate Successful!
Initialized MCP2515


data read = 0A04
data read = 06
data read = 07
data read = 08
data read = 09
data length = 4
 byte data to transmit over canbus  A 4 6 7 8 9Message Sent Successfully!


data read = 0B03
data read = 01
data read = 02
data read = 03
data length = 3
 byte data to transmit over canbus  B 3 1 2 3Message Sent Successfully!

receiver code

// CAN Receive Example
//

#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];                        // Array to store serial string

#define CAN0_INT 2                              // Set INT to pin 2
MCP_CAN CAN0(10);                               // Set CS to pin 10


void setup()
{
  Serial.begin(115200);
  
  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  // while(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) != CAN_OK)  // for Canbus shield V1
   while(CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) != CAN_OK)  // for Can MCP2515 board
    Serial.println("MCP2515 Initialized Successfully!");
       Serial.println("MCP2515 not initialized!");
   Serial.println("Initialized MCP2515");
  
  CAN0.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN0_INT, INPUT);                            // Configuring pin for /INT input
  
  Serial.println("MCP2515 Library Receive Example...");
}

void loop()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
    
    if((rxId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
      sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (rxId & 0x1FFFFFFF), len);
    else
      sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", rxId, len);
  
    Serial.print(msgString);
  
    if((rxId & 0x40000000) == 0x40000000){    // Determine if message is a remote request frame.
      sprintf(msgString, " REMOTE REQUEST FRAME");
      Serial.print(msgString);
    } else {
      for(byte i = 0; i<len; i++){
        sprintf(msgString, " 0x%.2X", rxBuf[i]);
        Serial.print(msgString);
      }
    }
        
    Serial.println();
  }
}

when run on a UNO with a Can MCP2515 board

Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 not initialized!
Initialized MCP2515
MCP2515 Library Receive Example...
Standard ID: 0x00A       DLC: 4  Data: 0x06 0x07 0x08 0x09
Standard ID: 0x00B       DLC: 3  Data: 0x01 0x02 0x03

Hi Horace,

Thank you!!!

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.