| Weitere Artikel aus dem Elo-Magazin |
ATtiny13-Elbug
von Ralf Beesner, DK5BU
(Foto: DL5MDA, http://de.wikipedia.org/wiki/Morsetaste)
Wir mussten beruflich bedingt in die Mikrocontroller-Programmierung einsteigen. Mein Kollege startete mit dem Franzis-Mikrocontroller-Lehrgang. Für Menschen, die sich mit Hardware nicht auskennen, ist der Lehrgang sicherlich ein guter Einstieg, weil er die Komplexität reduziert, nebenbei einige Grundlagen der Elektronik vermittelt und schnelle Erfolgserlebnisse schafft - aber kann ein Attiny 13 mit seinen beschränkten Ressourcen (nur 5 I/O-Ports , nur 1 kByte Programmspeicher) mehr als ein NE556 oder ein paar CMOS-Gatter? Kann man damit mehr bauen als einen Blinker oder ein Lauflicht? Ich war skeptisch. Ich hatte selber mit einem kleinen Mega8-Entwicklungssystem begonnen. Als Funkamateur und Telegrafie-Freund war ich schnell bei der naheliegenden Aufgabenstellung gelandet: der Programmierung einer elektronischen Morsetaste.
| Ganzen Artikel lesen... | ![]() |

Morsen kann man zwar auch mit einem Klingelknopf; üblich ist aber die Verwendung elektronischer Morsetasten. Sie erzeugen kurze und lange Morsezeichen (Punkte und Striche; ein Strich ist dreimal so lang wie ein Punkt) automatisch. 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. 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". Assembler ist mir zu umständlich, C zu kryptisch, aber Bascom ist auch für untalentierte Progammierer wie mich geeignet. Ein Programm war schnell geschrieben, und auch Bascom-Code ist so effizient, dass ein Mega8 völlig unterfordert ist; das Programm belegt nicht mal ein kByte. Daher reizte es mich, den Code auf den ATtiny13 zu portieren. Um es etwas spannender zu machen, war das Ziel, die Energiesparmodi so gut auszunutzen, dass das Gerät ständig an der Batterie verbleiben kann.
Konzeptionelle Überlegungen
Wirklich Energiesparen kann man nur im Power-Down-Modus. Da dann jedoch kein Takt läuft, kann man die flankengetriggerten Interrupt-Modi des Microcontrollers nicht verwenden. Der Mega8 hat zwei Pegel-sensitive Interrupt-Eingänge, an die man Punkt- und Strich-Hebel anschließen kann. Beide generieren jeweils ihre eigenen Interrupts und wecken so den Prozessor auf.
(Bitte anklicken für volle Auflösung)
Der Attiny hat nur einen pegelgetriggerten Interrupt (PB1). Daher habe ich Punkt- und Strich-Hebel an PB2 und PB3 angeschlossen (und die Pullup-Widerstände aktiviert); drückt man einen der Hebel, werden PB2 und 3 an Masse gezogen, aber beide ziehen über je eine Diode den Pin PB1 ebenfalls an Masse und wecken so den Prozessor aus dem Power-Down-Modus.
Die Morsegeschwindigkeit wird über den AD-Wandler eingestellt. Ein Potentiometer an PB4 gibt einen Analogwert vor, der die Zeitkonstante "len_dit" bestimmt. Man kann den Einstellbereich per Software oder per Hardware begrenzen. Wegen des Stromverbrauchs ist ein Poti mit 470 kOhm oder 1 MOhm günstig; da ich nur ein Potentiometer mit 100 kOhm 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, muß man sich den Einstellbereich per Software "zurechtbiegen". Das Poti sollte logarithmisch sein, weil dann der Einstellbereich etwas gleichmäßiger ist.
Da so bereits vier I/O-Ports verbraucht sind, bleibt nur ein einziger für die Erzeugung eines Mithörtons und die Tastung eines Senders übrig. Der Mithörton wird mit dem internen Timer erzeugt; der Timer- Ausgang liegt fest an PB0. Bei richtiger Wahl der Timer- Parameter ergibt sich ein hörbarer Ton, den man durch Umprogrammierung des Datenrichtungs-Registers DDRB.0 ein- und ausschalten kann. Diese NF treibt einen Piezo- Summer (Buzzer). Zusätzlich filtert ein Tiefpass die NF-Anteile weg, so dass der nachgeschaltete Transistor einen Sender jeweils für die Dauer der Punkte und Striche hochtastet.
An X1-3 und X1-4 werden- Punkt- und Strichhebel angeschlossen; sie schalten gegen Masse (X1-1). An X1-2 liegt das Schaltsignal für den Telegrafieanschluss eines Senders. Die Eingänge werden über interne Pullup-Widerstände des Mikrocontrollers auf Plus gezogen; sie sind gegen HF-Einstrahlung mit 3,3 nF abgeblockt.
Als Energieversorgung ist eine Lithium-Primärzelle im Mignon-Format vorgesehen (erhältlich z.B. bei Reichelt; ca. EURO 4.-). Sie liefert 3,6 Volt und sollte den Ruhestrom für die Schaltung (ca. 25 µA) jahrelang liefern können. Alternativ eignen sich auch zwei herkömmliche in Reihe geschaltete Mignonzellen. Allerdings wird ihre Kapazität nicht gut ausgenutzt, da der Attiny bei 2,7 Volt resettet (Brownout-Schaltung).
Wer auf den Mithörton verzichten will, kann den Buzzer, R1, R5 und C2 weglassen, benötigt dann aber eine abgeänderte Software, die nicht das Datenrichtungsregister umschaltet, sondern PB0 als digitalen Ausgang konfiguriert und PB0 direkt auf "low" oder "high" umschaltet
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.
Download: Bascom-Quelltext
Erläuterungen zur Software
Nach Einschalten bzw. Reset 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 am INT0- Eingang (PB1), denn ziemlich am Anfang der Programms wurde die Interruptroutine "Ondit" definiert.
Drückt man Punkt- oder Strich -Hebel, wird PB1/INT0 über eine der Dioden mit an Masse gezogen; der Controller wacht dadurch auf und springt die Interrupt- Routine "Ondit:" am Ende des Programms an.
' Morsekeyer mit Tonausgang / Buzzer und Schaltausgang an PB0
' Taktfrequenz 1200 kHz, Poti 100 k log + 560 k fest
' -------------------------------------------------------------------------------
' Grundeinstelllungen:
$regfile = "attiny13.dat"
$crystal = 1200000 'Standard- Takt 9,6 MHz / 8
$hwstack = 0
$swstack = 0
$framesize = 0
Baud = 9600
'
' - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
' ------------------------------------------------------------------------------
' VARIABLE UND KONSTANTEN
' ------------------------------------------------------------------------------
Dim Len_dit As Word
Dim Len_dah As Word
Dim P As Bit
' ------------------------------------------------------------------------------
' Initialisierung
' ------------------------------------------------------------------------------
Main:
On Int0 Ondit ' Interruptroutine bei Drücken von Punkt- oder Strichkontakt
Gimsk.6 = 1 ' INT0 enable
Sreg.7 = 1 ' Global Interrupt enable
Mcucr.0 = 0 ' INT0 (wiederholt) bei L an PB0
Mcucr.1 = 0 ' INT0 zweites Bit
Acsr.acd = 1 ' Analog-Komparator off
Ddrb = &B00000000 ' Port B: alle Pins Eingänge
Portb = &B00001110 ' Port B: Pullups an PB1,2,3 - kein Pullup am AD-Wandler PB4 und am getoggelten Ausgang PB0
Const Tone_freq = 120 ' Tonfrequenz, Wert 120 ergab sich beim Ausprobieren als recht brauchbar
'
'
'Tastgeschwindigkeit über AD- Wandler
'
Config Adc = Single , Prescaler = Auto
'Morseton mit Timer0 erzeugen (wenn Zähler = Wert in OCR0A, wird Ausgang OC0A getoggled.
Config Timer0 = Counter , Prescale = 8 , Compare A = Toggle , Clear Timer = 1
'Len_dit = 100 ' Anfangswert für Gebegeschwindigkeit
Ocr0a = Tone_freq
Do
Sreg.7 = 0 ' Interrupts sperren (Unterdrücken mehrfacher Interrupts)
Start Adc
Len_dit = Getadc(2)
Len_dit = Len_dit + 32 ' für sinnvollen Einstellbereich 100k-Poti + 560k gegen Plus
'Len_dit = Len_dit + 256 ' für sinnvollen Einstellbereich 1M-Poti
'Len_dit = Len_dit / 12 ' "
If Pinb.3 = 0 Then ' Punktkontakt gedrückt
Ddrb.0 = 1 ' bei 1 wird Ausgang OC0A an Pin PB0 durchgeschaltet; Ton hörbar
Waitms Len_dit
Ddrb.0 = 0 ' bei 0 wird Tonsignal unterdrückt
Waitms Len_dit
End If
Mark:
If Pinb.2 = 0 Then ' Strichkontakt gedrückt
Ddrb.0 = 1 ' bei 1 wird Ausgang OC0A an Pin PB0 durchgeschaltet
Len_dah = 3 * Len_dit
Waitms Len_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
Waitms Len_dit
If P = 1 Then
Ddrb.0 = 1 ' die folgenden Zeilen bildenSqueeze bzw. Punktspeicher
Waitms Len_dit
Ddrb.0 = 0
Waitms Len_dit
P = 0
Goto Mark
End If
End If
Sreg.7 = 1 ' Interrupts freigeben, um Aufwecken zu ermöglichen
Stop Adc ' Strom sparen
Powerdown ' stärkster Stromsparmodus (auch Taktoszillator wird gestoppt)
Loop
Ondit: ' Interruptroutine; holt den den Controller aus dem Powerdown
Return
Die Interrupt-Routine enthält keine eigenen Befehle, der Prozessor kehrt sofort aus der Interrupt- Routine zurück, springt den auf "Powerdown" folgenden Befehl an ("Loop") und beginnt die Do-Schleife aufs neue. Da jedoch PB2 und/oder PB3 auf Masse gezogen wurden, verzweigt das Programm in den IF-Schleifen; es laufen dann die Wait-Befehle und Umschaltbefehle für das Datenrichtungsregister ab, die den Ton durchschalten oder blocken.
Die If-Schleife für die Morsestriche ist umfangreicher, weil hier auch abgefragt wird, ob zusätzlich 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.
Stromspar-Tips: Analog-Komparator abschalten, Pullups nur so verwenden, dass im Ruhezustand kein Strom durch sie fließt (insbesondere am ADC- Eingang muss der Pullup-Widerstand deaktiviert werden, weil er nicht nur unnötig Strom verbraucht, sondern auch den ADC- Eingang niederohmig macht), ADC im Ruhezustand abschalten und nur während der Zeichenerzeugung einschalten.
Im Quelltext sind weitere Kommentare zu den einzelnen Befehlen angefügt.
Download: Der ungekürzte Beitrag mit Zusatzinformationen und Eagle-File
Literatur: Lernpaket Mikrocontroller
Neue Software
Auf Kurzwelle muss man manchmal lange herumrufen, um einen Funkpartner zu finden. Da ist eine Morsetaste mit Textspeicher praktisch. Meine Attiny- Morsetaste hatte zwar noch etwas Platz im RAM, aber keinen freien Pin, mit dem man die Speicherausgabe starten kann. Nun ist mir doch noch eine simple Möglichkeit eingefallen: der Reset- Pin. Der Speichertext wird nach einem Reset als erstes ausgegeben. Unterbrechen kann man die Ausgabe durch Antippen der Punkt- Taste; ab da arbeitet die Software wie bisher. Die alte Version ist jetzt auf die Programmteile "Keyer". "ADClesen", "Schlafen" und "Ondit" aufgeteilt. Hinzugekommen sind die Programmteile "Speicher", der die Data- Zeilen „abklappert", und "Morse", der die codierten Bytes in Morsezeichen wandelt (siehe: „Tiny- Morse-Keyer4-100k.bas"). Den Schaltplan habe ich nicht neu gezeichnet, weil lediglich an Pin1 des Attiny13 ein Taster gegen Masse angefügt werden muss.
Download: Bascom-Quelltext













