Einfacher Atmega 328 Timer code ungewollte pausen

Gast #5577658
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
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
Hi foobar,

leider verstehe ich die variante nicht wirklich...
und später muss/ will ich die eine LED durch drei ersetzen.
Dann muss jede led 4s nacheinander blinken mit einem zeitabstand von 4s.
Gast
> 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
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
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.
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
Ok, wie kann ich den zweiten code richtigstellen,
das ich anstatt einem getoggelten PortB einen Variable aufrufe und 
inkrementiere und diese variable dann für drei leds zum leuchten 
benutzen kann?
Gast
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

Eine eigene Frage? Dieser Thread ist über 8 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.