Cómo convertir datos analógicos y enviarlos a una PC con Ubuntu

En esta entrada te presento cómo digitalizar datos a 12 bits y enviarlos a una PC administrada por el sistema operativo Ubuntu. Usaremos el convertidor analógico – digital y la UART de un dsPIC30F4013, un módulo convertidor USB – serie, y códigos en lenguaje C. Para tener mayor control del experimento, obtendremos el valor analógico a convertir con un potenciómetro. El diagrama eléctrico del circuito de prueba está en la figura 1; la figura 2 es una captura de pantalla que obtuve al evaluar el prototipo.

Diagrama eléctrico del circuito de prueba.
Figura 1. Diagrama eléctrico del circuito de prueba. Obtendremos la energía para el circuito desde la PC a través del módulo USB; dibujé las conexiones de la fuente por dentro del dsPIC y del módulo porque las alambré por debajo de los componentes, la intensión es mantener alejadas las pistas que conducen valores analógicos de las que llevan tensiones y señales digitales. Usé un potenciómetro de 20 vueltas.
Foto del módulo USB – serie que usé.
Figura 1b. Foto del módulo USB – serie que usé. Por si requieres más información: es el mismo que etiqueté con el número 4 en la entrada Comunicación RS232 a través del USB.
Captura de pantalla al probar el prototipo.
Figura 2. Captura de pantalla al probar el prototipo. Tensiones aplicadas: 51.1 mV, 100.4 mV, 500 mv, 1 V, 2 V, 3 V y 4 V. El voltaje de referencia fue de 4.8 V.

Nombré cad.c al programa para el dsPIC:

#include <xc.h>
#pragma config FOSFPR = FRC
#pragma config WDT = WDT_OFF

void main(void)
{
 unsigned char cuantos;
 int n, dato;
 
 // Configuración de la UART.
 // 38400 bps a partir del oscilador interno a 7.37 MHz.
 U1BRG=2;
 // Usar terminales alternas (15 Y 16).
 U1MODEbits.ALTIO=1;
 // Habilitar la UART.
 U1MODEbits.UARTEN=1;
 U1STAbits.UTXEN=1;
 
 // Configura el CAD.
 // Selecciona la entrada analógica 9.
 ADCHS=0x9;
 // TAD = 814 ns.
 ADCON3=2;
 // Enciende el convertidor A/D.
 ADCON1bits.ADON=1;
 while(1)
 {
  // Espera a recibir un dato desde la PC.
  while(IFS0bits.U1RXIF==0);
  // Interpreta el dato recibido como la cantidad de conversiones a realizar.
  cuantos=U1RXREG;
  IFS0bits.U1RXIF=0;
  for (n=0; n<cuantos; n++)
  {
   IFS0bits.ADIF=0;
   ADCON1bits.SAMP=1; // Inicia el muestreo.
   asm("NOP");
   asm("NOP");
   asm("NOP");
   asm("NOP");
   // Finaliza el muestreo e inicia la conversión.
   ADCON1bits.SAMP=0;
   // Espera a que la conversión termine.
   while(IFS0bits.ADIF==0);
   dato=ADCBUF0;
   // Transmite el resultado a la PC en 2 bytes.
   while(IFS0bits.U1TXIF==0);
   // Parte más significativa.
   U1TXREG=((dato&0xF00)>>8);
   IFS0bits.U1TXIF=0;
   while(IFS0bits.U1TXIF==0);
   // Byte menos significativo.
   U1TXREG=(dato&0xFF);
   IFS0bits.U1TXIF=0;
  }
 }
}

LeeCadDspic.c es el programa para la PC:

#include <stdio.h>
#include <stdlib.h>
#include <fcntl.h>
#include <unistd.h>
#include <termios.h>
#include <sys/ioctl.h>

void main(int nargs, char *args[])
{
 unsigned char cuantas, lectura[2];
 int puerto, dato, n;
 struct termios atributos;
 
 if (nargs!=3)
 {
  printf("\nEjemplo:\n");
  printf("./LeeCad /dev/ttyUSB0 N\n\n");
  exit(1);
 }
 puerto=open(args[1],O_RDWR|O_NOCTTY);
 if (puerto<0)
 {
  printf("\nFalla al intentar abrir el puerto %s\n\n",args[1]);
  exit(1);
 }
 cuantas=n=atoi(args[2]);
 if (n>255) { cuantas=255; printf("Sólo se ejecutarán 255 lecturas\n"); }
 tcgetattr(puerto,&atributos); // Lee configuración del puerto
 atributos.c_lflag&=(~ICANON); // Elimina los caracteres de control
 atributos.c_lflag&=(~ECHO); // Elimina el eco
 // Habilita lectura e ignora lineas de control, 8 bits a 384000 bps
 atributos.c_cflag=B38400|CS8|CREAD|CLOCAL;
 // Regresa hasta obtener por lo menos 2 bytes
 atributos.c_cc[VMIN]=2; atributos.c_cc[VTIME]=0;
 // Permitir la transmisión y recepción de los códigos del 0 al 255
 atributos.c_iflag&=~ICRNL;
 atributos.c_iflag&=~IXOFF;
 atributos.c_iflag&=~IXON;
 atributos.c_lflag&=~ISIG;
 atributos.c_oflag&=~OPOST;
 // Establece la nueva configuración
 tcsetattr(puerto,TCSANOW,&atributos);
 // Envía un byte indicando el número de conversiones
 write(puerto,&cuantas,1);
 for (n=0; n<cuantas; n++)
 {
  // Lee 2 bytes por dato convertido
  read(puerto,lectura,2);
  // Convierte los 2 bytes en un entero y lo muestra en pantalla
  printf("%d\n",(int)(256*lectura[0]+lectura[1]));
 }
 close(puerto);
}

