Hallo, beim megaAT16 habe ich folgendes Problem: Sobald der Befehl SEI() aufgerufen wird, springt das Programm zurück auf den Reset Vektor. Die nachfolgende while-Schleife wird nie erreicht. Der Dissassembler zeigt ebenfalls nachdem sei-Befehle einen jump auf Adresse 0x0000 - also Reset an. Was mache ich hier falsch? Hier ein Auszug des Listing #include <avr/io.h> #include <avr/interrupt.h> #include <stdlib.h> #include <util/delay.h> #include <string.h> #include "USART.h" #define F_CPU 16000000 #define USART_BAUD_RATE 19200 #define USART_BAUD_SELECT (F_CPU/(USART_BAUD_RATE*161)-1) volatile uint16_t counterNew, counterOld; char frequency_ascii[6], newDigit, oldDigit; char zeichenspeicher[35],Ziffer[6], TransFlag, repetition[4], sequence[6]; unsigned char Blockzaehler=0, Resetzaehler=0, n, Zeichenzaehler, BurstCounter, Flag; int main(void) { MCUCSR &= ~(1<<ISC2); //INT2 reagiert auf fallende Flanke MCUCR &= ~(1<<ISC11); //INT1 löst bei Low-Pegel aus MCUCR &= ~(1<<ISC10); MCUCR &= ~(1<<ISC01); //INT0 löst bei Low-Pegel aus MCUCR &= ~(1<<ISC00); GICR |= (1<<INT2); //Aktiviere INT2 USART_Init(51); TCCR1B |= (1<<CS11); //Counter1-Prescaler auf 8 TIMSK |= (1<<TOIE0); //Aktiviere Timer0 Overflow Interrupt TCCR0 &= ~((1<<CS01) | (1<<CS00)); //Stoppe Timer0 TCCR2 |= (1<<CS22) | (1<<CS21) | (1<<CS20); // Timer2 Prescaler auf 1024 TIMSK |= (1<<TOIE2); //Aktiviere Timer2 Overflow Interrupt sei(); //Aktiviere Interrupts while (1) { if (Flag == 1) { Flag = 0; Zeichenzaehler=0; n=0; Blockzaehler=0; } } }
Was soll der Interrupt denn erledigen. Hier fehlt die entsprechende Routine.
Der externe Interrupt soll Frequenzen messen und dazu die Zeit zwischen den Flanken auswerten. Aber soweit kommt das Proigramm nicht, da es in der main-loop ständig zwischen int main (voit) und sei() kreist. Zur Info die Interrupt-Routine ISR(INT2_vect) { uint16_t frequency, diffe; counterOld = counterNew; counterNew = TCNT1; diffe = counterNew - counterOld; frequency = F_CPU / (diffe * 8); diffe = 1; TCNT0 = 0x00; // Timer löschen TCCR0 |= (1<<CS01) | (1<<CS00); //Timer 0 starten if (frequency > 1020 && frequency < 2660) { auswertung(frequency); } }
> TIMSK |= (1<<TOIE2); //Aktiviere Timer2 Overflow Interrupt
Die ISR dafür fehlt und das ist ein Resetgrund. Den Rest habe ich nicht
angesehen.
Danke, ich hatte das Programm zur Fehlersuche weitestgehend abgespeckt, aber nach hinzufügen der ISR ISR(TIMER0_OVF_vect) { int i; TCCR0 &= ~((1<<CS01) | (1<<CS00)); //Stoppe Timer0 for (i=0; i<=5; i++) { while (!( UCSRA & (1<<UDRE))) // warte, bis UDR bereit ; } Zeichenzaehler=0; n=0; Blockzaehler=0; } ist das Ergebnis unverändert. Was mich an der ganzen Geschicht stört ist der Dissassembler. Warum generiert er einen RJMP auf 0x0000 also auf Reset??? Das macht er immer, egal wo ich den Befehl in der main-loop einbaue! Ist irgendetwas an der Initialisierung der megaAT16 zu besonders zu beachten? Dies ist mein erstes Projecht mit diesem Rechner - bisher nur Erfahrung mit 6800 un 8051 Derivaten. 57: TIMSK |= (1<<TOIE2); //Aktiviere Timer2 Overflow Interrupt +000001A8: B789 IN R24,0x39 In from I/O location +000001A9: 6480 ORI R24,0x40 Logical OR with immediate +000001AA: BF89 OUT 0x39,R24 Out to I/O location 59: sei(); //Aktiviere Interrupts +000001AB: 9478 SEI Global Interrupt Enable +000001AC: CFFF RJMP PC-0x0000 Relative jump @000001AD: USART_Init ---- USART.c ------------------------
>+000001AC: CFFF RJMP PC-0x0000 Relative jump
Das ist ein relative Jump auf PC-0x0000 (Programm Counter minus
0x0000), d.h. eine Endlosschleife.
"Flag" wird nie 1 -- der Compiler hat es wegoptimiert! Könntest Du Deinen Code bitte innerhalb eines
1 | [c]..[/c] |
Blocks einstellen (anstelle ihn als reinen Text einzubinden)?
Wolfgang schrieb: > while (1) > { > if (Flag == 1) > { > Flag = 0; > Zeichenzaehler=0; > n=0; > Blockzaehler=0; > } > } Weil "Flag" nie auf 1 gesetzt wird, hat der Compiler (korrekterweise) die ganze while-Schleife zu einer einfachen Endlosschleife optimiert. Und wozu "Zeichenzaehler", "n" und "Blockzaehler" immer nur auf 0 gesetzt werden, ist mir unklar. Was Du vermeiden solltest, ist die Warterei in der ISR: Wolfgang schrieb: > while (!( UCSRA & (1<<UDRE))) // warte, bis UDR bereit > ;
Das mit der Warterei in der ISR ist mir bekannt, wurde nur für Testzwecke eingebaut. Das Problem ist der Befehl "sei()" in der main-loop. Sobald, und das ist im single stepp reproduzierbar, dieser Befehl ausgeführt wurde, wird der Programmablauf unterbrochen und startet wieder am Anfang. Verschiebt man den Befehl "sei()" an eine (jede) beliebige Stelle in der loop, so wird auch hier jedesmal das Programm abgebrochen.
Die > ISR(TIMER0_OVF_vect) für > TIMSK |= (1<<TOIE0); //Aktiviere Timer0 Overflow Interrupt ist jetzt vorhanden. Aber wo ist ISR(TIMER2_OVF_vect) für > TIMSK |= (1<<TOIE2); //Aktiviere Timer2 Overflow
Danke für die guten Ratschläge. Das Problem hat sich zwischezeitlich gelöst. Ursache war die leere while-Schleife in der main-loop. Im Laufe der weiteren Verabeitung habe ich diese durch eine If-Schelife ersetzt, in der ein Bit bei jedem Durchlauf getoggelt werden mußte. Seit dem läuft das Programm problemlos. Nochmals Allen vielen Dank für die Hilfe. Wolfgang
Leer ewhile Schleife als Problem? Wude die wegoptimiert? Das sollte doch eigentlich nicht passieren. Welchen Optimierrungsfaktor hast du denn eingestellt?
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.