Hi,
I'm currently working on a small project to monitor the voltage of a car battery using a tiny45.
The battery voltage scaled down and connected to a ADC. I can use the ADC in free running mode (generating interrupts when a conversion is ready), but then it samples the voltage way too often. All I need is a few times per second, and I need the rest of the time to correctly produce three different software-generated pwm signals - the indicator is a RGB LED (way cool!). When the ADC samples too often, the pwm is interrupted and the color of the LED flickers noticeably.
So, I'm trying to use a timer instead to trigger the ADC conversions. I'm using timer owerflow as a trigger source (I figured that was the easiest thing to do). The timer fires just fine and generates its interrupt, but the ADC doesn't seem to start converting once this happens.
I've set the ADTS bits in ADCSRB to "timer/counter overflow". Shouldn't the ADC start a conversion automatically once the timer overflows, or am I missing something important here? The tiny has 2 timers, but there is no such distinction in the trigger source - does I have to use one of the timers? I'm using timer1 now (less to read in the datasheet, since it has no pwm).
The code I'm using follows (with unimportant parts edited out):
#include#include #include #include "main.h" #include "out.h" ISR(ADC_vect) { uint16_t vin = ADC; [...] // Do some conversions and set registers controlling the led } ISR(TIM1_OVF_vect) { // Do nothing } int main () { [...] // Initialize led and ports cli(); // No interrupts during startup // *** Initialize ADC *** uint8_t ad_vref = (1 << REFS2) | (1 << REFS1); // 2.56 V internal source, uncoupled. uint8_t ad_select = meas_in; // Select ADC to use ADMUX |= ad_vref | ad_select; uint8_t ad_prescale = 0x07; // Divide by 128 uint8_t ad_interrupt_enable = (1 << ADIE); uint8_t ad_enable = (1 << ADEN); uint8_t ad_autotrig = (1 << ADATE); ADCSRA |= ad_prescale | ad_interrupt_enable | ad_enable | ad_autotrig; uint8_t ad_autotrig_source = (1 << ADTS2); // Use Timer/Counter Overflow for interrupt ADCSRB |= ad_autotrig_source; // *** ADC initialized *** // *** Initialize timer *** uint8_t timer_overflow_interrupt_enable = (1 << TOIE1); TIMSK |= timer_overflow_interrupt_enable; // *** Timer initialized *** sei(); // Startup ready, allow interrupts timer_start(); while (1) { [...] // Run led pwm } void timer_start() { uint8_t timer_prescale = 0x0F; // CK/16384 TCCR1 |= timer_prescale; }