1 #include <avr/interrupt.h>
6 #include <util/delay.h>
11 static unsigned char steps[] = { 60, 85, 121, 171, 242 };
12 static unsigned char intensity = 0;
14 static void timer_init()
16 power_timer1_enable();
20 TCCR1 = _BV(CS10); // clk/1 = 1 MHz
21 // TCCR1 = _BV(CS11) | _BV(CS13); // clk/512 = 2 kHz
22 GTCCR = _BV(COM1B1) | _BV(PWM1B);
27 static void set_pwm(unsigned char pwm)
32 static void adc_init()
36 ADCSRA = _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0); // clk/8 = 125 kHz
37 ADMUX = _BV(REFS1) | _BV(MUX1) | _BV(MUX0); // 1.1V ref., PB3 single-ended
41 static void status_led_init()
47 static void status_led_on()
52 static void status_led_off()
57 static unsigned char status_led_is_on()
59 return PORTB & _BV(PB2) ? 1 : 0;
62 static void buttons_init()
64 DDRB &= ~(_BV(PB0) | _BV(PB1)); // set as input
65 PORTB |= _BV(PB0) | _BV(PB1); // internal pull-up
67 GIMSK &= ~_BV(PCIE); // disable pin-change IRQs
68 PCMSK = 0; // disable pin-change IRQs on all pins of port B
71 static void buttons_susp()
76 PCMSK |= _BV(PCINT0) | _BV(PCINT1);
79 static unsigned char buttons_pressed()
82 (PINB & _BV(PB0) ? 0 : 1)
84 (PINB & _BV(PB1) ? 0 : 2)
88 #define WAKEUP_POLL 100 // msec
89 #define WAKEUP_LIMIT 5 // times WAKEUP_POLL
91 static unsigned char buttons_wait_for_release()
93 uint16_t wake_count = 0;
96 if (++wake_count > WAKEUP_LIMIT)
97 status_led_on(); // inform the user
99 _delay_ms(WAKEUP_POLL);
100 } while (buttons_pressed());
104 return wake_count > WAKEUP_LIMIT;
109 // empty - let it wake us from sleep, but do nothing else
112 static void wdt_init()
114 WDTCR = _BV(WDIE) | _BV(WDP1); // interrupt mode, 64 ms
117 static void wdt_susp()
122 static void hw_setup()
132 static void hw_suspend()
134 ADCSRA &= ~_BV(ADEN); // disable ADC
135 TCCR1 = 0; // disable T/C 1
144 static volatile unsigned char wdt_timer_fired;
150 static void power_down()
156 set_sleep_mode(SLEEP_MODE_PWR_DOWN);
166 // allow wakeup by long button-press only
167 } while (!buttons_wait_for_release());
173 static void button_one_pressed()
176 set_pwm(steps[--intensity]);
182 static void button_two_pressed()
184 if (intensity < N_STEPS-1) {
185 set_pwm(steps[++intensity]);
189 static unsigned char button_state, button_state_time;
191 static void timer_check_buttons()
193 unsigned char newstate = buttons_pressed();
195 if (newstate == button_state) {
196 if (newstate && button_state_time < 4)
202 button_state = newstate;
203 button_state_time = 0;
208 switch (button_state) {
209 case 1: button_one_pressed();
211 case 2: button_two_pressed();
213 default: // ignore when both are preseed
217 button_state = newstate;
220 static unsigned char blink_on_time, blink_off_time, n_blinks;
221 static unsigned char blink_counter;
223 static void timer_blink()
227 } else if (status_led_is_on()) {
229 blink_counter = blink_off_time;
230 } else if (n_blinks) {
233 blink_counter = blink_on_time;
235 n_blinks = intensity + 1;
250 while (!(ADCSRA & _BV(ADIF)))
254 while (!(ADCSRA & _BV(ADIF)))
261 // we try to be completely IRQ-driven, so just wait for IRQs here
264 set_sleep_mode(SLEEP_MODE_IDLE);
266 // keep BOD active, no sleep_bod_disable();
271 if (wdt_timer_fired) {
273 timer_check_buttons();