encoder4.c


1
/************************************************************************/
2
/*                                    */
3
/*            Commodore 64 Red Edition            */
4
/*            Encoder 4 - SD2IEC ID              */
5
/*                                    */
6
/************************************************************************/
7
#include <avr/io.h>
8
#include <avr/interrupt.h>
9
#include <avr/sleep.h>
10
#include <avr/eeprom.h>
11
#include <avr/pgmspace.h>
12
#include <util/delay.h>
13
14
// CPU: ATTiny44-20PU 8MHz
15
// =======================================================================
16
17
// Ein-/Ausgänge
18
// -----------------------------------------------------------------------
19
#define ENCODER_PORT      PORTB
20
#define ENCODER_DDR        DDRB
21
#define TASTER_PIN        PINB
22
23
#define AUSGANG_PORT      PORTA
24
#define AUSGANG_DDR        DDRA
25
#define AUSGANG_PIN        PINA
26
27
#define ENCODER_A        (PINB & (1 << PB0))
28
#define ENCODER_B        (PINB & (1 << PB1))
29
#define TASTER          (1 << PB2)
30
#define EIN_AUS          (1 << PA7)
31
32
// Schalt-Muster
33
// -----------------------------------------------------------------------
34
#define LO            0x00                // 0000 0000
35
#define HI            0xFF                // 1111 1111
36
#define SCHALT          0x3F                // 0011 1111
37
#define RESET          0x40                // 0100 0000
38
#define AKTIV          0x80                // 1000 0000
39
40
#define ID_LO          0x30                // 0011 0000
41
#define ID_8          0x30                // 0011 0000
42
#define ID_9          0x20                // 0010 0000
43
#define ID_10          0x10                // 0001 0000
44
#define ID_11          0x00                // 0000 0000
45
46
// LED-Muster
47
// -----------------------------------------------------------------------
48
unsigned char led_setzen[4] PROGMEM    = {0b0001, 0b0010, 0b0100, 0b1000};
49
unsigned char led_loeschen[5] PROGMEM  = {0b1110, 0b1101, 0b1011, 0b0111, 0b1111};
50
51
// Tastendruck
52
// -----------------------------------------------------------------------
53
#define REPEAT_MASK         (TASTER)
54
#define REPEAT_MASK2         (EIN_AUS)
55
#define REPEAT_START      250
56
#define REPEAT_NEXT        100
57
#define DELAY_RESET        500
58
#define DELAY_SEQUENZ      200
59
#define DELAY_VERZOEGERUNG    400
60
61
volatile uint8_t key_state;
62
volatile uint8_t key_press;
63
volatile uint8_t key_rpt;
64
65
volatile uint8_t key_state2;
66
volatile uint8_t key_press2;
67
volatile uint8_t key_rpt2;
68
69
volatile int8_t enc_delta;
70
volatile int8_t encoder      = 0;
71
volatile int8_t encoderwert    = 0;
72
volatile int16_t timeCount    = 0;
73
static int8_t last;
74
75
// Variablen/EEPROM
76
// -----------------------------------------------------------------------
77
uint8_t eeprom_sdid EEMEM    = 1;                // 1.Byte im EEPROM für ID-Wert
78
uint8_t eeprom_encoderid EEMEM  = 2;                // 2.Byte im EEPROM für ENCODER-Wert
79
uint8_t sdid;
80
81
// =======================================================================
82
// Timer-Routine
83
// -----------------------------------------------------------------------
84
ISR (TIM0_COMPA_vect)
85
{
86
  int8_t neu, diff;
87
88
  neu = 0;
89
  if(ENCODER_A)
90
    neu = 3;
91
  if(ENCODER_B)
92
    neu ^= 1;
93
  diff = last - neu;
94
  if(diff & 1)
95
  {
96
    last = neu;
97
    enc_delta += (diff & 2) - 1;
98
  }
99
100
  uint8_t i;
101
  static uint8_t ct0, ct1, rpt;
102
103
  i = key_state ^ ~TASTER_PIN;
104
  ct0 = ~(ct0 & i);
105
  ct1 = ct0 ^ (ct1 & i);
106
  i &= ct0 & ct1;
107
  key_state ^= i;
108
  key_press |= key_state & i;
109
110
  if((key_state & REPEAT_MASK) == 0)
111
    rpt = REPEAT_START;
112
  if(--rpt == 0)
113
  {
114
    rpt = REPEAT_NEXT;
115
    key_rpt |= key_state & REPEAT_MASK;
116
  }
117
118
  uint8_t h;
119
  static uint8_t ct2, ct3, rpt2;
120
121
  h = key_state2 ^ ~AUSGANG_PIN;
122
  ct2 = ~(ct2 & h);
123
  ct3 = ct2 ^ (ct3 & h);
124
  i &= ct2 & ct3;
125
  key_state2 ^= h;
126
  key_press2 |= key_state2 & h;
127
128
  if((key_state2 & REPEAT_MASK2) == 0)
129
    rpt2 = REPEAT_START;
130
  if(--rpt2 == 0)
131
  {
132
    rpt2 = REPEAT_NEXT;
133
    key_rpt2 |= key_state2 & REPEAT_MASK2;
134
  }
135
136
    if(timeCount > 0) timeCount--;
137
}
138
139
// Einschaltsequenz
140
// -----------------------------------------------------------------------
141
void einschalt(void)
142
{
143
  _delay_ms(DELAY_RESET);
144
  for (unsigned int a = 0; a < 4; a++)
145
  {
146
    AUSGANG_PORT |= pgm_read_word (& led_setzen[a]);
147
    _delay_ms(DELAY_SEQUENZ);
148
  }
149
  _delay_ms(DELAY_RESET);
150
  AUSGANG_PORT &= ~(pgm_read_word (& led_loeschen[4]));
151
  _delay_ms(DELAY_SEQUENZ);
152
}
153
154
ISR (PCINT0_vect)
155
{
156
}
157
158
// Tastendruck auswerten
159
// -----------------------------------------------------------------------
160
uint8_t get_key_press(uint8_t key_mask)
161
{
162
  cli();
163
  key_mask &= key_press;
164
  key_press ^= key_mask;
165
  sei();
166
  return key_mask;
167
}
168
169
uint8_t get_key_press2(uint8_t key_mask2)
170
{
171
  cli();
172
  key_mask2 &= key_press2;
173
  key_press2 ^= key_mask2;
174
  sei();
175
  return key_mask2;
176
}
177
178
uint8_t get_key_rpt(uint8_t key_mask)
179
{
180
  cli();
181
  key_mask &= key_rpt;
182
  key_rpt ^= key_mask;
183
  sei();
184
  return key_mask;
185
}
186
187
uint8_t get_key_short(uint8_t key_mask)
188
{
189
  cli();
190
  return get_key_press(~key_state & key_mask);
191
}
192
193
uint8_t get_key_long(uint8_t key_mask)
194
{
195
  return get_key_press(get_key_rpt(key_mask));
196
}
197
198
// Encoder auswerten
199
// -----------------------------------------------------------------------
200
int8_t encode_read(void)
201
{
202
  int8_t val;
203
204
  cli();
205
  val = enc_delta;
206
  enc_delta = val & 1;
207
  sei();
208
  return val >> 1;
209
}
210
211
// Prüfen ob Encoder gedreht wurde
212
// -----------------------------------------------------------------------
213
int8_t encode_read_timeout(void)
214
{
215
  int8_t tmp = encode_read();
216
217
  if(tmp != 0) timeCount = 3000;
218
  return tmp;
219
}
220
221
// LED setzen
222
// -----------------------------------------------------------------------
223
void led_setzen_loeschen(uint8_t led_ein_aus)
224
{
225
  AUSGANG_PORT |= pgm_read_word (& led_setzen[led_ein_aus]);    // Aktiven LED-PIN setzen
226
  AUSGANG_PORT &= ~(pgm_read_word (& led_loeschen[led_ein_aus]));  // Inaktive LED-PIN löschen 
227
}
228
229
// SD2IEC ID-Wert setzen
230
// -----------------------------------------------------------------------
231
void sd_id(int8_t sdid)
232
{
233
  AUSGANG_PORT &= ~(ID_LO);                    // Alle ID-PIN auf LO setzen
234
  AUSGANG_PORT |= (sdid);                      // ID-PIN setzen
235
}
236
237
// EPROM-Werte auslesen
238
// -----------------------------------------------------------------------
239
void eeprom_var(void)
240
{
241
  if(eeprom_read_byte(&eeprom_sdid) != HI)
242
  {
243
    sdid = eeprom_read_byte(&eeprom_sdid);            // KERNAL-Wert aus EEPROM auslesen
244
    encoder = eeprom_read_byte(&eeprom_encoderid);        // ENCODER-Wert aus EEPROM auslesen
245
    encoderwert = encoder;
246
    sd_id(sdid);                        // gespeicherten KENRAL aktivieren
247
  }
248
}
249
250
// SD2IEC-Reset durchführen
251
// -----------------------------------------------------------------------
252
void reset()
253
{
254
  AUSGANG_DDR |= (RESET);                      // ResetPIN = Ausgang
255
  AUSGANG_PORT &= ~(RESET);                    // ResetPIN = LO
256
  _delay_ms(DELAY_RESET);                      // Warten
257
  AUSGANG_DDR &= ~(RESET);                    // ResetPIN = Eingang
258
}
259
260
// Ein-/Ausänge zuweisen
261
// -----------------------------------------------------------------------
262
void init()
263
{
264
  AUSGANG_DDR = SCHALT;                      // SCHALT = Ausgang
265
                                  // RESET = Eingang (Tri-State)
266
                                  // AKTIV = Eingang
267
  AUSGANG_PORT = AKTIV;                      // AKTIV = PullUp
268
269
  ENCODER_DDR = LO;                        // ENCODER = Eingang
270
  ENCODER_PORT = HI;                        // ENCODER = PullUp
271
272
  set_sleep_mode(SLEEP_MODE_PWR_DOWN);              // Schlafmodus definieren
273
  sleep_enable();                          // Schlafmodus aktivieren
274
  PCMSK0 = (1<<PA7);
275
}
276
277
// Encoder initialisieren
278
// -----------------------------------------------------------------------
279
void encode_init(void)
280
{
281
  int8_t neu;
282
283
  neu = 0;
284
  if(ENCODER_A)
285
    neu = 3;
286
  if(ENCODER_B)
287
    neu ^= 1;
288
  last = neu;
289
  enc_delta = 0;
290
291
  TCCR0A = (1<<WGM01);
292
  OCR0A = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5);
