amForth Morse Code
Konfiguration der Arduino Pins und die Basis-Wörter des Morse-Programms. Dieser Teil wird für jedes der drei Morse-Programme benutzt:
\ 2011-10-26 EW
\ 2011-11-02 CS
\ arduino duemilanove + danger shield
\ morse code stuff (Potsdam/Augsburg/Oberhausen)
\ make marker loads:
\ lib/misc.frt
\ lib/bitnames.frt
\ lib/ans94/marker.frt
\ ../../amforth/releases/4.2/core/devices/atmega328p/atmega328p.frt
marker --base--
decimal
PORTD 5 portpin: led1
PORTD 6 portpin: led2
PORTD 3 portpin: bz
\ --- buzzer -------------------------------------------------
\ 2 ms T_period =^= 500 Hz
\ Ton-Ausgabe
: buzz ( cycles -- )
0 ?do
bz low
1ms
bz high
1ms
loop
;
\ Warten ohne Ton
: gap ( cycles -- )
0 ?do
bz high
1ms
bz high
1ms
loop
;
\ LED fuer 3ms blinken lassen
: blink ( cycles -- )
led1 high
0 ?do
1ms 1ms 1ms
loop
led1 low
;
\ Umschalter zwischen Morse-Ton und Morse-LED
Edefer transmit
: piepser ['] buzz is transmit ;
: blinker ['] blink is transmit ;
decimal
: kurz 50 transmit 50 gap ; \ Signal kurz
: lang 150 transmit 50 gap ; \ Signal lang
: Zend 100 gap ; \ Pause zwischen Zeichen
: Wend 300 gap ; \ Pause zwischen Worten
: init
led1 pin_output led1 low
led2 pin_output led2 low
bz pin_output
piepser
;
Simple Implementierung
Die erste Implementierung ist sehr gradlinig mit einem Forth-Wort für jeden Morse-Buchstaben und einer grossen IF-THEN Konstruktion im Hauptteil:
\ 2011-10-26 EW \ 2011-11-02 CS \ arduino duemilanove + danger shield \ morse code stuff (Potsdam/Augsburg/Oberhausen) marker --morse-- \ je ein Forth-Wort pro Morse-Buchstabe : _A kurz lang Zend ; : _B lang kurz kurz kurz Zend ; : _C lang kurz lang kurz ; : _D lang kurz kurz Zend ; : _E kurz Zend ; : _F kurz kurz lang kurz Zend ; : _G lang lang kurz Zend ; : _H kurz kurz kurz kurz Zend ; : _I kurz kurz Zend ; : _J kurz lang lang lang Zend ; : _K lang kurz lang Zend ; : _L kurz lang kurz kurz Zend ; : _M lang lang Zend ; : _N lang kurz Zend ; : _O lang lang lang Zend ; : _P kurz lang lang kurz Zend ; : _Q lang lang kurz lang Zend ; : _R kurz lang kurz Zend ; : _S kurz kurz kurz Zend ; : _T lang Zend ; : _U kurz kurz lang Zend ; : _V kurz kurz kurz lang Zend ; : _W kurz lang lang Zend ; : _X lang kurz kurz lang Zend ; : _Y lang kurz lang lang Zend ; : _Z lang lang kurz kurz Zend ; \ Variable zum Speichern des original 'emit' variable o-emit \ neues Emit zum Ausgeben von Zeichen als Morse-Code : morseemit ( key -- ) dup o-emit @ execute ( original 'emit' aufrufen ) dup [char] a = if _A then dup [char] b = if _B then dup [char] c = if _C then dup [char] d = if _D then dup [char] e = if _E then dup [char] f = if _F then dup [char] g = if _G then dup [char] h = if _H then dup [char] i = if _I then dup [char] j = if _J then dup [char] k = if _K then dup [char] l = if _L then dup [char] m = if _M then dup [char] n = if _N then dup [char] o = if _O then dup [char] p = if _P then dup [char] q = if _Q then dup [char] r = if _R then dup [char] s = if _S then dup [char] t = if _T then dup [char] u = if _U then dup [char] v = if _V then dup [char] w = if _W then dup [char] x = if _X then dup [char] y = if _Y then dup [char] z = if _Z then dup bl = if Wend then ( Leerzeichen = Wortende ) drop Zend ( Zeichenende ) ; \ neues 'morseemit' in 'emit' eintragen : morse ['] emit defer@ o-emit ! ['] morseemit is emit ; \ original 'emit' wieder herstellen : endmorse o-emit @ is emit ;
Implementierung mit einer Sprungtabelle
In dieser Version des Morse-Programms nutzen wir immer noch Forth-Wörter für die Signale, aber ersetzten die Grosse IF-THEN Verzweigung durch eine Spring-Tabelle. Die Sprung-Tabelle enhält 256 Einträge für die 256 ASCII-Zeichen. In den Tabellen-Einträgen befindet sich die Adresse des jeweiligen Forth-Worts (Execution Token = xt), welches die Signale für den Morse-Code ausgibt. Ist ein Tabelleneintrag '0' so ist dieser Eintrag nicht gefüllt und es wird kein Morse-Code ausgegeben.
\ 2011-10-26 EW
\ 2011-11-02 CS
\ arduino duemilanove + danger shield
\ morse code stuff (Potsdam/Augsburg/Oberhausen)
\ 2nd version
marker --morse--
: _A kurz lang Zend ;
: _B lang kurz kurz kurz Zend ;
: _C lang kurz lang kurz ;
: _D lang kurz kurz Zend ;
: _E kurz Zend ;
: _F kurz kurz lang kurz Zend ;
: _G lang lang kurz Zend ;
: _H kurz kurz kurz kurz Zend ;
: _I kurz kurz Zend ;
: _J kurz lang lang lang Zend ;
: _K lang kurz lang Zend ;
: _L kurz lang kurz kurz Zend ;
: _M lang lang Zend ;
: _N lang kurz Zend ;
: _O lang lang lang Zend ;
: _P kurz lang lang kurz Zend ;
: _Q lang lang kurz lang Zend ;
: _R kurz lang kurz Zend ;
: _S kurz kurz kurz Zend ;
: _T lang Zend ;
: _U kurz kurz lang Zend ;
: _V kurz kurz kurz lang Zend ;
: _W kurz lang lang Zend ;
: _X lang kurz kurz lang Zend ;
: _Y lang kurz lang lang Zend ;
: _Z lang lang kurz kurz Zend ;
\ erstelle Tabelle fuer execution token
variable mtable 256 cells allot
\ loesche Tabelle
mtable 256 cells erase
\ Hilfswort zum fuellen der Tabelle
: >mtable ( xt c -- )
cells mtable + !
;
\ Tabelle zur kompilierzeit fuellen
' _A char a >mtable
' _B char b >mtable
' _C char c >mtable
' _D char d >mtable
' _E char e >mtable
' _F char f >mtable
' _G char g >mtable
' _H char h >mtable
' _I char i >mtable
' _J char j >mtable
' _K char k >mtable
' _L char l >mtable
' _M char m >mtable
' _N char n >mtable
' _O char o >mtable
' _P char p >mtable
' _Q char q >mtable
' _R char r >mtable
' _S char s >mtable
' _T char t >mtable
' _U char u >mtable
' _V char v >mtable
' _W char w >mtable
' _X char x >mtable
' _Y char y >mtable
' _Z char z >mtable
' Wend bl >mtable
variable o-emit
: morseemit ( key -- )
dup o-emit @ execute ( altes emit ausfuehren )
255 and ( sicherstellen das wir nur 0-255 Werte bekommen )
cells mtable + @ ( execution token holen )
dup if execute ( wenn > 0 dann ausfuehren )
else drop then ( ansonsten wegwerfen )
;
: morse
['] emit defer@ o-emit !
['] morseemit is emit
;
: endmorse
o-emit @ is emit
;
gepackte Morse-Code Signale
Morse-Code Signale als Forth-Wörter speichern ist einfach, verbraucht aber recht viel Flash-Speicher. Morse-Code Signale können in je einem Byte (8 bit) gespeichert werden. In der dritten Version des Morse-Programms werden bis zu fünf Morse-Signale in den oberen 5 Bits gespeichert ( 0 = kurz, 1 = lang ), die unteren 3 Bits speichern die Anzahl der Signale im Morse-Code. Hierdurch reduziert sich der Speicherverbrauch des Programms.
Die Tabelle mit dem gepackten Morse-Code wird vom Forth-Interpreter zur Kompilierzeit erstellt und verbraucht bei der Ausführung keine extra Rechenzeit:
\ 2011-10-26 EW
\ 2011-11-04 CS
\ arduino duemilanove + danger shield
\ morse code stuff (Potsdam/Augsburg/Oberhausen)
\ 3nd version
marker --morse--
\ erstelle Tabelle fuer gepackte morse daten
variable mtable 256 allot
\ loesche Tabelle
mtable 256 erase
\ Hilfswort zum fuellen der Tabelle
: >mtable ( gepackter-morsecode c -- )
mtable + c!
;
\ Hilfswort zum packen vor morse code
: pack ( #zeichen code -- pcode )
3 lshift swap 7 and or
;
: unpack ( pcode -- #zeichen code )
dup 7 and swap 3 rshift
;
: binary 2 base ! ;
\ Tabelle zur kompilierzeit fuellen
binary 00010 decimal 2 pack char a >mtable
binary 00001 decimal 4 pack char b >mtable
binary 01010 decimal 4 pack char c >mtable
binary 00001 decimal 3 pack char d >mtable
binary 00000 decimal 1 pack char e >mtable
binary 00100 decimal 4 pack char f >mtable
binary 00011 decimal 3 pack char g >mtable
binary 00000 decimal 4 pack char h >mtable
binary 00000 decimal 2 pack char i >mtable
binary 01110 decimal 4 pack char j >mtable
binary 00101 decimal 3 pack char k >mtable
binary 00010 decimal 4 pack char l >mtable
binary 00011 decimal 2 pack char m >mtable
binary 00001 decimal 2 pack char n >mtable
binary 00111 decimal 3 pack char o >mtable
binary 00110 decimal 4 pack char p >mtable
binary 01101 decimal 4 pack char q >mtable
binary 00010 decimal 3 pack char r >mtable
binary 00000 decimal 3 pack char s >mtable
binary 00001 decimal 1 pack char t >mtable
binary 00001 decimal 3 pack char u >mtable
binary 00001 decimal 4 pack char v >mtable
binary 00011 decimal 3 pack char w >mtable
binary 01001 decimal 4 pack char x >mtable
binary 01011 decimal 4 pack char y >mtable
binary 00011 decimal 4 pack char z >mtable
variable o-emit
: domorse ( code #signale -- )
0 ?do ( Schleife Anzahl der Signale )
dup 1 and ( erstes bit maskieren )
if lang ( bit gesetzt = lang )
else kurz then ( sonst kurz )
2/ ( bits nach rechts schieben )
loop
drop Zend ( Zeichenende )
;
: morseemit ( key -- )
dup o-emit @ execute ( altes emit ausfuehren )
255 and ( sicherstellen das wir nur 0-255 Werte bekommen )
dup bl = if ( leerzeichen? )
Wend ( Wortende zeit warten )
then
mtable + c@ ( gepackten morse code holen )
unpack ( entpacken )
domorse ( signale ausgeben )
;
: morse
['] emit defer@ o-emit !
['] morseemit is emit
;
: endmorse
o-emit @ is emit
;
Aufgaben:
- Wie kann das Morse-Code Programm weiter optimiert werden (weniger Speicherverbrauch)?
- erweitere das Programm, so das auch Zifferns als Morse-Code ausgegeben werden
- erweitere das Programm, so das auch Sonderzeichen als Morse-Code ausgegeben werden
Antworten auf diese Aufgaben können auf Mastodon gepostet werden. Bitte Geduld wenn ich nicht sofort antworte, ich kann leider nicht immer online sein.