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.
Stell doch einfach mal dein Programm hier rein - da wird dir auch gerne geholfen.
@ 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?
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.
> welches zu Beginn einmal im Grunde in einer Warteschleife hängt,
delay_ms ist selten die Lösung, aber sehr oft das Problem.
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.
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...
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.
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.
@ 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.
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.