El valor ADC Atmega32 no es exacto

Estaba tratando de simular en proteus ADC con potenciómetro y obtener la lectura para controlar el motor de CC con PWM, está funcionando, pero el problema es que el valor de ADC no es preciso. ADCH alcanza el valor máximo antes de que el potenciómetro esté al 100%. No sé por qué este comportamiento. Espero que me lo puedas explicar. Aquí está el código.

#include <avr/io.h>
#define F_CPU 1000000UL
#include <util/delay.h>
void pwm_init()
{
DDRB |= (1<<PB3);
TCCR0 |= (1<<WGM00) | (1<<WGM01) | (1<<COM01) | (1<<CS01);
OCR0 = 0x00;
}

void adc_init()
{
DDRA =0x00;
ADMUX |= (1<<REFS0);// AVCC ref
ADCSRA |= (1<<ADEN) | (1<<ADPS2) | (1<<ADLAR) | (1<<ADATE); // 1MHZ With 
prescaler 8 gives adc freq 125 khz
}

uint8_t adc_read()
{
ADCSRA |= (1<<ADSC);
while(!(ADCSRA && (1<<ADIF)));
ADCSRA |= (1<<ADIF);
return ADC;
}

int main(void)
{
pwm_init();
adc_init();
while (1) 
{
    OCR0 = adc_read();
}
}

También puede ver en la imagen de abajo que el ciclo de trabajo es casi del 100%, mientras que el potenciómetro es solo del 12%.Simulación

¿Qué placa estás usando? ¿Está seguro de que no hay otros dispositivos/sensores integrados conectados al pin PA0?
@Ali Chen no estoy usando ningún tablero, estoy simulándolo en proteus en atmega32
¿Qué voltajes hay en RV4(2), VCC y AVCC? Muestra todo el circuito.
¿Por qué haces esta operación lógica AND: while(!(ADCSRA && (1<<ADIF))); en lugar de un AND bit a bit: while( !( ADCSRA & (1<<ADIF)) ) ; ??

Respuestas (2)

Si ADLAR = 1, entonces de acuerdo con la hoja de datos (sección 26.8.4, ver adjunto), el resultado de ADC se alinea a la izquierda con el par de 16 bits ADCH-ADCL.

Su función adc_read()devuelve un entero de 8 bits. Por lo tanto, devuelve solo ADCL(ver figura), porque los 8 bits superiores se pierden en la conversión uint_16->uint_8.

En otras palabras, si A0 o A1 son 1, obtendrá un valor de servicio grande, porque el valor devuelto por adc_read()estará entre 0x40 y 0xC0.

Solución: en su función adc_read()de retorno ADCHsolamente.

Además, el potenciómetro debe estar conectado a una fuente de voltaje con AREF volt, donde AREF es el voltaje de referencia del ADC. Si está utilizando la referencia interna, no conecte el potenciómetro directamente al pin AREF, porque dicho pin tiene una capacidad de corriente de salida muy pequeña.

ingrese la descripción de la imagen aquí

Gracias por señalar eso. He editado el código para que adc_read() devuelva ADCH solo, pero desafortunadamente la simulación mostró un ciclo de trabajo casi cero y no se produce ningún cambio cuando se cambia el valor del potenciómetro.
¡Entonces muestre los esquemas completos en su publicación! ¡Está oculto por el visor! Además, ¿qué es RV4(2)? ¿Es un voltaje igual a AREF?
RV4 es solo una etiqueta para el potenciómetro.
Tienes que poner un generador de voltaje con valor AREF en el pin superior del potenciómetro. De lo contrario, el voltaje en PA0 será siempre 0.
Este triángulo sobre el potenciómetro es el suministro de voltaje de CC con 5 v igual que aref
¿Puedes mostrarnos los esquemas completos?
Lo siento, no estoy cerca de mi computadora portátil ahora. Lo subiré tan pronto como tenga acceso a él.

Gracias, chicos, por su ayuda

Encontré el problema.

Configuré ADLAR en el registro ADCSRA y debería configurarse en ADMUX. Lo arreglé y todo funcionó bien.