Mit 16 tasten 16 relais schalten über can bus mcp2515 und mega

Da es bei mir mit der angegebenen Konfiguration läuft, sollte es nicht an der grundsätzlichen Programmlogik liegen ...

Hier Deine Sketche mit folgenden Anpassungen:

  • An beiden Seiten am Pin A0 (bei Bedarf ändern) eine Led anschließbar, die im Betrieb im Sekundentakt von der Gegenstelle per Canbus ein/ausgeschaltet wird
  • Dafür jeweils eigene canIDs vergeben (0xFF und 0XF0)
  • Damit nicht versehentlich auf mehr Relais zugegriffen wird, als mit den 2 Byte möglich, habe ich vorsorglich noch eine Begrenzung auf 16 in die Berechnung von relaisAnzahl eingebaut.

Wenn Du also am vorgegebenen Pin jeweils eine Led anschließt, kannst Du sehen, ob die Verbindung steht. Später kann man das auch zur Betriebssüberwachung einsetzen; z.B. ein Warnsignal ausgeben oder die CAN-Controller resetten oder ....

Taster-Seite:

/*
   Forum: https://forum.arduino.cc/t/mit-16-tasten-16-relais-schalten-uber-can-bus-mcp2515-und-mega/1216997/8

   2024/01/31
   ec2021
   
*/


#include <SPI.h>
#include <mcp2515.h>

// ****************************************************************************************
// **************************** Taster-Seite *******************************************
// ****************************************************************************************

const byte blinkPin = A0;
const unsigned long blinkInterval = 1000;


const byte CAN_CS = 53;
const unsigned long canIDOut = 0xFF;
const unsigned long canIDIn  = 0xF0;

struct can_frame canMsg;
MCP2515 mcp2515(CAN_CS);

enum kommandoTyp { SETZEN, ABFRAGE, LIVESIGNAL} kommando;



// Diese Struktur beinhaltet alles, was für die Behandlung eines Tasters/tasters erforderlich
// ist, das Initialisieren des Pins mit INPUT_PULLUP (so dass keine externen Widerstände erforderlich sind)
// und das Entprellen des Tasters/tasters per Software.
// die Funktion pressed() gibt genau dann einmal(!) true zurück, wenn der Zustand des Tasters
// von HIGH auf LOW wechsel (also gerade "gedrückt wird").

struct tasterTyp {
  byte pin;
  byte state = HIGH;
  byte lastState = HIGH;
  unsigned long lastChange = 0;
  void init(byte aPin) {
    pin = aPin;
    pinMode(pin, INPUT_PULLUP);
  }
  boolean pressed() {
    byte actState = digitalRead(pin);
    if (actState != lastState) {
      lastChange = millis();
      lastState = actState;
    }
    if (actState != state && millis() - lastChange > 20) {
      state = actState;
      return !state;
    }
    return false;
  }
};

// Hier kann man einfach weitere Pins eingeben, der Rest der Software
// behandelt dann auch diese Pins, ohne dass etwas am Code geändert werden muss

const byte tasterPin[] = { 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, };
// Die folgende Zeile berechnet, wieviele Einträge bei tasterPin[] vorhanden sind
const int tasterAnzahl = sizeof(tasterPin) / sizeof(tasterPin[0]);

// Entsprechend werden nun taster-Struktur-Objekte angelegt
tasterTyp taster[tasterAnzahl];
byte tasterZustand[tasterAnzahl];

void tasterInitialisieren() {
  // Hier werden die taster-Objekte initialisiert, indem ihnen der zugehörige Pin
  // zugewiesen wird.
  for (int i = 0; i < tasterAnzahl; i++) {
    taster[i].init(tasterPin[i]);
    tasterZustand[i] = LOW;  // Alle Leuchten werden hier mal auf LOW gesetzt.
  }
}

void tasterKommandoSenden() {
  mcp2515.sendMessage(&canMsg);
}

