#include #include #include #include #define max(a, b) \ ({ \ __typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ _a > _b ? _a : _b; \ }) #define min(a, b) \ ({ \ __typeof__(a) _a = (a); \ __typeof__(b) _b = (b); \ _a < _b ? _a : _b; \ }) // return a + (t/128)*(b-a) static uint8_t lerp(uint8_t a, uint8_t b, uint8_t t) { return a + (uint8_t)(((int16_t)(b - a) * t) >> 7); } static void eeprom_write(uint16_t addr, uint8_t data) { while (EECR & _BV(EEPE)) ; EEAR = addr; EECR = 0; EEDR = data; EECR |= _BV(EEMPE); EECR |= _BV(EEPE); } static uint8_t eeprom_read(uint16_t addr) { while (EECR & _BV(EEPE)) ; EEAR = addr; EECR = _BV(EERE); return EEDR; } enum { MODE_SOLID = 0, MODE_PULSE, MODE_ALTERNATE, MODE_FAST_PULSE, MODE_FAST_ALTERNATE, MODE_VFAST_PULSE, MODE_VFAST_ALTERNATE, NUM_MODE, }; uint16_t tickcount; static void tick(void); ISR(TIM0_COMPA_vect) { ++tickcount; tick(); } static uint8_t mode; ISR(PCINT0_vect) { static uint16_t down; if ((PINB & _BV(PB0)) == 0) { down = tickcount; } else { if (tickcount - down > 100) { eeprom_write(0, mode); } else { if (++mode == NUM_MODE) { mode = MODE_SOLID; } } } } static uint8_t brightness; ISR(ADC_vect) { brightness = ADCH; } static uint8_t oa_duty, ob_duty; ISR(TIM1_OVF_vect) { OCR1A = min(oa_duty, 127); OCR1B = max(255 - ob_duty, 128); } void tick(void) { ADCSRA |= _BV(ADSC); switch (mode) { case MODE_SOLID: oa_duty = ob_duty = brightness >> 1; break; case MODE_PULSE: case MODE_ALTERNATE: case MODE_FAST_PULSE: case MODE_FAST_ALTERNATE: case MODE_VFAST_PULSE: case MODE_VFAST_ALTERNATE: { static uint8_t dir; static uint8_t t; oa_duty = lerp(0, brightness >> 1, dir ? t : 128 - t); ob_duty = (mode & 1) ? oa_duty : ((brightness >> 1) - oa_duty); t += mode > MODE_FAST_ALTERNATE ? 4 : mode > MODE_ALTERNATE ? 2 : 1; if (t >= 128) { t = 0; dir = !dir; } } break; } } static void pwm_init(void) { TCCR1 = _BV(PWM1A) | _BV(COM1A1); GTCCR |= _BV(PWM1B) | _BV(COM1B1) | _BV(COM1B0); TCCR1 |= _BV(CS12); OCR1A = 0; OCR1B = 255; DDRB |= _BV(PB1) | _BV(PB4); TIMSK |= _BV(TOIE1); } static void adc_init(void) { ADMUX = _BV(ADLAR) | _BV(MUX0) | _BV(MUX1); DIDR0 = _BV(ADC3D); ADCSRA = _BV(ADEN) | _BV(ADIE) | _BV(ADPS2) | _BV(ADPS1); } static void tick_init(void) { GTCCR = _BV(TSM) | _BV(PSR0); TCCR0A = _BV(WGM01); TCCR0B = _BV(CS01) | _BV(CS00); OCR0A = 122; // 1M/64 = 15kHz / 122 = 128 hz tick TIMSK |= _BV(OCIE0A); GTCCR &= _BV(TSM); } int main(void) { mode = eeprom_read(0); if (mode >= NUM_MODE) { mode = 0; } tick_init(); pwm_init(); adc_init(); DDRB &= ~_BV(PB0); PORTB |= _BV(PB0); GIMSK = _BV(PCIE); PCMSK = _BV(PCINT0); sei(); for (;;) sleep_mode(); return (0); }