Attiny13-ElbugVersion 3
Mit
einem kleinen 8-poligen Attiny 13, der ca. 1 Euro kostet, wenigen
zusätzlichen Bauteilen und etwas Basic (Bascom-AVR; es reicht die
kostenlose Demo-Version) lässt sich recht einfach eine
elektronische Morsetaste realisieren.
Sie erzeugt kurze und
lange Morsezeichen automatisch (Punkte und Striche; ein Strich ist drei
mal so lang wie ein Punkt). Die Zeichen werden mit einem Bedienhebel
erzeugt, tippt man ihn rechts an, wird ein langes Zeichen plus
normgerechter Pause erzeugt; tippt man links, ein kurzes Zeichen plus
Pause. Es gibt auch "Squeeze"- Tasten, sie haben zwei Hebel;
drückt man beide, wird eine alternierende Folge von kurzen und
langen Zeichen erzeugt; so kann man komplexe Zeichen mit wenigen
Tastbewegungen "zusammensetzen".
Auf dem Bild sieht man eine
leichtgewichtige Portabel-Gebemechanik (ein Kontaktsatz aus einem
Spezialrelais) und das aufgeklappte Gehäuse (in der oberen
Halbschale die Elektronik, in der unteren ein 80-mAh-Akku mit 3 Zellen
und die Steckverbinder).
Auf Kurzwelle muss man manchmal
lange herumrufen, um einen Funkpartner zu finden. Daher ist ein
Speicher mit einem (fest programmierten) Ruftext hilfreich; er wird mit
dem kleinen Taster neben dem Drehknopf gestartet und durch Antippen
des Punkthebels gestoppt.
Bei den Versionen 1 und 2 des Attiny-
Elbugs, die auf www.elo-web.de unter der Rubrik
"Mikrocontroller/Bascom" zu finden sind, hatte ich das Aufwecken des
Microcontrollers aus dem Tiefschlafmodus auf eher ungeschickte Weise
gelöst. Beim Atmega8, mit dem ich die ersten Programmierversuche
unternommen hatte, geht das nur über die Interrupt- Pins INT0 und
INT1, neuere Prozessoren (auch der Attiny 13) lassen sich
eleganter mit Pin Change Interrupts (die für fast alle I-O-Pins
verfügbar sind), aufwecken.
Version 3 nutzt daher Pin
Change Interrupts; dadurch wird einer der knappen I-O-Pins frei, so
dass nun Mithörton und Sender- Schalttransistor auf separate Pins
gelegt werden konnten.
Der
Elbug soll ständig an der Batterie verbleiben und möglichst
wenig Strom verbrauchen, wenn er nicht genutzt wird. Eine so geringe
Energieaufnahme erfordert den Power-Down-Modus, in dem jedoch
der Taktoszillator abgeschaltet wird und der Mikrocontroller nur
durch den externen Interrupt INT0 und die Pin Change Interrupts geweckt
werden kann.
Punkt- und Strich- Eingang ("Dit" und "Dah")
liegen an PB3 und PB2. Die Eingänge werden über interne
Pullup- Widerstände des Microcontrollers auf Plus gezogen und sind
gegen HF- Einstrahlung mit 3,3 nF abgeblockt. Punkt- und Strichtaster
schalten gegen Masse und ziehen den jeweiligen Eingang auf "Low", wenn
sie gedrückt werden.
Die Morsegeschwindigkeit wird durch
den AD-Wandler vorgegeben. Ein Potentiometer an PB4 bestimmt die
Zeitkonstante. Man kann den Einstellbereich per Software oder per
Hardware festlegen. Wegen des Stromverbrauchs ist ein Poti mit 470 kOhm
oder 1 MOhm (log.) günstig; da ich nur ein Potentiometer mit 100
kOhm (log.) hatte, habe ich beides gemacht: in Reihe mit dem Poti habe
ich einen Festwiderstand mit 560 kOhm gelegt und zum ausgelesenen Wert
jeweils 32 addiert. Der AD-Wandler löst 10 bit auf
(0...1023). Verwendet man ein 1-MOhm-Poti, muss man sich den
Einstellbereich per Software "zurechtbiegen"
PB0 ist als
Ton-Ausgang konfiguriert. Bei richtiger Wahl der Timer- Parameter
ergibt sich ein hörbarer Ton, den man durch Umprogrammierung des
Datenrichtungs-Registerbits DDRB.0 ein- und ausschalten kann. Die NF
treibt einen Piezo-Summer (Buzzer); die Lautstärke ist mit dem
Trimmer R2 einstellbar.
Das Schaltsignal für den Sender
liegt an PB1, ein BC548 fungiert als (invertierender)
Schalttransistor. An "TX" liegt also das Schaltsignal für
den Telegrafieeingang eines Senders. Da für den Abruf des
Speichertextes kein Pin mehr frei ist, muss der Reset-Pin herhalten;
durch Drücken von S1 wird ein Reset ausgelöst.
Als
Energieversorgung ist eine Lithium-Primärzelle im Mignon-Format
vorgesehen (erhältlich z.B. bei Reichelt; ca. 4 EURO). Sie liefert
3,6 Volt und sollte den Ruhestrom für die Schaltung (ca. 25
µA) jahrelang liefern können. Man kann auch 3 Mignonzellen
oder einen kleinen 3-Zellen-NiMH-Akku 3,6V / 80 mAh verwenden (bei
Reichelt unter 3 EURO). Sicherung nicht vergessen!
Da die
Schaltung nur aus wenigen Bauteilen besteht, kann man sie leicht auf
einem Stück Streifenleitungsplatine aufbauen, sie ist so klein,
dass man sie im Gehäuse per Einlochbefestigung des Potis fixieren
kann. Lediglich die Batterie ist separat unterzubringen.
Erläuterungen zur Software
Die
Software ist in Basic geschrieben (Bascom-AVR - www.mcselec.com).
Zunächst werden die Variablen definiert und die Hardware- Register
des Attiny konfiguriert. Da der Reset-Pin als Speicher-Abruf- Taste
fungiert, wird nach einem Reset als erstes der Speichertext ausgegeben.
Unterbrechen kann man ihn durch Antippen der Punkt-Taste, dann
verzweigt das Programm in den Keyer-Betrieb (Unterprogramm Keyer). Der
Speichertext "steckt" in den Data-Zeilen am Ende des Programms. Die
Codierung der Zeichen ist im Kommentarbereich des Quelltextes genauer
beschrieben.
Ist keine Taste gedrückt, durchläuft das
Programm einmal die Do-Schleife bis zum Befehl "Powerdown". Er stoppt
fast die gesamte Hardware. Der Controller reagiert nur noch auf
Potentialwechsel an den beiden zuvor definierten PCINT- Eingängen
PB3 und PB2, an die der Punkt- und der Strich- Taster angeschlossen
sind.
Drückt
man einen der beiden, wacht der Controller
auf, springt den auf "Powerdown" folgenden Befehl an ("Loop") und
beginnt die Do-Schleife aufs neue. Da jedoch PB2 und/oder PB3 auf
"Low" gezogen wurden, verzweigt das Programm in den
IF-EndIf-Schleifen; es laufen dann die Wait-Befehle und Umschaltbefehle
für
das Datenrichtungsregister ab, die den Ton durchschalten oder blocken
und den TX-Pin umschalten.
Die If-EndIf-Schleife für die
Morsestriche ist umfangreicher, weil hier auch abgefragt wird, ob
zusätzlich auch der Morsepunkt-Hebel gedrückt wurde; dann
wird eine Folge von abwechselnden Strich-Punkt- Signalen erzeugt
(Sqeeze-Modus) bzw. ein rudimentärer Punktspeicher bei
Einhebel-Tasten realisiert. Im Quelltext sind weitere Kommentare zu den
einzelnen Befehlen angefügt.
Flashen des Attiny13
Zunächst
muss der Speichertext auf die eigenen Verhältnisse
angepasst und mit Bascom-AVR von MCS Electronis (www.mcselec.com)
kompiliert werden. Das entstandene HEX- File kann mit einem beliebigen
Programmer in den Chip übertragen werden. Da die
Morsetaste aus dem Franzis-"Lernpaket Microcontroller" enstanden ist,
bietet sich jedoch die Hardware und Software des Lernpakets an.
Das
Lernpaket enthält ein sehr einfach gehaltenes Programm
(LPMicroISP.exe), mit dem man Hexfiles über die serielle
Schnittstelle eines PC in den Attiny13 flashen und die Taktrate des
Attiny13 ändern kann. Es funktioniert auch mit
USB-Seriell-Wandlern; die Übertragung ist dann allerdings sehr
langsam. LPMicroISP.exe ist ein reiner Programmer, der den Code im
robusten ISP-Modus in den Microcontroller überträgt.
Auf
der Website des Autors gibt es ein Update des Programms unter
"www.b-kainka.de/LPmicrosUpdate.zip". Es enthält zwei exe-Files;
das zweite Programm LPMicros.exe ist auf die Experimente des Lernpakets
zugeschnitten und für das reine Programmieren eines Attiny13
weniger geeignet. Man kann zum Programmieren die Original-
Hardware verwenden oder eine weiter vereinfachte Schaltung mit nur 8
Bauteilen, die sich ebenfalls problemlos auf einem Stück
Streifenleitungsplatine aufbauen läßt.
Ab Werk
werden die Attiny13 mit einem Takt von 9,6 MHz und Vorteilerfaktor 8
ausgeliefert, also 1,2 MHz. Die Fusebits des Attiny13 brauchen daher
nicht umprogrammiert zu werden. Möchte man die Taktrate
ändern (z.B. um den Stromverbrauch noch weiter zu drosseln),
muss man die Variable $crystal und die
Timerkonstanten (Tonhöhe) anpassen.
Download:
Bascom-Firmware (update 19.3.13)
PDF-Version des Artikels
' Programm: Morsekeyer mit Textspeicher
'
' Sprache: Bascom-AVR-Basic
'
' Erläuterungen:
'
'
' Hardware:
'
' Tastkontakte für Punkt und Strich an PB3 und PB2.(Tastung gegen Masse).
' Tonausgang (Buzzer) an PB0.
' Schaltausgang an PB1.
' Poti zur Geschwindigkeitseinstellung an PB4
' (Spannungsteiler aus 560 kOhm und 100kOhm log. - Schleifer an PB4).
' Starten des Textspeicher- Auslesens durch Reset- Taster
'
'
' Software:
'
' Nach Reset wird der Textspeicher ausgelesen; nach Textende 5 sec. Wartezeit, dann
' Neustart des Auslesens.
' Unterbrechung durch Betätigen des Punkt- Tastkontakts, danach geht die Schaltung in den
' Gebemodus.
' Im Gebemodus geht der Prozessor in Powerdown, wenn kein Kontakt mehr gedrückt ist
' Aufwecken durch PinChange Interrupt
'
' Timer0 erzeugt den Mithörton. Pin PB0 wird als Timer0-Ausgang OC0A verwendet.
' ADC liest Gleichspannung an PB4, sie wird in die Punktdauer umgerechnet
'
'
' Codierung der Morsezeichen des Textspeichers:
'
' 1 Byte pro Zeichen, niederwertiges Bit zuerst.
' Hat das Bit den Wert 0: Morsepunkt (dit)
' Hat das Bit den Wert 1: Moersestrich (dah)
' Da Morsezeichen unterschiedlich lang sind, ist das Ende- Zeichen ebenfalls ein 1-Bit.
'
' Beispiel Morsezeichen "a" (dit dah): &B00000110
' Beispiel Morsezeichen "9" (dah dah dah dah dit): &B00101111
' Auslesen der codierten Zeichen:
' niederwertigstes Bit auslesen, Byte um 1 Stelle nach rechts schieben, niederwertigstes Bit
' auslesen. Ist der Wert des gesamten Bytes nur noch 1, ist das Zeichen komplett.
'
'
'
'
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Grundeinstelllungen:
$regfile = "ATtiny13.dat"
$crystal = 1200000 ' Taktfrequenz: 1,2 MHz
$hwstack = 8 ' Platz für nur 4 Unterprogramme reserviert, spart SRAM
$swstack = 0 ' wird nicht gebraucht
$framesize = 0 ' dito
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Konstanten
Const Tonhoehe = 14 ' Tonhöhe
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Variablen dimensionieren:
Dim I As Byte ' wird in Zählschleife verwendet
Dim N As Byte ' 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
Dim Dit As Word ' Länge Punkt
Dim Dah As Word ' Länge Strich
Dim Wort As Word ' Länge Wortabstand
Dim P As Bit ' Punktspeicher
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Initialisierung des Programms:
'
'On Int0 Ondit ' Interruptroutine bei Drücken von Punkt- oder Strichkontakt
Acsr.7 = 1 ' Analog-Komparator ausschalten, spart etwas Strom
Gimsk.5 = 1 ' Pin Change Interrupt Enable
Sreg.7 = 1 ' Global Interrupt Enable
Pcmsk.2 = 1 ' Pin Change Inerrupt PB2 aktivieren
Pcmsk.3 = 1 ' Pin Change Interrupt PB3 aktivieren
Ddrb = &B0000_0010 ' Pin PB1 als Ausgang konfigurieren (1), Rest ist Eingang (0)
Portb = &B0000_1100 ' PullUp-Widerstände für die Pins PB2 und PB3 aktivieren
'
'
' Morseton mit Timer0 erzeugen:
' Timer0 : Vorteilung(prescale) = 1 ; Bei Compare -match Toggle Pin Oc0a / Pb0
'
' 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 = Counter , Prescale = 64 , Compare A = Toggle , Clear Timer = 1
Ocr0a = Tonhoehe
' AD- Konverter konfigurieren und erst mal starten
Config Adc = Single , Prescaler = Auto
Start Adc
'-------------------------------------------------------------------------------
' Hauptprogramm:
Speicher: ' Erst mal Speicher auslesen
Restore Message ' Data- Zeiger auf Datenfeld 1 setzen
For N = 1 To 128 ' Elemente des Datenfelds lesen (max. 128)
Gosub Adclesen ' Morsegeschwindigkeit abholen
Read M ' Zeichen aus Kette rauspicken
If M = 255 Then ' Ende- Zeichen
Wait 5 ' Speichertext zu Ende,etwas warten
Goto Speicher ' Speichertext erneut auslesen
End If
If Pinb.3 = 0 Then ' Abbruch, wenn Punkt- oder Strichhebel gedrückt
Waitms 500
Goto Keyer
End If
Gosub Morse ' Morsezeichen erzeugen
Next N
Keyer: ' hier beginnt der händische Tastenbetrieb
Do
Start Adc
Gosub Adclesen
If Pinb.3 = 0 Then ' Punktkontakt gedrückt
Ddrb.0 = 1 ' bei 1 wird Ausgang OC0A an Pin PB0 durchgeschaltet; Ton hörbar
Portb.1 = 1 ' Schaltausgang ein
Waitms Dit
Ddrb.0 = 0 ' bei 0 wird Tonsignal unterdrückt
Portb.1 = 0 ' Schaltausgang aus
Waitms Dit
End If
Mark:
If Pinb.2 = 0 Then ' Strichkontakt gedrückt
Ddrb.0 = 1 ' bei 1 wird Ausgang OC0A an Pin PB0 durchgeschaltet
Portb.1 = 1
Waitms Dah
If Pinb.3 = 0 Then ' Punktkontakt gedrückt
P = 1 ' Squeeze- bzw. Punktspeicher
End If
Ddrb.0 = 0 ' bei 0 wird Tonsignal unterdrückt
Portb.1 = 0
Waitms Dit
If P = 1 Then
Ddrb.0 = 1 ' Squeeze bzw. Punktspeicher auslesen
Portb.1 = 1
Waitms Dit
Ddrb.0 = 0
Portb.1 = 1
Waitms Dit
P = 0
Goto Mark
End If
End If
Schlafen:
If Pinb.2 = 1 And Pinb.3 = 1 Then ' Punkt- oder Strichkontakt sind nicht gedrückt
Stop Adc ' Strom sparen
Powerdown ' stärkster Stromsparmodus (auch Taktoszillator wird gestoppt)
End If
Loop
Morse: ' Morsezeichenerzeugung (nur Speicherbetrieb):
If M = 0 Then ' Sonderfall: Leerzeichen;
Waitms Wort
Goto Sign_end
End If
For I = 1 To 8
If M = 1 Then ' Das Byte hat nur noch den Wert 1; Zeichenende!
Goto Sign_end
End If
L = M And &B0000001 ' niederwertigstes Bit lesen
Ddrb.0 = 1 ' Ausgänge einschalten
Portb.1 = 1
If L = 1 Then
Waitms Dah ' ist das Bit 1 -> dah
Else
Waitms Dit ' ist das Bit 0 -> dit
End If
Ddrb.0 = 0 ' Ausgänge abschalten
Portb.1 = 0
Waitms Dit ' Pause innerhalb des Morsezeichens
Shift M , Right , 1 ' Bits um eine Stelle nach rechts shiften
Next I
Sign_end:
Waitms Dah ' Pause zwischen Morsezeichen
Return
Adclesen:
Dit = Getadc(2)
Dit = Dit + 32 ' für sinnvollen Einstellbereich 100k-Poti + 560k gegen Plus
'Dit = Dit + 256 ' stattdessen für sinnvollen Einstellbereich 1M-Poti
'Dit = Dit / 12 ' ""
Dah = 3 * Dit
Wort = 8 * Dit
Return
End
'- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' Codierung der Morsezeichen. Bei einem Prozessor mit viel SRAM würde man alle Zeichen
' in ein Array einlesen (Übersetzungstabelle), den eigentlichen Bakentext in einen String packen
' und diesen String zeichenenweise abarbeiten.
'
' Da der Attiny13 zu wenig SRAM hat und auch Flash knapp ist, ist der Weg hier anders:
' Die auszusendenden Zeichen sind direkt in der codierten Form in den Data- Zeilen ganz am Ende
' enthalten, allerdings in einer leicht lesbaren Schreibweise.
'
' Die Übersetzungstabelle ist mit Konstanten realisiert. Nur die wirklich benötigten
' Zeichen werden (beim kompilieren des Programmes) umgewandelt.
Const #a = &B00000110
Const #b = &B00010001
Const #c = &B00010101
Const #d = &B00001001
Const #e = &B00000010
Const #f = &B00010100
Const #g = &B00001011
Const #h = &B00010000
Const #i = &B00000100
Const #j = &B00011110
Const #k = &B00001101
Const #l = &B00010010
Const #m = &B00000111
Const #n = &B00000101
Const #o = &B00001111
Const #p = &B00010110
Const #q = &B00011011
Const #r = &B00001010
Const #s = &B00001000
Const #t = &B00000011
Const #u = &B00001100
Const #v = &B00011000
Const #w = &B00001110
Const #x = &B00011001
Const #y = &B00011101
Const #z = &B00010011
Const #ae = &B00011010
Const #oe = &B00010111
Const #ue = &B00011100
Const #0 = &B00111111
Const #1 = &B00111110
Const #2 = &B00111100
Const #3 = &B00111000
Const #4 = &B00110000
Const #5 = &B00100000
Const #6 = &B00100001
Const #7 = &B00100011
Const #8 = &B00100111
Const #9 = &B00101111
Const Leerz = 0
Const Anfuehrz = &B01010010
Const Kl_auf = &B00101101
Const Kl_zu = &B01101101
Const Plus = &B00101010
Const Komma = &B01110011
Const Minus = &B01100001
Const Punkt = &B01101010
Const Slash = &B00101001
Const Dopp_pkt = &B01000111
Const Gleich = &B00110001
Const Fragez = &B01001100
Const Ende = 255
Message:
Data #c , #q , Leerz , #c , #q , Leerz , #c , #q , Leerz , #d , #e , Leerz , #d , #k , #5 , #b , #u , Leerz , #d , #k , #5 , #b , #u , Leerz,
Data #c , #q , Leerz , #c , #q , Leerz , #c , #q , Leerz , #d , #e , Leerz , #d , #k , #5 , #b , #u , Leerz , #d , #k , #5 , #b , #u , Leerz,
Data #c , #q , Leerz , #c , #q , Leerz , #c , #q , Leerz , #d , #e , Leerz , #d , #k , #5 , #b , #u , Leerz , #d , #k , #5 , #b , #u , Leerz,
Data Plus , #p , #s , #e , Leerz , #k ,
Data Ende,