void tasterKommandoAlleSetzen() {
  byte bis8 = 0;
  byte bis16 = 0;
  for (int i = tasterAnzahl - 1; i >= 0; i--) {
    if (i < 8) {
      bis8 = bis8 << 1;
      bis8 = bis8 + ((tasterZustand[i] == HIGH) ? 1 : 0);
    } else {
      bis16 = bis16 << 1;
      bis16 = bis16 + ((tasterZustand[i] == HIGH) ? 1 : 0);
    }
  }
  canMsg.can_id = canIDOut;
  canMsg.can_dlc = 3;
  canMsg.data[0] = SETZEN;
  canMsg.data[1] = bis8;
  canMsg.data[2] = bis16;
  tasterKommandoSenden();
}

void tasterAuswerten() {
  for (int i = 0; i < tasterAnzahl; i++) {
    if (taster[i].pressed()) {
      tasterZustand[i] = !tasterZustand[i];
      Serial.print("Leuchte Nr. ");
      Serial.print(i + 1);
      Serial.print(" ist ");
      Serial.println((tasterZustand[i] == HIGH) ? "EIN" : "AUS");
      tasterKommandoAlleSetzen();
    };
  }
}

boolean canMsgReceived() {
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
    return (canMsg.can_id == canIDIn);
  }
  return false;
}

void sendLiveMessage() {
  static unsigned long lastChange = 0;
  static byte state = LOW;
  struct can_frame canMsgOut;
  if (millis() - lastChange > blinkInterval) {
    lastChange = millis();
    state = !state;
    canMsgOut.can_id = canIDOut;
    canMsgOut.can_dlc = 2;
    canMsgOut.data[0] = LIVESIGNAL;
    canMsgOut.data[1] = state;
    mcp2515.sendMessage(&canMsgOut);
  }
}

void kommandoAuswerten() {
  switch (canMsg.data[0]) {
    case ABFRAGE:
      Serial.println("Abfrage empfangen ");
      // Hier müsste ggf. eine Rückmeldung per CAN realisiert werden
    case LIVESIGNAL:
      //Serial.println("Livesignal empfangen ");
      digitalWrite(blinkPin, canMsg.data[1]);
      break;
    default:
      Serial.print("unbekanntes Kommando ");
      Serial.println(canMsg.data[0]);
      break;
  }
}

// ****************************************************************************************
// ****************************   Setup         *******************************************
// ****************************************************************************************
void setup() {
  Serial.begin(115200);
  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();
  tasterInitialisieren();
}

void loop() {
  // In der loop() werden alle Taster schnell nacheinander ausgelesen.
  tasterAuswerten();
  sendLiveMessage();
  if (canMsgReceived()) {
    kommandoAuswerten();
  }
}

Relais-Seite:

/*
   Forum: https://forum.arduino.cc/t/mit-16-tasten-16-relais-schalten-uber-can-bus-mcp2515-und-mega/1216997/8

   2024/01/31
   ec2021

*/

#include <SPI.h>
#include <mcp2515.h>

// ****************************************************************************************
// ****************************   Relais-Seite  *******************************************
// ****************************************************************************************

const byte blinkPin = A0;
const unsigned long blinkInterval = 1000;
const byte CAN_CS = 53;
const unsigned long canIDIn   = 0xFF;
const unsigned long canIDOut  = 0xF0;

struct can_frame canMsg;
MCP2515 mcp2515(CAN_CS);

enum kommandoTyp { SETZEN,
                   ABFRAGE,
                   LIVESIGNAL } kommando;

struct relaisTyp {
  byte pin;
  byte zustand;
  void init(byte aPin) {
    pin = aPin;
    digitalWrite(pin, LOW);
    pinMode(pin, OUTPUT);
  }
  void setze(byte level) {
    zustand = level;
    digitalWrite(pin, zustand);
    Serial.print(zustand == HIGH ? "HIGH " : "LOW  ");
  }
};

