#include <avr/io.h>
#include <util/delay.h>
void init(){
// LED output.
DDRB |= 1<<4;
// Turn on ADC on third pin, continuous mode, prescaler 128.
ADMUX |= (1<<MUX0) | (1<<MUX1);
ADCSRA |= (1<<ADEN) | (1<<ADSC) | (1<<ADATE) | (1<<ADPS2) | (1<<ADPS1) | (1<<ADPS0);
}
int main(){
init();
uint16_t adc = 0;
while(1){
adc = (ADCH << 8) | ADCL;
// adc = (adc + 1) & 1023;
// _delay_ms(1);
if(adc > 512){
PORTB |= 1<<4;
}
else{
// PORTB = 0;
PORTB &= ~(1<<4);
}
}
}
Este es el código que tengo corriendo en mi ATtiny13A. Hay un LED conectado al pin B4 y un potenciómetro a B3. Se supone que el código enciende el LED si el valor analógico es mayor que 512 (la mitad del máximo 1024). Sin embargo, no funciona y el LED parece estar desactivado todo el tiempo.
Normalmente asumiría que hay algún problema en la configuración de los periféricos, pero están sucediendo algunas cosas muy extrañas. Por ejemplo, si cambio PORTB &= ~(1<<4);
a PORTB = 0
(que en este caso debería hacer exactamente lo mismo), el código mágicamente comienza a funcionar tal como se esperaba. Otra cosa que probé es cambiar el estado del LED usando un contador simple quitando el comentario de las dos líneas cercanas _delay_ms
, y nuevamente, el LED comienza a parpadear como se esperaba.
El único momento en que este código no funciona es cuando está exactamente en esta forma, por lo que debe haber algún problema con la combinación de lectura de ADC y escritura de bits del puerto de salida.
¿Por qué pasó esto?
Cuando se lee ADCL, el registro de datos ADC no se actualiza hasta que se lee ADCH.
En C, el orden de evaluación del |
operador no está definido, por lo que este código podría leerse ADCH
primero y luego leer ADCL
. Una vez que haya leído ADCL
, habrá bloqueado el registro de datos hasta el próximo paso por el ciclo, que ciertamente no es lo que desea.
Intenta cambiar esta línea a...
adc = ADC;
(el compilador de C debería generar la codificación de orden de acceso correcta).
Este diagrama sugiere fuertemente que el registro ADC se está actualizando hasta que ADIF sube...
Espero que los nuevos bits se muevan a su lugar con cada aproximación sucesiva, y la demora adicional de nop
podría ser suficiente para que el ADC esté listo para cuando lo golpee por casualidad.
Intenta reemplazar...
adc = (ADCH << 8) | ADCL;
...con...
while (! ADCSRA & _BV(ADIF) );
adc = ADC;
ADCSRA |= _BV( ADIF );
... y ver si eso resuelve el problema del tiempo.
Informe de nuevo si esto soluciona el problema. Si no, ¡pasaremos al próximo intento!
|
operador se evalúa de izquierda a derecha" - esto no es correcto. De hecho, el orden de evaluación no está especificado (a diferencia de, digamos, para ||
, donde es de izquierda a derecha para permitir la evaluación de cortocircuito).
akrasuski1
akrasuski1
PORTB = 0
(la línea que funcionó), pero luego agrego una solanop
, se vuelve a romper. Parece ser un problema de tiempo por alguna razón: agregar 4nop
s lo soluciona nuevamente ...