Sending data from Linux (via socketcan) is neat and works well. Sending data from Arduino (via AA_MCP2515) is working too. But receiving devices I only have one: the SERVO42D.
Thus it’s time to make the Arduino receive CAN frames and act on them. Since the MEGA2560 I have has the typical built-in LED, it’s what I’d like to control.
- to turn the LED on, send a 0x01
- to turn the LED off, send a 0x00
- to toggle the LED, send a 0x02
I chose CAN ID 2 and there’s no error checking whatsoever to keep it simple. Here is the complete code:
#include "AA_MCP2515.h"
const CANBitrate::Config CAN_BITRATE = CANBitrate::Config_8MHz_500kbps;
const uint8_t CAN_PIN_CS = 53;
const int8_t CAN_PIN_INT = 2;
const int ledPin = LED_BUILTIN;
int ledState = 0;
CANConfig config(CAN_BITRATE, CAN_PIN_CS, CAN_PIN_INT);
CANController CAN(config);
void onReceive(CANController&, CANFrame frame) {
/*
frame.print("RX");
int id = frame.getId();
uint8_t *data;
data = frame.getData();
int dlc = frame.getDlc();
Serial.print("Ch ");
Serial.print(id);
Serial.print(" DLC ");
Serial.print(dlc);
Serial.print(" data ");
for (int i=0; i<dlc; ++i) {
Serial.print(data[i]);
Serial.print(" ");
}
Serial.print('\n');
*/
if (id == 2) {
if (data[0] == 0) ledState = 0;
else if (data[0] == 1) ledState = 1;
else if (data[0] == 2) ledState = !ledState;
digitalWrite(ledPin, ledState);
}
}
void onWakeup(CANController& controller) {
controller.setMode(CANController::Mode::Normal);
}
void setup() {
Serial.begin(115200);
while(CAN.begin(CANController::Mode::Config) != CANController::OK) {
Serial.println("CAN begin FAIL - delaying for 1 second");
delay(1000);
}
Serial.println("CAN begin OK");
// CAN controller is in Config mode so setup receive filters, then change to Normal mode.
// The receive filters will be setup to only receive 11-bit ID's 0x0100, and 0x0103. All other ID's will be filtered out / ignored.
// 11-bit ID filter
// Filter for ID=1 and ID=2
CAN.setFiltersRxb0(0x001, 0x002, 0x07ff, false);
CAN.setFiltersRxb1(0x100, 0x001, 0x001, 0x001, 0x07ff, false);
CAN.setFilters(true);
// -or- 29-bit ID filter
// CAN.setFiltersRxb0(0x100, 0x106, 0x1FFFFFFF, true);
// CAN.setFiltersRxb1(0x100, 0x100, 0x100, 0x100, 0x1FFFFFFF, true);
// CAN.setFilters(true);
Serial.println("CAN filters setup");
CAN.setMode(CANController::Mode::Normal);
pinMode(ledPin, OUTPUT);
CAN.setInterruptCallbacks(&onReceive, &onWakeup);
}
void loop() {
delay(2000);
}
The filter is set up for ID=1 and ID=2. The code only acts on ID=2 though.
Now you can turn the LED on or off via
# LED on
cansend can0 '002#01'
# LED off
cansend can0 '002#00'
# Toggle LED
cansend can0 '002#02'
With that, I can control something more complex, like a bunch of WS2812B LEDs too!