1 | #include <avr/io.h>
|
2 | #include <avr/interrupt.h>
|
3 | #include <avr/sleep.h>
|
4 | #include <avr/eeprom.h>
|
5 | #include <avr/pgmspace.h>
|
6 | #include <util/delay.h>
|
7 |
|
8 | // CPU: ATTiny44-20PU 8MHz
|
9 | // =======================================================================
|
10 |
|
11 | // Ein-/Ausgänge
|
12 | // -----------------------------------------------------------------------
|
13 | #define ENCODER_PORT PORTB
|
14 | #define ENCODER_DDR DDRB
|
15 | #define TASTER_PIN PINB
|
16 |
|
17 | #define AUSGANG_PORT PORTA
|
18 | #define AUSGANG_DDR DDRA
|
19 | #define AUSGANG_PIN PINA
|
20 |
|
21 | #define EIN_AUS (1 << PA7)
|
22 |
|
23 | // Schalt-Muster
|
24 | // -----------------------------------------------------------------------
|
25 | #define LO 0x00 // 0000 0000
|
26 | #define HI 0xFF // 1111 1111
|
27 | #define SCHALT 0x3F // 0011 1111
|
28 | #define AKTIV 0x80 // 1000 0000
|
29 |
|
30 | // LED-Muster
|
31 | // -----------------------------------------------------------------------
|
32 | unsigned char led_setzen[4] PROGMEM = {0b0001, 0b0010, 0b0100, 0b1000};
|
33 | unsigned char led_loeschen[5] PROGMEM = {0b1110, 0b1101, 0b1011, 0b0111, 0b1111};
|
34 |
|
35 | // Tastendruck
|
36 | // -----------------------------------------------------------------------
|
37 | #define REPEAT_MASK (EIN_AUS)
|
38 | #define REPEAT_START 250
|
39 | #define REPEAT_NEXT 100
|
40 | #define DELAY_RESET 500
|
41 | #define DELAY_SEQUENZ 200
|
42 | #define DELAY_VERZOEGERUNG 400
|
43 |
|
44 | volatile uint8_t key_state;
|
45 | volatile uint8_t key_press;
|
46 | volatile uint8_t key_rpt;
|
47 |
|
48 | // =======================================================================
|
49 | // Timer-Routine
|
50 | // -----------------------------------------------------------------------
|
51 | ISR (TIM0_COMPA_vect)
|
52 | {
|
53 | uint8_t i;
|
54 | static uint8_t ct0, ct1, rpt;
|
55 |
|
56 | i = key_state ^ ~AUSGANG_PIN;
|
57 | ct0 = ~(ct0 & i);
|
58 | ct1 = ct0 ^ (ct1 & i);
|
59 | i &= ct0 & ct1;
|
60 | key_state ^= i;
|
61 | key_press |= key_state & i;
|
62 |
|
63 | if((key_state & REPEAT_MASK) == 0)
|
64 | rpt = REPEAT_START;
|
65 | if(--rpt == 0)
|
66 | {
|
67 | rpt = REPEAT_NEXT;
|
68 | key_rpt |= key_state & REPEAT_MASK;
|
69 | }
|
70 | }
|
71 |
|
72 | ISR (PCINT0_vect)
|
73 | {
|
74 | }
|
75 |
|
76 | // Tastendruck auswerten
|
77 | // -----------------------------------------------------------------------
|
78 | uint8_t get_key_press(uint8_t key_mask)
|
79 | {
|
80 | cli();
|
81 | key_mask &= key_press;
|
82 | key_press ^= key_mask;
|
83 | sei();
|
84 | return key_mask;
|
85 | }
|
86 |
|
87 | // Ein-/Ausänge zuweisen
|
88 | // -----------------------------------------------------------------------
|
89 | void init()
|
90 | {
|
91 | AUSGANG_DDR = SCHALT; // SCHALT = Ausgang
|
92 | // RESET = Eingang (Tri-State)
|
93 | // AKTIV = Eingang
|
94 | AUSGANG_PORT = AKTIV; // AKTIV = PullUp
|
95 |
|
96 | ENCODER_DDR = LO; // ENCODER = Eingang
|
97 | ENCODER_PORT = HI; // ENCODER = PullUp
|
98 |
|
99 | set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Schlafmodus definieren
|
100 | sleep_enable(); // Schlafmodus aktivieren
|
101 | PCMSK0 = (1<<PA7);
|
102 |
|
103 | TCCR0A = (1<<WGM01);
|
104 | OCR0A = (uint8_t)(F_CPU / 64.0 * 1e-3 - 0.5);
|
105 | TCCR0B = (1<<CS01 | 1<<CS00);
|
106 | TIMSK0 = (1<<OCIE0A);
|
107 | }
|
108 |
|
109 |
|
110 | // Einschaltsequenz
|
111 | // -----------------------------------------------------------------------
|
112 | void einschalt(void)
|
113 | {
|
114 | _delay_ms(DELAY_RESET);
|
115 | for (unsigned int a = 0; a < 4; a++)
|
116 | {
|
117 | AUSGANG_PORT |= pgm_read_word (& led_setzen[a]);
|
118 | _delay_ms(DELAY_SEQUENZ);
|
119 | }
|
120 | _delay_ms(DELAY_RESET);
|
121 | AUSGANG_PORT &= ~(pgm_read_word (& led_loeschen[4]));
|
122 | _delay_ms(DELAY_SEQUENZ);
|
123 | }
|
124 |
|
125 | // Ausschaltsequenz
|
126 | // -----------------------------------------------------------------------
|
127 | void ausschalt(void)
|
128 | {
|
129 | AUSGANG_PORT |= pgm_read_word (& led_loeschen[4]);
|
130 | _delay_ms(DELAY_VERZOEGERUNG);
|
131 | for (unsigned int b = 3; b > 0; b--)
|
132 | {
|
133 | AUSGANG_PORT &= ~(pgm_read_word (& led_setzen[b]));
|
134 | _delay_ms(DELAY_SEQUENZ);
|
135 | }
|
136 | AUSGANG_PORT &= ~(pgm_read_word (& led_loeschen[4]));
|
137 | }
|
138 |
|
139 | // Power-down aktivieren
|
140 | // -----------------------------------------------------------------------
|
141 | void schlafen()
|
142 | {
|
143 | TIMSK0 = 0;
|
144 | ausschalt();
|
145 | GIMSK = (1<<PCIE0);
|
146 | sleep_cpu();
|
147 | GIMSK = 0;
|
148 | TIMSK0 = (1<<OCIE0A);
|
149 | }
|
150 |
|
151 | // Hauptprogramm
|
152 | // -----------------------------------------------------------------------
|
153 | int main(void)
|
154 | {
|
155 | uint8_t schlafen_ein = 0;
|
156 |
|
157 | init(); // Startwerte setzen
|
158 | einschalt();
|
159 | sei(); // alle Interrupt aktivieren
|
160 |
|
161 | for(;;)
|
162 | {
|
163 | if(get_key_press EIN_AUS)
|
164 | {
|
165 | schlafen_ein = !schlafen_ein;
|
166 | }
|
167 |
|
168 | if(schlafen_ein && !(key_state & EIN_AUS) && (AUSGANG_PIN & EIN_AUS))
|
169 | {
|
170 | schlafen();
|
171 | }
|
172 | }
|
173 | }
|