Pfad:
Home =>
AVR-DE =>
Anwendungen => Eieruhr RGB M8515
This page in english:
 |
AVR-Anwendungen
Eieruhr RGB mit ATmega8515
Hardware, Aufbau, Verwendung und Software für eine 11-Minuten-Eieruhr |
Eieruhr RGB mit ATmega8515
- Eigenschaften
- Hardware
- Aufbau
- Software
- Fazit
Diese Seite beschreibt einen Timer, der mit 11 farbigen RGB-LEDs arbeitet. Er kann
zur Überwachung des Kochvorgangs von Eiern dienen.
Die Eigenschaften der Eieruhr sind:
- Maximal messbare Zeit: 11 Minuten,
- kann für eine Betriebsspannung von 3,7 oder 4.5
oder 5.0 V aufgebaut werden, einfach andere
Widerstände einbauen,
- die letzte voll abgelaufene Minute wird in rot angezeigt,
kann aber auch so konfiguriert werden, dass alle abgelaufenen
Minuten-LEDs in rot leuchten,
- die laufende Minute wird zu Beginn in grün angezeigt,
bei fortlaufender Zeit nimmt der Blau-Anteil zu und nach 30
Sekunden ist der Grünanteil Null, dann nimmt der Rot-Anteil
zu und der Blau-Anteil ab. Nach einer Minute ist die LED
rein rot und die nächste Minute beginnt. Arbeitet mit
512 Farben mit einer Pulsweiten-Auflösung von 8 Bits,
- exaktes Timing mit einem Quarztakt, kann mit drei verschiedenen
Quarzen betrieben werden (Anpassung über Software), aber
auch ohne Quarz mit dem internen RC-Oszillator bei 2 oder 4 MHz
(dann mit geringer Ungenauigkeit bei den Minutendauern),
- geringer Stromverbrauch wenn nicht benötigte Minuten-LEDs
abgeschaltet sind, ca. 30 mA bei Batteriebetrieb,
- kann bei Betrieb mit einer externen Stromversorgung mit
200 mA max. auch mit allen LED an betrieben werden,
- spielt nach jeder vollen Minute für eine Sekunde lang
den nächsten Tonleiter-Ton, dessen Oktave einstellbar
ist,
- kann mit einem Taster jederzeit angehalten und an dieser
Position auch wieder gestartet werden,
- flexibel konfigurierbarer Quellcode für viele Zwecke und
Varianten, mit ausgiebig dokumentiertem Code, Fließdiagrammen
und Zeitwerten,
- Hardware-Test-Routinen in einer extra Datei ermöglichen das
bequeme Testen aller Hardware-Komponenten zur Fehlersuche.
Entschuldigung: Ich habe mehrfach versucht, von der Eieruhr ein Video
anzufertigen. Wegen des 60-Hz-PWM-Zyklusses der Eieruhr ist mir das
mit meiner Fuji nicht gelungen, es gibt nur hässliches Flimmern
und einen unerträglichen Sound. Nichts was man gerne auf seiner
Webseite haben mag.
2.1 Auswahl des AVR-Typs
Der Zugriff auf 10 oder 11 RGB-LED-Dioden braucht mindestens vier ganze
8-Bit-I/O-Ports (30 bis 33 I/O-Pins). Zusätzliche Pins sollten es
ermöglichen
- Töne auf einem angeschlossenen Lautsprecher auszugeben,
- eine Taste zum Start und Stop des Timers anzuschließen.
Um den optimalen AVR-Typ für diese Aufgaben zu finden, der all dies
möglich macht, habe ich die benötigten Komponenten in die
Typauswahl-Sektion des Simulators
avr_sim gefüttert. Nur
die folgenden Typen ermöglichen es, vier komplette I/O-Ports für
die LED-Ansteuerung zu reservieren:
==> ATmega <==
ATmega16 - PDIP40
ATmega16A - PDIP40
ATmega32 - PDIP40
ATmega32A - PDIP40
ATmega83 - PDIP40
ATmega161 - PDIP40
ATmega162 - PDIP40
ATmega163 - PDIP40
ATmega323 - PDIP40
ATmega8515 - PDIP40
ATmega8535 - PDIP40
Schon die zusätzliche Anforderung, einen INT-Eingang für die
Taste zu reservieren schränkt die Auswahlmöglichkeiten
radikal ein:
==> ATmega <==
ATmega161 - PDIP40
ATmega162 - PDIP40
ATmega8515 - PDIP40
Wenn man nun noch einen OC-Pin für den Lautsprecher anfordert,
leert sich die Liste vollständig, da die meisten OC-Pins in der
Mitte von I/O-Ports angesiedelt sind. Die einzige Möglichkeit,
die geht, ist OC1B in den oben genannten drei Typen.
Da der ATmega161 nicht mehr produziert wird, bleiben ATmega162 und
ATmega8515. Ich habe den ATmega8515 gewählt, weil der leicht
zu beschaffen ist.
Der Typselektor vom avr_sim zeigt rechts auch die Pinbelegung des
ATmega8515 an. Nur ein Pin (PE1) bleibt übrig.
2.2 Schaltbild
Das Schaltbild zeigt, wie die 11 RGB-LEDs an die 32 I/O-Pins
des ATmega8515 angeschlossen sind: jeder Ausgang kriegt einen
farb-spezifischen Widerstand und wird an die Kathode der LEDs
angeschlossen, in der Reihenfolge blau-grün-rot mit steigender
Bit-Nummer. Die Widerstände bestimmen den Strom durch die
Farb-LEDs. Alle LEDs sind mit gemeinsamer Anode, die alle an die
positive Betriebsspannung angeschlossen sind. Wenn Du LEDs mit
gemeinsamer Kathode verwenden willst: geht auch, dann
- müssen die Kathoden an Minus, und
- in der Software müssen alle Pins mit ihrem PORTcn
(c=A/B/C/D, n=0..7) auf eins gesetzt werden.
Der Lautsprecher ist über einen 47 µF-Elko
angeschlossen. Er rumort dann sehr kräftig, auch bei niedrigen
Tönen. Die Taste ist direkt an den INT2-Pin angeschlossen, der
Pull-Up-Widerstand wird per Software eingeschaltet.
2.3 Takt
Der Quarz taktet den ATmega8515 mit 4,194304 MHz, was exakt
auf eine 8-Bit-PWM mit 512 Farbstufen passt (siehe weiter unten).
Es gehen aber auch andere Quarze noch, und ebenso exakt. Schon
der 2,097 MHz-Quarz bringt genug Speed, um die PWM korrekt
aussteuern zu können. Das ist das Ergebnis einer ersten
Code-Optimierung: wenn die Minute wechselt, brauchte der Code
zu lange für 2,097 MHz. Das ist in dieser Version
behoben, sodass auch diese Taktfrequenz noch bequem geht.
Für die Optimierung war es 6uuml;brigens nötig,
den gesamten Zeitbedarf mit allen Taktzyklen festzustellen,
wie es in der Software-Sektion gezeigt
wird.
Wird stattdessen ein 4 MHz-Quarz verwendet, geht die Uhr
pro Minute mit drei Sekunden nach, eine akzeptable Lösung
für eine Eieruhr. Gibt man der Software die
4.000.000 in der Konstanten clock an, beträgt die
Differenz nur noch 0,03 Sekunden pro Minute, weil dann
der CTC-Teiler automatisch einen Teil der Abweichung kompensiert.
Alle Quarze und ihre Eignung sind im Libre-Office-Tabellenblatt
Quarze hier untersucht
und ihre Abweichungen von den 60 Sekunden pro Minute
gerechnet. Genauigkeitsfanatiker bleiben beim Quarz
4,194304 MHz.
Wer es ungenauer mag und vielleicht Quarze für Teufelszeug
hält, schaltet den Quarz ab oder montiert ihn gar nicht erst.
Er verwendet dann den Internen RC-Oszillator. Der lässt
sich auf 1, 2, 4 oder 8 MHz einstellen.
Bei 1 MHz ist nicht genug Zeit, um einen Minutenwechsel
in der Interrupt-Service-Routine zu vollziehen. Bei 2, 4 und
8 MHz geht das einwandfrei. Die Differenzen zum exakten
Timing sind für eine 11-Minuten-Eieruhr auch hinnehmbar
und nur von akademischer Natur. Natürlich muss man die
Fuses entsprechend éinstellen und im Quellcode die Konstante
clock ändern.
Wer seine Batterie unbedingt mit 8 MHz Takt quälen
will, muss auch noch den Prescaler auf 8 einstellen. Die
Lösung ist daher in der Tabelle nicht aufgeführt.
2.4 ISP6-Schnittstelle
Nicht im Schaltbild eingezeichnet ist ein Sechs-Pin-Stecker,
der der Programmierung des ATmega8515 in der fertigen Schaltung
dient. Die Anschlüsse MOSI, MISO, SCK und RESET vertragen
sich mit der restlichen Peripherie.
2.5 Widerstände
Die Widerstände Rblau, Rgrün
und Rrot sind folgendermaßen zu bemessen:
- Maximal sind zwölf Einzel-LEDs gleichzeitig
eingeschaltet: in der elften Minute zehn rote (wenn
die Option mit Löschen nicht gewählt ist) sowie
die beiden in der 11ten LED, die gerade aktiv sind. Die
beiden letzten sind zwar nur zu Beginn des PWM-Zyklus
beide an, aber so ein Mikrocontroller spürt das.
- Der ATmega8515 kann maximal 200 mA über
seinen VCC- oder GDN-Pin max. treiben. Daher ist der
LED-Strom auf 200 / 12 = 16,7 mA zu begrenzen.
- Um noch genug Reserve für den ATmega8515 selbst
sowie für den kräftigen Lautsprecherton zu
lassen, wurden 15 mA LED-Strom festgelegt, was
genügend helle LEDs zur Folge hat.
- Bei 15 mA betragen die Durchlassspannungen der
Dioden (jeweils mit Exemplarschwankungen)
- blau: 2,92 V,
- grün: 3,09 V, und
- rot: 2,09 V.
Die Messungen am gebauten Exemplar ergaben etwas andere
Werte (siehe das Blatt gemessen in der LibreOffice-
Dateil hier.
- Bei 15 mA ist die Ausgangsspannung der ATmega8515
Portpins in Sink-Schaltung ca. 0,4 V. Faktisch wurde
eine Spannung von 358 mV gemessen, mit Schwankungen
zwischen 319 und 410 mV.
- Die Widerstände ergeben sich zu
RLED = (VBetrieb - VLED -
VSink) / ILED
- Ich habe die nähesten Werte der Reihe E24
gewählt (siehe Blätter widerstand und
widerstandsreihen im LibreOffice-Dokument), die
käuflich sind.
Das LibrOffice-Dokument zeigt ferner, dass beim Betrieb mit
der nächsthöheren Betriebsspannung keine Gefahr
besteht, Leuchtdioden zu beschädigen.
Die Tabelle zeigt die Widerstandswerte für die drei
üblichen Betriebsspannungen
- 3,7 V, was das Minimum darstellt und von
größeren Li-Zellen geliefert wird,
- 4,5 V, das aus drei gestapelten AA- oder
AAA-Batterien stammen kann, und
- 5,0 V, falls die Schaltung aus einer USB-Buchse
oder einer externen Spannungsquelle versorgt werden
soll.
Mein eigenes Gerät habe ich mit drei AA-Batterien gebaut
und die Widerstände entsprechend dimensioniert. Die
gemessenen Spannungen an allen Ausgängen lagen bei
4,2 V Betriebsspannung bei durchschnittlich 0,358 V
Sink-Spannung, der durchschnittliche Strom durch die 32 LEDs
lag bei 14,19 mA. Die Durchlassspannungen lagen bei den
blauen LEDs bei 2,798 V, bei den grünen bei
2,777 V und bei den roten 2,023 V. Der durchschnittliche
Strom bei blauen LEDs lag bei 13,11 mA, bei den grünen
bei 15,31 mA und bei den roten 14,04 mA. Diese geringen
Unterschiede sind optisch nicht wahrnehmbar.
3.1 Gedruckte Schaltung
Um das Gerät komfortabel zu bauen, wurde eine einseitig
beschichtete gedruckte Schaltung entwickelt. Sie ist auf eine
halbe Euro-Platine (100 x 80 mm) dimensioniert.
So sind die Komponenten auf der Platine platziert. Alle Löcher
sind 0,8 mm, nur die Anschlüsse für Lautsprecher
und Batterie sowie die ISP6-Pins sind 1 mm. Eine Brücke
liess sich nicht vermeiden.
Damit der ISP6-Stecker unter den Deckel passt, wurde eine
abgewinkelte Steckerversion verwendet.
3.2 Fertigstellung
Nach Bestückung können die Komponenten getestet werden,
wofür ein Testprogramm entwickelt wurde (siehe Kapitel
Software).
Die gedruckte Schaltung kriegt einen Deckel aus Plexiglas, mit
passenden Löchern für die LEDs, den Schalter und die
Taste. Genau genommen habe ich den Deckel zuerst gebohrt und
dann die LEDs eingelötet, damit alles genau passt. Der
Deckel wird mit Abstandshaltern auf Distanz gehalten.
Das ist der Blick von der Seite. Die unterste Ebene besteht aus
einer Plexiglasplatte, auf dem der Batteriehalter und der
Lautsprecher montiert ist. Der Lautsprecher kriegt kleine
3 mm-Löcher für den Schallaustritt nach unten
und ist mit Alleskleber aufgeklebt. Der Abstand zwischen der
Platte und der gedruckten Schaltung ist 25 mm.
4.1 Downloads
Die Software ist verfügbar im Assembler-Quellcode-Format
hier oder kann im
Browser hier
angesehen werden.
Zum separaten Testen aller Komponenten auf dem Board habe ich
den Quellcode hier
geschrieben. Siehe hierzu Kapitel 4.4 für Details.
4.2 Assemblieren
Vor dem Assemblieren ist sicherzustellen, dass die korrekten
Einstellungen im Quellcode ausgewählt sind. Die
voreingestellte Taktrate ist 4,194304 MHz. Ich
übernehme keinerlei Verantwortung für Eier, die
mit der Default-Taktrate von 1 MHz gekocht wurden und
daher vier mal so lang im kochenden Wasser blieben, nur weil
Du vergessen hast, per Fuse den externen Quarz als Taktgeber
einzuschalten oder weil Du die Konstante clock im
Quellcode nicht korrekt angepasst hast.
Für Simulationen habe ich im Quellcode einige Schalter
eingebaut, die den Ablauf beschleunigen. Stelle sicher, dass
alle diese Schalter auf Null stehen, bevor Du die finale
Variante assemblierst.
4.3 Fuses
Vor oder nach dem Programmieren des Flashs sind noch die Fuses
des ATmega8515 auf den externen Quarz umzustellen. Danach
läuft er mit 4,194304 MHz.
4.4 Hardwarediagnose
Zum Testen der Hardware der Eieruhr habe ich eine Vielzahl
von Testroutinen für die Hardwarekomponenten geschrieben.
Der Assembler-Quellcode ist
hier. Die Datei
muss editiert werden, um die Testroutinen auszuwählen,
dann assembliert und der Hexcode in das Flash gebrannt werden.
Die folgenden Testroutinen können eingestellt werden:
- Port I/O test: testet den Lautsprecher-Ausgang mit SBI-
und CBI-Instruktionen,
- Timer 1 IO: testet den Lautsprecher via OC1B-Torkeln
von Timer TC1,
- Led: Schaltet die LED auf weiß, indem alle drei
Farben eingeschaltet werden, die LED wird mit der
Konstanten dbgLedNr zwischen 1 und 11 eingestellt,
- LedRot: rotiert alle 11 LEDs durch Einschalten der blauen,
dann grünen und danach der roten LED,
- LedPwm: mischt die Farbe der LED mit der Nummer
dbgLedNmbr (1..11) aus dem Blauanteil in der Konstanten
dbgPwmBlue (0 ... 255), dem Grünanteil in der
Konstanten dbgPwmGreen und dem Rotanteil in der
Konstanten dbgPwmRed zusammen, eine Verzögerung
in der Konstanten delay (zwischen 0 und 255) reduziert
die Ausgabegeschwindigkeit (PWM-Frequenz),
- Key: wenn die Taste nicht gedrückt ist, ist LED1 blau,
wenn gedrückt grün,
- Key toggle: schaltet bei jedem Tastendruck die Farbe bzw.
die nächste LED ein, so dass Tastenprellen abgelesen
werden kann.
Alle Routinen können aktiviert werden, indem die entsprechenden
Konstanten auf 1 gesetzt werden. Nur die erste der gesetzten Routinen
wird ausgeführt.
4.5 Wie die PWM arbeitet
Zu der Eieruhr-Software zunächst generell: alle Funktionen wie
- die LED-PWM,
- die Tasteninterrupts, und
- der Start und das Anhalten von Tönen,
werden innerhalb von Interrupt-Service-Routinen erledigt.
Außerhalb dieser ISRs gibt es nichts zu erledigen, daher kann
auf ein Sichern und Wiederherstellen des SREG verzichtet werden.
4.5.1 Timing der PWM
Des Weiteren: Du wirst vergeblich nach Sekunden- und Minutenzählern
suchen. Die Software funktioniert aber anders. Das ist deshalb so, weil
sich aus einem 4,194304 MHz-Takt keine Sekunde machen lässt.
Diue Zeitzähler sind folgendermaßen aufgebaut:
- 240 (CTC-Teiler TC0) * 512 (Farben) * 256 (PWM-Zyklen-Schritte) * 8
(PWM-Wiederholungen pro Farbe) ergibt genau 251,658,240 Taktzyklen,
bei einem Takt von 4,194304 MHz exakt 60 Sekunden lang.
- Der CTC-Teiler von 240 (Compare A = 239) passt das gesamte Timing
der Uhr an die Taktfrequenz an. Es muss daher nur diese eine Konstante
geändert werden, wenn eine andere Taktfrequenz zum Einsatz kommt.
- Die Farben müssen von 0 bis 511 zählen, aufgeteilt in zwei
Phasen zu jeweils 256 Schritten.
- Der PWM-Schrittzähler zählt nur von 0 bis 0 (=256) und
schaltet LED-Farben zu vorgewählten Zeitpunkten aus.
- Der PWM-Wiederholzähler zählt nur von 8 an aus abwärts
und, wenn nicht Null, startet den nächsten PWM-Durchlauf mit der
gleichen Farbkombination, bzw., wenn Null, die nächste
Farbkombination.
Es macht daher keinen Sinn in der Software nach einem Sekundenzähler
zu suchen: sie hat keinen, und wenn, dann wäre er ziemlich krumm und
alles andere als eine Ganzzahl. Er ist auf die 60 Sekunden einer
vollen Minute hin ausgelegt, nicht auf eine Sekunde.
Das Timing der Eieruhr funktioniert so:
- Die Taktfrequenz von 4,194304 MHz taktet den TC0 mit
einem Vorteiler von 1.
- TC0 arbeitet im CTC-Modus, mit einem Compare-A-Wert von
239. Das teilt die Taktfreuenz durch 240 und löst
mit einer Frequenz von 17.476,26 Hz, alle
57,22046 µs, einen Compare-A-Interrupt aus.
- Der TC0-Interrupt gibt den Zustand aller 32 LED-Bits
aus, erhöht den PWM-Wert im Register rPwm und
prüft anschließend, ob die derzeit aktiven blauen,
(im Register rBlue), grünen (im Register
rGreen) oder roten (im Register rRed den
Vergleichswert in rPwm erreicht haben. Falls das
der Fall ist wird das entsprechende von den 32 Bits
gelöscht, aber erst beim nächsten TC0-Interrupt
an den vier Ports ausgegeben.
- Bei jedem 256-sten Mal erreicht rPwm beim
Erhöhen Null. In diesem Fall erfolgt kein Vergleich.
Alle Farben, deren Anteil im Vergleichsregister bei Null
liegt, werden zu Beginn des PWM-Zyklus gar nicht erst
eingeschaltet und müssen daher auch nicht ausgeschaltet
werden. Dieser Anfangszustand zu Beginn des PWM-Zyklusses
ist in den Registern R3:R2:R1:R0 gespeichert und
überschreibt beim PWM-Zyklus-Start die Ausgaberegister
R7:R6:R5:R4 und startet damit beim nächsten CTC-Interrupt
denselben PWM-Zyklus nochmals von vorne. Der Neustart erfolgt
acht Mal. Dann ist die nächste Farbe dran. Jeder PWM-Zyklus
benötigt 256*57,22046 µs = 14,648 ms. Das
entspricht eine PWM-Frequenz der LEDs von 1.000 / 14,648 =
68,267 Hz. Acht Durchläufe benötigen
117,188 ms.
- Sind acht PWM-Zyklen absolviert, dann ist die nächste
Farbe dran. In der Farbphase 1 wird dazu der grüne Wert
in rBlue um Eins vermindert und der blaue Wert in
rBlue um Eins erhöht. Das macht
256 urchläufe in dieser Phase, dann erreichen beide
Register wieder Null. Diese Phase dauert 256 * 117,188 ms =
30 Sekunden.
- In der Farbphase 2 nimmt der Blauanteil ab und der Rotanteil
zu. Auch diese Phase dauert 30 Sekunden. Ist diese absolviert
dann ist die n&aum;chste LED dran.
Das wiederholt sich elf Mal, wobei die elfte LED keinen Blau-Anschluss
hat und nur Grün und Rot aktiv sind.
4.5.2 Organisation der PWM-LED-Bits
Die nachfolgend beschriebene Organisation der PWM-Bits der 32 LEDs
optimiert den Aufbau und Ablauf der Software.
Die 32 LEDs (10 * 3 + 2) sind an den Portbits
angeschlossen wie in der Grafikare gezeigt. Während der PWM-Zyklen
werden eingeschaltete LEDs mit einer Eins, ausgeschaltete mit einer
Null belegt. Diese Bits schalten die Richtungstreiber DDcn an und aus.
Das ermöglicht den Betrieb mit gemeinsamer Anode (PORTcn = 0)
ebenso wie mit gemeinsamer Kathode (PORTcn = 1).
Diese Organisation der Register wurde gewählt, damit man nicht
für jede der 11 LEDs eigene Routinen schreiben musste. Da jeweils
drei Farben pro LED anzusteuern sind, liegen die Farben B, G und R
jeweils an spezifischen Orten im Byte, teils überlappend.
Für den Betrieb der PWMs sind zwei Registersätze nötig:
- R3:R2:R1:R0 speichert den Zustand der PWM-Ausgänge zu Beginn
jedes PWM-Zyklusses. Das ist nötig, da jede Farbkombination
acht Mal abgearbeitet werden muss. Diese vier Register
überschreiben den Wert der vier Ausgaberegister mit jedem
PWM-Zyklusstart. Zu Beginn der Minute ist nur die grüne LED
eingeschaltet, die blaue und rote wird erst hinzu eingeschaltet
wenn deren Wert in rBlue bzw. rRed mindestens Eins
ist.
- R7:R6:R5:R4 enthält den Zustand im Laufe des PWM-Zyklusses.
Die jeweilige blaue, grüne bzw. rote LED werden darin
ausgeschaltet, wenn ihr Vergleichswert erreicht wird.
hold the current condition at each PWM step. Diese vier Register
werden an die Richtungsports der vier LED-Ports ausgegeben.
4.5.3 CTC-Zugriff auf die PWM-LED-Bits
Der Zugriff auf die einzelnen Farbbits der 11 LEDs erfolgt etwas
eigenartig, damit das Schreiben von 11 Routinen vermieden werden kann.
Der Zugriff erfolgt mit zwei Zeigern:
- Das Doppelregister YH:YL zeigt auf dasjenige Register, in dem
sich die blaue LED der aktuellen Minute befindet. Zu Beginn zeigt
Y auf Null. Mit entsprechendem Zeitfortschritt zeigt es auf 1, 2
oder 3.
- Das Register rBB enthält eine binäre Eins an
derjenigen Stelle, an der sich die blaue LED der aktuellen Minute
befindet und ist ansonsten Null. rBB wird dreifach nach
links verschoben, wenn die nächste LED angesteuert werden
soll (z. B. wenn eine Minute um ist). Immer dann, wenn beim
Linksschieben eine Eins im Carry landet, muss
- der Zeiger Y um Eins erhöht werden, und
- das Carry-Bit mit ROL rBB in Bit 0 wieder eingeschoben
werden.
Der Quellcode für dre mal links schieben sieht dann so aus:
lsl rBB ; Einmal links schieben
brcc CNoBlue ; Kein Carry
inc YL ; Zeiger auf naechstes Byte
rol rBB ; Carry in Bit 0
CNoBlue:
lsl rBB ; Zweites Mal links schieben
brcc CNoGreen ; Kein Carry
inc YL ; Zeiger auf naechstes Byte
rol rBB ; Carry in Bit 0
CNoGreen:
lsl rBB ; Drittes Mal links schieben
brcc CNoRed ; Kein Carry
inc YL ; Zeiger auf naechstes Byte
rol rBB ; Carry in Bit 0
CNoRed:
Auf diese Weise sind alle Bits zugänglich. Es ist nur
sicherzustellen, dass beide Zeiger immer auf die aktuelle blaue
Minuten-LED zeigen. Die beiden Zeiger ersetzen also Sekunden- und
Minuten-Zähl-Register.
Das Setzen des aktuellen blauen Bits auf Eins im
PWM-Startregister-Satz geht dann so:
ld r,Y ; Lese Inhalt des Registers mit dem aktuellen blauen Bit
or r,rBB ; OR mit dem aktuellen blauen Bit
st Y,r ; Zuruekschreiben des Ergebnisses in das blaue Register
Soll das akuelle blaue Bit im Arbeits-Register-Satz ausgeschaltet
werden (z. B. wenn Gleichheit mit dem rPwm-Wert erreicht wird),
geht das so:
ldd r,Y+4 ; Lese Inhalt des blauen Arbeitsregisters (4 Byte Versatz)
eor r,rBB ; EXOR mit dem blauen Bit
std Y+4,r ; Zurueckschreiben in das blaue Arbeitsregister
Mit LDD kann Y nicht nur auf die vier untersten Byte zugreifen
sondern auch auf die genau vier Byte höhere Adresse im
Arbeitsregister. Der Unterschied zwischen LD und LDD ist kaum
merklich, LDD braucht genausoviel Taktzyklen wie LD auch (zwei).
Die Interrupt-Service-Routine kann je nach den anstehenden
Aufgaben länglich sein. Daher wurde entschieden, die
Ausgabe an den Beginn zu legen, dann erfolgt sie immer zum
gleichen Zeitpunkt und ist unabhängig davon, wie lange
Verzweigungen andauern. Außerdem ist sicherzustellen,
dass alle Verzweigungen nicht länger als
240 Taktzyklen benötigen, weil sonst die Gefahr
besteht, dass der CTC-Interrupt verpasst würde.
Die Software verbringt 89% der Zeit im Sleep-Modus, es ist
daher sinnvoll, diesen Modus zum Batteriesparen einzuschalten.
4.5.4 Ein normaler CTC-PWM-Zyklus: Farbvergleich
So (siehe rechts) sieht ein normaler PWM-Schritt aus. Es
beginnt mit der Ausgabe der vier Register auf die vier
Richtungs-Ports. Dann wird der PWM-Zyklus-Zähler
rPwm erhöht. Wenn dieser Null erreicht, geht
es mit einer anderen Routine weiter (siehe unten). Ist das
nicht der Fall, werden nacheinander die drei Farben
überprüft. Bei blau geht das mit den aktuellen
Zeigern Y und rBB. Bei grün muss der
Zeiger einmal links geschoben werden, bei der roten zwei
Mal. Zum Ende muss der Zeiger wieder auf blau zeigen, also
zwei Mal rechts geschoben werden.
Im Flussdiagramm wurden die Anzahl Taktimpulse hinzugefügt.
Insgesamt würden 57 Taktzyklen benötigt, wenn alle
Schiebereien mit gesetzten Carry-Bits laufen würden. Minimal
dauert es 41 Taktzyklen, wenn keine LED zu schalten ist und
kein Carry auftritt. Das entspricht zwischen 17 und 24% der
verfügbaren Takte bis zum nächsten CTC-Interrupts.
4.5.5 Wiederholungen des PWM-Zyklus
Wie oben beschrieben wird der PWM-Zyklus acht Mal wiederholt.
Dieser Teil der CTC-ISR erledigt das. Sie zählt den Zähler
abwärts, ist er nicht Null, werden die vier Startwerte über
die Arbeitsregister kopiert. Wenn der nächste CTC-Interrupt
zuschlägt, wird diese Kombination an die Ports ausgegeben.
Ist der Zähler Null, ist die nächste Farbkombination dran,
siehe unten.
Der Widerholungsteil ist kürzer als der Vergleichsteil. Aber
da dieser nur bei jedem 256sten Durchlauf bearbeitet wird, macht
dieser kurze Teil nicht viel am gesamten Zeitablauf aus.
4.5.6 Die nächste Farbe
Sind acht PWM-Zyklen mit denselben Blau-, Grün- und Rot-Werten
durchlaufen, dann sind sowohl rPwm als auch rPCnt
bei Null. Daher wird rPCnt wieder mit 8 neu gestartet. Ist
gerade die Stop-Flagge gesetzt und die Uhr angehalten, wird einfach
der Anfangszustand geschrieben.
Ist die Stop-Flagge nicht aktiv, kommt die nächste Farbe dran.
Das bedeutet, dass abhängig von der Farbphase
- in Phase 1 der Grünanteil um Eins vermindert und der
Blauanteil um Eins erhöht wird, oder
- in Phase 2 der Blauanteil um Eins vermindert und der
Rot-Anteil um Eins erhöht wird.
In beiden Fällen ist die entsprechende neue Farbe (blau in
Phase 1, rot in Phase 2) im PWM-Start-Register einzuschalten. Das
macht man mit einem binären ODER von rBB an der Adresse Y
(blau) bzw. mit dem zweifach links auf rot verschobenen rBB.
Natürlich ist beim Linksschieben wieder auf gesetzte
Carry-Flaggen zu achten.
Wenn beim Erhöhen bzw. Erniedrigen der Farbwerte Null erreicht
wird, wird in Phase 1
- die Phasenflagge gesetzt und Phase 2 eingeleitet, und
- die grüne LED im Startregister-Set gelöscht,
dazu wird rBB einmal links geschoben und das Bit mit EOR
ausgeschaltet, und
- rBB einmal rechts geschoben und damit wieder auf die
blaue LED eingestellt.
In Phase 2 wird beim Erreichen von Null die nächste LED
angesteuert (siehe das folgende Kapitel).
Die gesamte Routine braucht zwischen 29 und 50 Takte und
ist dauert etwa so lange wie auch der Farbvergleich.
4.5.7 Die nächste LED
Wenn der Ablauf in Phase 2 beim Erhöhen/Erniedrigen der
Farben eine Null herauskommt, ist eine Minute vorbei und
wird die nächste LED angesteuert.
Das Umschalten auf die nächste LED ist am Beispiel des
Übergangs von LED3 auf LED4 gezeigt. KED3 befindet
sich mit der blauen und grünen LED in der linken Seite
von R0 (bzw. R4) und mit der roten LED im Bit 0 von R1
(bzw. R5).
Die Schritte sind folgende:
- zuerst wird die Phase-2-Flagge gelöscht, da es jetzt
wieder mit Phase 1 weitergeht,
- dann wird die aktuelle blaue LED im Startregister-Set
gelöscht, die rote LED wird nicht gelöscht und
bleibt an (sie wird erst beim nöchsten LED-Zyklus
gelöscht),
- dann wird geprüft, ob die letzte LED, LED11, aktiv
ist. Das ist der Fall, wenn
- Y auf 3 steht, und
- wenn rBB 32 ist (= Bit 5).
Wenn beides der Fall ist, wird die Uhr abgeschaltet, was
folgendes zur Folge hat:
- die LED11 wird auf rot geschaltet,
- der Timer TC0 und seine Interrupts werden
abgeschaltet,
- die Bedingungen für den Neustart werden eingestellt,
(Y=0, rBB=1) zeigen auf den Beginn des Start-Sets, und
- die Stop-Flagge wird gesetzt.
- Wenn Y=3 ist und die LED10 aktiv ist (rBB ist bei 8 bzw. hat
Bit 3 gesetzt), dann
- wird rBB auf das rote Bit von LED10 eingestellt (LED11 hat
kein blaues Bit), und
- wird das grüne Bit von LED11 eingeschaltet.
Dann springt dieser Zweig zu der Routine mit dem Kopieren des
Startregister-Sets über den Arbeitsregister-Set.
- Wenn Y=3 ist und weder LED10 und LED11 aktiv ist, wird die
nächste grüne LED direkt aktiviert. Dazu wird rBB
vier Mal links geschoben, das gr&uul;ne Bit aktiviert und
die Kopierroutine absolviert.
- Derselbe Ablauf mit vier Mal links schieben und grün
anschalten wird auch dann absolviert, wenn entweder
- das Löschen der älteren roten LEDs
unterdrückt ist, oder
- LED1 aktiv ist (YL=0 und rBB bei 1).
In beiden Fällen wird die vergangene rote LED nicht
ausgeschaltet und direkt zum Setzen der nächsten
grünen LED verzweigt.
- Wenn Y nicht 3 ist, wenn das Löschen nicht ausgeschaltet
ist und wenn LED1 nicht aktiv ist, dann wird durch Rechtsschieben
von rBB das rote Bit der vorherigen LED angesteuert und mit EOR
ausgeschaltet. Danach wird rBB um fünf Stellen nach links
geschoben (jeweils mit Carry-Prüfung) und die grüne
LED einschaltet.
- rBB wird nach dem Anschalten der grünen LED um eine
Stelle nach rechts auf die blaue LED geschoben. Dann werden die
Einstellungen im Startregister-Set über die Arbeitsregister
kopiert und die Routine mit RET beendet.
Die gesamte Routine benötigt je nach den Verzweigungen zwischen
48 und 97 Taktzyklen. Da sie nur einmal pro Minute ausgeführt
wird, spielt sie keine Rolle für den Gesamtstrombedarf. Die 97
Taktzyklen begrenzen allerdings die Mindest-Taktrate des Prozessors.
Die Default-Rate mit 1 MHz Takt reicht dafür nicht aus. Es
könnte trotzdem funmktionieren, da der nächste CTC-Int
kürzer ist und nur der Schreibtakt des ersten CTC nach der
LED-Umschaltung etwas verspätet beginnt.
4.5.8 Gemeinsame-Kathoden-LEDs?
Die gesamte Software kann so bleiben wie sie ist, wenn LEDs mit
gemeinsamer Kathode verwendet werden sollen. Dazu müssen
zu Beginn alle Portregister PORTcn (mit c = A..D und n = 0..7)
auf Eins gesetzt werden. Die internen Pull-Ups, die mit dieser
Einstellung eingeschaltet werden, wenn DDcn auf Null steht,
machen nichts aus, da sie nur maximal 60 µA durch
die LEDs fliessen lassen. Das ist zu wenig, um sichtbar zu sein.
Natürlich muss die Hardware dann anders aussehen: alle mit
Plus verbundenen Anoden müssen als Kathode an Minus und die
gedruckte Schaltung entsprechend ge&aum;ndert werden.
4.6 Wie die Sound-Ausgabe funktioniert
4.6.1 TC1 als Tongenerator
Um Töne zu erzeugen, wird TC1 im CTC-Mode betrieben,
mit dem Compare-A-Portregister als Rücksetzwert.
Compare B wird auf Null oder 1 gesetzt und schaltet den
OC1B-Ausgang: ist der Ton angeschaltet, dann wird dieser
auf Torkeln eingestellt, ist er aus, dann wird er auf
Clear geschaltet.
Die Zeitdauer, über die der Ton angeschaltet bleibt,
wird im Registerpaar R25:R24 eingestellt. Dieses wird mit
16 Bits dekrementiert. Erreicht es Null, dann wird
- die Flagge bSound gelöscht, und
- der OC1B-Pin auf Clear gesetzt.
Der Compare-Match-Interrupt bleibt aktiv, allerdings
schaltet die Flagge auf eine andere Betriebsart um (siehe
unten).
Beim höchsten Ton, a6 mit 14,080 kHz,
beläuft sich die maximale Tondauer auf 2.3 s,
beim niedrigsten, A1minor mit 55 Hz, kann
der Ton bis zu 596 s andauern.
4.6.2 Die Tonleitertabelle
Um angenehme Töne zu produzieren, ist eine Tonleiter
in die Software integriert. Die Tonleitertabelle
GamutTable: besteht aus zwei Worten für jeden
Ton. Das erste Wort gibt den CTC-Teilerwert mit dem MSB
zuerst an (da das MSB als erstes in OCR1AH geschrieben
werden muss). Das zweite Wort gibt den Zälwert an,
für den der Ton anbleiben muss, um eine Sekunde lang
zu dauern, was die Frequenz mal zwei ist.
Alle Oktaven von A1minor über
Aminor und a0 bis g7 sind
in der Tabelle enthalten.
Im Quellcode bestimmt die Konstante cOctave, aus welcher
Oktave die auszugebenden Töne stammen sollen. Sie kann
zwischen -2 und +6 eingestellt werden. -2 startet mit
A1minor oder 55 Hz. Jede Minute wird ein
Ton höher ausgegeben, -2 erstreckt sich daher bis
zum Ton e (165 Hz). -1 beginnt mit Aminor
mit 110 Hz und geht bis e1 (330 Hz).
a2 als Startwert mit 880 Hz ist die
Default-Einstellung (cOctave=2).
Das Registerpaar ZH:ZL zeigt jeweils auf die aktuelle
Tonleiter-Position in der Tabelle. Wenn die Flagge
bPlay gesetzt ist, beginnt die Tonausgabe an dieser
aktuellen Position.
Die Tonleiter-Tabelle ist im Blatt sound in der
LibreOffice-Tabelle hier
zugänglich. Durch Markieren und Kopieren der Spalte
Assembler-Quellcode kann der Quellcode der Tabelle
in den Quellcode übernommen werden. Da die Tabelle
mit der Taktrate 4,194304 MHz erstellt wurde, ist
sie bei einer anderen Taktrate entsprechend umzurechnen
und zu überschreiben.
4.6.3 TC1 als Soundchecker
Wenn kein Ton aktiv ist, dient TC1 als Erkenner für
gesetzte bPlay-Flaggen. Dazu ist alle 1 ms
der CTC-Interrupt aktiv, der für eine voreingestellte
Zeit lang abwärts zählt. Ist er Null, wird
die Flagge bPlay abgefragt. Ist diese gesetzt, wird
die Tonausgabe gestartet.
Ist der Ton zu Ende gespielt, wird dieser Modus durch
Löschen der Flagge bSound wieder eingestellt.
Dieses Projekt zeigt, dass
- es möglich ist, eine Dreikanal-PWM mit
8 Bits Auflösung per Software zu realisieren,
- und das für 11 verschiedene LEDs, die alle
einzeln in ihren drei Farben ansteuerbar sind,
- die PWM-Frequenz mit augenfreundlichen 68 Hz
schnell genug ist,
- im Unterschied zu Timer-PWMs jeder Prozessorausgang
als PWM-Pin verwendbar ist,
- es möglich ist dies alles mit einem Prozessortakt
von weniger als 2 MHz zu realisieren,
- exaktes Timing kein Hexenwerk sondern Ergebnis
sorgfältiger Planung ist,
- mit der Nutzung sehr AVR-spezifischer Instruktionen
wie LD/ST und LDD/STD auf Register sehr elegant, flexibel
und einfach programmiert werden kann.
Das zeigt ferner die sehr klaren und eleganten
Möglichkeiten der Assembler-Programmierung auf.
Keine andere Programmiersprache eröffnet solche
Möglichkeiten für exaktes Timing. Versuche
das insbesondere nicht mit C, Du kriegst nur graue Haare
davon.
Ähnliche Projekte:
# | Uhrentyp und Link | LEDs | Audio | AVR-Typ |
1 |
Eieruhr mit 10 LEDs/Melodien |
10 Niedrigstrom, PWM |
Musiknoten, 10 Melodien |
ATtiny24 |
2 |
Eieruhr |
8 rot/grün, PWM |
Musiknoten, 8 Melodien plus Tonleiter |
ATtiny24 |
3 |
Eieruhr |
8 rot/grün, PWM |
Eine Melodie, Einton-Piepsen |
ATmega8 |
4 |
RGB-Eieruhr |
11 RGB, PWM |
Nur Musiknoten, keine Melodien |
ATmega8515 |
5 |
Eieruhr |
10 rot/grün |
Einton-Piepsen |
ATtiny2313 |
Lob, Tadel, Fehlermeldungen, Genöle und Geschimpfe oder Spam bitte über
das Kommentarformular an mich.
©2019-2022 by http://www.avr-asm-tutorial.net