ATtiny85 entrada analógica constantemente en máx.

0

Actualmente estoy ingresando en la programación de AVR y quiero leer dos valores de dos potenciómetros en las entradas analógicas PB3 / ADC3 PB4 / ADC2. Quiero (solo por ahora) encender dos LED (PB1 y PB2) cuando el valor de la entrada analógica está por encima (límite superior arbitrario) 900.

Aquí está el código con el que trato de hacerlo.

  #include <avr/io.h>
  #include <stdint.h>
  #include <util/delay.h>
//1MHz clock
#define F_CPU 1000000

uint8_t channelPB4 = 0x2;
uint8_t channelPB3 = 0x3;

int main(void){
    uint16_t resultAdc1 = 0, resultAdc2 = 0;

    //ADC enable
    ADCSRA |= (1<<ADEN);
    //set prescaler to 128 in order to be in recommended range
    ADCSRA |= (1<<ADPS1) | (1<<ADPS0) | (1<<ADPS2);
    //read value empty
    ADCSRA |= (1<<ADSC);
    while (ADCSRA & (1<<ADSC) ) {}
    //dummy readout
    (void) ((ADCH <<8 ) | ADCL);


    DDRB |= (1<<PB1) | (1<<PB2);


    while(1){
        ADMUX = (ADMUX & 0xf8) | channelPB3;
        //start conversion
        ADCSRA |= (1<<ADSC);
        //wait for completion of conversion
        while(ADCSRA & (1<<ADSC)){}
        resultAdc1 = (ADCH<<8) | ADCL;

        ADMUX = (ADMUX & 0xf8) | channelPB4;
        //start conversion
        ADCSRA |= (1<<ADSC);
        //wait for completion of conversion
        while(ADCSRA & (1<<ADSC)){}
        resultAdc2 = (ADCH<<8) | ADCL;

        if (resultAdc1 > 900){
            PORTB |= (1<<PORTB1);
        }else if(resultAdc1 < 900){
            PORTB &= ~(1<<PORTB1);
        }
        if(resultAdc2 > 900){
            PORTB |= (1<<PORTB2);
        }else if(resultAdc2 < 900){
           PORTB &= ~(1<<PORTB2);
        }
        _delay_ms(500);
    }

    return 0;
}

Pero lo que obtengo es que mis LED están encendidos constantemente. Incluso cuando quito el potenciómetro de la entrada analógica y conecto la entrada analógica a tierra. Mi referencia es VCC, por lo que la tierra debe ser 0 en el rango de 0 a 1023.

¿Puedes ver mi error?

ACTUALIZACIÓN: Esquema (lo siento, no está muy ordenado)

simular este circuito : esquema creado usando CircuitLab

    
pregunta AronC

1 respuesta

1

Su problema se debe a la forma en que accede al registro ADC. Los AVR de 8 bits solo tienen una ruta de datos de 8 bits, lo que significa que los accesos a registros de 16 bits se deben realizar en dos etapas, que por diseño requieren una secuencia específica.

Básicamente, primero debe leer el registro bajo, que al mismo tiempo moverá el valor del registro alto a un registro de acceso temporal (para los temporizadores generalmente), o bloqueará el valor del registro alto para permitir el acceso posterior. Este proceso es para evitar que se corrompa el valor si cambia entre la lectura de bytes bajos y altos.

Su acceso se realiza utilizando la línea resultAdc2 = (ADCH<<8) | ADCL; , que es incorrecta, ya que el compilador convertirá eso en primero leyendo el registro alto y luego leyendo el registro bajo. En su lugar, deberías hacer algo como:

uint8_t low = ADCL;
uint8_t high = ADCH; 
resultAdc2 = (high<<8) | low;. 

Además, su problema empeora debido a la forma en que funciona el acceso al registro de resultados ADC. Desde la página 137 de la hoja de datos , allí es la siguiente cita:

  

"Cuando se lee ADCL, el registro de datos de ADC no se actualiza hasta que se lee ADCH."

Lo que esto significa es que si lees ADCH primero, descartas el valor de ADCL. Esto no es necesariamente un problema, pero dañará el resultado a menos que tenga ADLAR configurado en 1.

Sin embargo, lo que también significa es que si continúa leyendo ADCL, bloqueará el registro de datos hasta que lea ADCH. La lectura de ADCH no se realiza hasta el siguiente bucle, lo que significa que, mientras tanto, el resultado de la siguiente conversión de ADC no se puede escribir en el registro de ADC, lo que significa que en su código el valor del registro nunca se actualiza.

    
respondido por el Tom Carpenter

Lea otras preguntas en las etiquetas