Do 'Beginn Hauptschleife Toggle Led1 Waitms 500 Loop 'Ende Hauptschleife
End
Hallo,
seht Euch mal das Beispiel oben an. Was macht es? Genau, eine LED blinkt mit 1Hz. Mehr nicht. Schade eigentlich, weil während dem "Waitms 500" verbringt der µC fast 4 Millionen Takte mit nix tun.
Ich will Euch nun zeigen, wie man das besser macht. Das Mittel der Wahl nennt sich "Timer".
Ein Timer ist ein Zähler, der die Systemtakte mitzählt. Und das macht er von ganz alleine, unser eigentliches Programm läuft gleichzeitig weiter, weil der Timer in einer eigenen "Baugruppe" des µC verbaut ist. Die Atmels haben (fast) alle mehrere Timer. Wieviele sagt Euch das Datenblatt. Unser Atmega8 hat 3 Stück, die da heißen: Timer0, 1 und 2. Es gibt noch Unterschiede, wie weit die Timer zählen können: Timer 0 und 2 sind 8-Bit-Timer, können also von 0 bis 255 zählen, der Timer 1 hat 16 Bit, kann also von 0 bis 65535 zählen.
Als weiteres Gimmick kann man "Prescaler" einschalten. Diese Vorteiler bewirken, das nur jeder x-te Systemtakt den Timer weiterzählen läßt. Mögliche Prescaler beim Atmega8 sind 8, 64, 256 und 1024. Z.B. wird Prescaler 8 konfiguriert, zählt der Timer nur bei jedem 8ten Systemtakt weiter. Die neueren Atmels haben übrigends noch mehr Prescaler die feiner abgestuft und größer sein können -> Datenblett gucken!
Während dem Programmlauf kann jederzeit der aktuelle Zählerstand des Timers ausgelesen werden. Ist ein Timer voll, bspw. der Timer0 hat bis 255 gezählt, kann er einen "Interrupt" auslösen. Dadurch wird der aktuelle Programmablauf unterbrochen, ein definierter Programmteil wird abgearbeitet und nach Erledigung geht´s an der vorherigen Stelle weiter.
Keine Angst, sooo schlimm ist´s gar nicht :-)
Jetzt mal zu unserem Beispiel: wir wollen ein Timer so konfigurieren, daß er uns alle 500ms einen Interrupt auslöst. Unser Atmega8 rennt mit 8MHz, er macht also je Sekunde 8 Millionen Takte. Wir müssen jetzt also 4 Millionen Takte mitzählen. Ich nehm jetzt mal den Timer1, der bis 65535 zählen kann. Jetzt stellt sich die Frage, wie groß der Prescaler sein muß. Ich rechne kurz: 4000000 / 65536 = 61,03 Der Prescaler muß größer sein, wir nehmen also Prescaler = 64. Gegenrechnung: wir teilen die 4 Millionen Takte durch den Prescaler: 4000000 / 64 = 62500 Paßt. Die 62500 sind kleiner als die 65535, die unser Timer zählen kann. Ganz zufällig ist mit 62500 ein genauer Wert rausgekommen. Meist kommt dort eine Kommazahl raus, man muß sich dann entweder mit der daraus entstehenden Ungenauigkeit zufrieden geben oder man versucht durch Auswahl eines anderen Timers oder Prescalers genau hinzukommen.
Eine kleine Hürde haben wir jetzt noch. Der Timer kann nur einen Interrupt auslösen, wenn er voll ist, also bis an seine Grenze gezählt hat. Dies umgeht man so, in dem man den Timer nicht bei 0 zu zählen beginnen läßt, sondern ihn vorlädt. Bei wieviel? Wir rechnen wieder: 65536 - 62500 = 3036 Wir sagen also dem Timer am Programmanfang und jedesmal, wenn er wieder bei 0 anfangen will, das ist gleich nachdem er den Interrupt ausgelöst hat, daß er bei 3036 anfängt.
Hier die Umsetzung des oben beschriebenen in Bascom:
'*** Subs ********************************************************************** Timerroutine: 'Beginn Subroutine Timer1 = 3036 'Timer auf neuen Startwert einstellen Toggle Led1 Return 'Ende Subroutine
Der Code sollte jetzt eigentlich für Euch nachvollziehbar sein. Achtet bitte im Bereich "Timer konfigurieren" auf die richtige Schreibweise. Das "Enable Interrupts" wird gerne vergessen, bewirkt dann, daß keine Interrupts ausgeführt werden.
Und schaut genau hin: unser Hauptprogramm ist leer! Dort könnte irgend etwas anderes passieren.
Ihr seid´s dran !!!
Gruß Gerhard
------------------------------------------------------------------------------------------- hier mein aktueller TinyKatalog
Dateianlage:
Aufgrund eingeschränkter Benutzerrechte werden nur die Namen der Dateianhänge angezeigt Jetzt anmelden!
bek08.bas.txt
Ich zeig Euch, wie ich meine Blinkmuster erzeuge. Ich erzeuge mir mit einem Timer eine Zeitbasis, die mir in einem festen Intervall eine Variable hochzählt. In der Main-Loop frag ich dann nur noch die Variable ab und reagiere entsprechend. In dem Beispiel ist der Timer0 mit Prescaler 1024 und Vorladewert 100 konfiguriert. Das ergibt genau alle 20ms einen Interrupt. Dort wird dann die Variable hochgezählt und wenn diese den Wert 50 (entspricht 1 Sekunde) erreicht, wieder auf 0 gesetzt. In der Main-Loop setz ich dann nur noch den Ausgang entsprechend. Fertig. In der Main-Loop ist auch noch genügend Zeit für etliche andere Dinge.