#! /usr/bin/python # -*- coding: utf-8 -*import RPi.GPIO as GPIO import time import LCDLIB16x2 as LCD GPIO.setmode(GPIO.BCM) Manejo del puerto SPI import spidev spi = spidev.SpiDev() spi.open(0, 0) LCD.lcd_init() LCD.lcd_string(" MCP3201 & PI",LCD.LINE_1) Función que maneja el hardware del conversor. def Conversor(): M0 =0 muestras =0 while muestras <= 15: adc = spi.xfer2([0, 0]) hi = (adc[0] & 0x1F) low = (adc[1] & 0xFe) dato = (hi << 8) | low M0 += dato muestras += 1 dato = M0 / 16 Va = (long) (dato) * 3.3 / 8192.0 LCD.lcd_string("Voltios:%.2f" % Va, LCD.LINE_2) while True: try: Conversor() Este trozo de código llama a la función que mide y permite una salida prolija del programa cerrando el puerto SPI except (KeyboardInterrupt, SystemExit): spi.close() GPIO.cleanup() raise Un comentario especial merece la línea que da formato a la presentación en la pantalla. LCD.lcd_string("Voltios:%.2f" % Va, LCD.LINE_2) Esto mostrará la variable Va en un formato float con dos decimales (%.2f ) en la segunda línea de la pantalla LCD.LINE_2, la palabra Voltios: aparecerá junto y antes de la variable a mostrar. Electrónica Digital con RaspberryPI Pagina 58 de 83 Conversor MCP3008 y sensor MCP9700. El conversor MCP3008 es un conversor de 10 bits, se controla también mediante SPI, como ya se dijo, es un protocolo de uso común en el mundo de la electrónica y microcontroladores. El manejo de este conversor es un poco mas complejo que el anterior en función que este tiene ocho canales, ocho fuentes de datos analógicos que podemos medir con una resolución de diez bits. Si bien no podemos medir los ocho canales en “tiempo real” ya que el modulo que mide es uno con ocho llaves conmutables mediante software a ocho pines diferentes, sin embargo como la medición es tan rápida, a escala humana parecería que los ocho canales están disponibles al mismo tiempo. Para este conversor usaremos el puerto SPI completo, todos sus pines de control estarán afectados al manejo de este conversor, siendo el el pin chip-set (CS) el encargado de habilitar o no el chip. Recuerde que la placa tiene dos puertos sin embargo ambos comparten los pines de control (CLK, MOSI, MISO) siendo la habilitación de chip (CS) independiente. Esto dice que si bien podemos tener dos dispositivos SPI en distinto puerto y controlarlos mediante el Chip-Set, solo podemos usar uno a la vez ya que comparten los pines de control. El protocolo en si mismo no es muy complejo, sin embargo la capa de software provista por Python y su librería nos ahorra todo el problema de lidiar con ventanas de tiempo y control de bits. La función encargada de la comunicación con el MCP3008 es: adc = spi.xfer2([1,(8+channel)<<4,0]) spi.xfer2() envía tres bytes y retornan también tres bytes. El primer byte enviado es siempre 1, es el bit de inicio, el segundo byte es la configuración del chip de acuerdo a su hoja de datos podemos ver la tabla 5-2. (ver imagen) Donde Single/Diff son los dos modos en que este conversor puede trabajar, simple o diferencial. Nos interesa el modo simple, luego vemos D0, D1, D2, con tres bits podemos hacer 8 combinaciones de 000 a 111 que corresponde a los 8 canales del conversor. Con esos tres bits elegimos el canal. (8+channel) Ocho es la selección del modo “simple” mas el canal que leemos, corremos todo cuatro lugares para ordenar los datos como el chip espera recibirlos <<4 , el tercer byte no importa y es siempre cero. Los datos leídos llegan a nuestra placa por el pin MISO bit a bit a bit al ritmo de los pulsos de reloj que salen por CLK. Los datos recibidos se guardan en adc que es una cadena de tres bytes. Son enviados por el conversor en formato LittleEndian lo que hace la decodificación un tanto engorrosa. La función encargada de la interpretación del dato es: dato = ((adc [1] & 3) << 8) + adc[2] Recordemos que el conversor tiene 10 bits por lo que pude generar datos comprendidos entre 0 y 1023. El dato mas alto será 0x3FF o lo que es igual al binario xxxxxx11 1111 1111 Electrónica Digital con RaspberryPI Pagina 59 de 83 Mirando la hoja de datos vemos la forma en que nos llegan los tres bytes enviados por el conversor El byte cero no tiene información de utilidad, el byte uno contiene los dos bits mas significativos del dato y el byte dos los ocho bits de la parte baja del dato. Recuerde el conversor es de 10 bits. Aquí ((adc [1] & 3) << 8) se toma el elemento 1 del la cadena de tres bytes contenida en adc[] y se aplica una máscara and con el número 3 para cortar los dos primeros bits, desplaza 8 lugares a la izquierda para dejar lugar a los ocho bits de la parte baja de la medición + adc[2] que están en el vector dos de la cadena de tres bytes. Para seleccionar dos de los ocho canales posibles podemos usar una función como se ve a continucación. def Canal_Selec(): canal = 0 global V1 V1 = Lee_Canal(canal) canal += 1 global V2 V2 = Lee_Canal(canal) Se lee en el canal 0 La variable V1 será global para leerla desde cualquier lugar En V1 se guarda lo que se lee en el canal Se incrementa el canal para medir en el canal 1 Variable V2 es global, visible desde cualquier parte del programa Lee el dato del conversor y lo amacena en la variable V2 Las variables V1 y V2 son las encargadas de recibir el dato de los canales, podríamos leer desde el cana 0 al 7 sin embargo solo nos interesan los canales de 0 y 1.Los canales se encuentran ordenados desde el pin 1 al 8, el pin 16 y 15 se conectan a +3.3 V. El pin 9 y 14 se conectan a masa (GND), los pines de comunicaciones SPI se conectan de la siguiente forma. CLK GPIO 11 Din GPIO 10 Dout GPIO 9 CS/SHDN GPIO 8 Electrónica Digital con RaspberryPI Pagina 60 de 83 Suponiendo que estamos usando Raspberry PI mdelo B+, si tenemos otro modelo solo debemos buscar los pines equivalentes. Para “armar” el dato tal cual lo veremos en la pantalla usaremos la siguiente línea de código. LCD.lcd_string("A0:%.2f A1:%.2f" % (V1, V2), LCD.LINE_2) Vemos los caracteres de formato %.2f aplicados a las variables V1 y V2, datos que se mostraran en la segunda línea de la pantalla. Sensor MCP9700. En nuestro ejemplo vamos a usar dos sensores fabricados por Microchip, los MCP9700, estos sensores son analógicos similares al clásico LM35. Básicamente el sensor envía un voltaje que es proporcional a la temperatura a la que esta sometida su cubierta plástica. El sensor envía 10mV por cada grado de temperatura, debemos saber que enviará 500 mV cuando el sensor esté a cero grados, es decir que a cero grados el sensor ya envía ½ voltio que debemos eliminar por software. (Este trabajo solo lee grados positivos, no se utilizan voltajes de referencia exteriores ni masas virtuales) Cuando se lea el conversor analógico debemos ajustar la lectura para una escala en grados centígrados, en las líneas siguiente podemos ver el trozo de código que lee la información desde el conversor y la escala a grados centígrados. def Lee_Canal(channel): adc = spi.xfer2([1,(8+channel)<<4,0]) dato = ((adc [1] & 3) << 8) + adc[2] temp = dato – 0.5 Se quitan los 500mV del “efecto cero grado” temp = temp / float(10) Se ajusta la resolución a 10mV por grado return temp El sensor al ser analógico está sujeto a ruidos e interferencias eléctricas del medio ambiente para su correcto funcionamiento es recomendable armar el siguiente circuito de conexión. La resistencia de 2K podemos no conectarla pero es indispensable que el filtro compuesto por la resistencia de 100 Ohms y el condensador de 100 nF (0,1 uF) estén presentes. Los dos sensores se conectan de la misma forma y se vincula su salida (marcada como 3) a cada uno de los canales que usaremos en el conversor MCP3008, pines 1 y 2. Electrónica Digital con RaspberryPI Pagina 61 de 83 Observe que hay un condensador de 100 nF junto al MCP3008 colocado entre los pines (+) y (–) de alimentación. El resultado final de la lectura de temperatura es como se aprecia en la siguiente imagen. Siempre que usamos circuitos integrados debemos colocar un condensador de 100 nF entre los pines de alimentación para desacoplar la fuente de energía y siempre cerca del propio chip y uno por cada integrado que estemos usando. Recuerde que a medida que agrega electrónica a su Raspberry agrega carga a su puerto USB, si alimenta todo desde la propia computadora, algo no aconsejable cuando trabajamos con electrónica experimental y poca experiencia en el manejo de hardware, recuerde, si algo sale mal nuestra computadora está conectada en la otra punta del cable. En nuestro caso hemos adaptado una fuente de alimentación de un viejo modem en desuso que proporciona +5 Voltios mismos que el USB. De esta forma preservamos el puerto USB de posibles errores de conexión que podrían terminar en la destrucción del puerto. El código completo que maneja los sensores de temperatura se puede ver a continuación, también está disponible en el material de curso. Este ejemplo solo lee grados sobre cero, si buscamos medir grados negativos sería necesario un voltaje de referencia (una masa virtual) para medir el voltaje que entrega el sensor respecto de esa referencia si embargo esto puede resultar engorroso y en la actualidad hay formas muchos mas Electrónica Digital con RaspberryPI Pagina 62 de 83 simples y eficientes de obtener esto usando sensores digitales en lugar de sensores analógicos. #!/usr/bin/env python # -*- coding: utf-8 -*import spidev import time import os import LCDLIB16x2 as LCD spi = spidev.SpiDev() spi.open(0, 0) V1 = 0.00 V2 = 0.00 def Lee_Canal(channel): adc = spi.xfer2([1,(8+channel)<<4,0]) dato = ((adc [1] & 3) << 8) + adc[2] temp = dato – 0.5 temp = temp / float(10) return temp def Canal_Selec(): canal = 0 global V1 V1 = Lee_Canal(canal) canal += 1 global V2 V2 = Lee_Canal(canal) canal = 0 LCD.lcd_init() LCD.lcd_string(" MCP3008 & PI",LCD.LINE_1) delay = 0.1 1 2 3 if __name__ == '__main__': try: while True: Canal_Selec() LCD.lcd_string("T0:%.1f T1:%.1f" % (V1, V2), LCD.LINE_2) except KeyboardInterrupt: GPIO.cleanup() sys.exit(0) El encabezado del script están las definiciones y llamado a los módulos necesarios. Y se pueden reconocer tres bloques bien diferenciados, el primero se encarga de la adquisición del dato desde la electrónica del conversor, el segundo bloque es el encargado de seleccionar el canal y el tercer bloque es la presentación en el LCD y disponer de una salida prolija si fuera el caso. Electrónica Digital con RaspberryPI Pagina 63 de 83 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 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. Electrónica Digital con RaspberryPI Pagina 64 de 83 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 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 Electrónica Digital con RaspberryPI Pagina 65 de 83 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 66 de 83 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, debe prestar especial cuidado al conectar el sensor, invertir alguna conexión dañará el LM35. Trabajo práctico: En base a lo ya visto, como sería un programa Python para leer la temperatura de este sensor? Electrónica Digital con RaspberryPI Pagina 67 de 83 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 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 Electrónica Digital con RaspberryPI Pagina 68 de 83 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. 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 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á. La siguiente imagen muestra el funcionamiento de uno de estos sensores digitales con el script de ejemplo. En Linux todo es un archivo, y como se comento, cada sensor tendrá un archivo asociado por medio del cual el sistema accede al hardware del sensor. Es por esto que nuestro programa tendrá que acceder a este archivo para conectar con el sensor. Recuerde estos sensores no son simples sensores analógicos como los visto anteriormente, estos Electrónica Digital con RaspberryPI Pagina 69 de 83 sensores ya son pequeñas unidades microcontroladas (como mini-computadoras dedicadas a medir temperaturas) es por esto que son mas complejos de operar pero muy eficientes y prácticos para implementarlos en nuestros proyectos. El código para hacerlo funcionar es el siguiente: #! /usr/bin/python # -*- coding: utf-8 -*import RPi.GPIO as GPIO import time import LCDLIB16x2 as LCD GPIO.setmode(GPIO.BCM) LCD.lcd_init() LCD.lcd_string(" DS18B20 & PI",LCD.LINE_1) import os import glob import time os.system('modprobe w1-gpio') os.system('modprobe w1-therm') def read_temp_raw(): f = open("/sys/bus/w1/devices/28-000003bbd16c/w1_slave", 'r') lines = f.readlines() f.close() return lines ID del sensor conectado def read_temp(): lines = read_temp_raw() while lines[0].strip()[-3:] != 'YES': time.sleep(0.2) lines = read_temp_raw() equals_pos = lines[1].find('t=') if equals_pos != -1: temp_string = lines[1][equals_pos+2:] temp_c = float(temp_string) / 1000.0 return temp_c while True: LCD.lcd_string("Temp:%.1f" % read_temp(), LCD.LINE_2) time.sleep(0.1) Observe la línea: f = open("/sys/bus/w1/devices/28-000003bbd16c/w1_slave", 'r') Esta es la función que abre el archivo que lleva como nombre del número de serie del sensor, recuerde, tendrá tantos archivos como sensores tenga en el sistema y cada uno de ellos llevará el nombre del número de serie que usted deberá usar para poder acceder a sus datos. Electrónica Digital con RaspberryPI Pagina 70 de 83 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. 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. Electrónica Digital con RaspberryPI Pagina 71 de 83 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. El ejemplo que sigue mide el voltaje en la entrada analógica del conversor MCP3201 y la envía por el puerto serial a 9600 baudios. El conversor se conecta de la misma forma que en el ejercicio anterior. #! /usr/bin/python # -*- coding: utf-8 -*from serial import Serial import time import RPi.GPIO as GPIO import spidev Velocidad de comunicación en Baudios. Misma que la fijada en el programa Terminal.exe. GPIO.setmode(GPIO.BCM) spi = spidev.SpiDev() spi.open(0, 0) puerto = Serial("/dev/ttyAMA0", baudrate=9600, timeout=2) if puerto.isOpen() == False: puerto.open() puerto.flushInput() puerto.flushOutput() def Conversor(): M0 =0 muestras =0 while muestras <= 15: Electrónica Digital con RaspberryPI Pagina 72 de 83