#include #include #include #include #include "ledpwmcurve.h" /* Pin 2: 10k potentiometer input When turned all the way to the left (off), resistance should be 0 Pin 5: PWM output */ // Forward declarations inline void initPWM(); inline void initADC(); inline uint16_t readADC(); inline void sleep(uint8_t prescale); int main() { // Set pin B0 (physical pin 5) to output mode, pin B2 (ADC1) to input DDRB = (DDRB | _BV(DDB0)) & ~_BV(DDB3); initPWM(); OCR0A = 255; initADC(); while (1) { uint8_t value = 255 - antilog(readADC()); OCR0A = value; if (value == 255) { // Off, go to sleep for 0.25s sleep(_BV(WDP2)); } } return 0; } inline void initPWM() { // Set timer to Fast PWM mode, clear OC0A on compare-match and set OC0A on top. // This inverts the PWM, but allows the LEDs to turn off completely. TCCR0A = _BV(COM0A1) | _BV(COM0A0) | _BV(WGM01) | _BV(WGM00); // Leave WGM02 empty for Fast PWM mode, and set clock select to no prescaling TCCR0B = _BV(CS00); // Disable timer 1 TCCR1 = 0; } inline void initADC() { // Use VCC as voltage reference and right adjust result, // set to single-ended input on ADC1 ADMUX = (ADMUX | _BV(MUX0) | _BV(MUX1)) & ~(_BV(MUX2) | _BV(MUX3) | _BV(REFS1) | _BV(REFS0) | _BV(ADLAR)); // Disable digital input on the analog pin to save power DIDR0 |= _BV(ADC3D); // Enable the ADC ADCSRA |= _BV(ADEN) | _BV(ADPS1) | _BV(ADPS0); } inline uint16_t readADC() { // Start conversion ADCSRA |= _BV(ADSC); // Wait for result loop_until_bit_is_clear(ADCSRA, ADSC); // ADCL must be read first uint8_t low = ADCL; return (ADCH<<8) | low; } inline void sleep(uint8_t prescaler) { // Disable watchdog reset flag MCUSR &= ~_BV(WDRF); // Enable watchdog WDTCR |= _BV(WDCE) | _BV(WDE); // Set timeout value and enable interrupt mode WDTCR = prescaler | _BV(WDIE); // Turn ADC off ADCSRA &= ~_BV(ADEN); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // Set sleep bit and halt the CPU sleep_enable(); sei(); sleep_cpu(); // ...goooood morning! cli(); // Disable watchdog (need to write a logic one first, see datasheet) WDTCR |= _BV(WDCE) | _BV(WDE); WDTCR = 0; sleep_disable(); ADCSRA |= _BV(ADEN); sei(); } // Interrupt for watchdog timer ISR(WDT_vect) { }