Lectura analógica

Algunos modelos de PICs (y Arduinos) cuentan con unas entradas llamadas analógicas. ¿Qué es una entrada analógica?

Hasta ahora hemos estado trabajando con entradas y salidas digitales, es decir, que pueden estar en estado alto o bajo, 5 voltios o 0 voltios. Sin embargo, el mundo real no está conformado de señales digitales ni mucho menos evoluciona como tal. Lo que nos permite un puerto analógico es leer y transformar un valor de tensión entre 0 y 5 voltios (en el modo más basico) en un valor numérico.

Dicho valor numérico viene determinado por el PIC y la programación, los hay que usan 8 bits.

Con 8 bits tenemos un recorrido de 2^8 = 256, si tenemos en cuenta que cuando lea 5 voltios tendremos un valor de 256, ésto nos da una resolución (paso) de 0.0195 voltios por cada 1 que se sume al valor.

También tenemos la posibilidad de usar 10 bits: 1024, lo cual nos da una resolución de 0.00488V por valor.

Para un sistema analógico bien acondicionado, es una precisión excelente ¿no creéis?

¿Cómo usamos dicho puerto analógico en la programación?

En primer lugar, se debe indicar al compilador que vamos a usar el “device ADC” y con qué resolución lo queremos (en bits), justo después de añadir la librería del PIC.

#Include <PICQUEVASAUSAR.h>
#Device ADC= Resolución //8 o 10 según os convenga
#Fuses
#Byte
Etc...

Y se debe poner justo ahí porque si no, ya he comprobado que no funciona. Así pues, necesitaremos una variable para almacenar el valor que nuestro ADC lea. Para intentar ahorrar espacio, si usas 8 bits te conviene un int, y si usas 10 bits mejor usar un int16. Como deduciréis, el primero ocupa 8 bits y el segundo 16.

También necesitaréis un float para almacenar el valor convertido a tensión (en caso de necesitarlo).

int16 lectura;
float valor;

El siguiente paso es configurar el puerto. En primer lugar, el pin del puerto que se vaya a usar para la lectura se debe declarar como entrada obligatoriamente, mientras el resto se usará como entradas o salidas digitales normalmente. Recordad que ésto se hace con el registro TRIS.

Para configurar el ADC podéis hacerlo accediendo directamente al registro ADCON0 y ADCON1 y según indique la datasheet los programáis al gusto, o bien podéis tomar el atajo y usar las funciones de CCS.

En primer lugar, decimos qué entradas queremos que sean analógicas:

setup_adc_ports(---);
// Donde he puesto --- hay una lista enorme de posibilidades, las más usadas serían:
// ALL_ANALOG -> Todas las patas del puerto analógico funcionan como tal
// NO_ANALOG -> Ninguna analógica, ésto viene por defecto
// AN0 -> Sólo la pata AN0 es usada como entrada analógica, la más usada.
// AN0_AN1_AN3 -> Ésas 3 serían analógicas
// Y más combinaciones que podéis ver en la librería .h de vuestro PIC
// También es posible seleccionarlos uno a uno escribiendo por ejemplo
// setup_adc_ports(sAN0 | sAN2 | sAN6);

Como ya he indicado, lo más normal es usar sólo una entrada analógica y el resto digitales, se pone AN0 o sAN0 según el PIC (ensayo y error).

El próximo paso es indicarle al ADC con qué velocidad de reloj va a funcionar:

setup_adc(---);
//ADC_CLOCK_DIV_2
//ADC_CLOCK_DIV_8
//ADC_CLOCK_INTERNAL
//Etc
//Lo más indicado es visitar la librería del pic para ver
//de qué dispone

Por último, hay que decir al pic, de entre todas las entradas analógicas que hemos configurado, cuál queremos que lea.

set_adc_channel(Canal);
//El canal vendría siendo 0 para AN0, 3 para AN3, ...

Cuando todo esté listo, podemos empezar a leer el ADC con la/s siguiente/s función/es:

Posibilidad 1:
lectura = Read_adc(); //que es lo mismo que usar
lectura = Read_adc(ADC_START_AND_READ);
delay_us(20); //Le damos un poco de tiempo

Posibilidad 2:
Read_adc(ADC_START_ONLY); //Inicia el ADC pero no lo lee
//Aquí haríamos lo que quisiéramos entre medias, más funciones
lectura = Read_adc(ADC_READ_ONLY); //Y cuando se lo pedimos lo lee
delay_us(20);

Lo más rápido y sencillo es usar la “posibilidad 1” con lect = read_adc() y punto.

Una vez hecho ésto habremos adquirido en la variable lect un valor correspondiente a la tensión que se encontrase en la pata analógica en ése momento. Si lo que queremos es saber el valor de la tensión que se ha leído, tenemos que hacer una regla de tres:

Si 1024 son 5 voltios ¿Cuántos voltios es lo que he leído?

1024 —- 5
lect —- valor

valor = lect*1024/5;

Y así se obtiene ya un valor decimal de dicha tensión.

Espero que os sea de utilidad.

Conversor AD y puerto USB

Como ya sabemos desde el pin A0 al A5 podemos meter una señal analógica y que nuestro Arduino la interprete. Con ciertas limitaciones.

El máximo son 5 voltios y su resolución es de 10 bits. Es decir, cuando tengamos 5 voltios a la entrada tendremos como resultado 1024, y si tenemos 0 voltios tendremos como resultado 0. Ésto nos da un paso de 0,005 voltios.

A su vez sabemos que la placa es capaz de enviar y recibir datos por USB. En éste programa usaremos ésa capacidad para ver el resultado.

A la  entrada analógica pondremos un potenciómetro conectado a +5 y GND, conformando un divisor de tensión para que la salida intermedia de un rango de 5 a 0 voltios. Éste será el funcionamiento generalizado de cualquier sensor, pero lo podemos manipular.

Vamos con el programa:

void setup(){
 pinMode(2,INPUT); //el pin 2 es input
 pinMode(13,OUTPUT); //el pin 13 output
 Serial.begin(9600); //mandar cosas por USB, a cierta velocidad (bits/s)
}
void loop(){
 double lecturas[4]; //declaramos un vector de 5 posiciones
 double mandar; //y una variable flotante
 if(digitalRead(2)==LOW){ //si apretamos el boton y dejamos que el pin 2 se conecte a tierra
 Serial.println("leyendo"); //mandas esto por USB
 for(int x=0;x<5;x++){ //y lees 5 veces
 lecturas[x]=analogRead(0); //el puerto analógico AN0 y lo vas guardando en el vector
 delay(100); //con un pequeño delay para que le dé tiempo
 }
 mandar=5*(lecturas[0]+lecturas[1]+lecturas[2]+lecturas[3]+lecturas[4])/(5*1024.0); //hacemos un promedio de las lecturas
 Serial.print(mandar); //y mandamos el resultado por USB
 }
}

Las instrucciones nuevas son:

Serial.begin(bauds) -> Inicializa el puerto serie (USB) para el envío de datos a una cierta cantidad de bits por segundo (bauds).

Serial.println(var) o Serial.println(“text”) -> Envía por el puerto USB una variable o un texto. También se puede utilizar Serial.print(var) para que no haga un salto de línea.

analogRead(pin) -> lee el pin analógico seleccionado, en éste caso 0, A0, y devuelve un número entre 0 y 1023.

He procesado el resultado de la lectura analógica para que muestre, en vez de un número entre 0 y 1024, un determinado valor de la tensión que está entrando por el pin analógico.

El resultado lo podéis ver en vuestro monitor serie, que se encuentra en la pestaña Herramientas -> Monitor Serial del software de arduino.