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?