Forum: Mikrocontroller und Digitale Elektronik Portpinabfrage innerhalb eines Timerinterrupts


von M. G. (ixil96)


Lesenswert?

Hallo,

ich suche nach einer Lösung für folgende Aufgabe:
1.) Eine Status LED soll im Sekundentakt blinken. Dieser Sekundentakt 
soll mit einem Timerinterrupt realisiert werden.

2.) Weiteres soll im Sekundentakt ein Taster abgefragt werden. Ist der 
Taster gedrückt, soll sich eine 2. LED für 10 Sekunden einschalten.

3.) Wird der Taster innerhalb dieser 10 Sekunden erneut gedrückt, 
verlängert sich die Einschaltzeit um weitere 10 Sekunden.

Und bei Punkt 3 stehe ich derzeit auf der "Leitung"!
Kann mir da bitte jemand helfen, wie ich das am einfachsten lösen kann?

Hier mein derzeitiger Code:
1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define led1 (1<<PB4)
5
#define led2 (1<<PB5)
6
7
unsigned int timer_overflow_counter = 0;
8
unsigned int glowtime = 10;
9
unsigned int glowtime_led_2;
10
unsigned char taster_flag = 0;
11
12
void init_timer_0 (void)
13
{
14
  TCCR0B = (1<<CS01) + (1<<CS00);    // Prescaler = 64 -> 8Mhz/64 = 125000 clockspeed
15
  TIMSK0 = (1<<TOIE0);        // Timer0 overflow interrupt enable
16
  TCNT0 = 6;              // Timer mit 6 vorladen (256-6 = 250 mal hochzählen bis zum overflow)
17
}  
18
19
int main(void)
20
{
21
  DDRB = 0xFF;            // PORTB Richtungsregister = Ausgang
22
  DDRC = 0xF0;            // PC0...PC3 auf Eingang
23
  PORTC = 0xF1;            // PC0 = Pull up
24
  
25
  init_timer_0();            // Timer 0 initialisieren
26
  sei();                // Interrupts einschalten
27
    while(1)
28
    {
29
        asm ("NOP");          // Nichts tun
30
    }
31
}
32
33
ISR(TIMER0_OVF_vect)
34
{
35
  if (timer_overflow_counter <= 499)        // Zählvariable 500 mal hochzählen
36
    timer_overflow_counter ++;
37
  else                      // Den else-Zweig beim 500 Durchlauf einmal ausführen
38
  {
39
    TCNT0 = 6;                  // reload timer0 
40
    PORTB ^= led1;                // LED toggeln
41
    timer_overflow_counter = 0;          // Zähler zurücksetzen
42
    
43
    if ((PINC &(1<<PINC0)) && (taster_flag == 0))     // Wenn Taster gedrückt wurde...
44
    {    
45
      taster_flag = 1;            // Flag für Taster wurde gedrückt setzen
46
      glowtime_led_2 = glowtime;        // glowtime_led_2 auf Anfangswert 10 setzen
47
    }
48
    
49
    if (taster_flag == 1)            // Taster wurde gedrückt
50
    {
51
      PORTB |= led2;              // LED ON
52
      glowtime_led_2 --;            // glowtime_led_2 pro Sekunde um 1 runter zählen
53
      
54
      if (glowtime_led_2 == 0)
55
      {
56
        PORTB &= ~led2;            // LED OFF
57
        glowtime_led_2 = glowtime;      // glowtime_led_2 auf Anfangswert 10 setzen
58
        taster_flag = 0;          // Taster flag zurücksetzen
59
      }
60
    }
61
  }
62
}

von User (Gast)


Lesenswert?

Du willst doch bei Tastendruck die glowtime um 10s erhöhen, richtig?

Dann addiere doch bei Tastendruck deine Konstante glowtime zu 
glowtime_led_2.
So wie es jetzt ist, wird sie ja immer auf 10 gesetzt.
1
    if ((PINC &(1<<PINC0)) && (taster_flag == 0))     // Wenn Taster gedrückt wurde...
2
    {    
3
      taster_flag = 1;            // Flag für Taster wurde gedrückt setzen
4
      glowtime_led_2 += glowtime;        // glowtime_led_2 + glowtime
5
    }

von M. G. (ixil96)


Lesenswert?

Hallo,

also eine Lösung habe ich gerade gefunden.
(Bin mal schnell von der "Leitung" runter)

