Chat (messenger) over the CAN BUS with Nano V3

Hello, I am starting to learn with the CAN BUS as use MCP2515 module (has been ordered and arrive my home about June 14) with Nano V3 or better whatever, I need to understand how works with BI-DIRECTIONS between CAN BUS Modules like use chat Such as messenger also unable to find a example codes because I see so many codes with "one receiver and one sender" which is I do not want.

Here what I am doing with code in BOTH NANO boards:

#include <CAN.h>
int serkeypress;
void setup() {
  Serial.begin(9600);
  while (!Serial)
    ;
  Serial.println("CAN INITIZING");
  if (!CAN.begin(500E3)) {
    Serial.println("Starting CAN failed!");
    while (1)
      ;
  }
  Serial.println("CAN BUS STARTED OK.");
  Serial.println("");
}
void loop() {
  if (Serial.available() > 0) {
    serkeypress = Serial.read();
    CAN.beginPacket(0x12);
    CAN.write(serkeypress);
    CAN.endPacket();
  }
  if (CAN.parsePacket()) {
    while (CAN.available()) {
      Serial.print((char)CAN.read());
    }
  }
}

WILL THAT WORKS?

Yes, the basic idea should work. CAN is not limited to one sender and one receiver; every node can both transmit and receive on the same bus.

With the same code on both Nano boards, typing in the Serial Monitor of one board should send that character over CAN, and the other board should print it.

For testing, your approach is fine. Later you may want to use different CAN IDs for each board, for example one board sends with 0x12 and the other with 0x13, so you can tell which node sent the message.

not used the Nano for Canbus but this example runs on a Mega using a MCP2525

// Mega MCP2515 CAN send/Receive Example 
//
// Mega <> MCP2515 connections
// MCP2515 INT to Mega  GPIO2
// MCP2515 SCK to Mega  GPIO52 CLK
// MCP2515  SI to Mega  GPIO51 MOSI
// MCP2515  SO to Mega  GPIO50 MISO
// MCP2515  CS to Mega  GPIO53  CS
// MCP2515 GND to Mega  GND
// MCP2515 VCC to Mega  5V

#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  // for Mega 
MCP_CAN CAN0(10);//53);   // 

void setup() {
  Serial.begin(115200);
  delay(2000);
  Serial.println("\n\nMega- CAN MCP2515 shield Send/Receive test - MCP2515 Initialize");
    Serial.print("MOSI: ");
  Serial.println(MOSI);
  Serial.print("MISO: ");
  Serial.println(MISO);
  Serial.print("SCK: ");
  Serial.println(SCK);
  Serial.print("SS: ");
  Serial.println(SS);  

  // Initialize MCP2515 baudrate of 250kb/s and the masks and filters disabled.
  //  check crystal frequency!! e.g. Canbus shield is 16MHz MCP2515 is 8MHz
  if (CAN0.begin(MCP_ANY, CAN_125KBPS, MCP_8MHZ) == CAN_OK)
    Serial.println("CAN Receive - MCP2515 Initialized Successfully!");
  else
    Serial.println("Error Initializing MCP2515...");
  CAN0.setMode(MCP_NORMAL);         // Set operation mode to normal so the MCP2515 sends acks to received data.
  pinMode(CAN0_INT, INPUT_PULLUP);  // Configuring pin for /INT input *** added PULLUP ***
  Serial.println("MCP2515 Library CAN Send/Receive Example\n enter space to send a frame");
}

void loop() {
  // check for data received
  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();
  }
  // transmit data when space entered on keyboard
  if(Serial.available()){
    if (Serial.read() != ' ') return;
    static byte data[8] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07 };
       for (byte i = 0; i < 8; i++) {
        sprintf(msgString, " 0x%.2X", data[i]);
        Serial.print(msgString);
      }
 
    // send data:  ID = 0x100, Standard CAN Frame, Data length = 8 bytes, 'data' = array of data bytes to send
    byte sndStat = CAN0.sendMsgBuf(0x100, 0, 8, data);
    if (sndStat == CAN_OK) {
      Serial.println(" Message Sent Successfully!");
    } else {
      Serial.println(" Error Sending Message...");
    }
    data[0]++;    // increment first byte of data
 }
}



Mega Serial monitor output sending/receiving canbus frames

Mega- CAN MCP2515 shield Send/Receive test - MCP2515 Initialize
MOSI: 51
MISO: 50
SCK: 52
SS: 53
Entering Configuration Mode Successful!
Setting Baudrate Successful!
CAN Receive - MCP2515 Initialized Successfully!
MCP2515 Library CAN Send/Receive Example
 enter space to send a frame
 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07 Message Sent Successfully!
 0x01 0x01 0x02 0x03 0x04 0x05 0x06 0x07 Message Sent Successfully!
Standard ID: 0x100       DLC: 8  Data: 0x00 0x4D 0x45 0x47 0x41 0x00 0x07 0x08
Standard ID: 0x100       DLC: 8  Data: 0x01 0x4D 0x45 0x47 0x41 0x00 0x07 0x08
Standard ID: 0x100       DLC: 8  Data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Extended ID: 0x000FF100  DLC: 8  Data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Standard ID: 0x100       DLC: 8  Data: 0x02 0x4D 0x45 0x47 0x41 0x00 0x07 0x08
 0x02 0x01 0x02 0x03 0x04 0x05 0x06 0x07 Message Sent Successfully!
 0x03 0x01 0x02 0x03 0x04 0x05 0x06 0x07 Message Sent Successfully!