// Hier sind die relaisPins einzutragen:
const byte relaisPin[] = {
  34,
  35,
  36,
  37,
  38,
  39,
  40,
  41,
  42,
  43,
  44,
  45,
  46,
  47,
  48,
  49
};
// Die folgende Zeilen berechnen, wieviele Einträge bei relaisPin[] vorhanden sind
// und begrenzen auf maximal 16
const int rAnzahl = (sizeof(relaisPin) / sizeof(relaisPin[0])) ;
const int relaisAnzahl = (rAnzahl <= 16) ? rAnzahl : 16;


relaisTyp relais[relaisAnzahl];

void relaisInitialisieren() {
  // Hier werden die relais-Objekte initialisiert, indem ihnen der zugehörige Pin
  // zugewiesen wird.
  for (int i = 0; i < relaisAnzahl; i++) {
    relais[i].init(relaisPin[i]);
    relais[i].setze(LOW);  // Alle Leuchten werden hier mal auf LOW gesetzt.
  }
}

void relaisSetzen(byte bis8, byte bis16) {
  for (int i = 0; i < relaisAnzahl; i++) {
    if (i < 8) {
      relais[i].setze((bis8 & 1 != 0) ? HIGH : LOW);
      bis8 = bis8 >> 1;
    } else {
      relais[i].setze((bis16 & 1 != 0) ? HIGH : LOW);
      bis16 = bis16 >> 1;
    }
  }
  Serial.println();
}

void relaisKommandoAuswerten() {
  switch (canMsg.data[0]) {
    case SETZEN:
      Serial.print(canMsg.data[1]);
      Serial.print(" - ");
      Serial.println(canMsg.data[2]);
      relaisSetzen(canMsg.data[1], canMsg.data[2]);
      break;
    case ABFRAGE:
      Serial.println("Abfrage vom Tasten-Controller empfangen ");
      // Hier müsste ggf. eine Rückmeldung per CAN realisiert werden
    case LIVESIGNAL:
      //Serial.println("Livesignal empfangen ");
       digitalWrite(blinkPin,canMsg.data[1]);
       break;
    default:
      Serial.print("unbekanntes Kommando ");
      Serial.println(canMsg.data[0]);
      break;
  }
}

boolean canMsgReceived() {
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
    return (canMsg.can_id == canIDIn);
  }
  return false;
}

void relaisAuswerten() {
  if (canMsgReceived()) {
    relaisKommandoAuswerten();
  }
}

void sendLiveMessage(){
  static unsigned long lastChange = 0;
  static byte state = LOW;
  struct can_frame canMsgOut;
  if (millis()-lastChange > blinkInterval){
    lastChange = millis();
    state = !state;
    canMsgOut.can_id = canIDOut;
    canMsgOut.can_dlc = 2;
    canMsgOut.data[0] = LIVESIGNAL;
    canMsgOut.data[1] = state;
    mcp2515.sendMessage(&canMsgOut); 
  }
}

// ****************************************************************************************
// ****************************   Setup         *******************************************
// ****************************************************************************************
void setup() {
  Serial.begin(115200);
  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS, MCP_8MHZ);
  mcp2515.setNormalMode();
  relaisInitialisieren();
  canMsg.can_id = 0x00;
}

void loop() {
  relaisAuswerten();
  sendLiveMessage();
}

So kannst Du sowohl per Led wie auch mittels der Serial-Ausgaben beider Seiten prüfen, ob und was jeweils auf der Gegenseite ankommt.

Dann wäre noch zu prüfen, wie Du Deine Taster angeschlossen hast ... Mein Sketch geht davon aus, dass der Taster-Pin per INPUT_PULLUP im "Ruhezustand" auf HIGH liegt und beim Tasten auf LOW gezogen wird. Ist das bei Deiner Verdrahtung auch so?

Ja stimmt, den Auslöser braucht es natürlich noch...
Aber schön, dass Du es probiert hast :slight_smile: Zeigt es doch, dass die Idee nciht ganz falsch war...