Ich frage den PINC0 unabhängig vom Tastenflag nochmals ab, ob er 
gedrückt wurde und setze die glowtime_led_2 wieder auf den Anfangswert.

Aber ich denke, für das Ganze gibt es sicher eine noch viel einfachere 
Lösung!
1
if (PINC &(1<<PINC0))
2
      glowtime_led_2 = glowtime;        // glowtime_led_2 auf Anfangswert 10 setzen

Hat hier jemand einen Vorschlag?

Danke!

von M. G. (ixil96)


Lesenswert?

User schrieb:
> Du willst doch bei Tastendruck die glowtime um 10s erhöhen, richtig?
>
> Dann addiere doch bei Tastendruck deine Konstante glowtime zu
> glowtime_led_2.

Ich habe mich hier vielleicht nicht gut ausgedrückt.
Bei einem Tastendruck soll sich die Leuchtzeit der LED auf 10 Sekunden 
zurücksetzen. Also so wie ein nachtriggerbares Monoflop.

von spe (Gast)


Lesenswert?

1
if ((PINC &(1<<PINC0)) && (taster_flag == 0))

wozu hast du die zweite Abfrage überhaupt drin?
1
if ((PINC &(1<<PINC0)))

reicht doch völlig aus (entspricht auch deiner lösung nur eben nur eine 
Abfrage)

von Fabian O. (xfr)


Lesenswert?

1. Warum stellst Du den Timer nicht langsamer ein? In 499 von 500 
Interrupts passiert nichts. Das Vorladen des Counters kannst Du Dir 
sparen, wenn Du den CTC-Modus nimmst.

2. Du fragst den Taster nur alle 10 Sekunden ab. Wenn er 
zwischenzeitlich kurz gedrückt wurde, merkst Du davon nichts.

3. Die Variable taster_flag ist unnötig, die Information steckt schon in 
glowtime_led2.

Eine Alternative wäre, den Taster in der main zu prüfen:
1
#define GLOW_TIME 10
2
volatile uint8_t glowtime_led_2 = 0;
3
4
int main(void)
5
{
6
  // ...
7
  while (1) {
8
    if (PINC & (1 << PINC0)) {
9
      glow_time_led2 = GLOW_TIME;
10
    }
11
  }
12
}
13
14
ISR() {
15
  // ...
16
  if (glow_time_led2 > 0) {
17
    glow_time_led2--;
18
    // LED on
19
  } else {
20
    // LED off
21
  }
22
}

von M. G. (ixil96)


Lesenswert?

spe schrieb:
>
1
if ((PINC &(1<<PINC0)) && (taster_flag == 0))
>
> wozu hast du die zweite Abfrage überhaupt drin?
>
>
1
if ((PINC &(1<<PINC0)))
>
> reicht doch völlig aus (entspricht auch deiner lösung nur eben nur eine
> Abfrage)

Ja, stimmt eigentlich. Danke!
1
ISR(TIMER0_OVF_vect)
2
{
3
  if (timer_overflow_counter <= 499)        // Zählvariable 500 mal hochzählen
4
    timer_overflow_counter ++;
5
  else                      // Den else-Zweig beim 500 Durchlauf einmal ausführen
6
  {
7
    TCNT0 = 6;                  // reload timer0 
8
    PORTB ^= led1;                // LED toggeln
9
    timer_overflow_counter = 0;          // Zähler zurücksetzen
10
    
11
    if (PINC &(1<<PINC0))             // Wenn Taster gedrückt wurde...
12
    {    
13
      taster_flag = 1;            // Flag für Taster wurde gedrückt setzen
14
      glowtime_led_2 = glowtime;        // glowtime_led_2 auf Anfangswert 10 setzen
15
    }
16
    
17
    if (taster_flag == 1)            // Taster wurde gedrückt
18
    {
19
      PORTB |= led2;              // LED ON
20
      glowtime_led_2 --;            // glowtime_led_2 pro Sekunde um 1 runter zählen
21
      
22
      if (glowtime_led_2 == 0)
23
      {
24
        PORTB &= ~led2;            // LED OFF
25
        glowtime_led_2 = glowtime;      // glowtime_led_2 auf Anfangswert 10 setzen
26
        taster_flag = 0;          // Taster flag zurücksetzen
27
      }
28
    }
29
  }
30
}

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.