1 | /* Timer von 1-999 Sekunden
|
2 |
|
3 | * 3 7-Segment LEDs werden im Multiplexbetrieb angesteuert
|
4 |
|
5 | #include <inttypes.h> // uint8_t usw.
|
6 | //#include <avr/io.h>
|
7 | #include <avr/interrupt.h> // Interrupts
|
8 | #include <avr/signal.h> // Interruptbehandlungsroutinen SIGNAL
|
9 | #include <avr/delay.h> // definiert _delay_ms und _delay_loop_2
|
10 | #include <avr/eeprom.h> // EEPROM Zugriffe
|
11 |
|
12 | #define delay_us(us) _delay_loop_2 (((F_CPU/4000)*us)/1000) // wartet µs
|
13 | #define EEPROM __attribute__ ((section (".eeprom"))) // für EEPROM-Zugriffe
|
14 |
|
15 | /*
|
16 | Aufbau 7-Segment
|
17 |
|
18 | // Welcher Port an welchem Segement:
|
19 | #define segm_a PD0
|
20 | #define segm_b PD1
|
21 | #define segm_c PD2
|
22 | #define segm_d PD3
|
23 | #define segm_e PD4
|
24 | #define segm_f PD5
|
25 | #define segm_g PD6
|
26 |
|
27 | // Welcher Port an welcher Digit:
|
28 | #define digit1 PC3 // Einer
|
29 | #define digit2 PC4 // Zehner
|
30 | #define digit3 PC5 // Hunderter
|
31 |
|
32 | // An welchem Port sind Taster
|
33 | #define btn_up PB0
|
34 | #define btn_down PB1
|
35 | #define btn_start PB2
|
36 |
|
37 | // An welchem Port hängt Relais
|
38 | //#define relais PD7
|
39 |
|
40 | // Ports definieren
|
41 | #define port_segment PORTD
|
42 | #define port_digit PORTC
|
43 | #define port_keys PORTB
|
44 | #define dir_segment DDRD
|
45 | #define dir_digit DDRC
|
46 | #define dir_keys DDRB
|
47 | #define pin_keys PINB
|
48 |
|
49 | // Definiert, welche Segmente für die einzelnen Zahlenwerte aufleuchten sollen. HIGH-Aktiv
|
50 | #define sign0 (1 << segm_a) | (1 << segm_b) | (1 << segm_c) | (1 << segm_d) | (1 << segm_e) | (1 << segm_f)
|
51 | #define sign1 (1 << segm_b) | (1 << segm_c)
|
52 | #define sign2 (1 << segm_a) | (1 << segm_b) | (1 << segm_g) | (1 << segm_e) | (1 << segm_d)
|
53 | #define sign3 (1 << segm_a) | (1 << segm_b) | (1 << segm_g) | (1 << segm_c) | (1 << segm_d)
|
54 | #define sign4 (1 << segm_f) | (1 << segm_g) | (1 << segm_b) | (1 << segm_c)
|
55 | #define sign5 (1 << segm_a) | (1 << segm_f) | (1 << segm_g) | (1 << segm_c) | (1 << segm_d)
|
56 | #define sign6 (1 << segm_a) | (1 << segm_f) | (1 << segm_g) | (1 << segm_e) | (1 << segm_d) | (1 << segm_c)
|
57 | #define sign7 (1 << segm_a) | (1 << segm_b) | (1 << segm_c)
|
58 | #define sign8 (1 << segm_a) | (1 << segm_b) | (1 << segm_c) | (1 << segm_d) | (1 << segm_e) | (1 << segm_f) | (1 << segm_g)
|
59 | #define sign9 (1 << segm_a) | (1 << segm_b) | (1 << segm_c) | (1 << segm_d) | (1 << segm_g) | (1 << segm_f)
|
60 |
|
61 | uint8_t num[] = { sign0, sign1, sign2, sign3, sign4, sign5, sign6, sign7, sign8, sign9 };
|
62 | uint16_t startwert EEPROM; // Speicherplatz für letzten Startwert im EEPROM
|
63 | volatile uint16_t display_value=0; // Startwert.
|
64 | volatile uint8_t run=0; // =0 Counter Stop; =1 Counter läuft
|
65 | volatile uint8_t relais=0; // =0 Relais off, =1 Relais on
|
66 | volatile uint8_t key_up=0, // Puffer für Tastendrücke
|
67 | key_down=0,
|
68 | key_start=0;
|
69 |
|
70 | /**
|
71 | @brief Gibt Zahlenwert auf 7 Segment Display aus
|
72 | @param zahl
|
73 | @return none
|
74 | */
|
75 | void ausgabe (uint16_t zahl)
|
76 | {
|
77 | uint16_t output = zahl;
|
78 | uint16_t warten = 500; // Enable Zeit für einzelnes Segment. Zeit in der LED leuchten
|
79 |
|
80 | // Hunderter-Dezimalstelle
|
81 | if (zahl >= 100)
|
82 | {
|
83 | port_segment = relais | num[output/100]; // Zahlenwert darstellen zzgl. Zustand für PB7
|
84 | port_digit = (1 << digit3); // 3. Digit HIGH
|
85 | delay_us(warten); // LEDs müssen gewisse Zeit leuchten
|
86 | port_digit = 0; // 3. Digit HIGH
|
87 | }
|
88 | output = output % 100;
|
89 |
|
90 | // Zehner-Dezimalstelle
|
91 | if (zahl >= 10)
|
92 | {
|
93 | port_segment = relais | num[output/10]; // Zahlenwert darstellen zzgl. Zustand für PB7
|
94 | port_digit = (1 << digit2); // 2. Digit HIGH
|
95 | delay_us(warten); // LEDs müssen gewisse Zeit leuchten
|
96 | port_digit = 0; // 2. Digit HIGH
|
97 | }
|
98 | output = output % 10;
|
99 |
|
100 | // einer Dezimalstelle
|
101 | port_segment = relais | num[output]; // Zahlenwert darstellen zzgl. Zustand für PB7
|
102 | port_digit = (1 << digit1); // 1. Digit HIGH
|
103 | delay_us(warten); // LEDs müssen gewisse Zeit leuchten
|
104 | port_digit = 0; // 1. Digit HIGH
|
105 |
|
106 | sei(); // Interrupts zulassen
|
107 | }
|
108 |
|
109 | /**
|
110 | @brief Interruptbehandlung für Timer zum Displayrefresh
|
111 | @param none
|
112 | @return none
|
113 | */
|
114 | SIGNAL (SIG_OVERFLOW0)
|
115 | {
|
116 | cli(); // Interrupts nicht zulassen
|
117 | ausgabe (display_value); // Zahl darstellen
|
118 | }
|
119 |
|
120 | /**
|
121 | @brief Interruptbehandlung für Timer zur Tastenabfrage.
|
122 | Für jede Taste erxistiert eine Variable, die inkrementiert wird, wenn Interrupt ausgelöst wird und Taste gedrückt ist
|
123 | Sind x Tastenimpulse zusammen, wird im Hauptprogramm die Taste als gedrückt angesehen
|
124 | @param none
|
125 | @return none
|
126 | */
|
127 | SIGNAL (SIG_OVERFLOW2)
|
128 | {
|
129 | cli(); // Interrupts nicht zulassen
|
130 |
|
131 | if (pin_keys & (1 << btn_up)) // Up-Taste gedrückt
|
132 | key_up++;
|
133 |
|
134 | if (pin_keys & (1 << btn_down)) // Down-Taste gedrückt
|
135 | key_down++;
|
136 |
|
137 | if (pin_keys & (1 << btn_start)) // Start-Taste gedrückt
|
138 | key_start++;
|
139 |
|
140 | sei(); // Interrupts zulassen
|
141 | }
|
142 |
|
143 | /**
|
144 | @brief Interruptbehandlung für Timer für Sekundentakt bei gestartetem Counter
|
145 | Wird jede Sekunde einmal ausgelöst und dekrementiert den Zähler
|
146 | @param none
|
147 | @return none
|
148 | */
|
149 | SIGNAL (SIG_OUTPUT_COMPARE1A)
|
150 | {
|
151 | cli(); // Interrupts nicht zulassen
|
152 | TCNT1H=0; // Timerstand zurücksetzen
|
153 | TCNT1L=0;
|
154 |
|
155 | display_value -= run;
|
156 | }
|
157 |
|
158 | int main(void)
|
159 | {
|
160 |
|
161 | dir_digit = (1 << digit1) | (1 << digit2) | (1 << digit3); // Ausgänge, für Digits
|
162 | dir_segment = 0xFF; // alles Ausgänge, für Segmente
|
163 | dir_keys &= ~(1 << btn_up) & ~(1 << btn_down) & ~(1 << btn_start); // Eingänge für Tasten
|
164 |
|
165 | // Timer für Displayrefresh
|
166 | // TCCR0 |= (1<<CS01); //8-Bit Timer, Timer clock = system clock/8
|
167 | TCCR0 |= (1<<CS01) | (1<<CS00); //8-Bit Timer, Timer clock = system clock/64
|
168 | // TCCR0 |= (1<<CS02); //8-Bit Timer, Timer clock = system clock/256
|
169 | // TCCR0 |= (1<<CS02) | (1<<CS00); //8-Bit Timer, Timer clock = system clock/1024
|
170 | TIFR |= (1<<TOV0); //Clear TOV0 Timer/Counter Overflow Flag. clear pending interrupts
|
171 | TIMSK |= (1<<TOIE0); //Enable Timer0 Overflow Interrupt
|
172 |
|
173 | // Timer für Tastenabfrage
|
174 | TCCR2 |= (1<<CS22) | (1<<CS20); //8-Bit Timer, Timer clock = system clock/1024
|
175 | TIFR |= (1<<TOV2); //Clear TOV2 Timer/Counter Overflow Flag. clear pending interrupts
|
176 | TIMSK |= (1<<TOIE2); //Enable Timer2 Overflow Interrupt
|
177 |
|
178 | // Timer für Sekundentakt
|
179 | OCR1AH = 0x1E; // 16Bit Timer Takt= 8MHz => 8.000.000/1024 = 7812,5 => 7,8125 Zählerschritte pro ms
|
180 | OCR1AL = 0x83; // Vergleichswert laden: 1 Sekunde
|
181 | TIMSK |= (1<<OCIE1A); // Interrupt wenn Timer Vergleichswert erreicht
|
182 |
|
183 | sei(); // Interrupts zulassen
|
184 |
|
185 | while (1)
|
186 | {
|
187 | if (key_up >= 50) // Up-Taste gedrückt
|
188 | {
|
189 | display_value++; // Wert +1
|
190 | if (display_value > 999) // Wenn Überlauf => Wert=0
|
191 | display_value = 1;
|
192 | key_up = 0; // Tastencounter leeren
|
193 | }
|
194 | if (key_down >= 50) // Down-Taste gedrückt
|
195 | {
|
196 | if (display_value <= 1) // Wenn Unterlauf => Wert=999
|
197 | display_value = 1000;
|
198 | display_value--; // Wert -1
|
199 | key_down = 0; // Tastencounter leeren
|
200 | }
|
201 |
|
202 | if (key_start >= 100) // Start-Taste gedrückt
|
203 | {
|
204 | key_start = 0; // Tastencounter leeren
|
205 | if (display_value == 0) // wenn angezeigter Wert = 0 und Start gedrückt => ermittler zuletzt verwendeten Startwert und setze diesen
|
206 | {
|
207 | display_value = eeprom_read_word(&startwert);
|
208 | }
|
209 | else
|
210 | {
|
211 | run ^= 1; // Wert XOR 1; => Start/Stop
|
212 | if (run) // Wenn Counter gestartet wird
|
213 | {
|
214 | if (display_value != eeprom_read_word(&startwert)) // wenn Start gedrückt und aktueller Startwert != letzter Startwert
|
215 | eeprom_write_word(&startwert, display_value); // dann speichere neuen Startwert
|
216 |
|
217 | TCNT1H=0; // Timerstand zurücksetzen, damit ab jetzt eine Sekunde zählt
|
218 | TCNT1L=0;
|
219 | TCCR1B = (1<<CS10)|(1<<CS12); // Timer mit Div 1024 starten
|
220 | relais = 0x80; // zusätzlich Relais HIGH
|
221 | }
|
222 | else // Counter angehalten
|
223 | {
|
224 | TCCR1B = 0; // Timer Stop
|
225 | relais = 0x0; // Relais LOW
|
226 | }
|
227 | }
|
228 | }
|
229 |
|
230 | if (display_value == 0) // Timer abgelaufen
|
231 | {
|
232 | run = 0; // Stop
|
233 | relais = 0x0; // Relais LOW
|
234 | }
|
235 | }
|
236 | }
|