133 lines
2.4 KiB
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)
|
|
{
|
|
} |