Capitulo III. Pantalla LCD Hitachi 44780. Si bien para visualizar datos los dígitos de siete segmentos son muy usados y útiles las pantallas LCD como la clásica Hitachi 44780 que brinda una solución elegante y de bajo costo. Básicamente podemos imaginar una pantalla LCD como una memoria de 40 caracteres de los cuales solo 16 son visibles (pantallas 16x2). Estas pantallas se pueden manejar en 8 o 4 bit's. En este manual usaremos el enfoque de 4 bit's ya que esta modalidad nos libera mas pines en el puerto de la Raspberry PI. El manejo de un LCD, no es nada del otro mundo si comprendemos la arquitectura de un modulo LCD. Los módulos LCD, llevan integrado a sus circuitos, 3 regiones de memorias que serán la base fundamental para el funcionamiento del modulo. Por un lado, tenemos dos regiones donde se albergan datos temporales con características RAM. Estas dos regiones, son las llamadas CGRAM y DDRAM, que son en si los espacios donde se almacenan los datos que se van a mostrar en pantalla. La diferencia entre una y otra, es que la CGRAM (Character Generator RAM), nos permite definir y Electrónica Digital con RaspberryPI Pagina 54 de 81 alojar 8 nuevos caracteres personalizados. En la CGRAM, es donde se alojan los caracteres creados por el usuario con matrices personalizadas, y la DDRAM (Data Display RAM), es un espacio temporal donde se almacenan los caracteres que se van a mostrar en pantalla. La DDRAM, tiene una capacidad de 80 bytes, 40 por cada línea, de los cuales sólo 32 se pueden visualizar a la vez (16 bytes por línea). Las dos direcciones más importantes de la DDRAM son: • Dirección 0x00, que es el comienzo de la primera línea. • Dirección 0x40, que es el comienzo de la segunda línea. Por otro lado, tenemos un espacio de memoria interna no volátil del tipo ROM, llamada CGROM (Character Generator ROM), que es donde se almacena una tabla con los 192 caracteres que pueden ser visualizados (ver el siguiente cuadro). Cada uno de los caracteres tiene su representación binaria de 8 bits. Para visualizar un carácter debe recibir por el bus de datos el código correspondiente. El módulo LCD además de tener definidos todo el conjunto de caracteres ASCII, permite al usuario definir 4 u 8 caracteres gráficos. La composición de estos caracteres se va guardando en una memoria llamada CGRAM con capacidad Electrónica Digital con RaspberryPI Pagina 55 de 81 para 64 bytes. Cada carácter gráfico definido por el usuario se compone de 16 u 8 bytes que se almacenan en sucesivas posiciones de la CGRAM. Se debe establecer la dirección en la memoria CGRAM a partir de la cual se irán almacenando los bytes que definen un carácter gráfico. Para la creación de caracteres gráficos hagamos un poco de memoria. Cuando enviamos el código de un carácter alfanumérico a la DDRAM del LCD, su chip interno buscará en la CGROM el patrón correspondiente y luego lo visualizará en la pantalla. Así se escriben todos los textos. Ahora bien, si el código enviado vale entre 0x00 y 0x07 (o 0x08 y 0x0F), el chip interno buscará su patrón de visualización en la CGRAM. Siendo ésta una RAM de lectura/escritura, podemos programar en ella los diseños que se nos ocurran. La CGRAM (Character Generator RAM) consta de 64 bytes en los que se pueden escribir los patrones de 8 nuevos caracteres de 5×7 puntos ó 4 caracteres de 5×10 puntos. Cuando los caracteres son de 5×7 puntos los 64 bytes se dividen en 8 bloques de 8 bytes cada uno, y cada bloque almacena el patrón de un nuevo carácter. El esquema mostrado arriba indica que: • El primer bloque de CGRAM, con direcciones desde 0b00000000 hasta 0b00000111, corresponde al código 0x00 (ó 0x80) de la DDRAM. • El segundo bloque CGRAM, con direcciones desde 0b00001000 hasta 0b00001111, corresponde al código 0x01 (ó 0x88) de la DDRAM; y así sucesivamente. Por ejemplo, la figura de arriba indica que se han rellenado los dos primeros bloques con los Electrónica Digital con RaspberryPI Pagina 56 de 81 patrones de dos pacmans. Hasta ahí solo se han creado dos nuevos caracteres. Para mostrarlos en el LCD habría que escribir un código con las funciones adecuadas para esto. Es importante dejar claro que los caracteres creados por el usuario se contienen en RAM por lo tanto cuando el LCD pierda su alimentación el carácter se perderá, esto implica que el código dentro del controlador debe contemplar la creación del carácter cada vez que el LCD arranque consumiendo en esto memoria de programa. Para el manejo de estas pantallas contamos con una librería que trabaja conjuntamente con WiringPi y siempre antes de usar comando para el LCD se debe haber ejecutado la función wiringPiSetup() y luego la función lcdInit(2, 16, 4, RS, EN, D0, D1, D2, D3, D0, D1, D2, D3); Donde 2 es la cantidad de líneas, 16 los caracteres visibles y el resto son los pines de acuerdo a la definición. const int RS = 3; const int EN = 14; const int D0 = 4; const int D1 = 12; const int D2 = 13; const int D3 = 6; GPIO_3 GPIO_14 GPIO_4 GPIO_12 GPIO_13 GPIO_6 Pines usados por el LCD. La función lcdPosition(lcdFD,0,1) indica donde estará l cursor, en este caso primera columna de la segunda fila (primer casillero-caracter de la segunda línea). La librería para el manejo de la pantalla consiste en dos archivos lcd.c y lcd.h que siempre estarán formando parte de los proyectos en que usemos la pantalla LCD. Distribución de pines en la pantalla Hitachi 44780. El pin R / W (pin 5) en la pantalla LCD debe estar conectado a 0V (GND), esto es muy importante si utiliza una pantalla de 5V, si conecta este pin a Raspberry destruirá el puerto. Esto es porque la pantalla intentará escribir en la Raspberry enviando niveles lógicos de 5V a un puerto que solo admite 3V. Veamos un pequeño código en C que verifica el funcionamiento de la pantalla. #include #include #include #include #include #include <stdio.h> <stdlib.h> <stdint.h> <unistd.h> <string.h> <wiringPi.h> Electrónica Digital con RaspberryPI Pagina 57 de 81 #include "lcd.h" #include <errno.h> const const const const const const int int int int int int RS EN D0 D1 D2 D3 = = = = = = 3; 14; 4; 12; 13; 6; int main(){ if (wiringPiSetup() < 0){ fprintf (stderr, "No puedo configurar el dispositivo %s\n", strerror (errno)) ; return 1 ; } int lcdFD; lcdFD = lcdInit(2, 16, 4, RS, EN, D0, D1, D2, D3, D0, D1, D2, D3); lcdPosition(lcdFD,2 ,0); lcdPrintf(lcdFD,"RaspBerry PI"); lcdPosition(lcdFD,0,1); lcdPrintf(lcdFD, "Firtec Argentina"); return 0; } Conversión Analógica Digital. En muchos proyectos tenemos que tratar con las señales o información del mundo analógico, como la temperatura, presión, corriente, etc . Estas señales son analógicas de forma predeterminada y en la mayoría de los casos se utilizan sensores que convierten estas señales a analógico de tensión eléctrica que será presentada en un pin del microcontrolador para hacer algún trabajo. Por desgracia, los microcontroladores son digitales y no pueden hacer frente a las señales analógicas por lo que estas señales deben ser convertidas en señales digitales que sean comprensibles por el núcleo del microcontrolador. Para este propósito, los fabricantes de microcontroladores suelen incorporar estos módulos en los microcontroladores sin embargo los chips Broadcom de Raspberry no lo tienen por lo que será necesario conectarlos como periféricos y vincularlos a Raspberry a través de un bus o línea de comunicaciones. Básicamente digitalizar algo es simplemente convertirlo a una secuencia de números de tal forma que si hacemos el proceso inverso de leer esos números podemos reconstruir la información original. Electrónica Digital con RaspberryPI Pagina 58 de 81 El valor analógico a digitalizar puede ser cualquiera pero los números que se puede tratar en el conversor tienen valores finitos que dependen de la precisión del conversor A/D. La operación de digitalización nos devuelve una secuencia de números que si usamos un convertidor de 12 bits serian entre 0 y 4095. En la mayoría de los conversores analógico-digitales hay dos operaciones se cumplen de forma separada. Sample y Hold convierte la señal en una señal que sigue siendo analógica, pero tiene valores sólo en instantes de tiempo discretos (muestreo y retención ). El ADC convierte la serie de muestras en números (conversor analógico a digital ). Electrónica Digital con RaspberryPI Pagina 59 de 81 Conversor A/D MCP3201. Como ejemplo vamos a implementar el conversor analógico digital MCP3201 fabricado por la empresa Microchip. Este conversor tiene una resolución de 12 bits pudiendo generar 4096 números por cada medición. Puede ser alimentado de 2.7 a 5V por lo que cubre perfectamente el rango de voltajes que nos interesa (3V) para Raspberry. El MCP3201 cuenta con un registro de aproximación sucesiva (SAR) y una interface serial SPI, lo que permite la capacidad de añadir un ADC de 12bits a cualquier Microcontrolador que implemente el protocolo de comunicaciones SPI. Algunas características del MCP3201 son la capacidad de tomar 100k muestras/segundos, posee un canal de entrada, muy bajo consumo de energía (5nA en standby, 400uA máximo en estado activo) y esta disponible en encapsulado de 8 pines PDIP, SOIC y TSSOP. Algunas de las aplicaciones donde puede incluirse el MCP3201 son adquisición de datos, instrumentos de medición, procesadores de datos, mediciones industriales, control de motores, robótica, automatismos industriales, pequeños sensores para instrumentación portátil y aplicaciones de medicina. Protocolo de comunicaciones SPI. El SPI es un protocolo de comunicación sincrónica de 4 cables. Desarrollado por Motorola en 1982 y con gran aceptación en la industria como sistema de comunicación de muy corta distancia, normalmente dentro la placa de circuito impreso vinculando distintos chips. Es un protocolo de transmisión que permite alcanzar velocidades muy altas y que se diseñó pensando en comunicar un microcontrolador con distintos periféricos y que funciona a full dúplex (Una forma retorcida de decir que puede enviar y recibir datos al mismo tiempo). SPI utiliza una solución síncrona, porque utiliza unas líneas diferentes para los datos y el reloj. El reloj (Clock) es una señal que indica al que escucha exactamente cuándo leer las líneas de datos, con lo que el problema de perdida de sincronía se elimina de raíz. Electrónica Digital con RaspberryPI Pagina 60 de 81 Por eso mismo, no se necesita pactar la velocidad de transmisión, ya que será el Clock quien fije la velocidad y puede ser variable a lo largo de la comunicación sin que sea un problema (Aunque por supuesto según el dispositivo habrá un límite de velocidad). Uno de los motivos por los que SPI es tan popular es que el hardware de recepción puede ser sencillo lo que es una solución mucho más simple que una UART que trataremos en el siguiente capítulo. En un bus SPI una de las partes genera el Clock al que llamamos master, (en nuestro caso raspberry es master) y el resto son los esclavos, pudiendo haber uno o varios en el bus. A la señal de reloj se le suele llamar CLK por Clock o SCK por Serial Clock. Cuando el master envía información, lo hace por una línea de datos normalmente de nombre MOSI (Master Out Slave In) y si el esclavo responde lo hace a través de una línea llamada MISO (Master In Slave Out). Como es el master quien genera el Clock, necesita saber de antemano, si un esclavo va a devolver una respuesta y de que longitud, para mantener el Clock hasta que la transferencia esté completa. Hay una última línea de control, llamada Slave Select o SS, que indica a un esclavo que el mensaje que viene es para él, o bien que se reclama que envié una respuesta a una petición del master. Electrónica Digital con RaspberryPI Pagina 61 de 81 La línea SS normalmente se mantiene alta y se activa con nivel bajo, lo que “despierta” al esclavo seleccionado. Cuando se termina la transferencia la línea es puesta a nivel alto y el esclavo se desactiva. Hay dos maneras de conectar múltiples esclavos a un bus SPI. Con una línea SS por cada esclavo o en cascada. En general cada esclavo requiere su propia línea SS para ser activado, y así evitar que dos hablen a la vez, porque el resultado sería ruido inútil. Basta con activar la línea correspondiente y el esclavo esta listo para recibir sus órdenes. Cuando el número de esclavos crece suele ser más frecuente conectarlos en cascada, con el MISO de uno (Salida), conectado al MOSI (Entrada) del siguiente. En este caso solo usamos una única línea SS, que se comparte entre todos los esclavos. Esta configuración es típica de una situación en la que le master envía datos pero no recibe nada de vuelta, como en el caso de una cadena de múltiples display LEDs ( Matrices de 8×8) , en los que se envía información para ser mostrada pero, no hay datos de retorno. Electrónica Digital con RaspberryPI Pagina 62 de 81 En este caso incluso podemos desconectar la línea MISO. En la placa Raspberry el periférico SPI no está activada de forma predeterminada. Para habilitarlo, haga lo siguiente. En la configuración de nuestra Raspberry, en la lengüeta interfaces debemos activar los puertos que nos interesan, reiniciamos el sistema. Luego desde la consola verificamos que los dos puertos SPI están activos escribiendo: ls /dev/*spi* Lo que debería responder: /dev/spidev0.0 Electrónica Digital con RaspberryPI /dev/spidev0.1 Pagina 63 de 81 Conectando el conversor MCP3201 a Raspberry. Una vez que tenemos todo preparado a nivel de protocolo SPI podemos pasar al hardware para obtener un resultado como el que se ve en la siguiente captura. Usaremos el siguiente conexionado para medir las variaciones de voltaje en el punto medio del potenciómetro de 10K. El siguiente es el programa para verificar el funcionamiento del puerto SPI con el conversor analógico digital MCP3201, Raspberry tiene dos puertos SPI, estamos usando el puerto 0. #include #include #include #include #include #include <stdio.h> <stdlib.h> <stdint.h> <unistd.h> <string.h> <wiringPi.h> Electrónica Digital con RaspberryPI Pagina 64 de 81 #include <wiringPiSPI.h> #include "lcd.h" #include <errno.h> void MCP3201(void); const const const const const const int int int int int int RS EN D0 D1 D2 D3 = = = = = = // Se informa que se creara una función llamada MCP3201. 3; 11; 4; 5; 6; 7; char buf [14]; int ce = 0; unsigned char ByteSPI[2]; unsigned char low; unsigned char hi; unsigned short int dato; unsigned int M0; unsigned char muestras =0; double Va; int lcdFD; int main(){ if (wiringPiSetup() < 0){ fprintf (stderr, "No puedo configurar wiringPI!! %s\n", strerror (errno)) ; return 1 ; } printf ("Conversor MCP3201\n") ; printf ("www.firtec.com.ar\n") ; if (wiringPiSPISetup (0, 100000) < 0) // Conexión a 1 MHz sobre SPI 0 { fprintf (stderr, "Error en dispositivo SPI 0: %s\n", strerror (errno)) ; exit (1) ; } lcdFD = lcdInit(2, 16, 4, RS, EN, D0, D1, D2, D3, D0, D1, D2, D3); lcdPosition(lcdFD, 0,0); lcdPrintf(lcdFD, "Conversor MCP3201"); while(1){ MCP3201(); // Función para leer el conversor. } return 0; } void MCP3201(void){ wiringPiSPIDataRW (0, ByteSPI, usleep(100); hi = (ByteSPI[0] & 0x1F); low = (ByteSPI[1] & 0xFe); dato = (hi << 8) | low; M0 += dato; 2); // Lee dos Byte // Espera 100 uS. // Salva la parte alta del byte. // Salva la parte baja del byte. // Alinea los bytes y los une en dato // Acumula en M0 16 mediciones. if (15 == muestras++){ // Ya se hicieron 16 mediciones? dato = M0/16; M0 =0; // Borra las variables para la siguiente medición. muestras =0; Va = (double) (dato) * 3.3 / 8192.0; // Escala el dato a voltios. sprintf (buf, "Voltios:%3.3f",Va); // Convierte el dato a valores ASCII. Electrónica Digital con RaspberryPI Pagina 65 de 81 lcdPosition(lcdFD,0,1); lcdPuts(0, buf); // Coloca el cursor en posición. // Muestra el voltaje. } } Escritorios remotos. Todo lo visto supone que usted tiene conectado a su Raspberry un monitor y un teclado lo cual está perfecto pero esto no es absolutamente necesario para usar Raspberry siendo que puede manejar todo desde su computadora conectada a la red y a través de escritorios virtuales. Para poder responder a las conexiones entrantes todo lo que hemos de hacer es instalar el paquete xrdp en nuestra Raspberry, primero ejecutamos el comando de actualización. sudo apt-get update y, a continuación, lanzamos la instalación del servidor de escritorios virtuales. sudo apt-get install xrdp Una vez instalado podemos conectarnos con cualquier cliente para escritorios remotos. El imagen siguiente se aprecia una computadora con GNU Linux Debian corriendo el cliente de escritorios remotos para KDE denominado KRDC. Observe podemos ver el mismo escritorio que vemos en el monitor conectado a Raspberry y ejecutar los mismos programas tal cual como si estuviéramos trabajando físicamente sobre nuestra placa Raspberry. Todo esto lo podemos hacer a través de nuestra red Wi-Fi sin necesidad incluso que la placa Raspberri se encuentra físicamente en el mismo lugar donde estamos trabajando. Desde el sistema Windows es lo mismo con la facilidad agregada que Windows ya trae un cliente Electrónica Digital con RaspberryPI Pagina 66 de 81 para escritorios virtuales por defecto solo debemos llamar a la aplicación y colocar la dir IP de nuestra placa Raspberry, podemos averiguarlo ejecutando. sudo ifconfig -a Ponemos el usuario (por defecto pi) y la clave que hayamos definido para nuestra Raspberry. Una vez cumplido estos pasos podemos conectarnos a nuestra Raspberry por la red Wi-Fi. Windows 7 mostrando el escritorio de Raspberry. Un detalle a tener presente es que siempre la conexión por escritorio remoto será un tanto mas lenta que si estamos vinculados físicamente a nuestra Raspberry. También nos puede ser muy útil instalar un servidor FTP para transferir archivos hacia y desde nuestra Raspberry por la misma red Wi-Fi. Para instalar el servidor en nuestra Raspberry escribimos en la terminal. sudo apt-get install vsftpd Luego que el programa se instala vamos a configuración para indicar que siempre lo queremos Electrónica Digital con RaspberryPI Pagina 67 de 81 activo, para esto escribimos en a terminal. sudo nano /etc/vsftpd.conf Y realizamos las siguientes reformas. Editando o descomentando las siguientes líneas Anonymous_enable = NO Local_enable = SI Write_enable = SI Ascii_upload_enable = SI Ascii_download_enable = SI Salvamos el archivo y reiniciamos el servicio con sudo /etc / init.d / vsftpd restart. Luego con cualquier cliente FTP podemos conectarnos a nuestra Raspberry para transferir archivos. El FileZilla es una buena opción, siendo muy simple de utilizar solo requiere que indiquemos la dir IP del servidor (IP de nuestra RaspBerry) el usuario (generalmente pi) y la clave de acceso de nuestra placa Raspberry. (El número de puerto lo podemos dejar libre FileZilla lo configura por defecto). Electrónica Digital con RaspberryPI Pagina 68 de 81 Sensor Analógico LM35 El LM35 es un sensor de temperatura con una precisión calibrada de 1ºC. Su rango de medición abarca desde -55°C hasta 150°C. La salida es lineal y cada grado Celsius equivale a 10mV. Por lo tanto las mediciones serian 1500 milivoltios equivalen a 150 ºC y -550 milivoltios serán -55 ºC . Sus características más relevantes son: • Está calibrado directamente en grados Celsius. • La tensión de salida es proporcional a la temperatura. • Tiene una precisión garantizada de 0.5 °C a 25 °C. • Baja impedancia de salida. • Baja corriente de alimentación (60 μA). • Bajo coste. El LM35 no requiere de circuitos adicionales para calibrarlo externamente. La baja impedancia de salida, su salida lineal y su precisa calibración hace posible que este integrado sea instalado fácilmente en un circuito de control. Debido a su baja corriente de alimentación se produce un efecto de auto calentamiento muy reducido. Se encuentra en diferentes tipos de encapsulado, el más común es el TO62 utilizada por transistores de baja potencia. La salida del sensor de temperatura se conecta a la entrada del conversor analógico. El mismo circuito que usamos con el potenciómetro cambiando el potenciómetro por el sensor de temperatura. Si bien se puede conectar el sensor a 3V la hoja de datos indica que su funcionamiento correcto se obtiene con un voltaje de alimentación mínimo de 4V. Para verificar su funcionamiento vamos a escribir el siguiente programa en C (también lo encontrará en las carpetas de ejemplos del curso). Debe prestar especial cuidado al conectar el sensor, invertir alguna conexión dañará el LM35. Electrónica Digital con RaspberryPI Pagina 69 de 81 Programa para el LM35. #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <string.h> #include <wiringPi.h> #include <wiringPiSPI.h> #include "lcd.h" #include <errno.h> void MCP3201(void); const int RS = 3; const int EN = 11; const int D0 = 0; const int D1 = 5; const int D2 = 6; const int D3 = 7; char buf [14]; int ce = 0; unsigned char ByteSPI[2]; unsigned char low; unsigned char hi; unsigned short int dato; unsigned int M0; unsigned char muestras =0; double Va, temperatura; int lcdFD; int main(){ if (wiringPiSetup() < 0){ fprintf (stderr, "No puedo configurar el dispositivo %s\n", strerror (errno)) ; return 1 ; } printf ("Probando el conversor MCP3201 y LM35\n") ; printf ("www.firtec.com.ar\n") ; if (wiringPiSPISetup (0, 100000) < 0){ fprintf (stderr, "ERROR en SPI 0: %s\n", strerror (errno)) ; } exit (1) ; Electrónica Digital con RaspberryPI Pagina 70 de 81 lcdFD = lcdInit(2, 16, 4, RS, EN, D0, D1, D2, D3, D0, D1, D2, D3); lcdPosition(lcdFD, 1,0); lcdPrintf(lcdFD, "MCP3201 & LM35"); while(1){ MCP3201(); } return 0; } void MCP3201(void){ wiringPiSPIDataRW (0, ByteSPI, 2); usleep(100); hi = (ByteSPI[0] & 0x1F); low = (ByteSPI[1] & 0xFe); dato = (hi << 8) | low; M0 += dato; if (15 == muestras++){ dato = M0/16; M0 =0; muestras =0; Va = (double) (dato) * 3.3 / 8192.0; temperatura = Va / (10.0 / 1000); sprintf (buf, "Temp:%2.1f",temperatura); lcdPosition(lcdFD,0,1); lcdPuts(0, buf); } } Sensor 1-Wire DS18B20 El sensor de temperatura DS18B20 es un dispositivo que se comunica de forma digital. Cuenta con tres terminales, los dos de alimentación y el pin de datos. Con Raspberry podemos “leer” la temperatura que registra este sensor que posee una característica muy peculiar. Utiliza la comunicación OneWire, la cual es un poco complicada para los que no tienen mucha experiencia en el área de electrónica digital. Básicamente se trata de un protocolo especial que permite enviar y recibir datos utilizando un solo cable, a diferencia de la mayoría de los protocolos que requiere dos vías. De hecho, Raspberry posee pines RX y TX que son los encargados de enviar y recibir información mediante la UART. Para muchas personas que intenten aprender a utilizar el sensor DS18B20 probablemente sea un poco difícil encontrar información precisa y concisa, debido a que se habla mucho de este protocolo de comunicación de un solo cable y los códigos de ejemplo normalmente complejos tratando de explicar al usuario una serie de conceptos que para nuestros propósitos no tienen relevancia. El sensor DS18B20 es un termómetro digital de alta precisión, entre 9 y 12 bits de temperatura en Electrónica Digital con RaspberryPI Pagina 71 de 81 grados Celsius (el usuario puede escoger la precisión deseada). Su temperatura operativa se encuentra entre -50 y 125 grados Celsius. La precisión, en el rango comprendido entre -10 y 85 grados es de ±0.5 grados. Su precio es económico, su interfaz de funcionamiento es sencilla y su uso es muy provechoso para proyectos que requieran mediciones precisas y confiables. Una particularidad interesante de estos sensores es que poseen un número ID, algo así como un número MAC único grabado por el fabricante en cada sensor lo que posibilita tener muchos sensores y direccionarlos por su ID para conocer la temperatura en ese punto en particular. Podemos ver en el siguiente diagrama la forma de conectar tres sensores (o mas) al pin GPIO-4 de Raspberry. El protocolo 1-Wire exige una resistencia de 4,7K colocada entre el pin de datos y 3,3V, recuerde estos sensores son en realidad un microcontrolador completo con un puerto de comunicaciones y claro un sensor de temperatura pero su electrónica interna es verdaderamente compleja a pesar de su aspecto simple. Recuerde, parecen un transistor pero no lo son. Rspberry no trae un puerto de comunicaciones en este protocolo y para hacerlo funcionar deberemos seguir algunos pasos. Primero vamos a editar un de configuración para definir un pin para este protocolo,para esto escribimos en la terminal. sudo nano /boot/config.txt Y al final del archivo agregamos lo siguiente.(preste atención a no cometer un error en la sintaxis de lo que escribe). dtoverlay=w1-gpio,gpiopin=4 Luego reiniciamos la Raspberry y ejecutamos los siguientes pasos: Dentro del directorio /sys/bus/w1/devices se encontrarán dos capetas, uno de ellos tendrá como Electrónica Digital con RaspberryPI Pagina 72 de 81 nombre el ID del sensor. Si tiene varios sensores cada uno tendrá una carpeta con su ID. Siempre primero deberá editar el archivo config.txt de lo contrario no funcionará. Una vez que tenemos nuestros sensores ubicados podemos escribir un simple programa en C para verificar su funcionamiento. (El proyecto completo lo encontrará en las carpetas de ejemplos). Con este programa veremos la temperatura en la pantalla Hitachi44780 como se aprecia en la imagen siguiente. #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <string.h> #include <sys/fcntl.h> #include <time.h> #include <wiringPi.h> #include "lcd.h" #include <errno.h> const int RS = 3; const int EN = 11; const int D0 = 0; const int D1 = 1; Pines GPIO asignados a la pantalla LCD const int D2 = 2; const int D3 = 10; static int lcdHandle ; char buf [4] ; char temp [5]; int main(int argc, char *argv[]){ int fd = -1, ret; char *tmp1, tmp2[10], ch='t'; char devname_head[50] = "/sys/devices/w1_bus_master1/28-00000482b243"; char devname_end[10] = "/w1_slave"; char dev_name[100]; long value; Electrónica Digital con RaspberryPI ID del sensor conectado Pagina 73 de 81 int integer, decimal; char buffer[100]; printf ("Corriendo DS18B20 & LCD 16*2\n") ; printf ("www.firtec.com.ar\n") ; if (wiringPiSetup() < 0){ } fprintf (stderr, "No puedo configurar el dispositivo %s\n", strerror (errno)) ; return 1 ; pinMode (0, OUTPUT) ; digitalWrite (0, 0) ; strcpy(dev_name, devname_head); strcat(dev_name, devname_end); int lcdFD; lcdFD = lcdInit(2, 16, 4, RS, EN, D0, D1, D2, D3, D0, D1, D2, D3); lcdPosition(lcdFD, 0,0); lcdPosition(lcdFD,1,0); lcdPrintf(lcdFD, "Sensor DS18B20"); lcdPuts(0, buf); lcdPosition(lcdFD,1,1); lcdPrintf(lcdFD, "Temp: "); while(1){ if ((fd = open(dev_name, O_RDONLY)) < 0){ perror("Error abriendo archivo"); exit(1); } lcdPosition(lcdFD,6,1); ret = read(fd, buffer, sizeof(buffer)); if (ret < 0){ perror("Error de Lectura"); exit(1); } close(fd); tmp1 = strchr(buffer, ch); sscanf(tmp1, "t=%s", tmp2); value = atoi(tmp2); integer = value / 100; sprintf (buf, "%03d", integer) ; temp [0]= buf[0]; temp [1]= buf[1]; temp [2]= '.'; temp [3]= buf[2]; Electrónica Digital con RaspberryPI Pagina 74 de 81 lcdPuts(lcdHandle, temp); delay (50) ; } return 0; } Funcionamiento de la UART. En la actualidad y ante la ausencia de puertos RS232 en las computadoras, acostumbramos a trabajar con puentes USB-RS232 que solucionan muchos o todos los problemas a la hora de vincularnos con computadoras a través del viejo protocolo 232. Raspberry tiene un puerto UART que utiliza el GPIO_15 para transmitir (TX) y el GPIO_16 para recibir (RX). El controlador no resuelve la capa física, es decir que para implementar las comunicaciones deberemos utilizar ya sea el clásico MAX232 o los modernos puentes USB232. Esto es particularmente interesante porque con esta tecnología podemos reutilizar los viejos programas en puertos COM que por cuestiones de licencias o complejidad son mas simples de implementar que las aplicaciones USB nativas. Protocolo RS-232 El protocolo RS-232 es una norma o estándar mundial que rige los parámetros de uno de los modos de comunicación serial. Por medio de este protocolo se estandarizan las velocidades de transferencia de datos, la forma de control que utiliza dicha transferencia, los niveles de voltajes utilizados, el tipo de cable permitido, las distancias entre equipos, los conectores, etc. Además de las líneas de transmisión (Tx) y recepción (Rx), las comunicaciones seriales poseen otras líneas de control de flujo (Hands-hake), donde su uso es opcional dependiendo del dispositivo a conectar. A nivel de software, la configuración principal que se debe dar a una conexión a través de puertos seriales. RS-232 es básicamente la selección de la velocidad en baudios (1200, 2400, 4800, etc.), la verificación de datos o paridad (parida par o paridad impar o sin paridad), los bits de parada luego de cada dato(1 ó 2), y la cantidad de bits por dato (7 ó 8), que se utiliza para cada símbolo o carácter enviado. La Norma RS-232 fue definida para conectar un ordenador a un modem. Además de transmitirse los datos de una forma serie asíncrona son necesarias una serie de señales adicionales, que se definen en la norma. Las tensiones empleadas están comprendidas entre +15/-15 voltios para el puerto original en computadoras en el caso de Raspberry los niveles son de 3,3 Voltios. Electrónica Digital con RaspberryPI Pagina 75 de 81 Para una comunicación punto a punto a una distancia no superior a 15 metros es lo que indica la norma. Para visualizar los datos recibidos vamos a usar la aplicación terminal.exe que se encuentra entre las herramientas del curso. Dato recibido Dato enviado El ejemplo que vamos a ver recibe los datos enviados desde el teclado de una PC y los re-transmite como un eco por el mismo puerto serial. Observe que la velocidad en baudios debe ser la misma en programa receptor que en el emisor. Condición absolutamente necesaria para que una transmisión serial asincrónica funcione. Electrónica Digital con RaspberryPI Pagina 76 de 81 Un detalle importante para hacer funcionar la UART con nuestra electrónica es que tenemos primero que deshabilitar el serial desde las opciones de Raspberry. Esto es necesario porque Linux hace uso del puerto serial, supone que lo usaremos para transferencias seriales con el propio sistema Linux y si no sacamos esta condición nuestros programas que hacen uso del serial se verán afectados por el propio sistema operativo que es “propietario” de la UART. #include <stdio.h> #include <string.h> #include <errno.h> #include <wiringPi.h> #include <wiringSerial.h> Velocidad de comunicación en Baudios. Misma que la fijada en el programa Terminal.exe. int main () { int fd ; // Descriptor del puerto serial char dato; if ((fd = serialOpen ("/dev/ttyAMA0", 115200)) < 0){ fprintf (stderr, "ERROR al abrir el dispositivo: %s\n", strerror (errno)) ; return 1 ; } if (wiringPiSetup () == -1){ fprintf (stdout, "ERROR al iniciar wiringPi: %s\n", strerror (errno)) ; return 1 ; } for (;;){ while (serialDataAvail (fd)){ dato = serialGetchar (fd); // Lee el carácter y lo guarda en dato. serialPutchar (fd, dato) ; // Envía el carácter por el puerto UART. fflush (stdout) ; // Limpia buffer interno } } return 0 ; } El ejemplo que sigue incorpora varios de los puntos vistos como son, el protocolo SPI para Electrónica Digital con RaspberryPI Pagina 77 de 81 conectarnos a un conversor analógico digital, una pantalla LCD 16x2 y el puerto UART conectado a un software informático que representa un voltímetro virtual donde veremos el voltaje leído por el conversor al mismo tiempo que se muestra en la pantalla LCD. (Todo el proyecto como el software informático está en la carpeta de ejemplos). /******************************************************************************* * Ejemplo para UART + SPI + LCD con Raspberry PI. * Mide la diferencia de voltaje generado con un potenciómetro aplicado a un conversor A/D MCP3201. El voltaje se muestra en una pantalla LCD 16x2 y se envía por la UART para ser interpretado por un voltímetro virtual en la PC. * www.firtec.com.ar - [email protected] *******************************************************************************/ #include <stdio.h> #include <stdlib.h> #include <stdint.h> #include <unistd.h> #include <fcntl.h> #include <termios.h> #include <unistd.h> #include <string.h> #include <wiringPi.h> #include <wiringPiSPI.h> #include "lcd.h" #include <wiringSerial.h> #include <errno.h> // Función para el conversor A/D void MCP3201(void); // Pines de la pantalla LCD const int RS = 3; const int EN = 11; const int D0 = 0; const int D1 = 1; const int D2 = 2; const int D3 = 6; // Variables del programa char buf [14]; unsigned char TX_HI=0; unsigned char TX_Low=0; unsigned char bandera_medir =0; int ce = 0; Electrónica Digital con RaspberryPI Pagina 78 de 81 unsigned char ByteSPI[2]; unsigned char low; unsigned char hi; unsigned short int dato; unsigned int M0; unsigned char muestras =0; double Va; int lcdFD; Función Principal del Programa int main(){ int fd ; // Descriptor del puerto serial if ((fd = serialOpen ("/dev/ttyAMA0", 9600)) < 0) { fprintf (stderr, "ERROR al abrir el dispositivo: %s\n", strerror (errno)) ; return 1 ; } if (wiringPiSetup() < 0) { fprintf (stderr, "No puedo configurar el dispositivo %s\n", strerror (errno)) ; return 1 ; } printf ("Probando el conversor MCP3201\n") ; printf ("www.firtec.com.ar\n") ; if (wiringPiSPISetup (0, 100000) < 0)//Conexion SPI a 1 MHz { fprintf (stderr, "Unable to open SPI device 0: %s\n", strerror (errno)) ; exit (1) ; } lcdFD = lcdInit(2, 16, 4, RS, EN, D0, D1, D2, D3, D0, D1, D2, D3); lcdPosition(lcdFD, 0,0); lcdPrintf(lcdFD, "Conv A/D MCP3201"); Bucle Principal del Programa while(1){ unsigned char dato_rx = 0; if(!(bandera_medir)) MCP3201(); // Se pueden tomar nuevos datos? // Obtiene nuevos datos desde el conversor while (serialDataAvail (fd)) Electrónica Digital con RaspberryPI Pagina 79 de 81 { if(serialDataAvail (fd) != 0){ // Algún dato para leer? dato_rx = serialGetchar (fd); // Obtiene el caracter recibido por la UART fflush (stdout) ; if(dato_rx == 0xFD) bandera_medir = 0; // Boton Conectar/Desconectar envía órden para // asegurar que no se bloquee el conversor. if(dato_rx == 0xFE){ // Soft-PC pide parte baja del dato. serialPutchar (fd, TX_Low) ; bandera_medir = 1; // No medir mientras se pasan los bytes. } if(dato_rx == 0xFF){ // Soft-PC pide parte alta del byte. serialPutchar (fd, TX_HI) ; bandera_medir = 0; // Permite medir nuevamente. } fflush (stdout) ; // Limpio registros } } } return 0; } Función para Leer el Conversor void MCP3201(void){ wiringPiSPIDataRW (0, ByteSPI, 2); usleep(100); hi = (ByteSPI[0] & 0x1F); low = (ByteSPI[1] & 0xFe); dato = (hi << 8) | low; M0 += dato; if (15 == muestras++){ dato = M0/16; M0 =0; muestras =0; TX_HI = dato/256; TX_Low = dato - (TX_HI * 256); Va = (double) (dato) * 3.3 / 8192.0; sprintf (buf, "Voltios:%3.2f",Va); lcdPosition(lcdFD,0,1); Electrónica Digital con RaspberryPI Pagina 80 de 81 lcdPuts(0, buf); } } /************ Fin de programa *************************************************/ En el próximo capitulo veremos como agregar a nuestra Raspberry un calendario y el manejo de otro protocolo importante en electrónica, el I2C y el manejo de datos por RF (Radio Frecuencia) muy útil a la hora de enviar y recibir información como teclados remotos, sensores de presencia, etc evitando tener que pasar cables con toda la incomodidad que esto presenta. También veremos el diseño de un sistema de seguridad con ingreso codificado y monitoreo por mail y video. Electrónica Digital con RaspberryPI Pagina 81 de 81