Fernsteuerung von Cronios-LED-Basic Controllern
Konzept, Hard- und Software
Die Firma LEDgenial
ist u.a. Anbieter von LED-Produken. Dazu gehören progrmmiebaren
Controllermodule zur Ansteuerung von WS2812-LED-Streifen, für
diese wurde eine spezielle, kostenlose Programmierumgebung und -sprache
LED-Basic
entwickelt.
Eine sehr attraktive Anwendung sind die Cronixie-Uhren,
die nach dem Flutlichprinzip (Lightguide
Display) funktionieren:
|
Das aktuelle LED-Basic (15.1.5) hat leider keine direkte
Input-Funktion. Außerdem verfügt das für
die Cronixie-Uhren genutzte Cronios-Controllerboard
über keine frei verfügbaren externen Schnittstellen, so
daß sich Geräte auf dessen Basis nicht ohne Weiteres
von außen steuern lassen.
Ich habe nun eine Möglichkeit entwickelt, dieses Manko zumindest
eingermaßen befriedigend zu umgehen:
LED-Basic unterstützt zwar die Abfrage
von Tastendrücken oder statische Pegel an einigen Eingängen (je
nach Modul). Aber eine komfortable und vor allem schnelle Dateneingabe
(z.B. von externen Controllern) ist nicht ohne Weiteres möglich,
da eine zyklische Abfrage von Eingangsports einige Probleme macht:
1. ein Eingangspegel muß während laufender Programme mindestens
40 ms anliegen, da ungünstigenfalles eine gerade laufende LED.show-Anzeige-Routine
abgewartet werden muß.
2. Selbst wenn in einer Abfrageschleife keine LED.show-Routine aufgerufen
wird, kann ein Portwechsel erst nach längerer Zeit festgestellt
werden (insbesondere Tastendrücke verzögern sich um bis zu 40 ms).
Damit wäre eine Dateneingabe sehr langsam, aber nicht unmöglich:
Ein Input kann mit Mitteln der LED-Basic-Programmierung
folgendermaßen implementiert werden und bedarf nur eines Eingangsportes.
Selbst ein Cronios-Modul ist somit steuerbar, wenn der Drehimpulsgeber-Tastenkonatkt
extern an Masse gelegt wird, so daß dessen Input-Port zur
Eingabe verwendet wird! Durch geschicktes Timing bleibt der Kontakt
auch weiterhin manuell bedienbar.
Port Status „Passiv“, Wert 0, Taste nicht gedrückt
Port Status „Aktiv“, Wert 1, Taste gedrückt bzw. extern an Masse
gelegt.
Timing für externe Dateneingabe:
1. Start-„Aktiv“ > 50 ms,
um ggf. aus einem laufenden Programm einschl. eventueller LED.show-Routine
auszuspringen,
in vorgeschlagener Lösung 60 ms, längerer Aktiv-Zustand wird als
manueller Tastendruck gedeutet und springt zurück in die ursprüngliche
Tastenabfrage.
2. Datum als Ziffern-„Passiv“,
zusammengesetzt aus 50 ms Mindest-Verarbeitungszeit plus (30 ms
* Ziffernwert), also
0 = 50 ms, 1 = 80 ms, 2 = 110 ms, 3 = 140 ms, … , 9 = 330 ms
3a. Trenn-„Aktiv“ mit 50 ms, daraufhin können weitere Ziffern-Passivs
folgen, oder
3b. Ende-„Aktiv“ mit 80 ms, damit wird die Eingabe insgesamt beendet
und zurück in das ursprüngliche Programm gesprungen.
Mindestdauer Input einer Null: 190
ms
Maximaldauer Ziffernfolge "9999999": 3,13 s
Die Datenübertragung ist zwar extrem langsam, aber mit diesem Timing
sehr zuverlässig!
Zusätzliche Timeouts prüfen die Warteschleifen auf Überschreitung
der Maximalzeiten. Um ein Blockieren des Hauptprogrammes zu vermeiden,
kann z.B. ein "Aktiv"-Zustand länger als 100 ms als
manueller Tastendruck gewertet werden.
Ein Eingabebeispiel (/=aktiv, \=passiv):
Input der Ziffer 3: /60\140/80\
Input der Zahl 123: /60\80/50\110/50\140/80\ (s. Abb.)
|
' ------ Hauptrogramm
-----
100:
... '(Hauptprogramm)
k = IO.getkey()
if k > 0 then gosub 20000 'Aufruf INPUT-Fersteuerung
... '(Hauptprogramm)
goto
100 '
' ===== Routine
INPUT Fernsteuerung empfangen =====
'
' IN: nach IO.GETKEY>0 in Hauptprogramm-Schleife
'
VAR: i: Aktiv-Timer
20000: 'Einsprung
i
= 0 'Aktiv-Timer
reset
20100: 'warte
auf Impulspause
delay
1 '(Start)
Empfangsbereitschaft...
i
= i + 1
k
= IO.keystate() 'Port-Abfrage
if
i > 100 then retun 'max.
100 ms Wartezeit (sonst manueller Tastendruck)
if
k = 1 then goto 20100 'Startimpuls
noch aktiv...
20200:
gosub
20900 'SUB:
ZIFFER EMPFANGEN -> n
if s = 0 then return 'Fehler-Aussprung!
' +++++++++++++++++++++++++++++++
' +
hier Ziffer "n" verarbeiten +
' +++++++++++++++++++++++++++++++
if
s = 1 then goto 20200 'weitere Ziffer folgt...
return 'fertig
' ------ Subroutine
einzelne Ziffer empfangen -----
'
' OUT: n: Ziffer
' o: Anzahl empfangene Ziffern
'
s: Schlußzeichen 0=Überlauf/Fehler,
'
1=weitere Ziffer folgt,
'
2=letzte Ziffer
' VAR: j: Passiv-Timer
' i: Aktiv-Timer
' k: Keystatus
20900: 'einzelne
Ziffer lesen... -> n
o = o + 1 'Reset
Anzahl Ziffern
j
= 0 'Reset
Impulspausenzähler
n = -1 'n<0:
Ziffer zunächst ungültig
s = 0 's=0:
Fehler
20910: '---
Passiv-Schleife ---
delay
1 'Zeitbasis
1 ms
j
= j + 1 'Zeitmessung
Impulspause ("passiv")
k = IO.keystate() 'warte
auf Impuls...
if j > 350 then return 'max. 350
ms Gesamtwartezeit ->
'Abbruch
(S=0: Fehler)
if k = 0 then goto 20910 '-> Passiv-Schleife
i = 0 'Aktiv:
Reset Impulslängenzähler
20920: '---
Aktiv-Schleife ---
delay
1 'Zeitbasis
1 ms
i
= i + 1 'Zeitmessung
Impulslänge ("aktiv")
k = IO.keystate() 'warte
auf Impulspause...
if i > 180 then return 'max. 150
ms Gesamtwartezeit ->
'Abbruch
(S=0: Fehler)
if k = 1 then goto 20920 'noch aktiv...
20950:
'Passiv-Länge -> Ziffernwert bestimmen n
= 0
if j > 50 then n = 1 '(Werte
experimentell ermittelt)
if j > 80 then n = 2
if j > 105 then n = 3
if j > 135 then n = 4
if j > 160 then n = 5
if j > 180 then n = 6
if j > 210 then n = 7
if j > 240 then n = 8
if j > 265 then n = 9
if j > 290 then n = 10
20990:
s
= 1 'Impuls
kurz s=1: weitere Ziffer folgt
if i > 55 then s = 2 'Impuls
mittel s=2: letzte Ziffer (Schlußzeichen)
if i > 150 then s = 0 'Impuls
lang s=0: Überlauf
o = o + 1 'Anzahl
Ziffern zählen
i = 0 'Ausstieg
return
|