UNO Serial monitor output sending/receiving canbus frames

UNO CAN MCP2515 shield Send/Receive test - MCP2515 Initialize
Entering Configuration Mode Successful!
Setting Baudrate Successful!
CAN Receive - MCP2515 Initialized Successfully!
MCP2515 Library CAN Send/Receive Example
 enter space to send a frame
Standard ID: 0x100       DLC: 8  Data: 0x00 0x01 0x02 0x03 0x04 0x05 0x06 0x07
Standard ID: 0x100       DLC: 8  Data: 0x01 0x01 0x02 0x03 0x04 0x05 0x06 0x07
 0x00 0x4D 0x45 0x47 0x41 0x00 0x07 0x08 Message Sent Successfully!
 0x01 0x4D 0x45 0x47 0x41 0x00 0x07 0x08 Message Sent Successfully!
Standard ID: 0x100       DLC: 8  Data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
Extended ID: 0x000FF100  DLC: 8  Data:0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
 0x02 0x4D 0x45 0x47 0x41 0x00 0x07 0x08 Message Sent Successfully!
Standard ID: 0x100       DLC: 8  Data: 0x02 0x01 0x02 0x03 0x04 0x05 0x06 0x07
Standard ID: 0x100       DLC: 8  Data: 0x03 0x01 0x02 0x03 0x04 0x05 0x06 0x07

don't forget Canbus is a peer-to-peer network - all devices are equal - all can transmit and all receive every message
it is a priority based protocol with the CAN IDs determining priority - if you have a number of nodes exchanging messages set the message IDs so high priority messages get thru first
receivers can use filters to filter out the messages which are of interest or for simplicity use if statements, e.g. a can module controlling the lights will accept only messages controlling light settings
unless you are using devices with preassigned Can IDs you assign each Can node on your vehicle a CAN ID - 11bit is probably sufficient
design a protocol which can be very simple - each CAN message can be up to 8ytes

I find when testing Can networks a USB-CAN dongle which plugs into a PC and displays traffic etc very useful for monitoring and debugging the network

I just got my dongle to work, I always used a Nano and the MCP2515 with Cory Fowler's mcp-can library. I am back to the Arduino where I just formatted the output as I like it and included a .ASCII in the line with the data. I have been doing this for years and have had no problems. I do run Linux and have several work spaces where that would run in one and in another would be the code I was testing. You need to be careful of the port you select in the IDE. I always leave the monitor terminal open that way another IDE will not grab it. Each module signs on with its filename and date of compile, this keeps things easy to follow.

Hi @RAM_ELECTRONICS !

When the CAN bus was specified the idea was to create a bus where

  • every participant can start transmission if the bus is free
  • without collision when two or more are starting at the same time
  • and without giving priorities to transmitting stations

The reason was that - in a vehicle environment - certain messages will be more relevant than others, e.g. the request to break is more important than the message to switch on/off the internal light ...

At the same time a specific transmitter station may be responsible for low as well as high priority functions.

This was solved by giving priorities to messages. Any transmittion starts with the message ID which is used to determine the priority. The specification says

Message IDs must be unique[12] on a single CAN bus, otherwise two nodes would continue transmission beyond the end of the arbitration field (ID) causing an error.

Source: https://en.wikipedia.org/wiki/CAN_bus

With the library you use the call to beginPacket() sets an 11bit message identifier.

Although it is not quite likely to create collisions in your application it would be "clean" to use different IDs for the messages your CAN bus participants use.

Good luck and have fun!
ec2021

Thank You!!

Those are extra more info and tips!!!

here what I am planning to use CANBUS:

My PC use touch screen, it can show me what water doing also auto shutoff when water is running for long also detect all light switch to alert me that someone forgot light off etc.... I will use LOT LOT of canbus everywhere in my house if it can?

remember the Canbus must have 120ohm resistor terminators at each end, e.g.

each Canbus interface module probably has a 120ohm terminator - the resistors must be removed from the nodes between the terminators
this may be by removing a link, cutting a link or unsoldering the resistor

Oh yes, I am aware that. and thank you.

YAY, I got MCP2515 module and built 3 of nano. I got them to communicate worked perfectly.

I fixed the code a bit:

#include <CAN.h>
int serkeypress;
int id = 0x04;

void setup() {
  Serial.begin(9600);
  while (!Serial)
    ;
  Serial.println("STARTING CANBUS INITIALIZE...");
  if (!CAN.begin(125E3)) {
    Serial.println("Starting CANBUS failed!");
    while (1)
      ;
  }
  Serial.println("CANBUS STARTED SUCCESSFUL.");
  Serial.print("THIS ID IS ");
  Serial.println(id);
  Serial.println("");
}


void loop() {
  // Read key from serial and write to CANBUS
  if (Serial.available() > 0) {
    serkeypress = Serial.read();
    CAN.beginPacket(id);
    CAN.write(serkeypress);
    CAN.endPacket();
  }
  // Read CANBUS and write to Serial
  if (CAN.parsePacket()) {
    Serial.print("ID:");
    Serial.print(CAN.packetId());
    Serial.print(" > MSG:");
    while (CAN.available()) {
      Serial.print((char)CAN.read());
    }
    Serial.println("");
  }
}

result:

Thanks!!

now I am doing more codes for one target to send such as command. also detect IDs.

Then consider a broadcast messages to all nodes as well as the ability to talk to a single node.

:+1: