Avr múltiples canales ADC y PWM

2

He estado tratando de hacer un programa que lea continuamente valores analógicos de 3 pines diferentes y luego haga una señal PWM correspondiente a cada uno de esos 3 pines. Básicamente, 3 canales PWM de salida con diferentes ciclos de trabajo correspondientes a 3 valores analógicos diferentes. El problema es que todos los canales PWM comparten el ciclo de trabajo de lo que noté, pero si ignoro el ADC y simplemente configuro el ciclo de trabajo en el código, funcionan bien. Aquí está el código:

#define F_CPU 16000000UL

#include <avr/io.h>
#include <avr/interrupt.h>

void selectADCchannel(uint8_t channel);
void initPWM();
void setupADC();

int main(void){

    sei();
    initPWM();
    //start with 0'th channel; no channel selected needed
    setupADC();

    while(1){

    }
}

ISR(ADC_vect){
    //get current channel
    uint8_t currentChannel = ADMUX & 0x0F;
    //set output compare registers for current channel
    switch(currentChannel){
        case 0x00: OCR0A = ADCH;
            break;
        case 0x01: OCR0B = ADCH;
            break;
        case 0x02: OCR2B = ADCH;
            break;
    }
    //loop through channels from 0 to 2 
    if(currentChannel == 2)
        selectADCchannel(0x00);
    else
        selectADCchannel(currentChannel+1);
    //restart conversion
    ADCSRA |= 1<<ADSC;
    }

void selectADCchannel(uint8_t channel){
    //0xE0 is 11100000
    //0x1F is 00011111
    ADMUX = (ADMUX & 0xE0) | (channel & 0x1F);
}

void setupADC(){
    //enable prescaler (128 for 16MHz => 125kHz)
    //would probably work with 250kHZ for 8 bits
    //set ADPS bits in ADCSRA to 111
    ADCSRA |= 1<<ADPS2 | 1<<ADPS1 | 1<<ADPS0;
    //enable result shift to ADCH to only read ADCH (8 bits)
    ADMUX |= 1<<ADLAR;
    //enable interrupt
    ADCSRA |= 1<<ADIE;
    //set voltage reference
    //reference is AVcc
    ADMUX |= 1<<REFS0;
    //turn on ADC
    ADCSRA |= 1<<ADEN;
    //start conversion
    ADCSRA |= 1<<ADSC;  
}

void initPWM(){
    //TIMER0 (8 bit timer)
    //set pins 5D(OC0B) and 6D(OC0A) as output
    DDRD |= 1<<DDD5 | 1<<DDD6;
    //set fast-pwm mode
    TCCR0A |= 1<<WGM00;
    //set non-inverting mode for both pins
    TCCR0A |= 1<<COM0A1 | 1<<COM0B1;
    //set prescaler to 256
    TCCR0B |= 1<<CS02;

    //TIMER2 (8 bit timer)
    //set pins 3D(OC2B) as output
    DDRD |= 1<<DDD3;
    //set fast-pwm mode
    TCCR2A |= 1<<WGM20;
    //set non-inverting mode for both pins
    TCCR2A |= 1<<COM2B1;
    //set prescaler to 256
    TCCR2B |= 1<<CS22 | 1<<CS21;
}

Entonces, qué debe hacer el programa, después de la inicialización, lea el valor de uno de los pines ADC y luego configure el registro de comparación PWM del pin correspondiente al valor ADCH. Gracias.

    
pregunta user3808318

1 respuesta

1

El código está bien. El problema era que solo estaba probando el ADC en un pin y flotando los otros dos. Esperaba que solo funcionara la que estaba probando, pero aparentemente hay una gran cantidad de interferencias entre los pines ADC si están flotando. Además, mucho ruido, incluso con condensadores en ARef y AVcc. Gracias y lo siento por publicar sin probar completamente antes.

    
respondido por el user3808318

Lea otras preguntas en las etiquetas