#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/sleep.h>
#include <util/delay.h>
enum {
setpoint = 13ll * 10230ll * 11ll / 2000ll
};
static void setup_adc(void) {
ADMUX |= (1 << REFS1) | (1 << MUX1);
ADCSRA |= (1 << ADEN) | (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0);
}
static void setup_pwm(void) {
PLLCSR |= (1 << PCKE);
_delay_us(100);
DDRB |= (1 << PB1);
OCR1C = 0xff;
TCCR1 |= (1 << PWM1A) | (1 << COM1A1) | (1 << CS10);
TIMSK |= (1 << TOIE1);
}
static int read_adc(void) {
ADCSRA |= (1 << ADSC);
while (!(ADCSRA & (1 << ADIF)));
ADCSRA &= ~(1 << ADIF);
return ADC;
}
static int oversample(void) {
int reading = 0;
reading += read_adc();
reading += read_adc();
reading += read_adc();
reading += read_adc();
return reading / 4;
}
ISR(TIM1_OVF_vect) {
int reading = oversample();
if (reading < setpoint) {
OCR1A += (OCR1A == OCR1C ? 0 : 1);
} else if (reading > setpoint) {
OCR1A -= (OCR1A == 0 ? 0 : 1);
}
}
int main(void) {
setup_adc();
setup_pwm();
sei();
for (;;) {
sleep_mode();
}
return 0;
}
I2luY2x1ZGUgPGF2ci9pby5oPgojaW5jbHVkZSA8YXZyL2ludGVycnVwdC5oPgojaW5jbHVkZSA8YXZyL3NsZWVwLmg+CiNpbmNsdWRlIDx1dGlsL2RlbGF5Lmg+CgplbnVtIHsKICBzZXRwb2ludCA9IDEzbGwgKiAxMDIzMGxsICogMTFsbCAvIDIwMDBsbAp9OwoKc3RhdGljIHZvaWQgc2V0dXBfYWRjKHZvaWQpIHsKICBBRE1VWCB8PSAoMSA8PCBSRUZTMSkgfCAoMSA8PCBNVVgxKTsKICBBRENTUkEgfD0gKDEgPDwgQURFTikgfCAoMSA8PCBBRFBTMikgfCAoMSA8PCBBRFBTMSkgfCAoMSA8PCBBRFBTMCk7Cn0KCnN0YXRpYyB2b2lkIHNldHVwX3B3bSh2b2lkKSB7CiAgUExMQ1NSIHw9ICgxIDw8IFBDS0UpOwogIF9kZWxheV91cygxMDApOwogIEREUkIgfD0gKDEgPDwgUEIxKTsKICBPQ1IxQyA9IDB4ZmY7CiAgVENDUjEgfD0gKDEgPDwgUFdNMUEpIHwgKDEgPDwgQ09NMUExKSB8ICgxIDw8IENTMTApOwogIFRJTVNLIHw9ICgxIDw8IFRPSUUxKTsKfQoKc3RhdGljIGludCByZWFkX2FkYyh2b2lkKSB7CiAgQURDU1JBIHw9ICgxIDw8IEFEU0MpOwogIHdoaWxlICghKEFEQ1NSQSAmICgxIDw8IEFESUYpKSk7CiAgQURDU1JBICY9IH4oMSA8PCBBRElGKTsKICByZXR1cm4gQURDOwp9CgpzdGF0aWMgaW50IG92ZXJzYW1wbGUodm9pZCkgewogIGludCByZWFkaW5nID0gMDsKICByZWFkaW5nICs9IHJlYWRfYWRjKCk7CiAgcmVhZGluZyArPSByZWFkX2FkYygpOwogIHJlYWRpbmcgKz0gcmVhZF9hZGMoKTsKICByZWFkaW5nICs9IHJlYWRfYWRjKCk7CiAgcmV0dXJuIHJlYWRpbmcgLyA0Owp9CgpJU1IoVElNMV9PVkZfdmVjdCkgewogIGludCByZWFkaW5nID0gb3ZlcnNhbXBsZSgpOwogIGlmIChyZWFkaW5nIDwgc2V0cG9pbnQpIHsKICAgIE9DUjFBICs9IChPQ1IxQSA9PSBPQ1IxQyA/IDAgOiAxKTsKICB9IGVsc2UgaWYgKHJlYWRpbmcgPiBzZXRwb2ludCkgewogICAgT0NSMUEgLT0gKE9DUjFBID09IDAgPyAwIDogMSk7CiAgfQp9CgppbnQgbWFpbih2b2lkKSB7CiAgc2V0dXBfYWRjKCk7CiAgc2V0dXBfcHdtKCk7CiAgc2VpKCk7CiAgZm9yICg7OykgewogICAgc2xlZXBfbW9kZSgpOwogIH0KICByZXR1cm4gMDsKfQo=