Hallo,
bin vor kurzem auch in den Genuss bekommen, mit Mikrocontrollern
rumbasteln zu dürfen. Habe mir ein paar ATtiny13's gegönnt, da diese
relativ günstig sind, aber für den Anfang meines Erachtens völlig
ausreichen.
Zuerst habe ich ein paar einfache Programme in C - welches ich schon
teilweise behersche - geschrieben. LEDs blinken und so, nichts
komplexes.
Aber ich habe mir gedacht, dass ich mir Assembler wenigstens mal
angucken kann. Einfache Dinge, wie ein paar LEDs zum Blinken bringen,
gingen hier auch - bis ich zu den Interrupts kam.
Der Aufbau des ATtinys ist richtig, aber irgendwie blinken die LEDs
nicht, wie sie sollten, sondern leuchten.
Da ich unter Linux arbeite, kann ich leider nicht in den Genuss eines
simulierenden AVR-Studios kommen. Ich hoffe, ihr könnt mir trotzdem
helfen.
An den Fuses habe ich nichts verstellt, der Tiny läuft also mit internem
Takt und so.
Du musst schnelle Augen haben :-)
Rechne doch mal nach mit welcher Frequenz deine LED 'blinken' :-)
(Beim Drüberschauen ist mir nichts aufgefallen, Pgm sieht auf die
Schnelle gut aus. Nur das Timing eben)
Hallo,
habe nur schnell rübergeschaut:
Prescaler auf 1, also läuft der Timer mit dem AVR-Takt.
Overflow-IRQ, also eine volle Runde -> 256 macht rund 4700Hz.
In der Interruptroutine zählst Du 5 Durchläufe, also schalten die LEDs
mit knapp 1000Hz.
Hast Du so schnelle Augen???
ÜS: grrr... wieder zu langsam... ;)
Gruß aus Berlin
Michael
Du vergleichst leds, gibst aber temp aus. leds wird aber nirgends
geändert. Deshalb kann auch nur einmal was passieren. Wozu zwei
Variablen? temp wird überhaupt nicht gebraucht.
Das Toggeln der LEDs geht übrigens wesentlich kürzer und einfacher mit
einem Einerkomplement (com) der LED-Zustände.
Also anstatt
1
[...]
2
ldi i, 0
3
cpi leds, 0xFF
4
brne leds_sind_an
5
breq leds_sind_aus
6
7
leds_sind_an:
8
ldi temp, 0x00 ; Ausschalten.
9
out PORTB, temp
10
reti
11
12
leds_sind_aus: ; Anschalten.
13
ldi temp, 0xFF
14
out PORTB, temp
15
reti
16
[...]
einfach
1
[...]
2
com leds ;leds invertieren
3
out PORTB, leds ;Zustände ausgeben
4
reti
5
[...]
In leds steht immer der aktuelle Zustand der LEDs. Der wird bei
Erreichen des Zählerstandes invertiert (dazu muss nur am Anfang einmal 0
oder 0xFF drin stehen). Wenn nicht alle Pins geändert werden sollen,
geht es mit einem eor (Exklusiv-ODER) mit einer entsprechenden
Bitmaske. Wenn nur die 4 LSB gesetzt werden sollen, dann
Michael U. wrote:
> Hallo,>> igitt... na ein Glück, daß nicht nur ich das übersehen habe... ;-)))>
:-)
Yep. Mit dieser ganzen unnützen Branch-Orgie in dieser ISR wird man ganz
schwumrig.
peda, deinen Einwand verstehe ich nicht ganz.
led wird ja nur einmal, und zwar in main, auf 0xFF gesetzt, danach ist
der Status ja abhängig vom Blinkstand der LEDs.
Habe das ganze nach euren Vorschlägen nochmal überarbeitet (war mir da
mit der Blinkfrequenz passiert ist, weiß ich selber nicht :-)) und
angehängt.
Eigentlich müsste das funktionieren, tut es aber nicht :/
"Mach mal aus den beiden "breq" jeweils ein "rjmp"."
Habe ich einfach mal gemacht, aber noch nichts so ganz verstanden,
wieso? Wäre nett, wenn du das nochmal eräutern könntest :)
Dass ich leds verändert, aber temp ausgegeben habe, war ebenso ein
Fehler, aber auch nach Korrektur mag es noch nicht so, wie ich es will
;D
Wie gesagt, ich bin blutiger Assembleranfänger. Über weitere
Lösungsansätze würde ich mich selbstverständlich sehr freuen :)
Hi
1. Eine Interruptroutine sollte nur ein 'reti' haben.
2. Schleifenzähler besser nach unten zählen. dann reicht:
dec rXY
breq abcd -> wenn Null
->wenn nicht Null
3. ' cpi leds, 0xFF' kannst du dir sparen, wenn du ein anderes
Register mit $FF lädst und 'eor leds,Register' machst.
4. In Interruptroutinen immer SREG sichern. Nichtbeachtung bringt
lustige Effekte.
5......
Keine Lust mehr
MfG Spess
Ein Überlauf des Timers tritt erst dann auf, wenn der Timer einmal
durchgezählt hat, und das ist bei einem 8-Bit-Timer nach 256 Timertakten
der Fall. Das gibt bei den Einstellungen etwa 3,8 Überläufe pro Sekunde,
was mit dem Zählen bis 100 ungefähr 26 Sekunden dauert, bis sich was
tut.
Und bitte benutze auch hier die Namen der Steuerbits, wie es in
Bitmanipulation beschrieben ist!
Und warum hast Du meinen Vorschlag oben ignoriert und die ganze
unsinnige Abfragerei stehen gelassen?
spess53 wrote:
> So in etwa könnte das aussehen.
Man muß ja nicht so umständlich programmieren, wie ein dummer
C-Compiler.
Reserviere ein low-Register fürs SREG sichern. Da es keine
Interruptprioritäten gibt, reicht ein Register für alle Interrupts.
Reserviere etwa 4 high Register und den Y-Pointer als Scratchpad für
Interrupts.
Dann ist in der Regel in Interrupthandlern kein PUSH/POP nötig.
Peter