[Duda] ATMEGA328P - Sistema de Control ON-OFF

Buen día a todos, compañeros.
Soy un estudiante y apenas me estoy adentrando en el mundo de los microcontroladores. He venido a consultar ya que me pidieron leer una entrada de voltaje analógico usando un ATMEGA328P. Lo hice haciendo uso del ADC y probé que la salida sí funcionara. Una vez superado eso, debo calcular en una variable la diferencia entre un valor fijo y el valor de lectura. Si esta diferencia es mayor o igual que 0 debo poner en alto un pin de salida, en caso contrario será estado bajo. Aquí mi problema, pues al principio probé mi código con un valor de consigna de 2.5 y funcionó, pero cuando pruebo otro valor no respeta la regla. Sé que me estoy equivocando en cómo interpreta el uC los números negativos y seguramente en otras cosas, pero repito, no tengo experiencia en este campo. Adjunto mi código aquí, les agradezco mucho de antemano su ayuda.

C:
#define F_CPU 16000000L
#include <avr/io.h>
#include <util/delay.h>

//Función de inicialización para el ADC
void ADC_init(void)
{
    //Se indica el voltaje de referencia (en este caso AVcc), la salida se posiciona a la izquierda en el reg ADC y se establece el ADC0 como entrada
    ADMUX  |= (1<<REFS0);
    //Se habilita el ADC y se usa un preescalador de 128 para que 16MHz/128 = 125kHz (valor dentro del rango adecuado)
    ADCSRA |= (1<<ADEN)|(1<<ADPS2)|(1<<ADPS1)|(1<<ADPS0);
}

int main(void)
{   
    ADC_init();
    
    //Se inhabilita la entrada digital de ADC0 para ahorro de energía
    DIDR0  |= (1<<ADC0D);
    
    //Se inician variables
    float setpoint = 3, Vref = 5, valor_dec, err;
    
    //Se habilita el primer bit del puerto D como salida
    DDRD = 1;
    //Bucle para leer el voltaje de entrada continuamente
    while (1)
    {   
        //Inicia la conversión
        ADCSRA |= (1<<ADSC);
        //Se convierte el valor de salida del ADC a decimal
        valor_dec = (ADC*Vref)/1024;
        //Cálculo del error
        err = setpoint - valor_dec;
        //Encendido o apagado del led
        if (err>=0) PORTD = 1;
        else        PORTD = 0;
    }
        return 0;
}
 
Dejando de lado posibles optimizaciones, en general el código pareciera estar bien, salvo que nunca esperás a que el conversor termine de convertir.

C:
int main(void)
{   
    ....
    //Bucle para leer el voltaje de entrada continuamente
    while (1)
    {   
        //Inicia la conversión
        ADCSRA |= (1<<ADSC);
        
        //<<<<<-------- Acá debería haber una espera, tendrías que estar esperando el status del ADC.
        
        //Se convierte el valor de salida del ADC a decimal
        valor_dec = (ADC*Vref)/1024; //Acá podrías incluir la constante 1024 como flotante=> 1024F
        //Cálculo del error
        err = setpoint - valor_dec;
        ....
    }
    return 0;
}
 
Dejando de lado posibles optimizaciones, en general el código pareciera estar bien, salvo que nunca esperás a que el conversor termine de convertir.

C:
int main(void)
{  
    ....
    //Bucle para leer el voltaje de entrada continuamente
    while (1)
    {  
        //Inicia la conversión
        ADCSRA |= (1<<ADSC);
       
        //<<<<<-------- Acá debería haber una espera, tendrías que estar esperando el status del ADC.
       
        //Se convierte el valor de salida del ADC a decimal
        valor_dec = (ADC*Vref)/1024; //Acá podrías incluir la constante 1024 como flotante=> 1024F
        //Cálculo del error
        err = setpoint - valor_dec;
        ....
    }
    return 0;
}
Te agradezco mucho tu comentario! Intenté implementar ambas sugerencias. Con la primera no tuve problemas, le puse un delay de 100us. En la segunda me marcó error al poner la F junto al 1024 (Atmel Studio). Quité la F de la constante y el programa funcionó sin problemas, tal como debería. Lo agradezco bastante!
 
No tendrías que poner un delay, deberías corroborar el bit ADSC del registro ADCSRA:

ADSC will read as one as long as a conversion is in progress. When the conversion is complete, it returns to zero. Writing zero to this bit has no effect.

Algo así deberías hacer:

C:
// wait for conversion to complete
// ADSC becomes ’0′ again
// till then, run loop continuously
while(ADCSRA & (1<<ADSC));

Otra cosa super importante que se me pasó, en ningún momento lees el valor del ADC, la variable "ADC" nunca cambia, ni se inicializa.

Para la lectura deberías leer los registros ADCH y ADCL según la configuración de ADLAR en el registro ADMUX.

Sobre lo del flotante, probá usando la letra minúscula con un decimal: 1024.0f.
 
Última edición:
Arriba