ja das ist bei mir genau so da ich grade am bauen vom Taster Feld bin drücke ich mit einem Draht der auf GND gesteckt ist die einzelnen Pins als Ersatz für die Taster was mir aufgefallen ist wenn ich den Sender am PC angeschlossen habe blinkt die Led D.h er sendet trenne ich aber die Verbindung und stecke die Relais Seite ein blinkt die Led nicht mehr des weiteren gibt Der A0 keine Ausgabe als über Prüfung sowie sind die Relais immer noch permanent auf HIGH und was Heist das wenn mir der Mega beim anschliesen am PC abraucht ich glaube meine beiden mega sind kaputt

Damit man Deine Erkenntnisse nachvollziehen kann, müsstest Du diese eindeutiger formulieren.

  • Welche Led meinst Du hier z.B.? Mit dem zuletzt von mir geposteten Sketch würden die Led am Pin A0 (der digital genutzt auch als Pin D14 angesprochen werden kann) auf beiden Seiten nur dann blinken, wenn beide Mega mit dem jeweiligen Code laufen und per CanBus miteinander verbunden sind ...
  • Erhältst Du Ausgaben im seriellen Monitor, wenn der Mega "Taster-Seite" angeschlossen ist und Du einen der Taster-Pins auf GND ziehst?

Testen im kompletten Verbund erhöht die Komplexität und verstellt i.d.R. den Blick für die tatsächliche Ursache ... Also vom Einfachen zum Schwierigen, vom Bekannten zum Unbekannten vorgehen ...

Ich würde zunächst mal beide Mega mit einem einfachen Blink-Sketch, z.B. für Pin 13, bespielen und prüfen, ob das funktioniert. Danach kann man die Prüfung ausweiten, bis die beiden Mega mittels MCP auf dem Can Daten verbunden werden. Auch dafür gibt es Beispielsketche, die man auf die eine und die andere Seite aufspielt (siehe CAN_read, CAN_write):
image

Viel Glück!

ich habe dein zuletzt geposteten Sketch verwendet aber der Fehler war am Bord selber die sind mir beide abgeraucht von daher vermute ich das dort der Fehler lag, 2 neue Mega2560 und MCP2515 sind bestellt dann werde ich es erneut versuchen VIELEN VEILEN DANK bis her für eure Unterstützung

Was heisst das?

Abrauchwoche für Arduinos :joy:

naja ich habe die beiden mit einer Extrenen Strom Versorgung angeschlossen (7V) und halt am PC zum programieren jetzt sind sie mir beide abgeraucht ich denke das die das nicht verkraftet haben und schon vorher was kaputt war

Die parallele Versorgung via 7V und anstecken von USB ist möglich und auch so vorgesehen.

Was hast Du getan, um festzustellen, dass die (beide) kaputt sind?

naja fest stellen muste ich nix sie haben beide rauch Zeichen gegeben vom Spannungsregler aus und ich habe es auch gesehen das die innerlich glühen von daher denke ich das dass Bord Überspannung bekommen hat und deshalb nix geht

:man_shrugging:

Das kennt man als "Magic Smoke" ...

Das ist der blaue Rauch, der in Elektronik verbaut ist und dafür sorgt, dass diese Teile funktionieren.

Der Beweis: Immer wenn man den Magic Smoke sieht, er also aus dem Bauelement ausgetreten ist, funktioniert das Teil nicht mehr. :wink:

Siehe https://de.m.wikipedia.org/wiki/Magic_Smoke

1 Like

@Sniperbk1172: Da Du wegen des Rauches pausieren mußt, habe ich mir mal #32 vorgenommen, um es zu testen.

Sendeprogramm für UNO angepaßt
#include <Keypad.h>

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

MCP_CAN CAN0(10);     // Set CS to pin on MEGA  --> agmue

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

