| 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 | }
 |