No uso Arduino, por lo que no sé lo que está sucediendo en esas rutinas, pero hay algunas formas comunes de tomar una medida ADC con AVR. Una de las mejores cosas de los chips AVR en las líneas ATtiny y ATmega es que muchos registros periféricos tienen los mismos nombres (o muy similares) en diferentes chips. Voy a utilizar el ATtinyx4 ( hoja de datos ) en este ejemplo.
También es de destacar que estos chips se programan más comúnmente en C (o ensamblaje), no en C ++, aunque Arduino usa una versión de C ++.
Primero se debe configurar el ADC. Por lo general, esto implica configurar el voltaje de referencia, inicializar el multiplexor ADC, configurar el prescaler de reloj ADC, configurar el modo y habilitar la interrupción ADC.
Por ejemplo (en C):
// _BV(BIT) is defined as (1<<(BIT))
ADMUX = _BV(REFS1); // Use internal 1.1V reference voltage, multiplexer = 0
ADCSRA =
_BV(ADPS1) | // Prescaler = 4: F_ADC = F_cpu / prescaler
_BV(ADEN); // Enable the ADC
ADCSRB = _BV(ADLAR); // Left Adjust Result for 8 bit resolution
Para tomar una medida, harías esto:
ADCSRA |= ADSC; // Start an ADC conversion
while(ADCSRA & _BV(ADSC)); // Wait until conversion is complete
ADC_Value = ADCH; // Read the ADC high register
Observe que solo leo el registro alto porque solo uso una resolución de 8 bits. Podría haber leído fácilmente el valor completo de ADC en su lugar.
Si, por el contrario, desea que el código maneje automáticamente el resultado de ADC, puede habilitar la interrupción completa de la conversión de ADC.
ADCSRA |= _BV(ADIE); // Enable ADC Interrupt
Y maneje el valor de ADC en la rutina de servicio de interrupción de ADC. Esto podría ser más eficiente en el tiempo, pero utilizará más espacio de código.
También hay un "modo de ejecución libre", lo que significa que el ADC tomará una lectura continuamente mientras esté habilitado para el canal seleccionado. Toda esta información se encuentra en la hoja de datos de los chips AVR con funcionalidad ADC en el capítulo "Convertidor analógico a digital".
Si desea crear su propia función para hacer esto, si se parece a esto:
uint8_t ADC_read(uint8_t channel)
{
ADMUX &= (_BV(REFS1) | _BV(REFS0)); // Clear the ADC Multiplexer
ADMUX |= channel; // Set the ADC multiplexer
ADCSRA |= ADSC; // Start an ADC conversion
while(ADCSRA & _BV(ADSC)); // Wait until conversion is complete
return (ADCH); // Return the ADC high register value
}
Otras cosas a considerar: la primera lectura después de habilitar el ADC suele ser basura, por lo que si no lo va a dejar habilitado (usa más energía de esta manera) tendrá que tomar dos medidas consecutivas, descartando la primera uno. Por supuesto, los pines que se están utilizando deben configurarse como entradas con los buffers de entrada digital desactivados (DIDRx).
Mis ejemplos anteriores utilizaron la macro _BV () para establecer un bit en particular en un byte, pero esta es solo una forma diferente de desplazar a la izquierda en 1 tantos lugares. La macro _BV () se define normalmente en uno de los archivos de encabezado AVR junto con las definiciones de los nombres de registro específicos del chip que se incluyen en la parte superior de un programa, pero no sé cómo se maneja en Arduino.
Si la macro _BV () no funciona, puede definirla usted mismo como:
#define _BV(BIT) (1<<(BIT))
Dado que un byte es de 8 bits, puede pensarse así: [bit7, bit6, ... bit1, bit0]. Al establecer un bit individual alto al desplazar a la izquierda un 1, muchos bits más significa que puede hacer que el código sea más legible (y modificable) y luego simplemente establecer un byte en un valor específico. Por ejemplo, este código:
ADCSRA =
_BV(ADPS1) | // Prescaler = 4: F_ADC = F_cpu / prescaler
_BV(ADIE) | // Enable ADC Interrupt
_BV(ADEN); // Enable the ADC
tiene mucho más sentido que este código:
ADCSRA = 0x8A; // 0b10001010
además de ser más portátil y más fácil de editar.
A algunas personas no les gusta usar (o ver) esta macro, por lo que prefieren usar solo el operando de cambio a la izquierda. De cualquier manera, está bien y utiliza la misma cantidad de espacio de código / ciclos de reloj para operar. Abandonando la macro _BV (), mis ejemplos se verían así:
// Setting up the ADC
ADMUX = (1<<REFS1); // Use internal 1.1V reference voltage, multiplexer = 0
ADCSRA =
(1<<ADPS1) | // Prescaler = 4: F_ADC = F_cpu / prescaler
(1<<ADEN); // Enable the ADC
ADCSRB = (1<<ADLAR); // Left Adjust Result for 8 bit resolution
// Taking a measurement
ADCSRA |= ADSC; // Start an ADC conversion
while(ADCSRA & (1<<ADSC)); // Wait until conversion is complete
ADC_Value = ADCH; // Read the ADC high register
// Enabling the ISR
ADCSRA |= (1<<ADIE); // Enable ADC Interrupt
//Function to read an ADC Channel (once the ADC is setup)
uint8_t ADC_read(uint8_t channel)
{
ADMUX &= (1<<REFS1) | (1<<REFS0)); // Clear the ADC Multiplexer
ADMUX |= channel; // Set the ADC multiplexer
ADCSRA |= ADSC; // Start an ADC conversion
while(ADCSRA & (1<<ADSC)); // Wait until conversion is complete
return (ADCH); // Return the ADC high register value
}
Nuevamente, estos ejemplos se basaron en los registros para el ATtinyx4. Un chip AVR diferente con un ADC puede tener nombres o ubicaciones de registro y valores de bits ligeramente diferentes ... Pero usar el registro real y los nombres de bits con comentarios significa que es fácil de modificar si es necesario.