Morseuhr V3a
Meine Morseuhr 3
"funkt" nun schon seit fünf Jahren tapfer die Uhrzeit, der
Bascom-Spaghetti-Code hat sich also hinreichend bewährt. Ich habe
allerdings im Laufe der Zeit einige kleinere Änderungen vorgenommen
(das obige Foto ist daher nicht mehr so ganz aktuell).
Hardware
Der Reset-Taster konnte entfallen, da die Uhr sich bisher nur
ein- oder zwei mal aufgehängte, als ich sie berührte und dabei statisch
aufgeladen war. Sollte das mal passieren, kann man auch kurz die
Batterien entnehmen, um sie zu resetten. Der Lautstärkeeinsteller stand
all die Jahre auf Maximum, da der Piezoschwinger bei 3 V und der
verwendeten NF-Frequenz relativ leise ist. Man kann ihn also ebenfalls
weglassen.
Den Quarz habe ich inzwischen mit 22pF-Bürdekapazitäten
beschaltet. Der Oszillator schwingt zwar auch ohne sie sicher, aber
Temperaturänderungen schlagen stärker durch (bei heftiger
Sonneneinstahlung hatte ich über den Tag bis zu 20 Sekunden
Gangabweichung). Offenbar ändern sich die Parasitärkapazitäten der
internen ATtiny-Oszillatorschaltung recht stark bei
Temperaturschwankungen. Aufgrund der parallelliegenden 22 pF
Bürdekapazitäten fallen die Parasitärkapazitäten nun kaum noch ins
Gewicht.
Mir war vorher nie wirklich bewußt, was für ein
Präzisionsinstrument eine billige Quarzuhr darstellt: das Jahr hat ca.
31,5 Millionen Sekunden, und 30 Sekunden Abweichung pro Jahr bedeuten
eine Genauigkeit von 10 hoch -6 . Bei vielen anderen Meßinstrumenten
freut man sich schon über 1% Genauigkeit ....
Software
Durch die etwas zu großen Bürdekapazitäten läuft die Uhr
tendenziell zu langsam. Der Befehl "K" (Korrsec; Korrektursekunden)
macht sie um 0 .... 9 Sekunden pro Tag schneller (um Mitternacht wird
die Uhr nicht auf "0", sondern den Wert von Korrsek zurückgesetzt, so
daß sie mit etwas Vorsprung in den neuen Tag startet).
Die alte Softwareversion 1.04 ließ sich mit neueren
BASCOM-Versionen nicht mehr übersetzen, da "Gong" versehentlich sowohl
als Variablenname als auch als Unterprogrammname verwendet wurde. Das
Unterprogramm ist nun in "_Gong" umbenannt.
Zwecks Stromersparnis läuft die Uhr nicht mit vollem
Quarztakt, sondern nur mit 1/8 des Quarztaktes. Ursprünglich mußte der
Vorteiler per Fusebit aktiviert werden. In der neuen Version wird der
Takt zur Laufzeit des Programms auf ein Achtel reduziert. Der ATtiny
kann so ganz normal auf Quarzbetrieb ohne den Vorteiler 1:8 gefust
werden (hfuse df, lfuse fd, efuse ff).
Die Slim-Version (ohne Weckfunktion und Korrektursekunden) ist entfallen.
Update 1.05: die neueste BASCOM-Freeware-Version warf eine Fehlermeldung,
Fehler korrigiert.
Download des Bascom-Quelltextes (Update 1.05): 0320-morseuhr3a.zip
' Attiny-45-Morseuhr Version 1.05 fat
'
' gibt alle 15 min. die Minutenzahl aus und zur vollen Stunde die Stundenzahl
' ("es ist X Uhr"),
' ausserdem kann die Zeit durch Eingabe von "T" unmittelbar abgefragt werden
'
' Befehlsliste:
'
' ? Auflistung aller Befehle
' Z Zeit setzen
' T Zeit abfragen
' W Weckzeit setzen
' A 1/0 Alarm ein /aus
' E Alarm Ende
' G 1/0 Gong (Schlagwerk) ein/aus
' M Morsegeschwindigkeit setzen
' C Check -> Ausgabe von Alarmstatus und Gongstatus
' K Korrektur ; N Sekunden Wartezeit um Mitternacht ; N = 1 ...9
'
' Pinbelegung:
'
' PB0 Buzzer
' PB1 Punktkontakt
' PB2 Strichkontakt
' PB3 und PB4: Quarz
'
'
' Quarz schwingt mit 3,686400 MHz; Oszillator wird duch 8 geteilt (Takt ist dann 460800 Hz)
'
' Timer1- Vorteiler teilt durch 2048, Timer 1 dann durch 225 -> Sekundenimpulse
'
' Nach 60 Interrupts ist eine Minute um; mit Minuten wird weitergerechnet.
'
' Da der Quarz ohne Bürdekondensatoren betrieben wird, ist der Timer grundsätzlich etwas zu schnell
' Ausgleich durch Wait- Befehl in der Interrupt- Routine ( 110 µsec * 86400 sec/Tag = 9,5 sec/Tag )
'
' Fusebits: lfuse: 0x7d hfuse: 0xdf (Taktquelle Quarzoszillator, Teiler 1/8 , kein Brown-Out)
'
'
' Bugfix Version 1.01: Geschwindigkeits- Feineinstellung in der Interrupt- Routine funktionierte nicht
' Die Wartezeit hatte keine Auswirkung, weil mit TCNT1 = 31 zwar der 8-Bit-Teiler, presetted wird,
' während der 200 µs Wartezeit lief aber der Vorteiler einfach weiter. Reset Vorteiler: GTCCR.PSR1 = 1
'
'
' Bugfix Version 1.02: GTCCR.PSR1 = 1 führt dazu, daß die Uhr stets zu langsam läuft (Bascom verbraucht
' Zeit für den Sprung in die Interrupt-Routine). Funktionalität des Befehls "K" daher umgedreht; "K"
' macht die Uhr um K Sekunden pro Tag schneller, indem er um Mitternacht die Uhr (um max. 9 Sek.) vorstellt
'
' Bugfix 1.03: Der Quarzoszillator ist ohne Bürdekapaziät relativ instabil. 2 * 22 pF eingebaut und Reset Vorteiler
' wieder deaktiviert. Uhr läuft mit 22 pF zu langsam; Funktion "K" daher beibehalten
'
' Bugfix 1.04: "Gong" wurde zwei mal verwendet; als Variable und als Unterprogrammname. Da neuere BASCOM-Versionen
' das "bemeckern", wurde das Unterprogramm in "_Gong:" umbenannt. Umschaltung auf Teilung des Quarztaktes durch 8
' muss nicht mehr durch fusebit gesetzt werden, sondern erfolgt zur Laufzeit des Programmes mit CLKPR
'
' Bugfix 1.05: In einer For-Next-Schleife war der Variablenname hinter dem "Next" falsch (Zeile 386). Ältere
' Bascom-Versionen hatten den offenbar gar nicht beachtet
'
' verwendeter Compiler: Bascom 2.0.7.9
'----------------------------------------------------------
$Regfile = "Attiny45.dat"
$Crystal = 460800 ' 3,6864 MHz / 8
$Hwstack = 32
$Swstack = 8
$Framesize = 24
' Variablen für Zeitberechnung
Dim S As Word ' Sekunden
Dim T As Word ' Tagesminuten 0 ..... 1440
Dim Korr As Byte
Dim Mi As Word ' Minuten- Rest zur vollen Stunde
Dim V As Word ' Minuten- Rest zur vollen Viertelstunde
Dim H As Word ' Stunden
Dim Zh As Word ' Zehnerstelle Stunden
Dim Eh As Word ' Einerstelle Stunden
Dim Zmi As Word ' Zehnerstelle Minuten
Dim Emi As Word ' Einerstelle Minuten
Dim Wmi As Word ' Minuten Weckzeit
Dim Wh As Word ' Stunden Weckzeit
Dim Wzh As Word ' Zehnerstelle Weckstunden
Dim Weh As Word ' Einerstelle Weckstunden
Dim Wzmi As Word ' Zehnerstelle Weckminuten
Dim Wemi As Word ' Einerstelle Weckminuten
Dim Ta As Word ' Alarmzeit in Tagesminuten
Dim Hilf As Word ' Hilfsgroesse für Tagesminutenberechnung
Dim Alarm As Byte ' Ein- / Ausschalter Alarm
Dim Gong As Byte ' Ein- / Ausschalter Gong
' Variablen für Morsezeichen- Erzeugung
Dim I As Byte ' wird in Zählschleife verwendet
Dim N As Word ' Aktueller Morsebuchstabe
Dim M As Byte ' wird fürs Auslesen der Morsebits verwendet
Dim L As Byte ' wird für niederwertigstes Bit von M verwendet
' Variablen für Morsezeichen- Decodierung
Dim E As Byte ' resultierendes ACCII-Byte der Decodierroutine
Dim D As Byte ' Morsebyte in der Decodierroutine
Dim K As Byte ' Byte, in dem eine "1" geshiftet wird
Dim J As Byte ' Zählvariable für tolerante Pausenprüfung
Dim P As Byte ' Punktspeicher-Bit der Decodierroutine
' Variablen für Ziffern- Eingabe
Dim G(4) As Byte ' nimmt die Ziffern auf
Dim R As Byte ' Anzahl angeforderter Ziffern
Dim W As Byte ' Zähler für Eingabewiederholung der Ziffern
Dim Notbremse As Byte ' Timer für Ausstieg aus unvollständigen Eingaben
Dim Txtstring As String * 84
Dim Txt(84) As Byte At Txtstring Overlay
' Variablen für Morsezeichen- Timing
Dim Punktlaenge1 As Word ' Punktlänge in "Empfangsrichtung"
Dim Punktlaenge2 As Word ' Punktlänge in "Senderichtung"
Dim Punktachtel As Word
Dim Strichlaenge1 As Word ' Strichlänge
Dim Strichlaenge2 As Word
Dim Wortpause1 As Word ' Länge Wortpause
Dim Wortpause2 As Word
Mcucr.sm0 = 0 ' mcucr für Idle konfigurieren
Mcucr.sm1 = 0 ' mcucr Idle zweites Bit
Pcmsk.1 = 1 ' PCINT für PB1 freigeben
Pcmsk.2 = 1 ' PCINT für PB2 freigeben
Gimsk.pcie = 1 ' PCints aktivieren
Sreg.7 = 1 ' Interrupts generell freigeben
Portb = &B0000110 ' Pullups für Strich- und Punktkontakt
Ddrb = &B00000000 ' erstmal alles Eingang
' Stromspar- Funktionen nutzen
Didr0 = &B00011001 ' digitale Eingänge ausser PB1 und PB2 abschalten
Acsr.acd = 1 ' Analog-Komparator ausschalten
Prr.prusi = 1 ' usi abschalten (power reduction usi)
Prr.pradc = 1 ' adc abschalten (power reduction adc)
' Morseton mit Timer0 erzeugen:
'
' Timer0 zählt das Register TCNT0 hoch. Es wird mit Register OCR0A verglichen.
' Wenn TCNT0 = OCR0A, wird Output OC0A/PB0 umgeschaltet (getoggled)
' Timer0 erzeugt so Dauerton; er wird jedoch nur an den Ausgangspin durchgeschaltet,
' wenn das Datenrichtungs- Register DDRB.0 = 1 ist. Bei 0 wird der Ton unterdrückt.
Config Timer0 = Timer , Prescale = 64 , Compare A = Toggle , Clear Timer = 1
' 1- Sekunden- Interrupts mit Timer 1 erzeugen
Config Timer1 = Timer , Prescale = 2048
Enable Timer1
On Timer1 Ontimer1 ' Interrupt-Routine für Timer1-Overflow
Const Tonhoehe1 = 12
Const Tonhoehe2 = 18
Buzzer Alias Ddrb.0
Punktkontakt Alias Pinb.1
Strichkontakt Alias Pinb.2
'----------------------------------------------------------
Init:
CLKPR = 128 ' Clock-Umschaltung vorbereiten
CLKPR = 3 ' Clock-Vorteiler auf 1:8 setzen
CLKPR = 3
'--- vorläufige Werte -------
Punktlaenge1 = 80 ' Punktlänge in "Empfangsrichtung"
Punktlaenge2 = 100 ' Punktlänge in "Senderichtung"
Punktachtel = 10
Strichlaenge1 = Punktlaenge1 * 3 ' Strichlänge
Strichlaenge2 = Punktlaenge2 * 3
Wortpause1 = Punktlaenge1 * 5 ' Länge Wortpause
Wortpause2 = Punktlaenge2 * 5
Gong = 1
Korr = 0
Gosub Zeitausgabe ' Kontrollausgabe nach Reset
'--- Hauptschleife -----------
Do
Prr.prtim0 = 0 ' Timer0 anschalten
Mcucr.se = 0 ' Sleeepmode verbieten
Mcucr.pcie = 0 ' Tasteninterrupts verbieten
If T > 1439 Then ' Prüfen auf Tageswechsel
T = 0
S = Korr ' Falls Korr > 0, wird Uhr um Mitternacht um <Korr> Sekunden vorgestellt
End If
Gosub Zeitberechnung
If Gong = 1 Then
Gosub _Gong
End If
If Alarm = 1 Then
Gosub Alarmsub
End If
Gosub Menue
' Idle- Modus vorbereiten
Prr.prtim0 = 1 ' Timer0 abschalten
Mcucr.pcie = 1 ' Pin Change Interrupt enable
Mcucr.se = 1 ' Sleep enable
!SLEEP
Loop
'------- Zeitberechnungen und Ausgabe der Zeiten ---------
Zeitberechnung:
H = T / 60 ' Uhrzeit auf Stunden gerundet
Mi = T Mod 60 ' Minuten- Rest (zur vollen Stunde)
Zh = H / 10 ' Zehnerstelle Stunden
Eh = H Mod 10 ' Einerstelle Stunden
Zmi = Mi / 10 ' Einerstelle Minuten
Emi = Mi Mod 10 'Einerstelle Minuten
V = T Mod 15 ' V = 0 bei vollen Viertelstunden
Return
Weckzeitberechnung:
Wh = Ta / 60 ' Uhrzeit auf Stunden gerundet
Wmi = Ta Mod 60 ' Minuten- Rest (zur vollen Stunde)
Wzh = Wh / 10 ' Zehnerstelle Stunden
Weh = Wh Mod 10 ' Einerstelle Stunden
Wzmi = Wmi / 10 ' Einerstelle Minuten
Wemi = Wmi Mod 10 'Einerstelle Minuten
Return
_Gong:
If S < 2 Then ' unterdrückt mehrfache Ausgabe
If V = 0 Then ' volle Viertelstunde
If Mi = 0 Then ' Sonderfall: volle Stunde
Txtstring = " ES IST "
Gosub Sendstring
If Zh > 0 Then ' wenn zweistellige Stundenzahl
M = Zh ' Zehnerstunde senden
Gosub Sendnumber
End If
M = Eh ' Einerstunde senden
Gosub Sendnumber
Txtstring = " UHR "
Gosub Sendstring
Else ' zur 15., 30., 45. Minute nur Minutenausgabe
M = Zmi ' Zehnerminute
Gosub Sendnumber
M = Emi ' Einerminute
Gosub Sendnumber
End If
End If
End If
Return
Zeitausgabe: ' wenn Taster gedrückt wurde
Txtstring = " ES IST "
Gosub Sendstring
If Zh > 0 Then
M = Zh ' Zehnerstelle Stunden
Gosub Sendnumber
End If
M = Eh ' Einerstelle Stunden
Gosub Sendnumber
Txtstring = " UHR "
Gosub Sendstring
If Zmi > 0 Then
M = Zmi ' Zehnerstelle Minuten
Gosub Sendnumber
End If
M = Emi ' Einerstelle Minuten
Gosub Sendnumber
Txtstring = " MIN"
Gosub Sendstring
Return
Weckzeitaugabe:
Gosub Weckzeitberechnung
M = Wzh ' Zehnerstelle Stunden
Gosub Sendnumber
M = Weh ' Einerstelle Stunden
Gosub Sendnumber
M = Wzmi ' Zehnerstelle Minuten
Gosub Sendnumber
M = Wemi ' Einerstelle Minuten
Gosub Sendnumber
Return
Alarmsub:
If T = Ta Then
Txtstring = " SOS"
Gosub Sendstring
If Punktkontakt = 0 Then ' Alarm abschalten mit "E", "I", "S" usw.
Alarm = 0
End If
End If
Return
'------- Aufbereitung der zu sendenden Morsezeichen ------
Sendnumber:
M = M + 48 ' Ascii- Wert 0: 048 ; Ascii- Wert 9: 057
M = Lookup(m , Morsetabelle) ' Morsezeichen aus Tabelle holen
Gosub Morse
Return
Sendstring:
For N = 1 To Len(txtstring) ' Textstring ausgeben
M = Txt(n)
M = Lookup(m , Morsetabelle) ' Morsezeichen aus Tabelle holen
Gosub Morse
Next N
Return
'------- Erzeugung der zu sendenden Morsezeichen -------
Morse:
Ocr0a = Tonhoehe1
If M = 0 Then ' Sonderfall: Leerzeichen;
Waitms Wortpause1
Goto Zeichenende
End If
For I = 1 To 8
If M = 1 Then ' Das Byte hat nur noch den Wert 1; Zeichenende!
Goto Zeichenende
End If
L = M And &B00000001 ' niederwertigstes Bit lesen
Buzzer = 1
If L = 1 Then
Waitms Strichlaenge1 ' ist das Bit 1 -> dah
Else
Waitms Punktlaenge1 ' ist das Bit 0 -> dit
End If
Buzzer = 0
Waitms Punktlaenge1 ' Pause innerhalb des Morsezeichens
Shift M , Right , 1 ' Bits um eine Stelle nach rechts shiften
Next I
Zeichenende:
Waitms Strichlaenge1 ' Pause zwischen Morsezeichen
Return
'--- Hier beginnt die Auswertung der Morse- Eingaben --------
'------ Menü ( Befehle bestehen aus 1 Zeichen ) -----
Menue:
Gosub Decodekeyer
Select Case E
Case 65 ' 65 : Ascii - Wert "A"
Txtstring = " ALARM?"
Gosub Sendstring
R = 1
Gosub Readnumbers
If G(1) = 1 Then
Alarm = 1
Else
Alarm = 0
End If
Case 71 ' 71 : Ascii - Wert "G"
Txtstring = " GONG?"
Gosub Sendstring
R = 1
Gosub Readnumbers
If G(1) = 1 Then
Gong = 1
Else
Gong = 0
End If
Case 67 ' 67 : Ascii- Wert "C"
Gosub Check
Case 75 ' 75 : Ascii- Wert "K"
Txtstring = " KORRSEK?"
Gosub Sendstring
R = 1
Gosub Readnumbers
Korr = G(1)
Case 77 ' 77 : Ascii - Wert "M"
Txtstring = " WPM?"
Gosub Sendstring
Gosub Speed
Case 84 ' 84 : Ascii - Wert "T"
Gosub Zeitausgabe
Case 87 ' 87 : Ascii - Wert "W"
Txtstring = " WECKZEIT?"
Gosub Sendstring
Gosub Weckzeitsetzen
Case 90 ' 90 : Ascii - Wert "Z"
Txtstring = " ZEIT?"
Gosub Sendstring
Gosub Zeitsetzen
Case 63 ' 63 : Ascii - Wert "?"
Txtstring = "BEFEHLE: ALARM CHECK ENDE GONG KORRSEK MORSESPEED TIME WECKZEIT ZEITSETZEN"
Gosub Sendstring
End Select
Return
' ----- hier folgen die Subroutinen, die durch das Menü aufgerufen werden ------
Zeitsetzen:
S = 0 ' Sekunden auf 0 setzen
R = 4
Gosub Readnumbers
Hilf = G(3) * 10 ' G(3) Zehnerstelle Minuten
T = G(4) + Hilf ' G(4) Einerstelle Minuten
Hilf = G(2) * 60 ' G(2) Einerstelle Stunden
T = T + Hilf
Hilf = 600 * G(1) ' G(1) Zehnerstelle Stunden
T = T + Hilf ' T Tagesminuten
If T > 1439 Then ' später als 23.59 Uhr
T = 1 ' Workaround, damit der Gong nicht anspricht
Txtstring = " RPT"
Gosub Sendstring
End If
Return
Weckzeitsetzen:
R = 4
Gosub Readnumbers
Hilf = G(3) * 10
Ta = G(4) + Hilf
Hilf = G(2) * 60
Ta = Ta + Hilf
Hilf = 600 * G(1)
Ta = Ta + Hilf ' Ta: Tagesminuten Alarmzeit
If Ta > 1439 Then
Txtstring = " RPT"
Gosub Sendstring
End If
Return
Speed:
R = 2
Gosub Readnumbers
' Aus dem abgefragten Wert neue Geschwindigkeit berechnen
Calcspeed:
G(1) = 10 * G(1) ' Zehnerstelle WPM
G(1) = G(1) + G(2) ' Einerstella addieren
Punktlaenge1 = 1320 / G(1) ' aus WPM Punkitlänge errechnen
Strichlaenge1 = Punktlaenge1 * 3
Wortpause1 = Punktlaenge1 * 5
Punktlaenge2 = 3 * Punktlaenge1 ' Sendegeschwindigkeit soll nur 2/3 der
Punktlaenge2 = Punktlaenge2 / 2 ' Empfangsgeschwindigkeit sein
Punktachtel = Punktlaenge2 / 8
If Punktachtel = 0 Then
Punktachtel = 1
End If
Strichlaenge2 = Punktlaenge2 * 3
Wortpause2 = Punktlaenge2 * 5
If G(1) < 10 Or G(1) > 30 Then ' auf plausiblen Wert prüfen
G(1) = 2
G(2) = 0
Goto Calcspeed ' Neuberechnung mit Default- Werten
End If
Return
Check:
Txtstring = " ALARM "
Gosub Sendstring
M = Alarm
Gosub Sendnumber
Txtstring = " GONG "
Gosub Sendstring
M = Gong
Gosub Sendnumber
Txtstring = " KORRSEK "
Gosub Sendstring
M = Korr
Gosub Sendnumber
Txtstring = " WECKZEIT "
Gosub Sendstring
Gosub Weckzeitaugabe
Return
'------ Morseingabe- Auswerteroutinen -------
Readnumbers:
I = 0
Notbremse = 0
Do
If Punktkontakt = 0 Or Strichkontakt = 0 Then ' Punkt - oder Strichkontakt gedrückt
I = I + 1
Gosub Decodekeyer
G(i) = E ' jeweils Ascii- Wert einstellige Zahl abholen
Select Case G(i)
Case 48 To 57
G(i) = G(i) - 48 ' auf Zahleneingabe prüfen
Case Else
Txtstring = "RPT"
Gosub Sendstring
Return
End Select
End If
Notbremse = Notbremse + 1
Waitms 20
If Notbremse > 250 Then ' Ausstieg nach längerer Eingabepause (5 sec)
Txtstring = "RPT"
Gosub Sendstring
Return
End If
Loop Until I = R
Waitms 200
For W = 1 To R ' zur Kontrolle die Zahlen ausgeben
M = G(w)
Gosub Sendnumber
Next
Return
'------- Interpretation der eingegebenen Einzel- Morsezeichen ----
Decodekeyer: ' Prinzip: eine 1 wird in der Variablen "K" von links nach rechts geschoben.
' nur wenn Strich gedrückt wurde, wird die 1 in die Variable D übernommen
Ocr0a = Tonhoehe2
D = 0
K = 1
Do
If Punktkontakt = 0 Then ' Punktkontakt gedrückt
Buzzer = 1 ' Ton an
Waitms Punktlaenge2
Buzzer = 0 ' Ton aus
Waitms Punktlaenge2
Shift K , Left ' Byteinhalt wandert 1 Stelle nach links, von rechts wird eine "0" eingeschoben
End If
Mark:
If Strichkontakt = 0 Then ' Strichkontakt gedrückt
Buzzer = 1 ' Ton an
Waitms Strichlaenge2
D = D + K ' die 1 für den Strich wird in die Variable "D" übernommen
Shift K , Left ' Byteinhalt wandert 1 Stelle nach rechts, von links eine "0" eingeschoben
If Punktkontakt = 0 Then
P = 1 ' wenn Punktkontakt ebenfalls gedrückt
End If ' Punktspeicher setzen
Buzzer = 0 ' Ton aus
Waitms Punktlaenge2
If P = 1 Then ' Punktspeicher prüfen
Buzzer = 1 ' Ton an
Waitms Punktlaenge2
Buzzer = 0 ' Ton aus
Waitms Punktlaenge2
Shift K , Left ' Byteinhalt wandert 1 Stelle nach links, rechts wird 0 eingeschoben
P = 0 ' Punktspeicher zurücksetzen
Goto Mark ' Prüfen, ob Strichkontakt bereits wieder gedrückt
End If
End If
J = 0
Do ' wir warten max. halbe Punktlänge, um unexakte Gebeweise abzufangen
If Punktkontakt = 0 Or Strichkontakt = 0 Then ' vorzeitiger Ausstieg, wenn Punktkontakt oder Strichkontakt gedrückt
Exit Do
End If
Waitms Punktachtel
J = J + 1
Loop Until J = 4 ' Abbruch bei halber Punktlänge
Loop Until Punktkontakt = 1 And Strichkontakt = 1 ' kein Kontakt mehr gedrückt; Morsezeichen fertig
D = D + K ' eine 1 wird als Endbit angehängt
E = Lookdown(d , Morsetabelle , 91) ' inverse Lookup in der Tabelle, um den zugehörigen Ascii- Wert zu ermitteln
E = E - 1 ' Data- Elemente werden ab 1 gezählt, Ascii- Tabelle beginnt bei Null
Return
'--- Interrupt- Routine Sekundentakt ------
Ontimer1: ' Timer1-Overflow-Interrupt-Routine
Tcnt1 = 31 ' Preset auf 31, damit der Timer 225 Takte bis Ueberlauf zählt
S = S + 1
If S > 59 Then ' Minutenwechsel
S = 0
T = T + 1
End If
Return
'--- Morsezeichen- Tabelle --------------------------
Morsetabelle:
'Ascii 0 - 32 ; hier wird nur Linefeed in <kn> umgesetzt
Data 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , &B00101101 , 0 , , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0 , 0
Data 0 , 0 , 0 , 0 , 0 , 0 , 0
' Ascii 32 - 47 -> _!"#$%&'()*+,-./
Data 0 , 0 , &B01010010 , 0 , 0 , 0 , 0 , 0 , &B00101101 , &B01101101 , 0 , &B00101010 , &B01110011 , &B01100001
Data &B01101010 , &B00101001
'Ascii 48 - 57 -> 0123456789
Data &B00111111 , &B00111110 , &B00111100 , &B00111000 , &B00110000 , &B00100000 , &B00100001 , &B00100011 , &B00100111 , &B00101111
'Ascii 58 - 64 -> :;<=>?@
Data &B01000111 , &B01110011 , &B00101101 , &B00110001 , &B01101101 , &B01001100 , 0
'Ascii 65 - 90 ABCDEFGHIJKLMNOPQRSTUVWXYZ
Data &B00000110 , &B00010001 , &B00010101 , &B00001001 , &B00000010 , &B00010100 , &B00001011 , &B00010000 , &B00000100
Data &B00011110 , &B00001101 , &B00010010 , &B00000111 , &B00000101 , &B00001111 , &B00010110 , &B00011011 , &B00001010
Data &B00001000 , &B00000011 , &B00001100 , &B00011000 , &B00001110 , &B00011001 , &B00011101 , &B00010011
'Ascii 91 - 127 -> Muell