Forum: Mikrocontroller und Digitale Elektronik timer geht nicht


von Holger (Gast)


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.

von johnny.m (Gast)


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.

von Holger (Gast)


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


      };
}

von Holger (Gast)


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.

von Karl heinz B. (kbucheg)


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.

von Holger (Gast)


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?

von unsichtbarer WM-Rahul (Gast)


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

von Holger (Gast)


Lesenswert?

Ich habe es jetzt printf("M") durch UDR='M' ersetzt und habe das gleiche 
Problem, dass die Daten nicht mit konstanten 50Hz geschcikt werden.

von johnny.m (Gast)


Lesenswert?

Anstatt
1
if (i == 1)
2
{
3
//...
4
}
einfach
1
if (i >= 1)
2
{
3
//...
4
}

von Karl heinz B. (kbucheg)


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.




von Holger (Gast)


Lesenswert?

Ich habe jetzt in der Hauptschleife if (i != 0) gesetz und immer noch 
das gleiche Problem.

von Karl heinz B. (kbucheg)


Lesenswert?

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

von Holger (Gast)


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


      };
}

von Peter D. (peda)


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

von Holger (Gast)


Lesenswert?

Ja mit dem Oszi.

von Peter D. (peda)


Lesenswert?

Triggert Dein Oszi auch richtig ?

Simuliers doch einfach mal (Avrstudio).


Peter

von unsichtbarer WM-Rahul (Gast)


Lesenswert?

Lass dann doch mal einen Pin togglen.
Dann könnte man auch überprüfen, ob deine Timer-ISR richtig geht.

von Holger (Gast)


Lesenswert?

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.

von unsichtbarer WM-Rahul (Gast)


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

von Holger (Gast)


Lesenswert?

Wie kann  ich mir denn den CTC-Mode des Timers anschauen?
Ich bin kein Experte, sondern eher Anfänger.

von unsichtbarer WM-Rahul (Gast)


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

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
Noch kein Account? Hier anmelden.