[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:
Hola buenos días, apenas estoy empezando en esto de la programación de micros. Estoy haciendo un taller sobre un comparador binario para dos números de cuatro bits, estoy usando los puertos C y D de un ATMega328p como entradas para recibir los datos de unos switches(En el puerto C recibo el primer número y en el puerto D el segundo número), e internamente dependiendo de si el primer número es mayor que el segundo se debe poner el alto un pin del puerto B, si ambos números son iguales se debe poner en alto otro pin, y el primero es menor que el segundo. Mi pregunta es cómo puedo usar los estados lógicos de los puertos C y D como si fuesen números constantes en un momento determinado, para así poder hacer comparaciones como mayor que, menor que o igual que. (No sé si me hago entender) Agradezco mucho la ayuda :)

#ifndef F_CPU
#define F_CPU 16000000UL // 16 MHz clock speed
#endif
#include <avr/io.h>

void mayor();

int main()

{
DDRC = 0b00000000;
DDRD = 0b00000000;
DDRB = 0b11111111;


while(1)
{
if(PINC > PIND)
{
PORTB = 0b00000001;
}
}



}
 
Mi pregunta es cómo puedo usar los estados lógicos de los puertos C y D como si fuesen números constantes en un momento determinado, para así poder hacer comparaciones como mayor que, menor que o igual que.

Busca como se usa los "IF" "ELSE IF" y "ELSE".

Que traducidos serian algo así como:

C:
IF (A == B) { Código } // SI A = B entonces...
ELSE IF (A > B) { Código} // SI A es mayor que B entonces...
ELSE IF (A < B) { Código} // SI A es menor que B entonces...
ELSE {Código}           // Si ninguna de las anteriores....
 
Hola gracias por la respuesta, pero lo que pasa es que así lo tengo, pero la cosa es que no funciona, por ejemplo:

while(1)
{
if(PINC > PIND)
{
PORTB = 0b00000001;
}
}

Eso es lo que hice (Bueno es el ciclo infinito del microcontrolador), en teoría si el estado lógico del puerto C es mayor al estado lógico del puerto D se debería poner el 1 el pin 0 del puerto B, pero pues hago el montaje (Estoy usando Simullide) y no funciona, creo que es porque estoy manejando mal el registro PIN, pero no sé cómo usarlo bien y no he encontrado información o un caso similar para poder aplicarlo. Agradezco la ayuda :)))
 
Arriba