TinyDimmer/src/main.c

133 lines
2.4 KiB
C

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
#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)
{
}