293
  TCCR0B = (1<<CS01 | 1<<CS00);
294
  TIMSK0 = (1<<OCIE0A);
295
}
296
297
// Ausschaltsequenz
298
// -----------------------------------------------------------------------
299
void ausschalt(void)
300
{
301
  encoder = encoderwert;
302
  AUSGANG_PORT |= pgm_read_word (& led_loeschen[4]);
303
  _delay_ms(DELAY_VERZOEGERUNG);
304
  for (unsigned int b = 3; b > 0; b--)
305
  {
306
    AUSGANG_PORT &= ~(pgm_read_word (& led_setzen[b]));
307
    _delay_ms(DELAY_SEQUENZ);
308
  }
309
  AUSGANG_PORT &= ~(pgm_read_word (& led_loeschen[4]));
310
}
311
312
// Power-down aktivieren
313
// -----------------------------------------------------------------------
314
void schlafen()
315
{
316
  TIMSK0 = 0;
317
  ausschalt();
318
  GIMSK = (1<<PCIE0);
319
  sleep_cpu();
320
  GIMSK = 0;
321
  TIMSK0 = (1<<OCIE0A);
322
}
323
324
// Hauptprogramm
325
// -----------------------------------------------------------------------
326
int main(void)
327
{
328
  uint8_t schlafen_ein = 0;
329
330
  init();                              // Startwerte setzen
331
  eeprom_var();                          // EEPROM-Werte auslesen
332
  einschalt();                          // LED Einschaltsequenz starten
333
  encode_init();                          // ENCODER initialisieren
334
  sei();                              // alle Interrupt aktivieren
335
336
  for(;;)
337
  {
338
    ADCSRA &= !(1<<ADEN);                    // ADC deaktivieren
339
    ACSR = 0x80;                        // Analogcomperator deaktivieren
340
341
    if(get_key_press2 EIN_AUS)
342
    {
343
      schlafen_ein = !schlafen_ein;
344
    }
345
346
    if(schlafen_ein && !(key_state2 & EIN_AUS) && (AUSGANG_PIN & EIN_AUS))
347
    {
348
      schlafen();
349
    }
350
351
    encoder += encode_read_timeout();              // ENCODER-Wert auslesen
352
353
    if (timeCount == 0) encoder = encoderwert;          // Nach Zeit zurück zum Ausgangswert
354
    if (encoder < 1) encoder = 0;                // ENCODER-Wert darf nicht kleiner als 0
355
    if (encoder > 2) encoder = 3;                // und größer als 3 werden
356
357
    switch(encoder)
358
    {
359
      case 0:
360
        led_setzen_loeschen(encoder);
361
        if (get_key_short(TASTER))              // bei kurzem Tastendruck
362
        {
363
          sd_id(ID_8);
364
          encoderwert = encoder;
365
          reset();
366
        }
367
        if(get_key_long(TASTER))              // bei langen Tastendruck
368
        {
369
          sd_id(ID_8);
370
          encoderwert = encoder;
371
          eeprom_write_byte(&eeprom_sdid, ID_8);      // KERNAL-Wert in EEPROM speichern
372
          eeprom_write_byte(&eeprom_encoderid, encoder);  // ENCODER-Wert in EEPROM speichern
373
          reset();
374
        }
375
        break;
376
377
      case 1:
378
        led_setzen_loeschen(encoder);
379
        if (get_key_short(TASTER))
380
        {
381
          sd_id(ID_9);
382
          encoderwert = encoder;
383
          reset();
384
        }
385
        if(get_key_long(TASTER))
386
        {
387
          sd_id(ID_9);
388
          encoderwert = encoder;
389
          eeprom_write_byte(&eeprom_sdid, ID_9);
390
          eeprom_write_byte(&eeprom_encoderid, encoder);
391
          reset();
392
        }
393
        break;
394
395
      case 2:
396
        led_setzen_loeschen(encoder);
397
        if (get_key_short(TASTER))
398
        {
399
          sd_id(ID_10);
400
          encoderwert = encoder;
401
          reset();
402
        }
403
        if(get_key_long(TASTER))
404
        {
405
          sd_id(ID_10);
406
          encoderwert = encoder;
407
          eeprom_write_byte(&eeprom_sdid, ID_10);
408
          eeprom_write_byte(&eeprom_encoderid, encoder);
409
          reset();
410
        }
411
        break;
412
413
      case 3:
414
        led_setzen_loeschen(encoder);
415
        if (get_key_short(TASTER))
416
        {
417
          sd_id(ID_11);
418
          encoderwert = encoder;
419
          reset();
420
        }
421
        if(get_key_long(TASTER))
422
        {
423
          sd_id(ID_11);
424
          encoderwert = encoder;
425
          eeprom_write_byte(&eeprom_sdid, ID_11);
426
          eeprom_write_byte(&eeprom_encoderid, encoder);
427
          reset();
428
        }
429
        break;
430
    }
431
  }
432
}