Forum: Mikrocontroller und Digitale Elektronik Taster Abfrage trotz Warteschleife


von Daniel (Gast)


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.

von Electronics'nStuff (Gast)


Lesenswert?

Stell doch einfach mal dein Programm hier rein - da wird dir auch gerne 
geholfen.

von Falk B. (falk)


Lesenswert?

@  Daniel (Gast)

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

Sicher, siehe Multitasking. Aber warum nicht einfach die Interrupts 
VORHER freischalten und nutzen?

von Mikel M. (mikelm)


Lesenswert?

du mußt doch nur während des Wartens, die Tasten abfragen. Eigentlich ne 
gute Zeit dafür, der Tiny hat ja eh nichts anderes zu tun :D
 Sollte es zeitkritisch sein, mußt du es eben entsprechend 
programmieren.

von Karl H. (kbuchegg)


Lesenswert?

> welches zu Beginn einmal im Grunde in einer Warteschleife hängt,

delay_ms ist selten die Lösung, aber sehr oft das Problem.

von Daniel (Gast)


Lesenswert?

Hallo Falk und die anderen,

vielen Dank für den Link mit dem Multitasking. Ich denke, das hilft :-)
Werde mir das mal genauer ansehen und auf meinen Fall versuchen 
anzuwenden.

Danke.

von Daniel (Gast)


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

von Karl H. (kbuchegg)


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.

von Daniel (Gast)


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.

von Falk B. (falk)


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.

von Karl H. (kbuchegg)


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.

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.