Hallo allerseits, obwohl ich die hier im Forum vorzufindenden Tutorials und das ATMega32 Datenblatt zu Rate gezogen habe, gelingt es mir einfach nicht, einen Timer-Overflow für den ATMega32 in Assembler zu erzeugen. Im beiliegenden Code wird nach der Initialisierung der Ports und Variablen eine LED eingeschaltet (das funktioniert noch). Dann soll ein Timer2-Overflow nach 4ms eine Zählvariable bis 250 hochzählen und so nach 1s die LED wieder löschen. Das funktioniert leider nicht mehr. Irgendwas muss ich noch übersehen haben, sonst würde es funtionieren. Hat jemand eine Idee? Thomas
OHne jetzt alle Pfade verfolgt zu haben, fehlt dir auf jeden Fall hier
1 | clr msCount ; Schleifenzähler löschen |
2 | ; |
3 | sei ; Interrupt enable |
4 | ; |
5 | TIM2_OVF: ; sollte alle 4ms erfolgen |
6 | push TEMP |
erst mal die Hauptschleife, in der der Prozessor die Zeit über Däumchen dreht, bis der Interrupt kommt
1 | clr msCount ; Schleifenzähler löschen |
2 | ; |
3 | sei ; Interrupt enable |
4 | |
5 | loop: ; * Hauptschleife |
6 | rjmp loop ; * |
7 | |
8 | ; |
9 | TIM2_OVF: ; sollte alle 4ms erfolgen |
10 | push TEMP |
Der Interrupt läuft auf ein reti, da dort alle Adressen falsch sind - Faktor 2.
1 | .equ TIMERwert = 256-250 ; für 4ms Timer bei 16MHz Takt und internem Prescaler 1/256 |
die Berechnung stimmt nicht. Das geht sich nie aus. Bei 16000000Mhz und einem Vorteiler von 1 würde der Timer in 1 Sekunde 16000000 Zählvorgänge machen. Bei einem Vorteiler von 256 logischerweise dann nur noch 1/256-tel davon. Wieviel ist das? Nun, das ist 16000000/256 gleich 62500 Zählvorgänge in der Sekunde. D.h. für 1 Zählvorgang braucht der Timer daher 0.000016 Sekunden. Für 6 Zählvorgänge (von 250 bis 256) braucht er daher 6 mal so lange. Das sind 0.000096 Sekunden. Das sind aber nicht 4ms sondern das sind 0.096 Millisekunden. Wenn alle 0.096 Millisekunden ein ISR Aufruf statt findet, dann dauert es daher 250 mal so lange, bis dein Zählregister den Wert 250 erreicht hat. Das ist daher nicht nach 1 Sekunde der Fall, sondern nach 0.024 Sekunden - etwas mehr als 2 Hunderstelsekunden. Immer unter der Voraussetzung, dass der Rest des Programms stimmt (nachdem du die Sache mit der Hauptschleife korrigiert hast). Hast du es mal unter Simulator-Kontrolle laufen lassen? Da kann man die Register wunderbar verfolgen und zusehen, was passiert. Ausserdem: Meag32 und Progbleme mit dem Port C. Da lautet die Standardfrage sofort: hast du das JTAG abgeschaltet?
:
Bearbeitet durch User
die Interrupt Tabelle ist IMHO auch falsch
1 | ; |
2 | ; Interrupt-Sprungleiste für ATMeag32 |
3 | ; |
4 | rjmp RESET ; Reset Handler |
5 | reti ;rjmp EXT_INT0 ; IRQ0 Handler |
6 | reti ;rjmp EXT_INT1 ; IRQ1 Handler |
7 | reti ;rjmp EXT_INT2 ; IRQ2 Handler |
8 | reti ;rjmp TIM2_COMP ; Timer2 Compare Handler |
9 | rjmp TIM2_OVF ; Timer2 Overflow Handler (8 Bit Zähler) |
10 | reti ;rjmp TIM1_CAPT ; Timer1 Capture Handler |
11 | reti ;rjmp TIM1_COMPA ; Timer1 CompareA Handler |
12 | reti ;rjmp TIM1_COMPB ; Timer1 CompareB Handler |
13 | reti ;rjmp TIM1_OVF ; Timer1 Overflow Handler (16 Bit Zähler) |
14 | reti ;rjmp TIM0_COMP ; Timer0 Compare Handler |
15 | reti ;rjmp TIM0_OVF ; Timer0 Overflow Handler ( 8 Bit Zähler) |
16 | reti ;rjmp SPI_STC ; SPI Transfer Complete Handler |
17 | reti ;rjmp USART_RXC ; USART RX Complete Handler |
18 | reti ;rjmp USART_UDRE ; UDR Empty Handler |
19 | reti ;rjmp USART_TXC ; USART TX Complete Handler |
20 | reti ;rjmp ADC ; ADC Conversion Complete Handler |
21 | reti ;rjmp EE_RDY ; EEPROM Ready Handler |
22 | reti ;rjmp ANA_COMP ; Analog Comparator Handler |
23 | reti ;rjmp TWSI ; Two-wire Serial Interface Handler |
24 | reti ;rjmp SPM_RDY ; Store Program Memory Ready Handler |
25 | ; |
auf einem Mega32 liegen die Interrupt Vektoren, nicht wie auf einem Mega8 auf aufeinanderfolgenden Adressen, sondern auf jeweils geraden Adressen. Du kannst dir selbst das Leben um einiges einfacher machen, wenn du dich nicht auf die implizite Adressvergabe aufgrund der Anzahl der reti Befehle verlässt, sondern indem du dem Assembler die jeweilige Adresse, an der der reti zu positionieren ist, explizit mit einem .org angibst. Dazu hat Atmel jeweils passende Namen in das inc-File eingefügt
1 | ; |
2 | ; Interrupt-Sprungleiste für ATMeag32 |
3 | ; |
4 | rjmp RESET ; Reset Handler |
5 | .org INT0Addr |
6 | reti ;rjmp EXT_INT0 ; IRQ0 Handler |
7 | .org INT1Addr |
8 | reti ;rjmp EXT_INT1 ; IRQ1 Handler |
9 | .org INT2Addr |
10 | reti ;rjmp EXT_INT2 ; IRQ2 Handler |
11 | .org ... |
Ich weiss jetzt die Namen aller Interrupt Vektoren auch nicht auswenig. Aber du kannst dir das "m32def.inc" File aufmachen und dort reinschauen. Die müssen da drinnen alle irgendwo gesammelt vorkommen. Verwende sie in der angegebenen Art und Weise und du hast weniger Probleme.
Vielen Dank an alle für die schnelle und kompetente Hilfe. Es funktioniert jetzt! Neben der fehlenden Leerschleife war wohl die Interrupt-Sprungleiste die Ursache für das beschriebene Problem. Ich hatte bisher schon etwas mit dem ATmega8 experimentiert, und mir war auch aufgefallen, dass der ATMega32 mehr Interrupts als der ATmega8 hat, dass diese aber nur auf geraden Adressen liegen hatte ich übersehen. Die Timerkonstanten gemäß meiner Initialisierung scheinen aber zu stimmen, denn der Timer zählt doch nicht 6x 0,000016 Sekunden, sondern 250x 0,000016 Sekunden = 4ms; wenn ich den Timer mit 256-250 = 6 lade, zählt er doch bis 256 hoch und das sind 250 Impulse. Jedenfalls geht die LED erst sichtbar verzögert aus.
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.