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.