#include #include #include void setup_adc() { //enable interrupts sei(); // setup external reference voltage. ADMUX &= ~(3UL << REFS0); ADMUX |= (1UL << REFS0); // set left adjusted ADC result so we can easily only use the upper 8 bits of the result ADCSRB |= (1UL << ADLAR); // enable ADC interrupt ADCSRA |= (1UL << ADIE); } void setup_timers() { //use system clock for timers, no prescaler. TCCR0B &= ~(7UL << CS00); TCCR0B |= (1UL << CS00); //set mode 5 (PWM, phase correct, top defined by OCRA) TCCR0A &= ~(3UL << WGM00); TCCR0B &- ~(1UL << WGM02); TCCR0A |= (1UL << WGM00); TCCR0B |= (1UL << WGM02); } void enable_ADC() { PRR &= ~(1UL << PRADC); ADCSRA |= (1UL << ADEN); } void disable_ADC() { ADCSRA &= ~(1UL << ADEN); PRR |= (1UL << PRADC); } void select_ADC_channel(int channel) { ADMUX &= ~(7UL << MUX0); ADMUX |= (channel << MUX0); } uint8_t get_ADC_result() { uint8_t result = ADCL; //conversion would be blocked if we don't also read ADCH although we won't use the upper 2 bits. uint8_t unblock = ADCH; return result; } void start_ADC() { ADCSRA |= (1UL << ADSC); } volatile uint8_t fan1; volatile uint8_t fan2; void start_polling_fans() { PRR &= ~(1UL << PRADC); enable_ADC(); select_ADC_channel(ADC1D); start_ADC(); } ISR(ADC_vect) { if(ADMUX & (7UL << MUX0) == ADC1D) { fan1 = get_ADC_result(); select_ADC_channel(ADC2D); start_ADC(); return; } if(ADMUX & (7UL << MUX0) == ADC2D) { fan2 = get_ADC_result(); disable_ADC(); return; } } int main() { set_sleep_mode(0); setup_adc(); setup_timers(); while(1); }