Archiv verlassen und diese Seite im Standarddesign anzeigen : Probleme mit Timer0 Interrupt
Hey,
Ich hab schon den ganzen mittag ziemliche Probleme mit Timer0 eines Atmega32. Ich möchte eigentlich nur das bei jedem overflow ein Interrupt ausgelöst wird. Sobald ich aber Interrupts aktiviere resetet sich der Controller. Um diese Stelle geht es:
TCCR0 |= (1 << CS00) | (1 << CS01 ) ; // Timer0 initialisierung
TCCR0 &= ~(1 <<CS02 ); // Vorteiler ist 64
TIMSK |= (1<<TOIE0); // Interrupt aktivieren
init_USART();
sei();
wenn ich "sei()" oder "TIMSK |= (1<<TOIE0);" rausnehme funktioniert das Programm wie es soll, aber sobald beide da sind resetet sich der Controller. Ich habe bestimmt wieder was total einfaches übersehen und such nun schon ewig danach. Also wär gut wenn mal kurz jemand drüber sehen könnte, hier mein gesamter Testcode:
int main( void )
{
sendUSART(" test1 \r \n");
_delay_ms(1000);
TCCR0 |= (1 << CS00) | (1 << CS01 ) ; // Timer0 initialisierung
TCCR0 &= ~(1 <<CS02 ); // Vorteiler ist 64
TIMSK |= (1<<TOIE0); // Interrupt aktivieren
init_USART();
sendUSART("test2 \r\n");
_delay_ms(1000);
sei();
sendUSART("test3 \r \n");
_delay_ms(1000);
while( 1 )
{ // Endlosschleife
sendUSART("test4 \r \n");
_delay_ms(1000);
}
return 0; //wird nie erreicht
}
ISR(TIMER0_OVF_vect)
{
sendUSART("interrupt");
}
Mit dem Code bekomm ich im Hyperterminal immer nur "test1" und "test2" inner Endlosschleife angezeigt. Ich weis im moment nichtmehr weiter...
Gruß
elayne
Hubert.G
11.02.2008, 22:55
Nachdem dein Code nicht komplett ist, der Timer aber OK scheint, würde ich sagen das du ein Probelm mit dem UART hast. Du kannst z.B. nicht senden bevor du initialisiert hast.
Okey, stimmt. Habe ich übersehen. Aber wenn ich den ersten Sendebefehl rausnehme geht es auch nicht.
Hier ist nochmal die main.c
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/delay.h>
#include "usart.c"
#ifndef F_CPU
#define F_CPU 16000000L // Systemtakt in Hz, das L am Ende ist wichtig, NICHT UL verwenden!
#endif
volatile int32_t t,zahl;
int main( void )
{
TCCR0 |= (1 << CS00) | (1 << CS01 ) ; // Timer0 initialisierung
TCCR0 &= ~(1 <<CS02 ); // Vorteiler ist 64
TIMSK |= (1<<TOIE0); // Interrupt aktivieren
init_USART();
sendUSART("test2 \r\n");
_delay_ms(1000);
sei();
sendUSART("test3 \r \n");
_delay_ms(1000);
while( 1 )
{ // Endlosschleife
sendUSART("test4 \r \n");
_delay_ms(1000);
}
return 0; //wird nie erreicht
}
ISR(TIMER0_OVF_vect)
{
sendUSART("interrupt");
}
und die usart.c
/*### Senden per USART - RS232-Kommunikation ###*/
/*Zum senden von Zeichen im Hauptprogramm entweder
char irgendwas[] = "meintext";
sendUSART(irgendwas);
oder direkt
sendUSART("meinText");
verwenden.*/
void init_USART(void)
{
UCSRB |= (1<<TXEN); //UART TX (Transmit - senden) einschalten
UCSRC |= (1<<URSEL)|(3<<UCSZ0); //Modus Asynchron 8N1 (8 Datenbits, No Parity, 1 Stopbit)
UBRRH = 0; //Highbyte ist 0
UBRRL = 103; //Lowbyte ist 103 (dezimal) -> (Frequenz_in_Hz / (Baudrate * 16)) - 1 <- Quarfrequenz = 16*1000*1000 Hz!!!!
}
void sendchar(unsigned char c)
{
while(!(UCSRA & (1<<UDRE))) //Warten, bis Senden möglich ist
{
}
UDR = c; //schreibt das Zeichen aus 'c' auf die Schnittstelle
return 0;
}
void sendUSART(char *s) //*s funktiniert wie eine Art Array - auch bei einem String werden die Zeichen (char) einzeln ausgelesen - und hier dann auf die Sendeschnittstelle übertragen
{
while(*s)
{
sendchar(*s);
s++;
}
}
Die Uart routinen habe ich aus dem Wiki, und ohne Interrupt ging es bisher immer. Deswegen dachte ich da gibt es kein Problem. Aber mit dem jetzigen code bekomm ich im HyperTerminal nur "test2" fortlaufend angezeigt.
Gruß
elayne
[/code]
du musst ERST TIMSK setzen DANN TCCR, bei mri gabs zwar kein reset aber der timer verhielt sich merkwürdig
TCCR0 &= ~(1 <<CS02 ); kannste weglassen alles was nicht mit |= gesetzt wird ist sowieso 0!
Hubert.G
12.02.2008, 13:23
Die UART-Ausgabe dauert länger als der Timer0 OVL, setze einmal den Prescaler auf 1024.
Hey,
Denke für eure Hilfe erstmal.
Ich habe jetzt beides versucht, ich hab aber immer noch den blöden Fehler mit dem Reset. Vielleicht sollte ich mal erwähnen das ich ein RN Controll 1.4 verwende. Vor ein paar wochen hatte ich die selbe Schaltung auf einem Steckbrett aufgebaut und damals viel komplizierteres problemlos programmiert. Damals hatte ich noch einen Quarzoszillator, jetzt benuze ich den Quarz. Aber das können doch alles keine Gründe für so ein Phänomän sein.
Hier nochmal mein aktueller Code:
#include <avr/io.h>
#include <avr/interrupt.h>
#include <inttypes.h>
#include <avr/delay.h>
#include "usart.c"
#ifndef F_CPU
#define F_CPU 16000000L // Systemtakt in Hz, das L am Ende ist wichtig, NICHT UL verwenden!
#endif
int main( void )
{
TIMSK |= (1<<TOIE0); // Interrupt aktivieren
TCCR0 |= (1 << CS00 ) | (1 << CS02) ; // Timer0 initialisierung
TCCR0 &= ~(1 <<CS01 ); // Vorteiler ist 1024
init_USART();
sendUSART("test2 \r \n");
_delay_ms(1000);
PORTA = 0x00;
sei();
sendUSART("test3 \r \n");
_delay_ms(1000);
while( 1 )
{ // Endlosschleife
sendUSART("test4 \r \n");
_delay_ms(1000);
}
return 0; //wird nie erreicht
}
ISR(TIMER0_OVF_vect)
{
sendUSART("interrupt");
}
Im Uart gibt das wieder nur Test2 in einer Endlosschleife :(
Gruß
elayne
Hallo,
falls du eine Optimierung eingeschaltest hast, nimm die bitte erst einmal raus.
Edit: Dann musst du die delays auskommentieren.
Dann probier mal
sendUSART((char*)"interrupt");
hth
Jens
Hubert.G
13.02.2008, 18:24
Ich würde einmal sagen du hast da ein anderes Problem. Auf meinem STK funktioniert das einwandfrei.
Allerdings würde mich interessieren mit was du schreibst und kompilierst oder ist das noch immer nicht der komplette Code. Mein AVR-Studio lässt mir diesen Code ohne usart.h nicht zu.
Das _delay_ms(1000); funktioniert auch nicht, schau mal in die <util/delay.h> da steht das drinnen.
Dake erstmal für eure Tipps.
Also der Code ist komplett. Ich habe bloß eine main.c und eine Usart.c. Ich finde das auch komisch weil auf einem Steckbrett vor ein paar Wochen hat das ganze noch einwandfrei funktioniert. Ich verwende zum Programmieren Programmers Notepad. Ich habe jetzt nocheinmal ein anderes Testprogramm geschrieben. Komplett ohne Uart. Das Programm mach jetzt nurnoch einen Pieps mit dem Piepser auf dem Board. Dannach geht es ine eine Endlosschleife. Aber auch hier habe ich das Problem das sobald ich sei() und TIMSK |= (1<<TOIE0); zusammen aktivier das sich das Board resetet, sprich ich bekomm ein dauerpiepsen.
Ich habe jetzt auch shcon mehrere Controller und mehrere Oszilatoren und Quarze versucht. Aber es kann doch eigentlich kein Hardwarespezifisches Problem sein, oder?
Hier der neue Code:
#include <avr/io.h>
#include <avr/delay.h>
#include <avr/interrupt.h>
int main( void )
{
DDRA = 0xFF;
DDRB = 0xFF;
DDRC = 0xFF;
DDRD = 0xFF;
PORTA = 0x00;
PORTB = 0x00;
PORTC = 0x00;
PORTD = 0x00;
for(uint16_t i=0; i<270*15; i=i+(2*6))
{
PORTD |= (1<<7);
_delay_ms(6);
PORTD &= ~(1<<7);
_delay_ms(6);
}
TIMSK |= (1<<TOIE0);
TCCR0 |= (1 << CS00 ) | (1 << CS02) ;
TCCR0 &= ~(1 <<CS01 );
sei();
while(1)
{
}
return 0;
}
WWas genau an der _delay_ms(1000); nich funktionieren soll versteh ich auch nicht.
Gruß
elayne
Dir fehlt das Grundwissen,
daß Dein Programm abstürzt ist ganz normal, man aktiviert auch keine Interrupts, ohne die pasende Interupt Service Routine.
Und die Sache mit delay, tja
The maximal possible delay is 262.14 ms / F_CPU in MHz.
... sagt das Handbuch zu avr-gcc
Gruß Sebastian
Jo, mit dem Grundwissen wirst du nicht ganz Unrecht haben obwohl ich von Anfang an eigentlich versucht habe richtig vorzugehen. Ich hab mit Assembler angefangen und wollt mich jetzt an C versuchen. Aber dafür will ich ja was lernen.
In meinem neuen Programm habe ist mein größstes delay 6ms. Das mit der ISR wusst ich nich, aber ich habe jetzt mal noch eine einfache dazugeschrieben.
ISR(TIMER0_OVF_vect)
{
PORTB = 0xAC;
}
Aber damit bin ich immernochnicht weiter. Ich versteh einfach das verhalten von dem AVR nicht das der ein Reset macht. Und Hubert.G hat ja gesagt bei ihm würde es gehen und ich selbst hatte das Programm auch schon am laufen jedoch ohne RN Control. Ich habe das Board ja gebraucht gekauft und deswegen auch schon an ein Defekt geglaubt, aber hier fällt mir auch keiner ein der zu diesem Verhalten führt. Aber auf jdenfall danke für deine Hilfe.
Gruß
elayne
Hubert.G
13.02.2008, 21:07
Ich glaube das dein Compiler da was nicht richtig macht und du die Warnings ignorierst. Ich schicke dir mein *.zip, das läuft bei mir einwandfrei. Den Wert im UBRRL musst du ändern, ich hatte nur eine 11,0592MHz Quarz zur Verfügung.
Dein letzter Code kann nicht funktionieren und wenn meiner bei dir auch nicht geht, dann hast du ein Problem das nicht direkt mit diesem Code zusammenhängt.
Aber damit bin ich immernochnicht weiter. Ich versteh einfach das verhalten von dem AVR nicht das der ein Reset macht.
Das ist recht einfach.
Du schreibst, daß Du mit Assembler angefangen bist,gut.
Also Du aktivierst einen Interrupt, und wenn der zuschlägt will der AVR in die ISR von diesem Interrupt springen.
Das ganze organisiert gcc in einer Tabelle, ich habe die aus meinem jetzigem Programm kopiert
Disassembly of section .text:
00000000 <__vectors>:
0: 0c 94 2a 00 jmp 0x54 ; 0x54 <__ctors_end>
4: 0c 94 a9 00 jmp 0x152 ; 0x152 <__vector_1>
8: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
10: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
14: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
18: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
1c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
20: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
24: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
28: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
2c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
30: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
34: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
38: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
3c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
40: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
44: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
48: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
4c: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
50: 0c 94 47 00 jmp 0x8e ; 0x8e <__bad_interrupt>
00000054 <__ctors_end>:
Wenn man sich das ganze jetzt anschaut, habe ich nur einen Interrupt definiert (EXT 0), da springt er in 0x152 <__vector_1>.
Der rest ist undefiniert und wenn durch falsches Programmieren mal einer zuschlagen sollte geht es nach 0x8e <__bad_interrupt> die wiederum so aussieht:
0000008e <__bad_interrupt>:
8e: 0c 94 00 00 jmp 0 ; 0x0 <__vectors>
Ich hoffe, Du weißt was unter jmp 0 zu verstehen ist ;-)
Und wenn Du einen Interrupt zuläßt, aber keinen Vektor definierst, tja dann geht es in __bad_interrupt, verständlicher ?
und du die Warnings ignorierst
Das ist sehr wichtig!
Alles was Lila im Ausgabefenster von PN erscheint, sollte Deine Alarmglocken läuten lassen...
Gruß Sebastian
Hey,
deine kleine Exursion ist ganz interessant, danke das habe ich jetzt verstanden. Und nun habe ich Hubert's Programm compilled und sehe da es funktioniert. Was genau jetzt bei meinem Programm nicht ging weiss ich nochnicht. Aber ich schau mir das jetzt genau an.
Danke euch allen für eure Mühen! Schlauer bin ich jetzt auf jeden Fall.
Gruß
elayne
Powered by vBulletin® Version 4.2.5 Copyright ©2024 Adduco Digital e.K. und vBulletin Solutions, Inc. Alle Rechte vorbehalten.