timer geht nicht

Gast #441268
Lesenswert?

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.
Gast #441318
Lesenswert?

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.
Gast #441342
Lesenswert?

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;
      }


      };
}
Gast #441614
Lesenswert?

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.
#441680
Lesenswert?

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.
Gast #441696
Lesenswert?

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?
Gast #441706
Lesenswert?

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...
#441723
Lesenswert?

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.



Gast #441756
Lesenswert?

#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;
      }


      };
}
#441766
Lesenswert?

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
Gast #441816
Lesenswert?

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...).
Gast #441829
Lesenswert?

>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...

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren