Letztens war im GCC Forum ein guter Artikel zu sog. state machines
(endliche Automaten)
Auf dein Beispiel übertragen, sieht das so aus:
Deine Maschine kennt genau zwei Zustände - LED ist aus (Zustand LED_AUS)
und LED ist an (Zustand LED_AN). Die Anfangsbedingung sei mal, dass die
LED aus ist.
Vom Zustand LED_AUS kommt man in den Zustand LED_AN, indem man einen
Taster drückt.
Vom Zustand LED_AN kommt man in den Zustand LED_AUS, indem man 5
Sekunden wartet. Ein Drücken des Tasters im Zustand LED_AN ist
wirkungslos.
Also sieht die Grundroutine so aus
1 | #include <avr/io.h>
|
2 | #ifndef F_CPU
|
3 | /* Definiere F_CPU, wenn F_CPU nicht bereits vorher definiert
|
4 | (z.B. durch Übergabe als Parameter zum Compiler innerhalb
|
5 | des Makefiles). Zusätzlich Ausgabe einer Warnung, die auf die
|
6 | "nachträgliche" Definition hinweist */
|
7 | #warning "F_CPU war noch nicht definiert, wird nun mit 1000000 definiert"
|
8 | #define F_CPU 1000000UL
|
9 | #endif
|
10 | #include <util/delay.h>
|
11 |
|
12 | // Symbolische Namen für die Zustände
|
13 | // Beliebig wählbar, müssen aber unterscheidbar sein
|
14 | #define LED_AN 23
|
15 | #define LED_AUS 42
|
16 |
|
17 | // Hardwarefummeleien an einer Stelle im Quellcode gibt
|
18 | // bessere Lesbarkeit im Programm unten und eine Stelle
|
19 | // zentral fürs Entwanzen oder Hardwareanpassen...
|
20 | #define LED_PC0_ANSCHALTEN() do { PORTC &= ~(1 << PC0); } while(0)
|
21 | #define LED_PC0_AUSSCHALTEN() do { PORTC |= (1 << PC0); } while(0)
|
22 | #define TASTER_PB0_GEOEFFNET() (PINB & (1 << PB0))
|
23 | #define TASTER_PB0_GESCHLOSSEN() !(TASTER_PB0_GEOEFFNET())
|
24 |
|
25 | // http://www.mikrocontroller.net/articles/AVR-GCC-Tutorial#Warteschleifen_.28delay.h.29
|
26 | void warte_5s(void)
|
27 | {
|
28 | unsigned char i, j;
|
29 |
|
30 | for (i=0; i<5 ; i++) // 5 * 100 * 10 ms = 5000 ms = 5 s
|
31 | for (j=0; j<100; j++)
|
32 | _delay_ms(10); // funktioniert bis F_CPU 20 MHz
|
33 | }
|
34 |
|
35 | int main(void)
|
36 | {
|
37 | unsigned char zustand;
|
38 |
|
39 | // Hardware vorbereiten
|
40 | DDRB &= ~( 1 << PB0 ); //PB0 Eingang
|
41 | PORTB |= ( 1 << PB0 ); //Pull up an
|
42 | DDRC |= ( 1 << PC0 ); //PC0 Ausgang
|
43 |
|
44 | // Anfangsbedingung setzen
|
45 | zustand = LED_AUS;
|
46 | LED_PC0_AUSSCHALTEN();
|
47 |
|
48 | while(1)
|
49 | {
|
50 | if (zustand == LED_AUS)
|
51 | {
|
52 | // Taster abfragen, ob Zusand gewechselt werden soll
|
53 | if (TASTER_PB0_GESCHLOSSEN())
|
54 | {
|
55 | // Zustand wechseln
|
56 | zustand = LED_AN;
|
57 |
|
58 | // Dafür sorgen, dass die Hardware in diesen Zustand kommt
|
59 | LED_PC0_ANSCHALTEN();
|
60 | }
|
61 | }
|
62 | else if (zustand == LED_AN)
|
63 | {
|
64 | warte_5s();
|
65 |
|
66 | // Zustand wechseln
|
67 | zustand = LED_AUS;
|
68 |
|
69 | // Dafür sorgen, dass die Hardware in diesen Zustand kommt
|
70 | LED_PC0_AUSSCHALTEN();
|
71 | }
|
72 | }
|
73 | }
|