byte hexaKeys[ROWS][COLS] =  //  --> agmue
{
  {0x0, 0x1, 0x2, 0x3},
  {0x4, 0x5, 0x6, 0x7},
  {0x8, 0x9, 0xA, 0xB},
  {0xC, 0xD, 0xE, 0xF}
};

byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad  --> agmue
byte colPins[COLS] = {9, 8, 7, 6}; //connect to the column pinouts of the keypad  --> agmue

Keypad keypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void setup()
{
  Serial.begin(9600);
  Serial.println(F("Start..."));
  keypad.addEventListener(keypadEvent); // Add an event listener for this keypad
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK)  //  --> agmue
  {
    Serial.println(F("MCP2515 Initialized Successfully!"));
  }
  else
  {
    Serial.println(F("Error Initializing MCP2515..."));
  }
}
uint16_t data;

constexpr uint16_t canId {0x100};
// byte customKey;  --> agmue

void loop()
{
  keypad.getKey();
}

// Taking care of some special events.
void keypadEvent(KeypadEvent key)
{
  byte myByte[8] = {0, 0, 0, 0, 0, 0, 0, 0};
  if (keypad.getState() == PRESSED)
  {
    if (bitRead(data, key))
    {
      bitClear(data, key);
    }
    else
    {
      bitSet(data, key);
    }
    Serial.println(data, HEX);
    myByte[0] = data >> 8;
    myByte[1] = data;
    CAN0.sendMsgBuf(canId, 0, 2, myByte); // Normalmode, 2 byte, -> Datenpaket
  }
}
serieller Monitor Sender

Start...
Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully!
2
0
2
0
2
0

Empfangsprogramm wie "Empfangsprogramm für UNO mit ID je Relais" siehe unten.

Leider bleibt der Empfänger still und ich finde den Fehler nicht:

serieller Monitor Empfänger
Start ...
Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully!

Also habe ich das Sende- und Empfangsbeispiel zur Überprüfung der Hardware verwendet
-> funktioniert.

Dann habe ich Sender und Empfänger für Tasten und Relais umgebaut, allerdings mit unterschiedlichen IDs je Relais, so wie von mir und @ec2021 in #19 und #20 vorgeschlagen
-> funktioniert

Sendeprogramm für UNO mit ID je Relais
// Sender
#include <Keypad.h>

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

MCP_CAN CAN0(10);     // Set CS to pin 10

const byte ROWS = 4; //four rows
const byte COLS = 4; //four columns

byte hexaKeys[ROWS][COLS] =
{
  {0x0, 0x1, 0x2, 0x3},
  {0x4, 0x5, 0x6, 0x7},
  {0x8, 0x9, 0xA, 0xB},
  {0xC, 0xD, 0xE, 0xF}
};

byte rowPins[ROWS] = {5, 4, 3, 2}; //connect to the row pinouts of the keypad
byte colPins[COLS] = {9, 8, 7, 6}; //connect to the column pinouts of the keypad

Keypad keypad = Keypad( makeKeymap(hexaKeys), rowPins, colPins, ROWS, COLS);

void setup()
{
  Serial.begin(9600);
  Serial.println(F("Start..."));
  keypad.addEventListener(keypadEvent); // Add an event listener for this keypad

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
  else Serial.println("Error Initializing MCP2515...");

  CAN0.setMode(MCP_NORMAL);   // Change to normal mode to allow messages to be transmitted
}

byte data[1] = {0x00};

void loop()
{
  keypad.getKey();
}

void keypadEvent(KeypadEvent key)
{
  if (keypad.getState() == PRESSED)
  {
    Serial.print("Event: ");
    Serial.println(key, HEX);
    INT32U id = 0x100 + key;
    // send data:  ID, Standard CAN Frame, Data length, 'data' = array of data bytes to send
    byte sndStat = CAN0.sendMsgBuf(id, 0, 1, data);
    if (sndStat == CAN_OK) {
      Serial.println("Message Sent Successfully!");
    } else {
      Serial.println("Error Sending Message...");
    }
    if (data[0]) {
      data[0] = 0;
    } else {
      data[0] = 1;
    }
  }
}
Empfangsprogramm für UNO mit ID je Relais
// Empfänger
#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

