Table of Contents
Última actualización: 14 de mayo de 2011
Las características, el coste y la naturaleza abierta de GNU/Linux lo convierten en una plataforma muy adecuada para el desarrollo de sistemas de adquisición de datos.
Los grandes proveedores de sistemas de adquisición de datos ofrecen productos para esta plataforma, pero, como ocurre con otros sistemas operativos, cada fabricante emplea una interfaz (API, librería de funciones) distinta, con lo que es necesario adaptar el programa desarrollado a una determinada tarjeta y/o fabricante.
La experiencia personal con la informática en general es que casarse con un proveedor cerrado lleva casi siempre a un callejón sin salida. En la adquisición de datos esto es más acusado, así que sería perfecto que los desarrollos que incluyan sistemas de adquisición de datos se hagan de manera que no tengamos que preocuparnos por los caprichos y/o políticas de los fabricantes (falta de soporte, actualizaciones que dejan inoperativo al sistema, falta de información, dependencia del proveedor, etc).
En GNU/Linux hay una opción de código abierto denominada COMEDI (Linux Control and Measurement Interface) que pretende resolver este importante problema. COMEDI ofrece una interfaz común a todas las tarjetas de adquisición de datos, facilitando muchísimo la migración de un programa desarrollado para una tarjeta de adquisición de datos a otra tarjeta del mismo o de otro fabricante. Ojala existiese esto para Windows.
Al tratarse de un proyecto libre y abierto, mucha gente se ha dedicado a adaptar su tarjeta de interés a este entorno y después ha compartido el código siguiendo el espíritu de GNU/Linux, con lo que es fácil encontrar tarjetas compatibles o adaptar las propias.
Como lo mejor es pasarase las cosas por las manos para hacerse una idea, el objetivo de este artículo es ofrecer una idea práctica de cómo poner a punto COMEDI en GNU/Linux, y usarlo con una tarjeta de adquisición de datos gratuita: el puerto paralelo del PC.
Para desarrollar la experiencia se necesita:
Un ordenador viejo con, al menos, 512 MB de RAM y 10 GB de disco duro, y procesador Pentium que disponga de puerto paralelo de impresora (conector DB-25 hembra).
Una instalacion de la distribucion GNU/Linux Ubuntu 10.04 LTS. Utilizar la version Desktop i386, que suele funcionar en cualquier ordenador.
(En principio se puede usar cualquier distribución de Linux, pero se ha probado con ésta porque es de soporte largo, LTS=Long-term support).
Una conexión a Internet para poder descargarse los paquetes para Linux.
Un multimetro para medir voltios en los pines del puerto de la impresora.
![]() | Important |
|---|---|
Esta experiencia se debe realizar con un ordenador apto para destrozar. No hacer en el ordenador de trabajo habitual. |
Hay que asegurarse que tenemos instaladas las utilidades de Linux necesarias (compiladores, preprocesadores, cabeceras, bibliotecas, etc). Con el paquete build-essential es suficiente.
Se puede usar Synaptic para localizarlas e instalarlas o abrir un terminal y hacer lo siguiente:
$ sudo apt-get install build-essential
Lo primero es descargarse los paquetes de COMEDI. Se puede usar apt-get, como antes, o Synaptic. La siguiente imagen muestra en verde los paquetes a instalar: comedi-source, libcomedi, libcomedi-dev. No hacen falta todos, per así se puede cotillear mejor.
Vamos ahora a crear un archivo de configuración de los módulos kernel de COMEDI. Para ello abriremos un terminal y escribiremos:
$ sudo bash # echo "options comedi comedi_autoconfig=0" > /etc/modprobe.d/comedi.conf
Con esta orden se ha creado el archivo de texto
comedi.conf que le dice a COMEDI que no se
autoconfigure automáticamente.
Ahora se puede probar si COMEDI está disponible cargando los módulos del kernel asociados. Para ello abriremos un terminal y trabajaremos en modo superusuario.
$ sudo bash # modprobe comedi # modprobe kcomedilib
Si no se queja, posiblemente está todo bien instalado. Si protesta, utilizar la orden dmesg para ver los mensajes del kernel.
# dmesg
El puerto paralelo del PC se puede utilizar como una tarjeta de adquisición de datos con capacidad para hacer E/S digital compatible TTL. Históricamente, con un puerto paralelo era bastante sencillo controlar todo tipo de dispositivos digitales, hacer programadores de micros y memorias, hacer lectores de tarjetas, controlar motores, etc.
Este tipo de puerto tiende a desaparecer en los nuevos ordenadores por lo que es probable que nuestro ordenador más moderno no disponga de él. En ese caso, esta experiencia no se puede desarrollar pues el resto de puertos (USB, Firewire, Ethernet, etc.) no tiene esta capacidad.
Para comprobar si disponemos de dicho puerto, deberemos localizar en el chasis del PC un conector de tipo DB-25 hembra como el que se muestra en la siguiente imagen.
Incluso si no localizamos el conector, es muy probable que la placa base disponga de él. Será necesario consultar la información de la placa base para saber si está disponible y que conexión hay que realizar.
Dado el poco uso actual de este tipo de puerto, los ordenadores suelen venir con el desactivado, es decir, como si no estuviese.
Para activarlo, deberemos entrar en el BIOS del PC y activarlo en el menú que corresponda. Más o menos, se deberían seguir estos pasos:
Arrancar el ordenador y pulsar la tecja "Supr" o la que diga el manual de la placa base para entrar en el BIOS.
Entrar en el menú "periféricos" y activar el dispositivo "Parallel port" en modo estándar (SPP).
Anotar la dirección del puerto y la interrupción que le ha sido asignada por el sistema. Por ejemplo: dirección 378H e interrupción (IRQ) 7
Guardar la configuracion de BIOS y rearrancar el ordenador.
Todo debería seguir funcionando bien.
También es muy probable que el ordenador no tenga el conector DB-25 en la carcasa pero sí esté disponible en los conectores de la placa base. Habrá que buscar la información de la placa base para saber dónde conectar el adaptador.
Para poder usar el puerto paralelo desde COMEDI es necesario cargar los módulos del kernel necesarios y crear un "dispositivo" asociado a dicho puerto.
Cuando Linux detecta la presencia del puerto paralelo, se cargan automáticamente los módulos que gestionan la impresora. Lo primero es desactivar los módulos empleados para el servicio de impresión o cualquier otro que emplee dicho puerto. Si abrimos un terminal y ejecutamos la orden lsmod (listar módulos) podemos ver los módulos que el kernel tiene cargados. Entre muchos módulos veremos los siguientes:
$ lsmod ... parport_pc 36260 1 ... parport 37832 3 ppdev,lp,parport_pc ...
Para desactivar los módulos que están usando el puerto paralelo, se debe usar la orden rmmod o modprobe -r (quitar módulo) en el orden adecuada. Por ejemplo, se puede hacer en el terminal:
$ sudo bash # modprobe -r ppdev # modprobe -r lp # modprobe -r parport_pc # modprobe -r parport
Ahora se pueden cargar los módulos de COMEDI y el módulo particular para el puerto paralelo de la siguiente manera:
# modprobe comedi # modprobe kcomedilib # modprobe comedi_parport
En los sistemas *nix, casi todo se accede mediante archivos, y COMEDI no es una excepción, así que el siguiente paso es crear un archivo de dispositivo que será la vía por la que nuestros programas accederán al sistema de adquisición de datos. Para ello podemos hacer en el terminal:
# mknod -m 666 /dev/comedi0 c 98 0
Más o menos, esto es crear un archivo de dispositivo con permisos de lectura y escritura para todo el mundo (666), que es de tipo char (c) y con major "98" y minor "0".
El siguiente paso es asociar el archivo de dispositivo con el controlador del puerto paralelo y configurar el controlador. para ello, siguiendo en el terminal, hacemos:
# comedi_config /dev/comedi0 comedi_parport 0x378,7
Resumiendo, se han cargado los drivers de COMEDI para el puerto paralelo y se ha creado un dispositivo de adquisición de datos llamado /dev/comedi0 asociado al puerto de impresora con dirección 378H e interrupcion 7.
NOTA: Cada vez que se arranque Linux se deberán seguir los pasos de este apartado. Si alguien le va a sacar provecho a todo esto, pues ya se añadirá en esta guía cómo hacerlo automáticamente.
Las tensiones suministradas/aceptadas por el puerto paralelo son compatibles TTL ("1"=5V., "0"=0v) (en mi ordenador yo leo 0 y 3.36 voltios, debe haber cambiado algo).
En el conector hay líneas para entradas digitales, líneas para salidas digitales y líneas bidireccionales (entrada y salida). La siguiente figura muestra el conector y el tipo de líneas de que se dispone. (No hacer caso de la columna "inverted", pues COMEDI resuelve esa pega).
La líneas pueden suministrar una corriente suficiente para encender un led, pero es mejor no abusar y utilizar algún integrado que haga de buffer si no tenemos claro cuanta corriente vamos a consumir. Para las entradas basta con hacerles llegar 5V o 0V para tener un "0" o un "1" respectivamente.
La siguiente imagen muestra un ejemplo de conexionado obtenido de una pagina con un proyecto de control de un motor paso a paso.
En internet se pueden encontrar montones de ejemplos con diseños para el puerto paralelo.
En nuestro caso, para probar podemos conectar un multímetro para ver el estado de las salidas.
Usar COMEDI es muy parecido a lo que se ha hecho con las bibliotecas NIDAQMx de National Instruments empleadas en clase. De hecho, la ideas de las bibliotecas de National Instruments (que también funcionan en Linux) se basa en COMEDI, y LabView para Linux utiliza COMEDI para acceder a las tarjetas de adquisición de datos de National Instruments.
Simplificando, en COMEDI cada tarjeta es un device (dispositivo), cada periférico en la tarjeta es un subdevice (subdispositivo) y cada línea es un channel (canal). La siguiente tabla resume los subdevice y channels del puerto paralelo.
Los subdevice del puerto paralelo tienen el siguiente significado:
Subdevice 0: Entrada/salida digital. Por defecto se configura como salida.
Subdevice 1: Entrada digital.
Subdevice 2: Salida digital. El pin 1 (chan 0) siempre está a 1 y no se puede cambiar.
Subdevice 3: Entrada digital pero que siempre devuelve 0. Pero se puede usar con el pin 10 y una orden scan_begin_src=TRIG_EXT como un pin de disparo que puede utilizarse para despertar tareas.
A continuación se lista un ejemplo de programa que invierte el valor del pin 2 (subdevice=0, chan=0). Para poder comprobar la salida, conectar un tester entre los pines 2 y 20(GND).
/*** provacomedi.c **********************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <comedilib.h> /* incluir cabecera de comedi */
const char *filename = "/dev/comedi0"; /* dispositivo que se usara */
int main(int argc, char *argv[])
{
int subdevice;
int channel;
int ret;
comedi_t *device;
int i;
subdevice = 0; /* subdevice elegido */
channel = 0; /* channel elegido */
device = comedi_open(filename);
if (!device) {
comedi_perror(filename); /* fallo abriendo el dispositvo */
exit(0);
}
/* configurar todas los canales como salida */
for (i=0;i<8;i++) {
ret = comedi_dio_config(device,subdevice,i,COMEDI_OUTPUT);
if (ret<0) {
comedi_perror(filename); /* algo ha fallado */
exit(0);
}
}
/* continuamente invertir el canal seleccionado */
while(1) {
/* poner la linea a "1" */
ret = comedi_dio_write(device,subdevice,0,1);
if (ret<0) {
comedi_perror(filename);
exit(0);
}
printf("Pongo la linea a 1\n");
sleep(2);
/* poner la linea a "0" */
ret = comedi_dio_write(device,subdevice,0,0);
if (ret<0) {
comedi_perror(filename);
exit(0);
}
printf("Pongo la linea a 0\n");
sleep(2);
} /* del while() */
}
/***************************** FIN LISTADO ***********************************/
Para compilar y probar el programa hay que abrir un terminal y hacer lo siguiente. Trabajamos como superusuario, cuidadín.
# cd # mkdir provacomedi # cd provacomedi
Descargamos ahora el programa en el directorio creado o lo editamos con cualquier editor de texto. Para compilar hacemos:
# gcc -oprovacomedi -lcomedi -lm provacomedi.c
Si todo ha ido bien, podemos ejecutar el programa y ver que pasa. Recordar conectar el tester entre los pines 20 (GND) y 2.
# ./provacomedi
Suerte.
Antes de adquirir una tarjeta de adquisición de datos comercial para usar con COMEDI es fundamental comprobar que existen drivers para ella.
En este apartado se va a mostrar como hacer funcionar una tarjeta de adquisición de datos multifunción ADLink PCI-9111, y partimos de que se ha instalado COMEDI y la tarjeta la hemos montado en cualquier ranura PCI libre. La tarjeta tiene el aspecto mostrado en la siguiente figura.
Arrancamos Linux y ... ¡toma!, ya está todo funcionando. Automáticamente la tarjeta PCI se ha "enumerado" y los drivers de comedi para la tarjeta se han cargado.
Usándo en el terminal la orden lspci vemos que es reconocida.
00:12.0 Signal processing controller: Adlink Technology PCI-9111 (rev 02)
Si en el terminal hacemos lsmod, podemos ver los módulos cargados y localizar los relacionados con comedi.
comedi_fc 1757 1 adl_pci9111 comedi 32559 2 adl_pci9111,comedi_fc
Vamos a probar. Siguiendo, más o menos, los pasos para el puerto paralelo, terminamos de generar una configuración apropiada para la tarjeta. Abrimos un terminal y, trabajando como superusuario.
$ sudo bash # modprobe kcomedilib # mknod -m 666 /dev/comedi1 c 98 1 # comedi_config /dev/comedi1 adl_pci9111
Ahora podemos hacer un programa y probar. El siguiente fragmento de código, que es una adpatación del anterior, emplea las salidas digitales de la tarjeta (subdevice 3).
/* provacomedi.c
Programa sencillo para probar COMEDI con la ADLink PCI9111
Angel perles. Mayo 2011.
Conectar un tester a los pines 2 y 17(GND) del conector de salidas digitales
*/
#include <stdio.h>
#include <stdlib.h>
#include <comedilib.h> /* incluir cabecera de comedi */
const char *filename = "/dev/comedi1"; /* dispositivo que se usara */
/** función para mostrar los errores de OMEDI y salir **/
void mostrar_error(void) {
printf("COMEDI ha fallado. Razon: %s\n", comedi_strerror(comedi_errno()));
exit(1);
}
int main(int argc, char *argv[])
{
int subdevice;
int channel;
int ret;
comedi_t *device;
int i;
subdevice = 3; /* subdevice elegido */
channel = 0; /* channel elegido */
device = comedi_open(filename);
if (!device) {
comedi_perror(filename); /* fallo abriendo el dispositvo */
exit(1);
}
/* continuamente invertir el canal seleccionado */
while(1) {
/* poner la linea a "1" */
ret = comedi_dio_write(device,subdevice,0,1);
if (ret<0) {
mostrar_error();
}
printf("Pongo la linea a 1\n");
sleep(2);
/* poner la linea a "0" */
ret = comedi_dio_write(device,subdevice,0,0);
if (ret<0) {
mostrar_error();
}
printf("Pongo la linea a 0\n");
sleep(2);
} /* del while() */
}
/***************************** FIN LISTADO ***********************************/
Compilamos igual que antes y probamos.
NOTA: Apartado chuleta para mi. No apto para blandengues.
Instalar primero las utilidades de Linux necesarias, que son: build-essential, autoconf, automake.
$ sudo bash # apt-get install build-essential autoconf automake
Se supone descargado e instado comedi-source.
El siguiente paso es preparar e instalarlo todo abriendo un terminal y siguiendo estos pasos. Destacar que trabajamos como superusuario.
$ sudo bash # cd /usr/src # tar xjvf comedi.tar.bz2 # cd modules/comedi # ./autogen.sh # ./configure # make # make install # depmod -a # make dev
En algunas configuraciones sale algún mensaje raro, pero parece que, a pesar del mensaje, el sistema funciona. A continuación va el posible mensaje:
configure.ac:6: installing `./config.guess' configure.ac:6: installing `./config.sub' Makefile.am:41: `:='-style assignments are not portable Makefile.am:41: shell find $(srcdir: non-POSIX variable name Makefile.am:41: (probably a GNU make extension)
La última versión de COMEDI probada (0.7.76) tiene un error en el código fuente de el driver nocheque. Pero tira p'alante.
Información sobre COMEDI
Información sobre el puerto paralelo del PC