Einfacher Atmega 328 Timer code ungewollte pausen

Gast #5577658
Lesenswert?

Hallo Mikrocontroller-Freunde,

ich versuche einen Atmega328p eine LED jede zweite sekunde eine sekunde 
leuchten zu lassen. Habe ich jetzt hinbekommen mit dem Timer1,
macht der MCU nach 4 mal blinken 10s lang gar nichts...
1
#include <avr/io.h>
2
  #include <avr/interrupt.h>
3

4
  int t = 0;
5
  int main(void)
6
  {
7
    DDRB = 0b000100000;
8
    OCR1A = 0x3D08;
9

10
    TCCR1B |= (1 << 3);
11
    // Mode 4, CTC on OCR1A
12

13
    TIMSK1 |= (1 << 1);
14
    //Set interrupt on compare match
15

16
    TCCR1B |= 0x05;
17
    // set prescaler to 1024 and start the timer
18

19

20
    sei();
21
    // enable interrupts
22

23

24
    while (1)
25
    {
26
      while(t==1)
27
      {
28
        PORTB = 0xFF;
29
      }
30
      PORTB = 0x00;
31
      t=0;
32
      
33
    }
34
  }
35

36
  ISR (TIMER1_COMPA_vect)
37
  {
38
    t++;
39
  }

Könnt ihr mir weiterhelfen? Ich bin am verzweifeln :(
Danke
Gast #5577668
Lesenswert?

Die Interaktion zwischen Interruptroutine und Hauptprogramm robust zu 
bekommen, ist nicht trivial. Das volatile nannte Jim schon. Reicht 
leider nicht, du brauchst auch noch nen atomaren Datentyp (z.B. char 
oder uint8_t).

Und dann muß das Protokoll auch noch korrekt sein - deines ist es 
nicht. Stell dir vor, t ist 0 und kurz nach dem Test "while(t==1)" und 
noch vor dem "t=0" kommt der Interrupt, t wird 1 und von main sofort 
wieder auf 0 gesetzt ohne jemals gemerkt zu haben, dass es kurz auf 1 
war.
Gast #5577678
Lesenswert?

> leider verstehe ich die variante nicht wirklich

Die läßt den Timer einfach durchlaufen. Je nachdem, ob der gerade oder 
ungerade ist, werden die LEDs ein- oder ausgeschaltet.

Etwas flexibler wäre man z.B. mit so etwas:
1
// user timers, will count down to zero and then stop
2
volatile uint8_t t1, t2, t3; // t1 for leds, t2 and t3 are free
3

4
ISR (TIMER1_COMPA_vect)
5
{
6
    if (t1) t1--;
7
    if (t2) t2--;
8
    if (t3) t3--;
9
}
10

11
int main() {
12
    // setup
13
    ...
14
    for (;;) {
15
        if (t1 == 0) { // led timer expired?
16
            // turn leds off and on
17
            ...
18
            t1 = 4; // restart led timer
19
        }
20
        // do something else
21
        ...
22
    }
23
}
Gast #5577679
Lesenswert?

Jetzt habe ich was anderes ausprobiert,
und ich versteh die welt nicht mehr.
1
#include <avr/io.h>
2

3
int main(void)
4
{
5
  // connect led to pin PC0
6
  DDRB |= (1 << 5);
7
  
8
  TCCR1B |= (1 << WGM12)|(1 << CS11)|(1 << CS10);
9
  TCNT1 = 0;
10
  OCR1A = 25000;
11
  
12
  int counter = 0;
13

14
  while(1)
15
  {
16
    counter = 0;
17
    if (TIFR1 & (1 << OCF1A))
18
    {
19
    counter = 1;
20
    for (int i=0; i < 30000; i++);  
21
    }
22
    PORTB ^= (1 << 5);
23
    TIFR1 |= (1 << OCF1A);    
24
  }
25
}

füge ich bei
[code]
if (TIFR1 & (1 << OCF1A))
    {
    counter = 1;
    for (int i=0; i < 30000; i++);
    }
[\code]

dies ein:
[code]
if (TIFR1 & (1 << OCF1A))
    {
    PORTB ^= (1 << 5);
    }
[\code]

Warum bekomme ich wenn ich die for-schleife im if-vergleich drin habe 
ein schnelleres blinken? und wenn nur der toggelbefehl drin steht die 
gewünschte zeitspanne?
Gast #5577682
Lesenswert?

Zielloses rumballern auf Registern ist selten sinnvoll (deine "while 
(1)" Loop wird mehrere 100000 mal pro Sekunde durchlaufen...). Deine 
zwei Varianten machen halt was ganz anderes. Btw, die for-busy-loop wird 
eh wegoptimiert.
#5577782
Lesenswert?

foobar schrieb:
> Stell dir vor, t ist 0 und kurz nach dem Test "while(t==1)" und
> noch vor dem "t=0" kommt der Interrupt, t wird 1 und von main sofort
> wieder auf 0 gesetzt ohne jemals gemerkt zu haben, dass es kurz auf 1
> war.

So ist es. Das Programm ist logisch falsch.
Ein Interrupt kommt asynchron zum Main und das muß man berücksichtigen.
Gast #5577995
Lesenswert?

fred schrieb:
>>PORTA = (t & 1) ? 0xff : 0x00;
> leider verstehe ich die variante nicht wirklich...

Das bedeutet in Worten:

Wenn in t das Bit 1 gesetzt ist, dann setze PORTA auf 0xff (alle 
Ausgänge auf High).
Wenn in t das Bit 1 nicht gesetzt ist, dann setze PORTA auf 0x00 (alle 
Ausgänge auf High).

Ziel = (Ausdruck) ? (Wert wenn wahr) : (Wert wenn falsch)

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