1 | /************************************************************************/
|
2 | /* */
|
3 | /* Debouncing 8 Keys */
|
4 | /* Sampling 4 Times */
|
5 | /* With Repeat Function */
|
6 | /* */
|
7 | /* Author: Peter Dannegger */
|
8 | /* danni@specs.de */
|
9 | /* */
|
10 | /************************************************************************/
|
11 |
|
12 | #include <avr/io.h>
|
13 | #include <stdio.h>
|
14 | #include <stdlib.h>
|
15 | #include <string.h>
|
16 | #include "main.h"
|
17 | #include "lcd.h"
|
18 | #include <avr/wdt.h>
|
19 | #include <avr/interrupt.h>
|
20 | #include <util/delay.h>
|
21 | #include <inttypes.h>
|
22 |
|
23 | #ifndef F_CPU
|
24 | #define F_CPU 7372800 // processor clock frequency
|
25 | #warning kein F_CPU definiert
|
26 | #endif
|
27 |
|
28 | #define KEY_DDR DDRC
|
29 | #define KEY_PORT PORTC
|
30 | #define KEY_PIN PINC
|
31 | #define KEY_mitte 7
|
32 | #define KEY_links 3
|
33 | #define KEY_rechts 4
|
34 | #define KEY_oben 6
|
35 | #define KEY_unten 2
|
36 | #define ALL_KEYS (1<<KEY_mitte | 1<<KEY_links | 1<<KEY_rechts | 1<<KEY_oben | 1<<KEY_unten)
|
37 |
|
38 | #define REPEAT_MASK (1<<KEY_links | 1<<KEY_rechts | 1<<KEY_mitte | 1<<KEY_oben | 1<<KEY_unten) // repeat: key1, key2
|
39 | #define REPEAT_START 50 // after 500ms
|
40 | #define REPEAT_NEXT 20 // every 200ms
|
41 |
|
42 | #define LED_DDR DDRD
|
43 | #define LED_PORT PORTD
|
44 | #define LED0 0
|
45 | #define LED1 1
|
46 | #define LED2 2
|
47 | #define LED3 3
|
48 | #define LED4 4
|
49 | #define LED5 5
|
50 |
|
51 | #define ADCINPUTS 8 // Anzahl der ADC Eingänge
|
52 |
|
53 | volatile uint8_t key_state; // debounced and inverted key state:
|
54 | // bit = 1: key pressed
|
55 | volatile uint8_t key_press; // key press detect
|
56 |
|
57 | volatile uint8_t key_rpt; // key long press and repeat
|
58 | uint16_t display_update = 100; // Aktualisierungstimer Display in ms
|
59 | volatile uint8_t menu =0;
|
60 | volatile uint16_t countdown =0;
|
61 |
|
62 | /*
|
63 | Globale Variablen im RAM
|
64 | */
|
65 | char ram_string[32];
|
66 | uint8_t counter=0 , ledcounter=0;
|
67 | volatile uint8_t flag_update_display = 0; // Variable jederzeit änderbar
|
68 | volatile uint8_t flag_start=1;
|
69 | volatile uint8_t flag_countdown=0;
|
70 | volatile uint8_t flag_firstcount=0;
|
71 | uint16_t sekunden=0;
|
72 | uint16_t adc[ADCINPUTS];
|
73 | uint8_t flag_high[ADCINPUTS];
|
74 |
|
75 |
|
76 | void timer0()
|
77 | {
|
78 | TCCR0 = (1<<CS02)|(1<<CS00); // divide by 1024
|
79 | TCNT0 = (-72); // preload for 10ms
|
80 | TIMSK |= 1<<TOIE0; // enable timer interrupt
|
81 | }
|
82 |
|
83 | ISR( TIMER0_OVF_vect ) // every 10ms
|
84 | {
|
85 | static uint8_t ct0, ct1, rpt;
|
86 | uint8_t i;
|
87 |
|
88 | TCNT0 = (-72); // preload for 10ms
|
89 | i = key_state ^ ~KEY_PIN; // key changed ?
|
90 | ct0 = ~( ct0 & i ); // reset or count ct0
|
91 | ct1 = ct0 ^ (ct1 & i); // reset or count ct1
|
92 | i &= ct0 & ct1; // count until roll over ?
|
93 | key_state ^= i; // then toggle debounced state
|
94 | key_press |= key_state & i; // 0->1: key press detect
|
95 |
|
96 | if( (key_state & REPEAT_MASK) == 0 ) // check repeat function
|
97 | rpt = REPEAT_START; // start delay
|
98 | if( --rpt == 0 )
|
99 | {
|
100 | rpt = REPEAT_NEXT; // repeat delay
|
101 | key_rpt |= key_state & REPEAT_MASK;
|
102 | }
|
103 |
|
104 | counter++;
|
105 | if(!(flag_start)) // Kein Startzustand mehr
|
106 | {
|
107 | if((countdown==0) && (flag_firstcount!=0))
|
108 | {
|
109 | flag_countdown = 0;
|
110 | }
|
111 | else countdown--;
|
112 | if(flag_countdown==0)
|
113 | {
|
114 | menu = 1;
|
115 | PORTB &= ~(1<<PB0);
|
116 | lcd_clear();
|
117 | lcd_setcursor(0,0);
|
118 | lcd_string("Standardmodus");
|
119 | flag_countdown=1;
|
120 | }
|
121 | }
|
122 | if(menu==2)
|
123 | {
|
124 | if(counter==(display_update)/10)
|
125 | {
|
126 | flag_update_display = 1;
|
127 | }
|
128 | }
|
129 | if(menu==1)
|
130 | {
|
131 | if(counter==(display_update)/10)
|
132 | {
|
133 | flag_update_display = 1;
|
134 | }
|
135 | if(counter==100) // 1 Sekunde
|
136 | {
|
137 | sekunden++;
|
138 | switch(ledcounter)
|
139 | {
|
140 | case 0: PORTD ^= (1<<PD0); break;
|
141 | case 1: PORTD ^= (1<<PD1); break;
|
142 | case 2: PORTD ^= (1<<PD2); break;
|
143 | case 3: PORTD ^= (1<<PD3); break;
|
144 | case 4: PORTD ^= (1<<PD4); break;
|
145 | case 5: PORTD ^= (1<<PD5); break;
|
146 | case 6: PORTD ^= (1<<PB6); break;
|
147 | case 7: PORTD ^= (1<<PB7); break;
|
148 | }
|
149 | ledcounter++;
|
150 | if(ledcounter==8)ledcounter=0;
|
151 | counter=0;
|
152 | }
|
153 | }
|
154 |
|
155 | ///////////////////////////////////////////////////////////////////
|
156 | //
|
157 | // check if a key has been pressed. Each pressed key is reported
|
158 | // only once
|
159 | //
|
160 | uint8_t get_key_press( uint8_t key_mask )
|
161 | {
|
162 | cli(); // read and clear atomic !
|
163 | key_mask &= key_press; // read key(s)
|
164 | key_press ^= key_mask; // clear key(s)
|
165 | sei();
|
166 | return key_mask;
|
167 | }
|
168 |
|
169 | ///////////////////////////////////////////////////////////////////
|
170 | //
|
171 | // check if a key has been pressed long enough such that the
|
172 | // key repeat functionality kicks in. After a small setup delay
|
173 | // the key is reported being pressed in subsequent calls
|
174 | // to this function. This simulates the user repeatedly
|
175 | // pressing and releasing the key.
|
176 | //
|
177 | uint8_t get_key_rpt( uint8_t key_mask )
|
178 | {
|
179 | cli(); // read and clear atomic !
|
180 | key_mask &= key_rpt; // read key(s)
|
181 | key_rpt ^= key_mask; // clear key(s)
|
182 | sei();
|
183 | return key_mask;
|
184 | }
|
185 |
|
186 | ///////////////////////////////////////////////////////////////////
|
187 | //
|
188 | // check if a key is pressed right now
|
189 | //
|
190 | uint8_t get_key_state( uint8_t key_mask )
|
191 |
|
192 | {
|
193 | key_mask &= key_state;
|
194 | return key_mask;
|
195 | }
|
196 |
|
197 | ///////////////////////////////////////////////////////////////////
|
198 | //
|
199 | uint8_t get_key_short( uint8_t key_mask )
|
200 | {
|
201 | cli(); // read key state and key press atomic !
|
202 | return get_key_press( ~key_state & key_mask );
|
203 | }
|
204 |
|
205 | ///////////////////////////////////////////////////////////////////
|
206 | //
|
207 | uint8_t get_key_long( uint8_t key_mask )
|
208 | {
|
209 | return get_key_press( get_key_rpt( key_mask ));
|
210 | }
|
211 |
|
212 |
|
213 | void ADC_Init(void)
|
214 | {
|
215 | cli();
|
216 | PORTB &= ~(1 << PB0); // Blaue LED resetten
|
217 | ACSR = (1<<ACD); // Analog Comperator AUS
|
218 |
|
219 | // die Versorgungsspannung AVcc als Refernz wählen:
|
220 | ADMUX = (1<<REFS0);
|
221 |
|
222 | /* oder interne Referenzspannung als Referenz für den ADC wählen:
|
223 | ADMUX = (1<<REFS1) | (1<<REFS0);
|
224 |
|
225 | Bit ADFR ("free running") in ADCSRA steht beim Einschalten
|
226 | schon auf 0, also single conversion
|
227 |
|
228 |
|
229 | ADC Takt zwischen 50-200kHz
|
230 | TFmin = CLK/200kHz = 36,8 (7,372MHz)
|
231 | Nächstgrößerer Teilungsfaktor: 64
|
232 | mit ADPS2 = 1 , ADPS1 = 1 und ADPS0 = 0 */
|
233 |
|
234 | ADCSRA = ((1<<ADPS2)|(1<<ADPS1));
|
235 | ADCSRA &= ~(1<<ADPS0);
|
236 | ADCSRA = (1<<ADEN); // ADC aktivieren
|
237 |
|
238 | /* nach Aktivieren des ADC wird ein "Dummy-Readout" empfohlen, man liest
|
239 | also einen Wert und verwirft diesen, um den ADC "warmlaufen zu lassen" */
|
240 |
|
241 | ADCSRA |= (1<<ADSC); // eine ADC-Wandlung
|
242 | while (ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung warten
|
243 | {
|
244 | }
|
245 | /* ADCW muss einmal gelesen werden, sonst wird Ergebnis der nächsten
|
246 | Wandlung nicht übernommen. */
|
247 |
|
248 | sei();
|
249 | (void) ADCW;
|
250 | }
|
251 |
|
252 |
|
253 | uint16_t ADC_Read( uint8_t channel )
|
254 | {
|
255 | // Kanal waehlen, ohne andere Bits zu beeinflußen
|
256 | ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
|
257 | ADCSRA |= (1<<ADSC); // eine Wandlung "single conversion"
|
258 | while (ADCSRA & (1<<ADSC) ) // auf Abschluss der Konvertierung warten
|
259 | {
|
260 | }
|
261 | return ADCW; // ADC auslesen und zurückgeben
|
262 | }
|
263 |
|
264 | /* ADC Mehrfachmessung mit Mittelwertbbildung */
|
265 | /* beachte: Wertebereich der Summenvariablen */
|
266 | uint16_t ADC_Read_Avg( uint8_t channel, uint8_t nsamples )
|
267 | {
|
268 | uint32_t sum = 0;
|
269 |
|
270 | for (uint8_t i = 0; i < nsamples; ++i )
|
271 | {
|
272 | sum += ADC_Read( channel );
|
273 | }
|
274 |
|
275 | return (uint16_t)( sum / nsamples );
|
276 | }
|
277 |
|
278 |
|
279 |
|
280 | void declaration()
|
281 | {
|
282 | /* WDTCR = (1<<WDTOE);
|
283 | WDTCR &= ~(1<<WDE); // Watchdog deaktivieren */
|
284 | DDRB = 0xFF; // Blaue LED: Ausgang
|
285 | PORTB &= ~(1<< PB0);
|
286 | DDRC = 0x00; // Eingänge
|
287 | DDRC = ((1 << DDC0) | (1 << DDC1)) ; // PC0-3 Ausgang
|
288 | PORTC = 0xFF;
|
289 | PORTC &= ~((1<<PC0) | (1 <<PC1));
|
290 |
|
291 | DDRD = 0xFF; // Alle Pins von Port D als Ausgang
|
292 | PORTD = (0<<PD0)| (0<<PD1)|(0<<PD2)|(0<<PD3)|(0<<PD4)|(0<<PD5)|(0<<PD6);
|
293 |
|
294 | DDRA = 0xFF; // LCD Ausgänge
|
295 | DDRA &= ~((1<<PA6) | (1<<PA7)); // ADC Eingänge
|
296 | }
|
297 |
|
298 |
|
299 | int main( void )
|
300 | {
|
301 | double dAufloesung = 5000/(2*2*2*2*2*2*2*2*2*2);
|
302 | char cEingang;
|
303 | int8_t i=6, k=0;
|
304 |
|
305 | LED_PORT = 0xFF;
|
306 | LED_DDR = 0xFF;
|
307 |
|
308 | // Configure debouncing routines
|
309 | KEY_DDR &= ~ALL_KEYS; // configure key port for input
|
310 | KEY_PORT |= ALL_KEYS; // and turn on pull up resistors
|
311 |
|
312 |
|
313 | /* IOs initialisieren */
|
314 |
|
315 | declaration();
|
316 | lcd_init();
|
317 | ADC_Init();
|
318 | timer0(); // 10ms
|
319 | sei();
|
320 |
|
321 | // Strings aus dem RAM ausgeben
|
322 | // sinnvoll, wenn Variablen in die Formatierung eingebaut werden sollen.
|
323 | lcd_clear();
|
324 | lcd_setcursor(0,0); // (Spalte,Zeile)
|
325 | lcd_string("System Bereit?");
|
326 | lcd_setcursor(0,1);
|
327 | //lcd_string("78 aktiv!");
|
328 |
|
329 | for(uint8_t m=6; m<ADCINPUTS; m++)
|
330 | {
|
331 | adc[m] = ADC_Read_Avg(m,5);
|
332 | }
|
333 | for (uint8_t l=6; l<ADCINPUTS; l++)
|
334 | {
|
335 | if(adc[l]>255)flag_high[l]=1;
|
336 | else flag_high[l]=0;
|
337 | }
|
338 | uint8_t x =0;
|
339 | if(flag_high[6]==1)
|
340 | {
|
341 | lcd_string("7");
|
342 | x++;
|
343 | lcd_setcursor(x,1);
|
344 | }
|
345 | if(flag_high[7]==1)
|
346 | {
|
347 | lcd_string("8");
|
348 | x++;
|
349 | lcd_setcursor(x,1);
|
350 | }
|
351 | lcd_string(" aktiv!");
|
352 |
|
353 | for(uint8_t n=0; n<(ADCINPUTS-2); n++)
|
354 | {
|
355 | flag_high[n]=0;
|
356 | }
|
357 | /*while(menu==0)
|
358 | {
|
359 |
|
360 | if(get_key_short(ALL_KEYS))
|
361 | {
|
362 | menu=1;
|
363 | }
|
364 | }
|
365 | lcd_clear();
|
366 | lcd_setcursor(0,0);
|
367 | lcd_string("ADC Werte Test!"); // verbraucht unnötig RAM beim AVR
|
368 | lcd_setcursor(0,1);*/
|
369 |
|
370 |
|
371 |
|
372 | while(1)
|
373 | {
|
374 | //if( get_key_short( 1<<KEY_mitte ))
|
375 |
|
376 | //LED_PORT ^= 1<<LED1;
|
377 | /*
|
378 | for(uint8_t m=0; m<ADCINPUTS; m++)
|
379 | {
|
380 | adc[m] = ADC_Read_Avg(m,5);
|
381 | } */
|
382 | if((PINC & 0b00100000)&& (menu!=4))
|
383 | {
|
384 | menu=4;
|
385 | lcd_clear();
|
386 | lcd_setcursor(0,0);
|
387 | lcd_string("Poti Test");
|
388 | }
|
389 | switch(menu)
|
390 | {
|
391 | case 0: // Start
|
392 | {
|
393 | if(get_key_short(ALL_KEYS))
|
394 | {
|
395 |
|
396 | lcd_clear();
|
397 | lcd_setcursor(0,0);
|
398 | lcd_string("Standardmodus!"); // verbraucht unnötig RAM beim AVR
|
399 | lcd_setcursor(0,1);
|
400 | menu=1;
|
401 | flag_start=0;
|
402 | }
|
403 | } break;
|
404 |
|
405 | case 1: // Standardbetrieb
|
406 | {
|
407 | for(uint8_t m=0; m<ADCINPUTS; m++)
|
408 | {
|
409 | adc[m] = ADC_Read_Avg(m,5);
|
410 | }
|
411 | for(uint8_t j=6;j<8;j++)
|
412 | {
|
413 | if((adc[j]<256) && flag_high[j])
|
414 | {
|
415 | lcd_setcursor(k,1);
|
416 | if(j==6)lcd_string("A");
|
417 | else if(j==7) lcd_string("B");
|
418 | k++;
|
419 | if(k==16)k=0;
|
420 | }
|
421 | else if(adc[j]>255)flag_high[j]=1;
|
422 | }
|
423 | if(get_key_short(ALL_KEYS))
|
424 | {
|
425 | lcd_clear();
|
426 | lcd_setcursor(0,0);
|
427 | lcd_string("Testmodus");
|
428 | countdown = 1000; // 5 Sekunden
|
429 | flag_firstcount=1;
|
430 | menu = 2;
|
431 | LED_PORT = 0x00;
|
432 | PORTB |= (1<<PB0);
|
433 | }
|
434 | } break;
|
435 | case 2: // Testmodus, ADC läuft weiter, 5 Sekunden ohne Eingabe
|
436 | {
|
437 | for(uint8_t m=0; m<ADCINPUTS; m++)
|
438 | {
|
439 | adc[m] = ADC_Read_Avg(m,5);
|
440 | }
|
441 | if(flag_update_display)
|
442 | {
|
443 | flag_update_display =0;
|
444 | cEingang = '0'+i+1; // ASCII Codes erzeugen
|
445 | lcd_setcursor(0,1);
|
446 | sprintf_P(ram_string, PSTR("In %c: %i"), cEingang, (int)(adc[i]*dAufloesung));
|
447 | lcd_string(ram_string); // hier sinnvoll
|
448 | }
|
449 | if( get_key_short( 1<<KEY_unten))
|
450 | {
|
451 | LED_PORT ^= 1<<LED0;
|
452 | countdown = 1000; // 5 Sekunden
|
453 | }
|
454 | if( get_key_long( 1<<KEY_unten))
|
455 | {
|
456 | LED_PORT ^= 1<<LED1;
|
457 | countdown = 1000;
|
458 | }
|
459 | if( get_key_short( 1<<KEY_oben))
|
460 | {
|
461 | LED_PORT ^= 1<<LED1;
|
462 | countdown = 500; // 5 Sekunden
|
463 | }
|
464 | if( get_key_short( 1<<KEY_links))
|
465 | {
|
466 | LED_PORT ^= 1<<LED2;
|
467 | countdown = 1000; // 5 Sekunden
|
468 | }
|
469 | if( get_key_short( 1<<KEY_rechts))
|
470 | {
|
471 | LED_PORT ^= 1<<LED0;
|
472 | countdown = 1000; // 5 Sekunden
|
473 | }
|
474 | if (get_key_long(1<<KEY_rechts))
|
475 | {
|
476 | LED_PORT ^= 1<<LED1;
|
477 | countdown = 1000; // 5 Sekunden
|
478 | }
|
479 | if( get_key_short( 1<<KEY_mitte))
|
480 | {
|
481 | i++;
|
482 | if(i==8)i=6;
|
483 | countdown = 1000; // 5 Sekunden
|
484 | flag_update_display=1;
|
485 | }
|
486 |
|
487 | // single press and repeat
|
488 | if( get_key_press( 1<<KEY_oben ) || get_key_rpt( 1<<KEY_oben ))
|
489 | {
|
490 | countdown = 1000; // 5 Sekunden
|
491 | uint8_t i = LED_PORT;
|
492 | i = (i & 0x07) | ((i << 1) & 0xF0);
|
493 | if( i < 0xF0 )
|
494 | i |= 0x08;
|
495 | LED_PORT = i;
|
496 | }
|
497 | } break;
|
498 | case 4:
|
499 | {
|
500 | for(uint8_t m=0; m<ADCINPUTS; m++)
|
501 | {
|
502 | adc[m] = ADC_Read_Avg(m,5);
|
503 | }
|
504 | if(adc[i]<128)LED_PORT=0b00000010;
|
505 | else if((adc[i]>127)&&(adc[i]<256)) LED_PORT=0b00000011;
|
506 | else if((adc[i]>255)&&(adc[i]<385))LED_PORT=0b00000111;
|
507 | else if((adc[i]>384)&&(adc[i]<512))LED_PORT=0b00001111;
|
508 | else if((adc[i]>511)&&(adc[i]<683))LED_PORT=0b00011111;
|
509 | else if((adc[i]>682)&&(adc[i]<853))LED_PORT=0b00111111;
|
510 | else if(adc[i]>852)LED_PORT=0b01111111;
|
511 | if(!(PINC && 0b00100000))flag_countdown=0;
|
512 | } break;
|
513 | }
|
514 | }
|
515 | }
|