Hallo, ich habe folgendes Problem. ich möchte, dass mein Mikrocontroller die Daten im 50 Hz Takt rausschickt. Dafür habe ich interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0=0xB8; i++; } void main(void) {TCCR0=0x05; while (1) { if (i == 1) { printf("M"); i=0; }}} Leider wird das M aber manchmal mit 50Hz geschickt und dann wieder nicht. ich habe ein externes 3,6864MHz quarz drauf und einen ATmega8L.
Wie ist i deklariert? Wenn es nicht volatile ist, könnte das zu Problemen führen, da es sowohl in der ISR als auch im Hauptprogramm benutzt wird. Schicke demnächst doch bitte einen vollständigen (lauffähigen) Code.
i ist als volatile int deklariert. Hier ist der ganze Code. #include <mega8.h> #include <stdio.h> volatile int i=0; interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0=0xDC; i++; } void main(void) { PORTB=0x00; DDRB=0x00; PORTC=0x00; DDRC=0x00; PORTD=0x00; DDRD=0x02; TCCR0=0x05; TCNT0=0x00; TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; MCUCR=0x00; TIMSK=0x01; UCSRA=0x00; UCSRB=0x08; UCSRC=0x86; UBRRH=0x00; UBRRL=0x01; ACSR=0x80; SFIOR=0x00; #asm("sei") while (1) {if (i==1) { printf("M"); i=0; } }; }
Weiß denn keiner woran es liegen könnte? Ich bekomme ca. 20 mal das M mit 50Hz dann längere Zeit nichts und dann wieder 20 mal das M mit 50 Hz. Im Code muß es natürlich TCNT0=0xB8 anstelle von TCNT0=0xDC heißen um 50 Hz zu bekommen.
Du hast ziemlich sicher eine Race-Condition: In deinem Pgm laufen 2 Dinge 'gleichzeitig' ab. Der Overflow Interrupt versucht i zu erhöhen, während in der Schleife das kontinuierlich auf 0 zurückgesetzt wird. Wenn der Interrupt nur schnell genug ist, dann erhöht er dir i auf 2 und damit ist die hauptschleife erst mal lahmgelegt. Die muss warten, bis der Overflow das i weiter- gezählt hat 2, 3, 4, 5, ....., 32767, -32768, -32767, -32765, ... -1, 0, 1 bis der if in der Hauptschleife das nächste mal zuschlägt.
Aber warum funktioniert es denn manchmal, dass ich die Daten in 50Hz Absatnd bekomme und manchmal nicht. Eigentlich müßte das Overflow Interrupt doch dann immer schneller sein als die Schleife. Auch wenn ich den Timer langsamer mache klappt es nicht. Wie kann ich das denn vielleicht auch anders lösen?
Liegt vielleicht daran...
>printf("M");
Mit UDR = 'M';
sollte es wesentlich "schneller" gehen.
Man könnte auch einen Zähler von 33 bis 127 durchlaufen lassen und den
aktuellen Wert ausgeben lassen; so etwa:
if (i)
{
UDR = z++;
if (z==128) z = 33;
}
Ansich müssten die Daten ja schon verschickt worden sein, wenn die
nächsten ins UDR geschrieben werden.
Sonst müsste man das UDRE-Flag noch abfragen...
Ich habe es jetzt printf("M") durch UDR='M' ersetzt und habe das gleiche Problem, dass die Daten nicht mit konstanten 50Hz geschcikt werden.
Holger wrote: > Aber warum funktioniert es denn manchmal, dass ich die Daten in 50Hz > Absatnd bekomme und manchmal nicht. Eigentlich müßte das Overflow > Interrupt doch dann immer schneller sein als die Schleife. > Auch wenn ich den Timer langsamer mache klappt es nicht. Weil der Zeitbedarf für einen Interrupt und der Zeitbedarf für den print nicht gleich ist. Wenn du in 1.3 Sekunden Abständen auf deine Uhr siehst, dann siehst du den Sekunden zeiger zunächst auf der 1, dann auf der 2, dann auf der 3. Bis jetzt sind 3 * 1.3 Sekunden also 3.9 Sekunden vergangen. Wenn du das nächste mal auf die Uhr siehst, sind aber schon 5.2 Sekunden vergangen. D.h. du siehst den Sekundenzeiger auf der 5. Auf der 4 hast du ihn nie gesehen. > Wie kann ich das denn vielleicht auch anders lösen? Versteif dich halt nicht darauf, dass i in der Hauptschleife genau den Wert 1 haben muss. Alles was nicht 0 ist (also 1 oder 2 oder was auch immer), sagt dir, dass der Overflow erfolgt ist: if (i != 0) und schon sollte es gehen.
Ich habe jetzt in der Hauptschleife if (i != 0) gesetz und immer noch das gleiche Problem.
> Ich habe jetzt in der Hauptschleife if (i != 0) gesetz und immer noch > das gleiche Problem. Seltsam. Hab keine Erklärung mehr dafür. Zeig noch mal das jetztige Programm.
#include <mega8.h> #include <stdio.h> volatile int i=0; interrupt [TIM0_OVF] void timer0_ovf_isr(void) { TCNT0=0xDC; i++; } void main(void) { PORTB=0x00; DDRB=0x00; PORTC=0x00; DDRC=0x00; PORTD=0x00; DDRD=0x02; TCCR0=0x05; TCNT0=0x00; TCCR1A=0x00; TCCR1B=0x00; TCNT1H=0x00; TCNT1L=0x00; ICR1H=0x00; ICR1L=0x00; OCR1AH=0x00; OCR1AL=0x00; OCR1BH=0x00; OCR1BL=0x00; ASSR=0x00; TCCR2=0x00; TCNT2=0x00; OCR2=0x00; MCUCR=0x00; TIMSK=0x01; UCSRA=0x00; UCSRB=0x08; UCSRC=0x86; UBRRH=0x00; UBRRL=0x01; ACSR=0x80; SFIOR=0x00; #asm("sei") while (1) {if (i !=0) { UDR = 'M'; //egal auch mit printf("M") nicht i=0; } }; }
Holger wrote: > Leider wird das M aber manchmal mit 50Hz geschickt und dann wieder > nicht. Woher weißt Du denn überhaupt, daß es nicht klappt ? Überprüfst Du das mit nem Oszi ? Mit nem Terminalprogramm (PC) kannst Du es jedenfalls nicht überprüfen, da Du dort Zeitscheiben zugeteilt bekommst. Peter
Triggert Dein Oszi auch richtig ? Simuliers doch einfach mal (Avrstudio). Peter
Lass dann doch mal einen Pin togglen. Dann könnte man auch überprüfen, ob deine Timer-ISR richtig geht.
Ich weiß zwar nicht was toggeln ist, aber ich habe einen Pin kurz high und wieder low geschaltet und habe dabei immer noch das gleiche problem.
togglen: einen Pin kurz high und wieder low schalten Liegt also nicht am USART... Guckt dir mal den CTC-Mode des Timers an, der produziert dir einen wunderschöne Frequenz durch einmaliges Konfigurieren (und vorheriges Rumgerechne...).
Wie kann ich mir denn den CTC-Mode des Timers anschauen? Ich bin kein Experte, sondern eher Anfänger.
>Wie kann ich mir denn den CTC-Mode des Timers anschauen? Im Datenblatt (complete datasheet) ist der neben allen anderen beschrieben... >Ich bin kein Experte, sondern eher Anfänger. Macht ja nichts...
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.