constexpr byte pinNums {6};
constexpr byte outPin[pinNums] {4, 5, 6, 7, 8, 9};

void setup()
{
  Serial.begin(9600);
  Serial.println("Start ...");

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK)
    Serial.println("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
  for (byte b = 0; b < pinNums; b++)
  {
    pinMode(outPin[b], OUTPUT);
  }
}

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)
    sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", rxId, len);
    Serial.print(msgString);
    for (byte i = 0; i < len; i++) {
      sprintf(msgString, " 0x%.2X", rxBuf[i]);
      Serial.print(msgString);
    }

    byte id = 0xf & rxId;
    if (id < pinNums) 
    {
      digitalWrite(outPin[id], rxBuf[0] & 0x1);
      sprintf(msgString, "\t Pin %u %u", outPin[id], rxBuf[0] & 0x1);
      Serial.print(msgString);
    }
    Serial.println();
  }
}
serieller Monitor Sender
Start...
Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully!
Event: 1
Message Sent Successfully!
Event: 1
Message Sent Successfully!
serieller Monitor Empfänger
Start ...
Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully!
Standard ID: 0x101       DLC: 1  Data: 0x00	 Pin 5 0
Standard ID: 0x101       DLC: 1  Data: 0x01	 Pin 5 1

Da steh' ich nun, ich armer Tor,
Und bin so klug als wie zuvor!
Quelle: Goethe, Faust. Der Tragödie erster Teil

3 Likes

Ich hab noch nicht durchgeschaut.
Empfängt der Empfänger gar nix?
Das sendmsg() hat einen Rückgabewert, den könnte man abfragen.

Wenn beim Empfänger etwas ankommt, aber nicht passt, dann ist es die bitfolge -> ich schiebe evtl. falsch.

Nix, auch keine leeren Zeilen!

    byte sndStat = CAN0.sendMsgBuf(canId, 0, 2, myByte); // Normalmode, 2 byte, -> Datenpaket
    if (sndStat == CAN_OK) {
      Serial.println("Message Sent Successfully!");
    } else {
      Serial.println("Error Sending Message...");
    }

Sender:

Start...
Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully!
2
Message Sent Successfully!
0
Message Sent Successfully!

Empfänger:

Start ...
Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully!

so meine neuen Bords sind da aber es geht immer noch nicht was kann ich jetzt noch tun

Tolle Fehlermeldung. Damit kann jeder etwas anfangen.
Beschreie klar was geht und was nicht geht.

Gruß Tommy

der mega erkennt die eingaben aber irgend wie sendet er diese nicht .die relais sind auch dauerhaft auf HIGH geschalten als ob die MCP2515 nicht senden auf denn seriallen monitor sehe ich die eingaben aber nicht auf dem empfänger das diese ankommen

ich frage mal ander muss ich den INT auch noch anschliesen weil ich da nix gefunden habe wo der angeschlossen wird

Die Relais sind LOW-Aktiv.
Das heisst, wenn Du den Controller initialisierst, ist der Ausgang auch LOW.
Und damit sagst Du dem Relaisboard, das es aktiv sein soll.

Das war aber schon immer so! Auch schon bevor Du die neuen Controller in Betrieb genommen hast!

Du musst also die gesamte Logik umstellen.

Und dann mach das nicht alles auf einmal, sondern nach und nach.

Empfänger aufbauen.
Mit einer Simulation austesten, ob die Relais richtig auslösen.

Wenn das geht, dann einen Sender und einen Empfängersketch bauen, der nur rudimentät ein Byte überträgt und Du gesichert dieses Byte auswerten kannst.

Auf dem MCP-Shield ist ein Jumper für den Abschlußwiderstand des Bus vorgesehen. Die sind aktiviert?