Taster Abfrage trotz Warteschleife

Gast #2784262
Lesenswert?

Hallo,

Prozessor Attiny13, Sprache C

Ich habe ein Programm, welches zu Beginn einmal im Grunde in einer 
Warteschleife hängt, da es etwas ausgibt und dazwischen immer kurz 
warten muss.
Dies geschieht direkt nach main(), aber vor der Hauptschleife.

Der Benutzer kann aber mit einem Taster in das Programm eingreifen bzw. 
Sachen aktivieren, deaktivieren. Die Taster werden über eine 
Entprellroutine aber erst in Hauptschleife erkannt.
Ich hätte aber gerne, dass der Benutzer schon vor Beginn der 
Hauptschleife, also während der Warteschleife schon mit Tastenimpulsen 
interagieren kann.

Ist dies irgendwie möglich außer die Taster in einem Interrupt 
abzufragen?

Danke.
Gast #2784369
Lesenswert?

1
*
2
 
3
Multitasking Demo, zweiter Versuch
4
 
5
ATmega32 @ 3,6468 MHz
6
 
7
LED + 1KOhm Vorwiderstand an PB0
8
Taster nach GND an PA0
9
UART an RXD und TXD
10
 
11
*/
12
 
13
#define F_CPU 3686400
14
// Baudrate, das L am Ende ist wichtig, NICHT UL verwenden!
15
#define BAUD 9600L          
16
 
17
#include "avr/io.h"
18
#include "util/delay.h"
19
 
20
// Berechnungen
21
// clever runden
22
#define UBRR_VAL  ((F_CPU+BAUD*8)/(BAUD*16)-1)  
23
// Reale Baudrate
24
#define BAUD_REAL (F_CPU/(16*(UBRR_VAL+1)))     
25
// Fehler in Promille 
26
#define BAUD_ERROR ((BAUD_REAL*1000)/BAUD-1000) 
27
 
28
#if ((BAUD_ERROR>10) || (BAUD_ERROR<-10))
29
  #error Systematischer Fehler der Baudrate grösser 1% und damit zu hoch! 
30
#endif
31
 
32
uint8_t taste_lesen(void) {
33
    if (PINA & (1<<PA0))
34
        return 1;
35
    else 
36
        return 0;
37
}
38
 
39
void led_blinken(uint8_t taste) {
40
    static uint16_t zaehler=0;
41
 
42
    if (taste) {
43
        if (zaehler>=999) {
44
            PORTB ^= (1<<PB0);
45
            zaehler=0;
46
        }
47
    }
48
    else {
49
        if (zaehler>=99) {
50
            PORTB ^= (1<<PB0);
51
            zaehler=0;
52
        }
53
    }
54
 
55
    zaehler++;
56
    _delay_ms(1);       // 1 ms warten
57
}
58
 
59
void uart_lesen(void) {
60
    uint8_t tmp;
61
    if((UCSRA & (1<<RXC))) {                // empfangenes Zeichen abholbereit im UART ?
62
        tmp = UDR;
63
        while (!(UCSRA & (1<<UDRE)));       // Warte auf freien Sendepuffer vom UART
64
        UDR = tmp;
65
    }
66
}
67
 
68
int main(void) {
69
    int8_t taste;
70
 
71
    // IOs initialisieren
72
    
73
    PORTA = 1;              // Pull Up für PA0
74
    DDRB  = 1;              // PB0 ist Ausgang
75
 
76
    // UART initialisieren
77
    
78
    UBRRH = UBRR_VAL >> 8;
79
    UBRRL = UBRR_VAL & 0xFF;
80
    UCSRB = (1<<RXEN) | (1<<TXEN);
81
    
82
    // Endlose Hauptschleife
83
 
84
    while (1) {
85
        taste = taste_lesen();
86
        led_blinken(taste);
87
        uart_lesen();
88
    }
89
}

