CharlieDemo.ino
/**
* CharlieDemo
* Zeigt das Prinzip von CharliePlexing für ein Viessmann Ks-Signal 4045.
*
* $Id: CharlieDemo.ino 15125 2022-04-10 08:05:56Z martin $
*
* (C) 2022 by Martin Pischky (martin@pischky.de)
*
* Beschreibung:
* Es werden die Pins D8..D12 abgefragt. Ist einer davon mit Masse verbunden
* wird das entsprechende Signalbild angezeigt. Dabei wird Charlieplexing
* (in Modellbahnerkreisen auch als IngoPlexing bekannt) verwendet. Die
* vier Pins D14..D17 werden dabei mit etwa 100Hz angesteuert. Hier kann
* direkt ein Ks-Signal von Viessmann (4045) angeschlossen werden. Die
* Vorwiderstände sollten etwa 180 Ohm betragen.
*
* Dieses ist nur ein Programm was die Funktion von CharliePlexing
* demonstrieren soll. Dinge wie Blinken und Überblenden sind nicht
* implementiert. Ebenso sollten natürlich Hardware-Timer verwendet werden.
*
* Benutzt wurden:
* Arduino Nano clone mit CH340 oder Arduino Nano Every
* Arduino IDE 1.8.19 (https://www.arduino.cc)
* ArduinoSTL 1.3.3 (https://github.com/mike-matera/ArduinoSTL)
* Sloeber V4.4.0 (https://eclipse.baeyens.it/)
*
* Hinweis:
* Select "Arduino AVR Boards" by Arduino 1.8.2 in Boardmanager/Platform and Boards
* (see https://github.com/mike-matera/ArduinoSTL/issues/56)
* For Arduino Nano Every use: with Registers emulation "ATMEGA328"
*
*/
#if defined(ARDUINO_ARCH_AVR) || defined(ARDUINO_ARCH_MEGAAVR)
#include <Arduino.h>
#include <ArduinoSTL.h> // use ArduinoSTL 1.3.3 https://github.com/mike-matera/ArduinoSTL
#endif
#include <cstdint> // uint8_t
#include <iostream> // cout, endl
#include "KsSignalCharliePlexer.hpp" // class KsSignalCharliePlexer
using std::uint8_t;
using std::cout;
using std::endl;
using std::ostream;
constexpr uint8_t TRIGGER = 2; // Ausgang für Oszilloskop Trigger
constexpr uint8_t BASE_SIGNAL_PIN = 14; // Arduino Pins D14..D17 für das Signal
// (Atmega328P: PC0..PC3)
constexpr uint8_t BASE_INPUT_PIN = 8; // Arduino Pins D8..D12 als Eingang
// (Atmega328P: PB0..PB4)
/**
* Instanz des CharliePlexers.
*/
KsSignalCharliePlexer kscp{ BASE_SIGNAL_PIN };
/**
* Lese Eingänge und ermittle das Signalbild wenn ein Pin LOW ist.
* Wenn kein Pin mit LOW gefunden wurde ist der Rückgabewert 0.
* Wir verwenden "uint16_t" statt "SignalBild" als Rückgabetyp damit Sloeber
* glücklich ist.
*/
KsSignalCharliePlexer::SignalBild readSignalBild() {
for (int i = 0; i < 5; ++i) {
if (digitalRead(BASE_INPUT_PIN + i) == LOW) {
switch (i) {
case 0: return HALT;
case 1: return FAHRT;
case 2: return FAHRT_ZS3;
case 3: return HALT_ERWARTEN;
case 4: return FAHRT_ZS3_ZS3V;
}
}
}
return 0;
}
/**
* Schöne Ausgabe des Signalbildes.
*/
const char* signalBildString(KsSignalCharliePlexer::SignalBild sb) {
if (sb == HALT) return "HALT";
if (sb == FAHRT) return "FAHRT";
if (sb == FAHRT_ZS3) return "FAHRT_ZS3";
if (sb == HALT_ERWARTEN) return "HALT_ERWARTEN";
if (sb == FAHRT_ZS3_ZS3V) return "FAHRT_ZS3_ZS3V";
return "unbekannt";
}
/**
* Lasse die eingebaute LED auf dem Arduino Board blinken.
*/
void alive() {
static uint8_t count = 0;
if (count == 0) digitalWrite(LED_BUILTIN, !digitalRead(LED_BUILTIN));
count = (count + 1) % 100;
}
void setup() {
// Starte den seriellen Port mit 115200 bps und warte.
Serial.begin(115200);
while (!Serial) {
; // Warte auf den seriellen Port. Für native USB Ports erforderlich.
}
pinMode(LED_BUILTIN, OUTPUT);
pinMode(TRIGGER, OUTPUT);
for(int i = 0; i < 5; ++i) pinMode(BASE_INPUT_PIN + i, INPUT_PULLUP);
cout << "setup(): kscp.status=0b" << kscp.getStatus() << " "
<< signalBildString(kscp.getStatus()) << endl;
kscp.setAllTristate();
cout << "setup(): kscp.setStatus(HALT)" << endl;
kscp.setStatus(HALT);
cout << "setup(): kscp.status=0b" << kscp.getStatus() << " "
<< signalBildString(kscp.getStatus()) << endl;
}
void loop() {
alive();
if (KsSignalCharliePlexer::SignalBild nb = readSignalBild();
nb != 0 && nb != kscp.getStatus())
{
cout << "loop() : kscp.setStatus(0b" << nb << ")" << " "
<< signalBildString(nb) << endl;
kscp.setStatus( nb );
}
digitalWrite(TRIGGER, !digitalRead(TRIGGER)); // Trigger Ausgang toggeln
kscp.cycle();
}