El diagrama a bloques del convertidor A/D del dsPIC30F4013 está en la figura 3. Entre las características más relevantes están:

  • El convertidor es de aproximaciones sucesivas, por eso se observa que incluye un convertidor digital – analógico (DAC); e implica el uso de un reloj (que NO está representado en el diagrama).
  • Hay un circuito de muestreo y retención (S/H).
  • Hay entradas para aplicar tensiones de referencia y alimentación exclusiva para los circuitos analógicos.
  • Aunque hay sólo un convertidor A/D, se puede procesar varias entradas analógicas por que el módulo también incluye un multiplexor.
Diagrama a bloques del convertidor analógico – digital del dsPIC30F4013
Figura 3. Diagrama a bloques del convertidor analógico – digital del dsPIC30F4013. Esta figura pertenece a Microchip y está en la página 131 de la hoja de datos del dsPIC.

Existen múltiples opciones para configurar el convertidor A/D, de hecho hay muchos registros (figura 4) relacionados con este módulo del dsPIC. En las líneas siguientes me limitaré a explicar la configuración del ejemplo, en la que aproveché muchos de los valores que los registros toman por omisión.

Registros que intervienen en la configuración y funcionamiento del CAD.
Figura 4. Registros que intervienen en la configuración y funcionamiento del CAD. Esta figura pertenece a Microchip y corresponde a la tabla 19-2 de la hoja de datos del dsPIC30F4013.

Reloj para el procedimiento de aproximaciones sucesivas

En una serie de iteraciones o pasos, los CAD de aproximaciones sucesivas “proponen” valores digitales, los convierten en analógicos y los comparan con la señal a convertir. Es por esto que requieren de un reloj que les indique en que momento se debe ejecutar un paso del procedimiento. Cuando se usan las tensiones analógicas de alimentación también como voltajes de referencia, el periodo de este reloj (TAD) debe ser mayor a 668 ns.

La duración de TAD se obtiene a partir del ciclo de instrucción (TCY), que a su vez, depende de la frecuencia del oscilador principal (FOSC) del dsPIC.

T_{CY}=\frac{4}{F_{OSC}}

T_{{AD}}=\frac{T_{{CY}}}{2}*(ADCS+1)

Ya que estoy usando el oscilador interno a una frecuencia de 7.37 MHz (#pragma config FOSFPR = FRC), el menor valor que se puede usar en los bits de control ADCS para satisfacer la condición TAD > 668 ns es 2, lo que establece TAD = 814 ns. Línea 37 del código.

Circuito de muestreo y retención (sample and hold, S/H)

Ya que efectuar una conversión requiere tiempo, es necesario mantener temporalmente la señal analógica a convertir sin cambios. Esto se logra “copiando” el voltaje analógico en un condensador. Como se puede ver en las figuras 5 y 6, el tiempo de muestreo se mide en TADs. El análisis de esta gráfica y especificaciones, me llevó al retardo que producen las cuatro instrucciones NOP que están entre la orden de iniciar el muestreo, y la que lo detiene para iniciar la conversión. Líneas 50 a 56 del código.

Diagrama de tiempos que muestra la secuencia de muestreo y conversión.
Figura 5. Diagrama de tiempos que muestra la secuencia de muestreo y conversión. Esta figura pertenece a Microchip y se encuentra en la página 208 de la hoja de datos del dsPIC30F4013.
Tabla que muestra numéricamente los requerimientos de los tiempos indicados en la figura 5.
Figura 6. Tabla que muestra numéricamente los requerimientos de los tiempos indicados en la figura 5. Cero que las unidades encerradas en rojo son incorrectas ya que el parámetro se expresa como un múltiplo de TAD. Esta figura pertenece a MIcrochip y corresponde a la tabla que está en la página 209 de la hoja de datos del dsPIC.

Voltajes analógicos de alimentación (AVDD y AVSS) como voltajes de referencia

En la sección de configuración, NO se nota que ordené el uso de las tensiones analógicas de alimentación como voltajes de referencia para el CAD. Esto se debe a que dicha situación corresponde a la configuración por omisión.

Observa que utilicé un filtro pasa bajas pasivo de orden 1 para disminuir el ruido en AVDD (figura 1). Esto redujo la tensión de alimentación analógica y de referencia a 4.8 V. ¿Resultaría conveniente obtener 4.095 V ó 4.096 V?

Si deseas hacer conversiones más rápido, NO podrás usar AVDD y AVSS como voltajes de referencia. El uso de tensiones de referencia independientes permite cambiar el límite de TAD > 668 ns a TAD > 334 ns.

Comentario final

Como habrás notado, la versatilidad del módulo de conversión AD del dsPIC4013 lo hace complejo. Aquí te presenté sólo un ejemplo que podría facilitarte empezar su estudio, deberás continuar usando los documentos siguientes:

dsPIC30F Family Reference Manual

dsPIC30F3014/4013 Data Sheet

Si requieres más información respecto a la comunicación serie de la PC, te recomiendo:

The GNU C Library Reference Manual. Chapter 17: Low-Level Terminal Interface

¡Hasta la próxima!

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos necesarios están marcados *