Ich habe mir gerade obiges Beispiel aus dem Tutorial mal genauer 
durchdacht.
Dabei ist mir aufgefallen, dass in der Funktion led_blinken() immer 1ms 
gewartet wird, bis der Zähler bei >=999 bzw. >99 ist (also 1000ms oder 
100ms).
Allerdings hat das Programm bzw. die anderen Programmteile ja selbst 
auch eine Durchlaufzeit. So wird in Summe die Vielzahl der Durchläufe 
des Programms+die Wartezeit für das Leuchten der LEDs genommen oder bin 
ich falsch?
Das entspricht ja prinzipiell nicht dem Ursprungsprogramm mit 1000ms 
delay...
#2784380
Lesenswert?

Daniel schrieb:

> Dabei ist mir aufgefallen, dass in der Funktion led_blinken() immer 1ms
> gewartet wird, bis der Zähler bei >=999 bzw. >99 ist (also 1000ms oder
> 100ms).
> Allerdings hat das Programm bzw. die anderen Programmteile ja selbst
> auch eine Durchlaufzeit. So wird in Summe die Vielzahl der Durchläufe
> des Programms+die Wartezeit für das Leuchten der LEDs genommen oder bin
> ich falsch?

Nein, bist du nicht.
Im Prinzip hast du recht.
Allerdings reden wir hier um ein paar µs pro Schleifendurchlauf. Bei 
1000 Durchläufen summiert sich der Fehler zu ~1 Millisekunde auf.
Kannst du tatsächlich mnit freiem Auge feststellen, ob das Blinken einer 
LED genau 1 Sekunde oder 1 Sekunde + 1 Tausendstel Sekunde lang ist?


Wenn du genaue Zeiten brauchst, taugen diese ganzen _delay_ms Ansätze 
sowieso nichts. Wie schon gesagt: _delay_ms ist oft nicht die Lösung, 
sondern das Problem.
Gast #2784385
Lesenswert?

Hallo,

nein, für diesen Anwendungsfall "LED" ist das für das Auge natürlich 
nicht erfassbar/messbar.
Ich wollte nur bestätigt haben, dass ich das Programm, so wie es da 
steht, richtig durchschaue.
Um es genaue zu machen, würde man wahrscheinlich die Zählvariable 
"zaehler" einfach entsprechend in einem Timer inkrementieren und bei 
entsprechendem Inkrement die Abbruchbedienung in der if-Anweisung 
setzen.

Danke.
#2784397
Lesenswert?

@  Daniel (Gast)

>Allerdings hat das Programm bzw. die anderen Programmteile ja selbst
>auch eine Durchlaufzeit. So wird in Summe die Vielzahl der Durchläufe
>des Programms+die Wartezeit für das Leuchten der LEDs genommen

Ja.

>Das entspricht ja prinzipiell nicht dem Ursprungsprogramm mit 1000ms
>delay...

Muss es auch nicht, weil es nur ein einfaches Beipiel ist, bei dem es 
nicht auf die letzte Mikrosekunde ankommt.
#2784401
Lesenswert?

Daniel schrieb:

> Um es genaue zu machen, würde man wahrscheinlich die Zählvariable
> "zaehler" einfach entsprechend in einem Timer inkrementieren und bei
> entsprechendem Inkrement die Abbruchbedienung in der if-Anweisung
> setzen.
>

Praktisch JEDES ernst zu nehmende Programm aus der realen Welt (also 
abseits von Tutorien) hat in irgend einer Form einen Timer als 
'Heartbeat'. In diesem Heartbeat wird zb die Tastenentprellung gemacht 
und er dient als Zeitbasis für das komplette Programm.
Das ist einfacher realisiert als viele glauben. Nur muss man sich halt 
mal mit Timern beschäftigt haben.


Der spingende Punkt bei diesem Multitasking Beispiel ist der: das man 
Aktionen aufteilt und nicht auf die Fertigstellung wartet. Darum gehts.

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