1 | // ************************************************************************
|
2 | // * *
|
3 | // * Arcade Stick *
|
4 | // * Tastenprogrammierung *
|
5 | // * *
|
6 | // ************************************************************************
|
7 |
|
8 | #include <avr/eeprom.h>
|
9 | #include <avr/interrupt.h>
|
10 | #include <avr/pgmspace.h>
|
11 | #include <util/delay.h>
|
12 |
|
13 | #ifndef F_CPU
|
14 | #define F_CPU 1000000 // Processor Takt-Frequenz definieren
|
15 | #warning kein F_CPU definiert
|
16 | #endif
|
17 |
|
18 | // Tasteneingänge definieren
|
19 | // =========================
|
20 | #define KEY_DDR DDRB
|
21 | #define KEY_PORT PORTB
|
22 | #define KEY_PIN PINB
|
23 | #define KEY0 6
|
24 | #define KEY1 7
|
25 | #define KEY2 0
|
26 | #define KEY3 1
|
27 | #define KEY4 2
|
28 | #define KEY5 3
|
29 | #define KEY6 4
|
30 | #define KEY7 5
|
31 | #define ALL_KEYS (1<<KEY0 | 1<<KEY1 | 1<<KEY2 | 1<<KEY3 | 1<<KEY4 | 1<<KEY5 | 1<<KEY6 | 1<<KEY7)
|
32 |
|
33 | // Tastendrückwiederholungsdauer definieren
|
34 | // ========================================
|
35 | #define REPEAT_MASK (1<<KEY0 | 1<<KEY1)
|
36 | #define REPEAT_START 50 // nach 500ms
|
37 | #define REPEAT_NEXT 20 // alle 200ms
|
38 |
|
39 | // Segment und Tasten-Ausgänge definieren
|
40 | // ======================================
|
41 | #define SEGMENT_DDR DDRD
|
42 | #define SEGMENT_PORT PORTD
|
43 | #define OUT_DDR DDRC
|
44 | #define OUT_PORT PORTC
|
45 | #define OUT1 0
|
46 | #define OUT2 1
|
47 | #define OUT3 2
|
48 | #define OUT4 3
|
49 | #define OUT5 4
|
50 | #define OUT6 5
|
51 | #define ALL_OUT (1<<OUT1 | 1<<OUT2 | 1<<OUT3 | 1<<OUT4 | 1<<OUT5 | 1<<OUT6)
|
52 |
|
53 | #define LED0 (1<<PC0)
|
54 | #define LED1 (1<<PC1)
|
55 | #define LED2 (1<<PC2)
|
56 | #define LED3 (1<<PC3)
|
57 | #define LED4 (1<<PC4)
|
58 | #define LED5 (1<<PC5)
|
59 |
|
60 | #define NR_KONFIGS 9
|
61 | #define NR_KEYS 6
|
62 | #define DELAY 300
|
63 |
|
64 | uint8_t KonfigPattern[NR_KONFIGS][NR_KEYS] PROGMEM =
|
65 | {
|
66 | {LED0,LED1,LED2,LED3,LED4,LED5}, // Konfiguration 1
|
67 | {LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 2
|
68 | {LED1,LED0,LED3,LED2,LED4,LED5}, // Konfiguration 3
|
69 | {LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 4
|
70 | {LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 5
|
71 | {LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 6
|
72 | {LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 7
|
73 | {LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 8
|
74 | {LED0,LED2,LED4,LED1,LED3,LED5}, // Konfiguration 9
|
75 | };
|
76 |
|
77 | volatile uint8_t key_state; // Entprellt und invertierte Tastenstatus:
|
78 | // Bit=1 -> Taste wurde gedrückt
|
79 | volatile uint8_t key_press; // Tastendruck registriert
|
80 | volatile uint8_t key_rpt; // Tastendruckdauer
|
81 | volatile uint8_t nKonfig; // Tasten-Konfiguration
|
82 | volatile uint8_t nFire = 0; // Dauerfeuer-Konfiguration
|
83 | volatile uint8_t nFireTime = 12; // Dauerfeuer-Zeit
|
84 | volatile uint8_t repeatFire;
|
85 | volatile uint8_t nSelect = 0; // Select-Taste
|
86 | volatile uint8_t Marker; // Speichermarkierung im 7-Segment
|
87 | volatile uint8_t Summe;
|
88 |
|
89 | unsigned char led = 0xFF;
|
90 | uint8_t eeKonfigByte; // EEPROM Konfigurationsvariable
|
91 |
|
92 | // Zeichentabelle für 7-Segment
|
93 | // ============================
|
94 | const unsigned char Tabelle[] PROGMEM = {192, 249, 164, 176, 153, 146, 130, 248, 128, 144};
|
95 |
|
96 | // Timer Interrupt von 10ms definieren
|
97 | // ===================================
|
98 | ISR(TIMER0_OVF_vect)
|
99 | {
|
100 | static uint8_t ct0, ct1, rpt, cntTicks;
|
101 | uint8_t i;
|
102 |
|
103 | TCNT0 = (uint8_t)(int16_t)-(F_CPU / 1024 * 10e-3 + 0.5);
|
104 |
|
105 | i = key_state ^ ~KEY_PIN; // Taste geändert?
|
106 | ct0 = ~(ct0 & i); // resete oder zähle CT0
|
107 | ct1 = ct0 ^ (ct1 & i); // resete oder zähle CT1
|
108 | i &= ct0 & ct1; // Überlauf gezählt?
|
109 | key_state ^= i; // dann Entprellstatus ändern
|
110 | key_press |= key_state & i; // 0->1: Tastendruck erkannt
|
111 |
|
112 | if((key_state & REPEAT_MASK) == 0) // Überprüfe Tastenwiederholfunktion
|
113 | rpt = REPEAT_START; // Starte Verzögerung
|
114 | if(--rpt == 0)
|
115 | {
|
116 | rpt = REPEAT_NEXT; // Wiederhole Verzögerung
|
117 | key_rpt |= key_state & REPEAT_MASK;
|
118 | }
|
119 |
|
120 | cntTicks++;
|
121 | if(cntTicks == nFireTime) // Ist Variable <nFireTime> mal 10ms
|
122 | {
|
123 | repeatFire ^= 0x01; // Wechselt PortC.0 nach Zeit von 0 auf 1
|
124 | cntTicks = 0;
|
125 | }
|
126 | }
|
127 |
|
128 | // Überprüfen, ob eine Taste gedrückt wurde.
|
129 | // Jede gedrückte Taste wird nur einmal gemeldet
|
130 | // =============================================
|
131 | uint8_t get_key_press(uint8_t key_mask)
|
132 | {
|
133 | cli(); // Interrupts deaktivieren
|
134 | key_mask &= key_press; // Tasten auslesen
|
135 | key_press ^= key_mask; // Tasten löschen
|
136 | sei(); // Interrupts aktivieren
|
137 | return key_mask;
|
138 | }
|
139 |
|
140 | // Erfolgt ein längerer Tastendruck, so wird nach einiger Zeit
|
141 | // der Tastendruck automatisch wieder verworfen.
|
142 | // ===========================================================
|
143 | uint8_t get_key_rpt(uint8_t key_mask)
|
144 | {
|
145 | cli(); // Interrupts deaktivieren
|
146 | key_mask &= key_rpt; // Tasten auslesen
|
147 | key_rpt ^= key_mask; // Tasten löschen
|
148 | sei(); // Interrupts aktivieren
|
149 | return key_mask;
|
150 | }
|
151 |
|
152 | // Kurzer Tastendruck
|
153 | // ==================
|
154 | uint8_t get_key_short(uint8_t key_mask)
|
155 | {
|
156 | cli(); // Interrupts deaktivieren
|
157 | return get_key_press(~key_state & key_mask);
|
158 | }
|
159 |
|
160 | // Langer Tastendruck
|
161 | // ==================
|
162 | uint8_t get_key_long(uint8_t key_mask)
|
163 | {
|
164 | return get_key_press(get_key_rpt(key_mask));
|
165 | }
|
166 |
|
167 | // Einschaltsequenz, Initialisierung der Ports
|
168 | // ===========================================
|
169 | void init()
|
170 | {
|
171 |
|
172 | // Ports initialisieren
|
173 | // --------------------
|
174 | OUT_DDR |= ALL_OUT; // Controller als Ausgang definieren
|
175 | KEY_DDR |= ALL_KEYS; // Tastenports als Ausgang definieren
|
176 |
|
177 | // LED-Test
|
178 | // --------
|
179 | for (uint8_t LED=1; LED<=32;)
|
180 | {
|
181 | KEY_PORT = ~LED; // Untere 8 Bit auf Taster-PORT B ausgegeben
|
182 | LED=LED<<1; // LED um 1 Bit weiterschieben
|
183 | _delay_ms(DELAY);
|
184 | }
|
185 | KEY_PORT=0xF6;
|
186 | _delay_ms(DELAY);
|
187 | KEY_PORT=0xED;
|
188 | _delay_ms(DELAY);
|
189 | KEY_PORT=0xDB;
|
190 | _delay_ms(DELAY);
|
191 | KEY_PORT=0xF8;
|
192 | _delay_ms(DELAY);
|
193 | KEY_PORT=0xC7;
|
194 | _delay_ms(DELAY);
|
195 | KEY_PORT=0xFF;
|
196 | _delay_ms(DELAY);
|
197 | KEY_PORT=0xC0;
|
198 | _delay_ms(DELAY);
|
199 | KEY_PORT=0xFF;
|
200 | _delay_ms(DELAY);
|
201 | KEY_PORT=0xC0;
|
202 | _delay_ms(DELAY);
|
203 | KEY_PORT=0xFF;
|
204 | _delay_ms(DELAY);
|
205 |
|
206 | // Segment-Test
|
207 | // ------------
|
208 |
|
209 | // 1
|
210 | // -
|
211 | // 32| 64|2
|
212 | // -
|
213 | // 16| 8 |4
|
214 | // -
|
215 | SEGMENT_DDR = 0xFF; // 7-Segmentports als Ausgang definieren
|
216 |
|
217 | for (uint8_t LED=1; LED<=64;)
|
218 | {
|
219 | SEGMENT_PORT = ~LED; // Untere 8 Bit auf 7-Segment-PORT D ausgegeben
|
220 | LED=LED<<1; // Segment um 1 Bit weiterschieben
|
221 | _delay_ms(DELAY);
|
222 | }
|
223 |
|
224 | // Interrupt aktvieren
|
225 | // -------------------
|
226 | TCCR0 = (1<<CS02)|(1<<CS00); // Teilen bei 1024
|
227 | TIMSK = 1<<TOIE0; // TimerInterrupt aktivieren
|
228 |
|
229 | // Ports für Funktion setzen
|
230 | // -------------------------
|
231 | KEY_DDR &= ~ALL_KEYS; // Tastenports als Eingang definieren
|
232 | KEY_PORT |= ALL_KEYS; // Tastenports PullUp
|
233 | }
|
234 |
|
235 | int main(void)
|
236 | {
|
237 | init(); // Einschaltsequenz starten
|
238 |
|
239 | nKonfig = eeprom_read_byte(&eeKonfigByte); // Aktuellen Wert aus EEPROM auslesen
|
240 | Marker = nKonfig; // EEPROM-Wert für Marker speichern
|
241 |
|
242 | sei(); // Interrupts aktivieren
|
243 |
|
244 | while(1)
|
245 | {
|
246 | Summe = 0;
|
247 |
|
248 | if(!(KEY_PIN & 0x01)) // Wenn Taste PortB.0 auf HIGH
|
249 | Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][0]);
|
250 | if(!(KEY_PIN & 0x02)) // Wenn Taste PortB.1 auf HIGH
|
251 | Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][1]);
|
252 | if(!(KEY_PIN & 0x04)) // Wenn Taste PortB.2 auf HIGH
|
253 | Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][2]);
|
254 | if(!(KEY_PIN & 0x08)) // Wenn Taste PortB.3 auf HIGH
|
255 | Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][3]);
|
256 | if(!(KEY_PIN & 0x10)) // Wenn Taste PortB.4 auf HIGH
|
257 | Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][4]);
|
258 | if(!(KEY_PIN & 0x20)) // Wenn Taste PortB.5 auf HIGH
|
259 | Summe |= pgm_read_byte(&KonfigPattern[nKonfig-1][5]);
|
260 |
|
261 | if(nFire != 0)
|
262 | {
|
263 | OUT_PORT = Summe | repeatFire;
|
264 | }
|
265 | else
|
266 | {
|
267 | OUT_PORT = Summe;
|
268 | }
|
269 |
|
270 | if(nSelect == 0)
|
271 | {
|
272 | SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]); // Konfigurationswert an 7-Segment übergeben
|
273 | if (nKonfig == Marker)
|
274 | {
|
275 | SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]) & ~(1 << 7);
|
276 | }
|
277 | }
|
278 | else
|
279 | {
|
280 | SEGMENT_PORT = pgm_read_byte(&Tabelle[nFire]); // Dauerfeuerwert an 7-Segment übergeben
|
281 | }
|
282 |
|
283 | if(get_key_short(1<<KEY0)) // kurzer Tastendruck (PinB.6)
|
284 | {
|
285 | if(nSelect == 0) // Ist Konfiguration gewählt
|
286 | {
|
287 | SEGMENT_PORT = 0x8E; // Buchstabe: F anzeigen
|
288 | nSelect = 1;
|
289 | _delay_ms(DELAY);
|
290 | SEGMENT_PORT = pgm_read_byte(&Tabelle[nFire]); // aktuellen Dauerfeuerwert am 7-Segment anzeigen
|
291 | }
|
292 | else
|
293 | {
|
294 | SEGMENT_PORT = 0xC6; // sonst Buchstabe: C anzeigen
|
295 | nSelect = 0;
|
296 | _delay_ms(DELAY);
|
297 | SEGMENT_PORT = pgm_read_byte(&Tabelle[nKonfig]);// aktuellen Konfigurationswert am 7-Segment anzeigen
|
298 | }
|
299 | }
|
300 |
|
301 | if(get_key_short(1<<KEY1)) // kurzer Tastendruck (PinB.7)
|
302 | {
|
303 | if(nSelect == 0)
|
304 | {
|
305 | if(nKonfig < 9) // Konfigurationswert kleiner als 8,
|
306 | {
|
307 | nKonfig++; // Wert erhöhen
|
308 | }
|
309 | else
|
310 | {
|
311 | nKonfig = 1; // ansonsten zu ersten Wert
|
312 | }
|
313 | }
|
314 | else
|
315 | {
|
316 | if(nFire < 9) // Dauerfeuerwert kleiner als 8,
|
317 | {
|
318 | nFire++; // Wert erhöhen
|
319 | nFireTime--;
|
320 | }
|
321 | else
|
322 | {
|
323 | nFire = 0; // ansonsten zu letzten Wert
|
324 | nFireTime = 12;
|
325 | }
|
326 | }
|
327 | }
|
328 |
|
329 | if(get_key_long(1<<KEY1) && (nSelect == 0)) // langer Tastendruck
|
330 | {
|
331 | eeprom_write_byte(&eeKonfigByte, nKonfig); // Wert in EEPROM speichern
|
332 | Marker = nKonfig; // EEPROM-Wert für Marker speichern
|
333 | }
|
334 | }
|
335 | }
|