das hat mir jetzt keine Ruhe gelassen.
Glücklicherweise habe ich ein Packerl mit MCP23S17 gefunden. Was nicht so alles rumliegt.
das ist jetzt mein Testaufbau:
Im Sketch war eine Referenz falsch. Jetzt müsste es klappen.
Zumindest bleiben bei mir jetzt die LEDs nur kurz an.
Zum testen gibts jetzt auch ein Serial Interface.
Probier mal MIT LEDs (!!!) und berichte.
getestet mit Hardware daher auch mal direkt im Forum:
/*
POC Weiche, Fahrstraße, Zieltaste
https://forum.arduino.cc/t/schattenbahnhofsteuerung/1208510/46
Simulation: https://wokwi.com/projects/386439244339395585
by noiasca
2024-01-09 Grundgerüst
2024-01-11 MCP23S17 eingebunden, Debug Meldungen, erstes Time Management
2024-02-15 fixed class WeicheMCP https://forum.arduino.cc/t/schattenbahnhofsteuerung/1208510/63
2024-03-03 fixed class WeicheMCP, 4 turnouts
Anmerkung: durch die fehlende SPI Kommunikation wird der Sketch im Wokwi Simualtor nicht funktionieren
*/
#include <Streaming.h> // Streaming by Peter Polidoro (boardmanager) - macht das Serial.print einfacher.
#include <Adafruit_MCP23X17.h>
constexpr uint8_t csPinA {5}; // chip select für ersten MCP23S17
constexpr uint8_t buttonPinA {A0}; // nur mal ein Test Button
constexpr uint8_t buttonPinB {A1}; // noch ein Test Button
constexpr uint8_t buttonPinC {A2}; // noch ein Test Button
constexpr uint8_t buttonPinD {A3}; // noch ein Test Button
Adafruit_MCP23X17 mcpA; // ein MCP Objekt muss angelegt werden - @todo: Umbauen auf Array
// Weichen an einem MCP23S17
class WeicheMCP {
Adafruit_MCP23X17 &mcp; // Referenz auf ein MCP Objekt - ein konkreter MCP23S17
const uint8_t pinGerade; // Ausgang für Gerade - 0..15
const uint8_t pinAbbiegen; // Ausgang für abbiegen
const uint8_t pinRueckGerade; // Rückmeldung für Gerade
const uint8_t pinRueckAbbiegen; // Rückmeldung für Abbiegen
uint32_t previousMillis = 0; // Zeitmanagement
const uint16_t interval = 2000; // hard off der Magnetantriebe
bool isActive = false; // Magnetantrieb ist ein oder aus
uint8_t direction = 0; // 0 gerade, 1 abbiegen
public:
WeicheMCP(Adafruit_MCP23X17 &mcp, uint8_t pinGerade, uint8_t pinAbbiegen, uint8_t pinRueckGerade, uint8_t pinRueckAbbiegen /*, welcher MCP*/) :
mcp{mcp},
pinGerade {pinGerade},
pinAbbiegen {pinAbbiegen},
pinRueckGerade {pinRueckGerade},
pinRueckAbbiegen {pinRueckAbbiegen} {}
// Einstellungen im setup() - könnte auch für das Rücklesen der Stellung z.B. aus dem EEPROM genutzt werden
void begin() {
mcp.pinMode(pinGerade, OUTPUT);
mcp.pinMode(pinAbbiegen, OUTPUT);
mcp.pinMode(pinRueckGerade, INPUT); // tbc INPUT_PULLUP?
mcp.pinMode(pinRueckAbbiegen, INPUT); // tbc INPUT_PULLUP?
}
// Aktion für Geradeausfahrt
int gerade() {
if (!isActive) {
mcp.digitalWrite(pinGerade, HIGH);
direction = 0;
isActive = true;
previousMillis = millis();
Serial << "gerade " << pinGerade << '\n';
return 0; // OK
}
return -1; // befehl nicht angenommen
}
// Aktion für abbiegen
// @todo - codeduplikate von gerade/abbieben in eine Funktion auslagern
int abbiegen() {
if (!isActive) {
mcp.digitalWrite(pinAbbiegen, HIGH);
direction = 1;
isActive = true;
previousMillis = millis();
Serial << "abbiegen " << pinAbbiegen << '\n';
return 0; // ok
}
return -1; // befehl nicht angenommen
}
// Rückgabe des aktuellen Status
int getStatus() {
return direction;
};
// RUN: automatische Abschaltung der Magnetartikel
void update(uint32_t currentMillis = millis()) {
if (isActive && currentMillis - previousMillis > interval) {
mcp.digitalWrite(pinGerade, LOW);
mcp.digitalWrite(pinAbbiegen, LOW);
isActive = false;
Serial << "abschalten " << '\n';
}
}
};
WeicheMCP weiche[] {
{mcpA, 0, 1, 8, 9}, // Anlage einer Weiche
{mcpA, 2, 3, 10, 11}, // Anlage einer weiteren Weiche (am gleichen MCP)
{mcpA, 4, 5, 12, 13}, // Anlage einer weiteren Weiche (am gleichen MCP)
{mcpA, 6, 7, 14, 15}, // Anlage einer weiteren Weiche (am gleichen MCP)
};
// Eingänge der Buttons initialisieren
void buttonBegin() {
pinMode(buttonPinA, INPUT_PULLUP);
pinMode(buttonPinB, INPUT_PULLUP);
pinMode(buttonPinC, INPUT_PULLUP);
pinMode(buttonPinD, INPUT_PULLUP);
}
// Buttons abfragen und etwas ausführen
void buttonRead() {
if (digitalRead(buttonPinA) == LOW) weiche[0].gerade();
if (digitalRead(buttonPinB) == LOW) weiche[0].abbiegen();
if (digitalRead(buttonPinC) == LOW) weiche[1].gerade();
if (digitalRead(buttonPinD) == LOW) weiche[1].abbiegen();
}
// Befehle über die serielle Schnittstelle
void serialRead() {
int c = Serial.read();
switch (c) {
case -1 : break;
case '1': weiche[0].gerade(); break;
case '2': weiche[0].abbiegen(); break;
case '3': weiche[1].gerade(); break;
case '4': weiche[1].abbiegen(); break;
case '5': weiche[2].gerade(); break;
case '6': weiche[2].abbiegen(); break;
case '7': weiche[3].gerade(); break;
case '8': weiche[3].abbiegen(); break;
}
}
void setup() {
Serial.begin(115200);
Serial << "Weichensteuerung\n";
delay(500);
SPI.begin();
if (!mcpA.begin_SPI(csPinA)) {
Serial << "mcpA Error.\n";
}
for (auto &i : weiche) {
i.begin(); // jede Weiche initialisieren
}
buttonBegin();
Serial << "ende setup\n";
}
void loop() {
buttonRead(); // taster auslesen
serialRead();
// Hintergrund-Aktivitäten auslösen
for (auto &i : weiche) i.update(); // jeder Weiche etwas Zeit für Hintergrundaktivitäten geben
}
//