Universidad de Costa Rica Facultad de Ingenierı́a Escuela de Ingenierı́a Eléctrica Diseño de un sistema de control de acceso del laboratorio Licit, utilizando hardware Wi-Fi Por: Joel G. Chaves Elizondo Ciudad Universitaria “Rodrigo Facio”, Costa Rica 16 de diciembre de 2014 Diseño de un sistema de control de acceso del laboratorio Licit, utilizando hardware Wi-Fi Por: Joel G. Chaves Elizondo IE-0499 Proyecto eléctrico Aprobado por el Tribunal: Ing. Gustavo Nuñez Segura Profesor guı́a Ing. Marco Villalta Fallas Profesor lector Ing. Julián Gutiérrez Monge Profesor lector Resumen Este trabajo consiste en el diseño e implementación de un sistema de control de acceso encargado de controlar el acceso en el laboratorio Licit, mediante el uso de una comunicación Wifi. El sistema fue diseñado para que fuese simple, económico y fácil de usar. El diseño se desarrolló en etapas para cumplir con los requerimientos propuestos. Estás etapas son fundamentales en el correcto funcionamiento del sistema, la etapa de ingreso de datos, de comunicación por Wifi y la etapa de acople para controlar el sistema. Se usó un microcontrolador, Spark Core, para manejar el sistema ya que provee un procesador ARM y un módulo de conexión Wifi. v Índice general Índice de figuras ix Índice de cuadros x 1 Introducción 1.1 Alcance del proyecto . . . . . . . . . . . . . . . . . . . . . . . . 1.2 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1.3 Metodologı́a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 2 3 4 2 Marco Teórico 2.1 Microcontrolador - Spark Core . . . . . . . 2.2 Control de Acceso . . . . . . . . . . . . . . 2.3 Wifi . . . . . . . . . . . . . . . . . . . . . . 2.4 TCP, Protocolo de Control de Transmisión . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 5 5 8 12 13 3 Desarrollo 3.1 Conectando el Spark Core . . . . . . . . . . . . . 3.2 Diseño del control de acceso . . . . . . . . . . . . 3.3 Diseño del teclado numérico. . . . . . . . . . . . 3.4 Diseño de Pantalla LCD . . . . . . . . . . . . . . 3.5 Diseño del Botón para el interior del laboratorio 3.6 Diseño del Relé . . . . . . . . . . . . . . . . . . . 3.7 Programación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15 15 18 20 23 27 28 30 4 Pruebas . . . . . . . . 35 5 Conclusiones y Recomendaciones 37 5.1 Conclusiones . . . . . . . . . . . . . . . . . . . . . . . . . . . . 37 5.2 Recomendaciones . . . . . . . . . . . . . . . . . . . . . . . . . . 38 Bibliografı́a 39 A Acrónimos 41 B Materiales 43 C Código 45 vii D Librerı́a liquid-crystal-spi 53 viii Índice de figuras 2.1 2.2 2.3 2.4 2.5 2.6 2.7 2.8 STM32F103CB - ARM 32-bit Cortex M3.[Spark, 2014] . . . . TI’s CC3000 module for the WiFi.[Spark, 2014] . . . . . . . . . Microchip MCP1825S-3302E. [Spark, 2014] . . . . . . . . . . . Identificación de entradas y salidas del regulador. [Spark, 2014] Diagrama de entradas y salidas[Spark, 2014]. . . . . . . . . . . Lectora de huellas dactilares.[Frax, 2013] . . . . . . . . . . . . . Lectora de tarjetas. [dointech, 2013] . . . . . . . . . . . . . . . Teclado Numérico. Kaba [2014] . . . . . . . . . . . . . . . . . . . . . . . . . . 5 6 6 7 7 10 11 11 3.1 3.2 3.3 3.4 3.5 3.6 3.7 3.8 Aplicación Android del Spark Core, pantalla inicial . . . . . . . . . Aplicación Android del Spark Core, información de red Wifi . . . . Aplicación Android del Spark Core, bienvenida . . . . . . . . . . . Aplicación CuteCom, configurada . . . . . . . . . . . . . . . . . . . Diagrama general del control de acceso . . . . . . . . . . . . . . . . Teclado numérico usado en el proyecto. Ebay [2013] . . . . . . . . Circuito comprobado en TINA . . . . . . . . . . . . . . . . . . . . Funcionamiento de registro de desplazamiento 74HC595. [Dave Auld, 2011] . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . Tomado del Datasheet del LCD GDM1602K, usado en el proyecto. Configuración de pantalla LCD controlado en 3 pines por el Spark Core. [technobly, 2013] . . . . . . . . . . . . . . . . . . . . . . . . . Configuración de Botón de Emergencia . . . . . . . . . . . . . . . . SAXXON ZKYM350M, un cerrojo magnético usado. [TVC, 2013] . Diseño del funcionamiento planteado del relé . . . . . . . . . . . . Diagrama de bloques general . . . . . . . . . . . . . . . . . . . . . Diagrama de bloques, etapa inicial . . . . . . . . . . . . . . . . . . Diagrama de bloques general, recepción de datos . . . . . . . . . . Diagrama de bloques general, envio de datos . . . . . . . . . . . . Diagrama de bloques general, respuesta del servidor . . . . . . . . 16 16 17 18 19 20 21 3.9 3.10 3.11 3.12 3.13 3.14 3.15 3.16 3.17 3.18 ix . . . . . . . . 23 24 26 27 28 29 30 31 32 33 34 Índice de cuadros 3.1 3.2 Resumen de información obtenida del circuito y del Spark Core . . Lista de salidas de Interfaz de Control de LCD . . . . . . . . . . . 22 25 B.1 Lista de Materiales Usados en el Proyecto . . . . . . . . . . . . . . 43 x 1 Introducción La automatización se ha desarrollado durante mucho tiempo, ya que se desea realizar las diferentes clases de tareas a las que nos enfrentamos a diario de la forma más rápida y sencilla posible. El automatizar se define como la conversión de una accion corporal en una accion automática; ahora, a partir de esta definición se justifica el proyecto que se desarrollará, ya que se utilizará el microcontrolador Spark Core, porque este presenta caracterı́sticas como el procesador ARM Cortex, compatibilidad con Arduino, un módulo integrado para conexión Wi-Fi, y un bajo consumo energético. Este microcontrolador, es una nueva propuesta en el mercado, ya que nació en el año 2013 por medio de una propuesta en la página https://www.kickstarter.com, por lo que no es conocido. Con estas, que son sus principales caracterı́sticas, se ajustó para llevar a cabo un proyecto de domótica, donde toda la conexión del sistema se puede llevar a cabo inalámbricamente. Este proyecto nace con el fin de administrar, de una forma inteligente y eficiente, la entrada y salida de usuarios del Laboratorio de Investigación de Circuitos Integrados (LICIT) en el Edificio de Ingenierı́a Eléctrica de la Universidad de Costa Rica, usando el Spark Core y este al conectarse por medio del Wi-Fi a un servidor en la red local, verificará la autenticidad y permitirá el ingreso. 1 2 1.1 1 Introducción Alcance del proyecto Este proyecto tiene como fin lograr un acceso de control al Laboratorio de Investigación de Circuitos Integrados (LICIT) utilizando el Spark Core, el cierre electro-magnético, un teclado numérico, pantalla LCD, diseñado de tal forma que el ingreso al laboratorio sea seguro y rápido. Para su implementación el sistema se programó y se diseñó de la forma más óptima posible. Con el fin de implementarlo en el laboratorio LICIT, y más adelante, si es posible, sea replicado en otros laboratorios y aulas. El micro controlador debe registrar el ingreso de un código por medio de un teclado numérico, este código se verificará por medio de Wi-Fi, por lo tanto los datos se envı́an, después deberá recibir una confirmación del acceso, con esta confirmación el sistema deberá accionar un actuador instalado en la puerta. 1.2. Objetivos 1.2 3 Objetivos Objetivo general Diseñar un sistema de control de acceso mediante una autentificación remota y comunicación Wi-Fi para el laboratorio LICIT que se ubica en el edificio de Ingenierı́a Eléctrica de la Universidad de Costa Rica. Objetivos especı́ficos • Programar un micro controlador con conexión Wi-Fi, para enviar y recibir información de un servidor de la red local. • Diseñar un sistema de ingreso de datos al micro controlador desde la interfaz usuario. • Diseñar un sistema electro-magnético que permita el acople entre un micro controlador y una cerradura electro-magnética en el acceso del laboratorio. 4 1 Introducción 1.3 Metodologı́a El desarrollo del trabajo incluyó los siguientes pasos y procedimientos, listados en secuencia: 1. Obtención del equipo necesario, como Spark Core, teclado numérico y pantalla LCD. 2. Investigación sobre los temas a tratar, como control de acceso, servidores, comunicación Wifi, y microcontroladores. 3. Diseño del prototipo funcional para controlar el cierre electro-magnético. 4. Programación del microcontrolador y puesta en marcha de un servidor en la red local de internet, para realizar pruebas de comunicación. 5. Realización de pruebas en el sitio con la infrestructura de red, conectando el sistema al servidor destinado para el proyecto. 2 Marco Teórico 2.1 Microcontrolador - Spark Core El microcontrolador es un sistema computacional que se compone de una unidad de procesamiento central (CPU), memoria, y periféricos de entrada y salida. El Spark Core es un microcontrolador que fue diseñado para ser compatible con las librerı́as y los desarrollos que se han efectuado en la plataforma Arduino. El Spark Core cuenta con un procesador ARM Cortex M3, arquitectura de 32 bits, trabajando a una frecuencia máxima de 72 MHz, cuenta con 128KB de memoria Flash interna, 20KB de memoria RAM y 2MB de memoria flash externa. Spark [2014] Figura 2.1: STM32F103CB - ARM 32-bit Cortex M3.[Spark, 2014] El Micro controlador cuenta con conexión inalámbrica, mediante un chip CC3000 SimpleLink de Texas Instruments, con un rango que va de 30 metros hasta 90 metros efectivos. El chip CC3000 trabaja con los sistemas de seguridad inalámbrica WEP, WPA Personal y WPA2 Personal. Trae instalado un regulador de tensión eléctrica, por lo que se puede alimentar por una fuente de tensión entre 3,6 V a 6.0 V DC. Al tener instalado el puerto Micro USB 2.0, cuenta con la opción de ser programado y alimentado por este medio. 5 6 2 Marco Teórico Figura 2.2: TI’s CC3000 module for the WiFi.[Spark, 2014] Figura 2.3: Microchip MCP1825S-3302E. [Spark, 2014] Posee 16 pines que funcionan como entradas y salidas, todo dependerá de la programación que se cargue en el microcontrolador, 8 son analógicas y 8 digitales, entre estos pines hay 8 pines con la funcionalidad de generar un “PWM”(“Pulse Width Modulation”, en español, modulación por ancho de pulsos) que son 6 pines analógicos A0, A1, A4, A5, A6 A7 y dos pines digitales, D0 y D1. Todos los pines trabajan a 3,3 V DC, excepto los pines D0, D1, D3, D4, D6 y D7 que pueden soportar entradas de hasta 5 V DC. El mı́nimo y máximo de corriente que pueden manejar estos pines es de 8 mA y 20 mA, respectivamente. El microcontrolador posee dos formas de conectarse 2.1. Microcontrolador - Spark Core 7 Figura 2.4: Identificación de entradas y salidas del regulador. [Spark, 2014] por medio del Serial (UART, Universal Asynchronous Receiver-Transmitter o en español Transmisor-Receptor Ası́ncrono Universal), usando los pines TX y RX, y la segunda es por medio del puerto USB. Figura 2.5: Diagrama de entradas y salidas[Spark, 2014]. 8 2 Marco Teórico 2.2 Control de Acceso El control de acceso se puede definir como una autorización de acceso. Las reglas de autorización las establecen los responsables de la seguridad del recinto. El objetivo de establecer las reglas para realizar un control de acceso, es restringir la entrada y proveer un nivel de seguridad a los usuarios y encargados de un área restringida que contenga información o equipo que no pueda ser accedido por cualquiera, y con esto prevenir entradas no autorizadas. De lo anterior, los accesos se dan a partir de una categorización de los usuarios, generando diferentes niveles de autorización, para que esta acción sea segura, se debe establecer una identificación y después una autentificación. Los usuarios y encargados tienen la responsabilidad de mantener la seguridad e integridad del control de acceso, entendiendo que deben velar por el correcto uso y entendiendo los problemas que se generan si comprometen el sistema, por lo que el sistema debe generar registros y los encargados deben realizar constantes inspecciones a los mismos. James F. [2004] El control de acceso cuenta con varios criterios, como: 1. Localización: ubicación del lugar donde se acceda. 2. Identificación: proceso donde se autentifica el acceso. 3. Tiempo: controlar los recursos limitando su uso. 4. Operación: como reaccionar ante malos usos y buenos usos. 5. Privilegios: definir los niveles de acceso que poseen los usuarios. Usos del control de acceso: 1. Correctivo: solucionar acciones que han estado ocurriendo. 2. Investigación: averiguar que sucedió. 3. Disuadir: evitar que suceda algún acto. 4. Manejo: al indicar las polı́ticas, procedimientos, y responsabilidades de uso para controlar el sistema. 5. Operacional: ajustar los procedimientos para proteger el sistema. 6. Técnico: automatizar el control y seguridad del sistema. 2.2. Control de Acceso 9 Modelos administrativos de control de acceso Existen tres modelos para administrar los accesos de control, se encuentran el centralizado, descentralizado y existe una versión hı́brida. El modelo de administración centralizado está basado en que solamente exista un encargado de la tarea, o una sola oficina debe de encargarse del acceso de control. La ventaja que proporciona este modelo administrativo, es que mejora y permite un control más estricto y da una uniformidad en el acceso. Esto se da ya que el acceso a realizar cambios o ajustes solo lo pueden realizar un pequeño grupo de personas. Ası́ que si se necesita un cambio o ajuste, el encargado con acceso realiza las modificaciones en el lugar donde se realiza los controles de acceso, pero antes, el administrador del sistema deberá aprobar los cambios o ajustes a realizar. Otra ventaja es que todas las cuentas pueden ser monitorizadas y se puede restringir accesos a cuentas que estén incumpliendo alguna regla, o que ya no deban ingresar. Un inconveniente del modelo administrativo centralizado es que los cambios o ajustes deben ser aprobados y coordinados por el administrador y los encargados. En el modelo de administración descentralizado, los accesos son controlados por un documento o archivo, esto permite el acceso solamente a los responsables del control. Los encargados deben de ser los adecuados de administrar quien necesite el acceso, y que tipo de acceso necesita. La desventaja es que puede existir una falta de coherencia entre los creadores de permisos y los administradores, esto con respecto a los procedimientos y los criterios que se utilizan para dar acceso, además de que no se pueden registrar y monitorizar todos los accesos. El modelo de administración hı́brido combina aspectos de ambos modelos en un mismo enfoque. Donde se centraliza la administración, pero a la vez se reparte la administración a encargados de accesos básicos. La principal desventaja de un enfoque hı́brido es la discusión sobre lo que debe y no debe ser centralizado Mecanismos de Control de Acceso Durante los años, se han desarrollado sistemas que dan un control sobre los accesos, y estos sistemas son internos y externos, lo cuál? puede hacer que varı́en en términos de precisión, costo, y tecnologı́a. La elección de cuales sistemas se deben instalar en los accesos a controlar, varı́a dependiendo de lo que el administrador requiera, tomando en cuenta el costo, beneficio y lo que se necesita. Las contraseñas siempre están presentes en la autentificación, el uso de las mismas puede reducir la seguridad debido a que se presten las contraseñas entre usuarios, pero el uso de contraseñas en los controles de acceso hace que el sistema sea económico, ya que es un sistema muy simple. La seguridad dependerá del uso que empleen los usuarios, ya que si las contraseñas son muy 10 2 Marco Teórico extensas y complicadas, pueden tener problemas para recordarlas, entonces deberán de escribirlas o las contraseñas serán muy simples. Las contraseñas deben ser usadas individualmente, además deben de estar siendo renovadas por decisión del usuario, o por algún sistema que obligue a cambiarlas. La encriptación es otro mecanismo para mantener un control sobre accesos, al encriptar alguna información, se debe desencriptar mediante una llave criptográfica. Este método aumenta la eficiencia de la seguridad del sistema. Las listas de usuarios son otro mecanismo de control de acceso, ya que se le asignan permisos a estos usuarios dependiendo del uso y nivel de administración que van a tener. Además, se puede administrar de manera que se realicen grupos o a nivel individual. James F. [2004] Sistemas de control de acceso Existen muchos sistemas para realizar un control de acceso, todo depende del requerimiento y qué es lo mejor para solucionar la petición. Entre esos sistemas tenemos: 1. Control Biométrico: utilizado por su alta eficiencia, ya que hacen un análisis de atributos personales únicos en cada individuo, como lo son las huellas dactilares, la retina, el iris y la geometrı́a de la mano. Ası́ que la identificación es única por cada usuario, no es necesario memorizar claves, además, no es necesario cargar con tarjetas o controles y por tanto no es posible extraviarla. Figura 2.6: Lectora de huellas dactilares.[Frax, 2013] 2. Tarjetas de control o proximidad: estas permiten tener toda la información de cada usuario en una base de datos. La mayor ventaja está en el control de dar autorización a ciertas puertas o zonas, generando una mayor seguridad y control sobre el acceso de las personas. Toda la transmisión de datos entre la tarjeta y el lector está encriptada utilizando un algoritmo de seguridad. Al estar encriptada se reduce el riesgo de copiar las tarjetas sin autorización. Al ser una tarjeta el costo es bajo al tener 2.2. Control de Acceso 11 que reemplazarla, y en caso de que se pierda el permiso de ingreso, se desactiva en el sistema. Una desventaja frente al control biométrico, es que la tarjeta puede ser robada y con esto generar un problema en la seguridad. Figura 2.7: Lectora de tarjetas. [dointech, 2013] 3. Teclados para digitación de códigos alfanuméricos: son los sistemas más sencillos, más baratos, y realizan el mismo control de acceso que los anteriores sistemas, ya que se debe registrar a cada usuario, cada usuario deberá usar una única contraseña. Figura 2.8: Teclado Numérico. Kaba [2014] Estos terminales trabajan de una manera similar, ya que utilizan una base de datos, propia o externa, que deben consultar para corroborar si se está autorizado o no para ingresar a cierta área, por lo que deben trabajar recopilando los datos, enviándolos, y esperando una autorización para trabajar en conjunto a un actuador, como una puerta con magneto. 12 2.3 2 Marco Teórico Wifi Es un sistema de conexión inalámbrica, que permite la comunicación de distintos tipos de dispositivos finales dentro de una red que utiliza un mismo estándar, el IEEE 802.11. Los dispositivos al utilizar un estándar, como el 802.11, para comunicarse con otros dispositivos que utilicen el mismo estándar o nuevas versiones del mismo, como la 802.11 bgn, no se ven afectados aunque sean dispositivos de otras marcas. Al poseer la capacidad de comunicarse y conectarse entre ellos, pueden acceder a redes de computadoras locales o a internet si es necesario. Uno de los beneficios de permitir una conexión a una red local de computadoras, es que se puede dar desde distintos puntos sin afectar la infraestructura, ya que no se necesita llevar cables de red. La seguridad de una conexión inalámbrica se da mediante el uso de protocolos de cifrado de datos, como el WEP, el WPA, el WPA2, el filtrado de MAC, entre otros más comunes. IEEE [2013] 2.4. TCP, Protocolo de Control de Transmisión 2.4 13 TCP, Protocolo de Control de Transmisión TCP por sus siglas en inglé, Transmission Control Protocols, y en español, Protocolo de Control de Transmisión, se diseñó especı́ficamente para proporcionar un flujo de bytes en una red interna entre dos puntos. La diferencia entre una red interna y una sola red es que diversas partes podrı́an tener diferentes topologı́as, anchos de banda, retardos, tamaños de paquete y otros parámetros. TCP se diseñó para que se adapte de manera dinámica a las propiedades de la interred y evitar fallas. TCP funciona, primero ambos, el servidor y el cliente, crean sockets. Cada socket tiene un número que es una dirección, que en si, es la dirección IP del servidor, y un número de 16 bits, que es local a ese servidor, llamado puerto. Para obtener el servicio TCP, se debe establecer de manera explı́cita una conexión entre un socket en la máquina emisora y uno en la máquina receptora.En el protocolo TCP, las conexiones siguen usando el acuerdo de tres vı́as. Para establecer una conexión, el servidor está a la espera de una conexión entrante, y se encuentra ejecutando las acciones de escuchar y aceptar alguna conexión. Esta debe especificar cierto origen o bien nadie en particular. En el otro lado el cliente realiza la acción: conectarse, pero debe especificar la dirección IP y el puerto con el que se debe de conectar, el tamaño máximo de segmento bytes que está dispuesto a aceptar y opcionalmente algunos datos de usuario. El cliente al realizar una conexión, se lleva a cabo un proceso de sincronización y confirmación con el servidor, donde el servidor verifica si existe algún proceso que estuviera esperando la conexión entrante, con la dirección IP y el puerto indicado, si no existe el proceso: se envı́a una respuesta indicando que se rechaza la solicitud. John, Tanenbaum [2004] 3 Desarrollo 3.1 Conectando el Spark Core Para iniciar a trabajar con el Spark Core, se debe conectar a una red Wifi, la conexion se puede realizar de dos métodos para conectarlo a una red Wifi, la primera es usando la aplicación para teléfono inteligente (“Smartphone”) que use alguno de los siguientes sistemas operativos, Android, versión superior a 4, o IOS para teléfonos Iphone, y la otra forma es por medio de una conexión por USB. Para empezar, el Spark Core debe estar alimentado y estar en el modo de escucha (“LISTENING MODE ”). Una vez alimentado, se debe tocar el botón “MODE ”por tres segundos, el led multicolor (“RGB LED”) instalado en el Spark Core, cambia de color a un azul intermitente. Para borrar todas las contraseñas y conexiones Wifi previas, el botón debe ser sostenido por diez segundos, en ese momento el led tendrá el color azul intermitente, pero de forma más rápida, por un momento muy pequeño. Una vez en este modo, el Spark Core está a la espera de que se le indique la información necesaria para conectarse a la red Wifi. Conexión mediante aplicación móvil El teléfono debe estar en la misma red WIFI, ası́ que una vez instalada la aplicación es necesario crear una cuenta con contraseña, con esta cuenta se registrará el Spark Core en caso de ser la primera vez que se conecta. A continuación la aplicación automáticamente llena el nombre de la red, por lo que es necesario ingresar la contraseña si es que existe. La anterior configuración se llevará un corto periodo, menos de un minuto. La secuencia de colores del led, si la información es correcta y la red está funcionando, es la siguiente: 1. Azul Intermitente, esperando información de red Wifi. 2. Azul fijo, información obtenida y almacenada. 3. Verde Intermitente, conectando a la red Wifi. 4. Celeste Intermitente, conectando al sistema “Spark Cloud”. 5. Celeste Intermitente muy lento, confirma que está conectado al sistema. 15 16 3 Desarrollo Figura 3.1: Aplicación Android del Spark Core, pantalla inicial Figura 3.2: Aplicación Android del Spark Core, información de red Wifi Después de que el Spark Core este en la última etapa, la aplicación lo agrega a la lista de dispositivos de la cuenta creada, además se debe de dar un nombre al dispositivo. Al terminar la configuración, la aplicación presenta una pantalla de bienvenida con información básica. 3.1. Conectando el Spark Core 17 Figura 3.3: Aplicación Android del Spark Core, bienvenida Conexión por medio de USB Debe estar en modo de escucha, instalar una aplicación para comunicación por medio del Serial USB, como ejemplo se utilizó la aplicación CuteCom en Ubuntu, pero existen otros programas para los diferentes sistemas operativos, lo que si es necesario es la siguiente configuración: 1. Baud Rate: 9600 2. Data Bits: 8 3. Parity: None 4. Stop Bits: 1 Una vez conectado el cable USB a la computadora y el programa configurado, se ingresan los comandos “w”, seguido de un espacio, el nombre de la red Wifi, otro espacio, y la contraseña en caso de que la red tenga una. Si el Spark Core está siendo usado por primera vez y la conexión es por medio de la conexión USB, debe ser registrado por otro medio, ya que usando la aplicación móvil lo hace automáticamente. Se debe instalar la interfaz de lı́nea de comando de Spark, “spark-cli”, (en inglés “Spark Command Line Interface”), en el siguiente enlace se encuentra una guı́a bastante completa para realizar la instalación, https://github.com/spark/spark-cli . Después de instalado se usa la siguiente instrucción, “spark setup”, y se siguen las instrucciones. 18 3 Desarrollo Figura 3.4: Aplicación CuteCom, configurada Al terminar de registrar el Spark Core podemos ingresar al IDE Web, https://www.spark.io/build/ que proporciona la empresa para poder trabajar. En ella se puede programar, compilar, y buscar librerı́as para desarrollar proyectos propios. 3.2 Diseño del control de acceso El sistema se diseñó para ser una terminal que controle un actuador y con ello mantener un control más estricto; además, se diseñó cumpliendo una serie de caracterı́sticas, que se aclaran a continuación. 1. Definir un protocolo de comunicación por medio de una conexión de red inalámbrica. 2. Conectar se con un servidor dedicado y verificar la validez de la solicitud verificando la dirección MAC, que se encargue de atender sus solicitudes. 3. Establecida una conexión con el servidor, entra en un ciclo de trabajo a la espera de entradas, el ingreso de información, un numero de usuario, definido como la cédula de identificación, y una contraseña, definido como cuatro dı́gitos. 4. Enviar la información al servidor para comprobar, y recibir una autorización. 3.2. Diseño del control de acceso 19 5. Autentificación del servidor, en esta etapa el servidor nos informa si se está o no autorizado 6. Operar, dependiendo de la información del servidor, abro el cierre magnético, o se ı́ndica en pantalla la solicitud fue rechazada. La terminal posee una serie de entradas y salidas para cumplir con requerimientos solicitados en el diseño. El microcontrolador Spark Core se encarga de procesar la información y conectarse a la red local. Para ingresar información al microcontrolador se instaló un teclado numérico estilo telefónico, además un botón de emergencia para abrir la puerta. Figura 3.5: Diagrama general del control de acceso 20 3.3 3 Desarrollo Diseño del teclado numérico. El funcionamiento del teclado numérico usado en el proyecto, es de tipo telefónico, ya que inicia la numeración en la parte superior. Eléctricamente se representa como una matriz de botones, tres columnas y cuatro filas. Existen dos formas de leer el botón presionado, digital o analógicamente. Digitalmente, se deben conectar las siete terminales del teclado numérico a siete pines del Spark Core, pero al no contar con una gran cantidad de pines, se decidió realizar una implementación analógica, de forma que solo se necesite un pin. Figura 3.6: Teclado numérico usado en el proyecto. Ebay [2013] Se utilizó un sistema para leer el teclado desde un solo pin, esto se da con un divisor de tensión, mediante mediciones de tensión eléctrico para obtener una lectura analógica y ası́ se identificara cada tecla individualmente 1 . 1 http://www.instructables.com/id/Arduino-3-wire-Matrix-Keypad/step2/Wiring-upthe-resistors/ 3.3. Diseño del teclado numérico. El sistema se comprobó en TINA: Figura 3.7: Circuito comprobado en TINA 21 22 3 Desarrollo En la tabla 3.1, tenemos el valor real, valor esperado del diseño y simulación, y el valor que lee el Spark Core y que lo escala, de 0 a 4096 valores. Se utilizó la alimentación del microcontrolador, obtenido desde el pin 3V3, ya que existen varios pines que no soportan valores mayores al 3,3 V DC. Por ejemplo, para la tecla del número 1, la tensión leı́da teóricamente debe de ser, V3v3 − 180Ω ∗ i − 1kΩ ∗ i − 820Ω ∗ i − 1kΩ ∗ i = 0 (3.1) V3v3 = (180Ω + 1kΩ + 820Ω + 1kΩ) ∗ i (3.2) V3v3 /(3kΩ) = i (3.3) V1 = 3, 3V /3000Ω ∗ 2820Ω = 3, 102V (3.4) La tensión eléctrica teórica que lee el Spark Core, es de 3,102 V, y como se observa en la ?? el valor real medido es de 3,01 V, valor un poco inferior. Tecla Valor de tensión teórico (V) 1 2 3 4 5 6 7 8 9 0 * # 3.1 3 2.8 2.53 2.44 1.77 1.333 1 0.6396 0.803 1.1 0.496 Valor de tensión eléctrica real/medido (V) 3.01 2.89 2.75 2.49 2.32 1.7 1.281 0.971 0.611 0.798 1.06 0.474 Valor leı́do por el Spark Core 3802 3648 3333 3108 2744 2153 1640 1245 800 1003 1356 628 Cuadro 3.1: Resumen de información obtenida del circuito y del Spark Core 3.4. Diseño de Pantalla LCD 3.4 23 Diseño de Pantalla LCD Como se diseña con el requisito de usar la menor cantidad de pines, la pantalla LCD que se usó también debe de cumplir este requerimiento, ya que la instalación tı́pica de este tipo de pantallas necesita siete pines entre entradas, salidas y alimentación. Por lo tanto se buscó una opción que cumpla con este requerimiento, ası́ que en las librerı́as existentes y soportadas para Spark Core, existe una implementación ya verificada. Esta implementación utiliza un circuito integrado 74HC595, que se define como un registro de desplazamiento de 8 bits, con entrada serie, salida serie o paralelo con latch de 3 estados. Ası́ que con esa definición se puede usar para controlar 8 salidas simultáneas usando unos pocos pines del microcontrolador, en este caso usando solamente 3 pines. Entonces para su funcionamiento como registro de desplazamiento se necesitan al menos los 3 pines para una comunicación serial, que son: 1. Datos (DS). 2. Clock (SH CP). 3. Almacenamiento (ST ST). Figura 3.8: Funcionamiento de registro de desplazamiento 74HC595. [Dave Auld, 2011] En la imagen 3.8, podemos observar un poco mejor cómo funciona el 74HC595, por la entrada de datos (DS) se ingresan los datos de forma serial, mediante el reloj (SH CP) los datos se empiezan a mover por los distintos pines, de una manera interna, en el momento que el pin de almacenamiento, (ST CP), se activa los pines usados van a reflejar los valores. Por lo que pasamos de una entrada serial a una salida en paralelo. La pantalla LCD que se usa, cuenta con el controlador Hitachi HD44780 LCD, diseñado especialmente para desplegar caracteres alfanuméricos, que de una manera sencilla se 24 3 Desarrollo puede acoplar a cualquier micro controlador. El controlador está diseñado e implementado para facilitar el uso de la pantalla LCD. Figura 3.9: Tomado del Datasheet del LCD GDM1602K, usado en el proyecto. La pantalla LCD para uso de microcontroladores, está diseñada para utilizar una interfaz paralela, lo que significa que el microcontrolador debe manipular varios pines de interfaz a la vez para controlar lo que se visualiza en ella. La interfaz consta de los pines que están agrupados en la tabla 3.2. El selector de registro (RS) controla en que parte en la memoria del LCD se está escribiendo los datos. Este pin puede seleccionar entre dos registros, el registro de datos o el registro de instrucciones. El registro de datos es donde se contiene lo que se escribe en la pantalla, mientras que el registro de instrucciones, es donde el controlador de la pantalla LCD consulta para obtener instrucciones sobre qué hacer a continuación. Los pines del 7 al 14 son de datos (D0 -D7). Los datos escritos en estos pines (altas o bajas) son los bits que se están escribiendo a un registro. Para controlar la pantalla LCD, se debe seguir un proceso de control de la pantalla que consiste a través de los pines D0 al D7, en colocar los datos que forman la imagen de lo que se desea mostrar en el registro de datos, y después, poniendo las instrucciones a usar en el registro de instrucciones. Se han desarrollado librerı́as de funciones y definiciones, además de código para utilizar dispositivos como la pantalla LCD, por lo que se usan las librerı́as LiquidCrystal y LiquidCrystalSPI, que es una variante 3.4. Diseño de Pantalla LCD PIN 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 SIMBOLO GND VCC VO RS R/W CLK BIT 0 BIT 1 BIT 2 BIT 3 BIT 4 BIT 5 BIT 6 BIT 7 LED + LED - 25 DESCRIPCION Tierra Fuente de Alimentación eléctrica Ajuste de contraste Selector de,registro Lectura o Escritura Reloj Datos 0 - D0 Datos 1 - D1 Datos 2 - D2 Datos 3 - D3 Datos 4 - D4 Datos 5 - D5 Datos 6 - D6 Datos 7 - D7 Luz de Fondo, positivo + Luz de Fondo, negativo - Cuadro 3.2: Lista de salidas de Interfaz de Control de LCD de la primera, ya que simplifican el uso de funciones y no necesita saber las instrucciones a bajo nivel. La pantalla LCD, al tener instalado el controlador Hitachi para LCD, obtiene la facilidad para que se pueda controlar en dos modos, uno en 4 bits y otro en 8 bits. La facilidad recae en que el modo de 4 bits requiere siete pines del microcontrolador entre entradas, salidas, tierra y alimentación, mientras que en el modo de 8 bits se requieren 11 pines. Ahora, la implementación de la pantalla LCD con su controlador, además de usar el circuito integrado 74HC595 como registro de desplazamiento, logra disminuir la cantidad de pines, pasando de los siete pines a los tres. En la anterior implementación, podemos observar que usando los pines del Spark Core D2, D3 y D4, se puede imprimir cualquier mensaje en la pantalla. La configuración es la siguiente: Los pines del Spark Core al 74HC595, 1. D4 al pin 14 (DS). 2. D3 al pin 11 (SH CP). 3. D2 al pin 12 (ST ST). Los pines del 74HC595 a la pantalla LCD 1. Pin 1 (Q1) al pin 4 (RS). 26 3 Desarrollo Figura 3.10: Configuración de pantalla LCD controlado en 3 pines por el Spark Core. [technobly, 2013] 2. Pin 2 (Q2) al pin 6 (CLK). 3. Pin 3 (Q3) al pin 14 (D7). 4. Pin 4 (Q4) al pin 13 (D6). 5. Pin 5 (Q5) al pin 12 (D5). 6. Pin 6 (Q6) al pin 11 (D4). En el código, para poder usar la pantalla, debemos agregar la librerı́a incluyéndola en el código, además, tenemos que definir un tipo LiquidCrystal, y definir en cuales pines está conectado el registro de desplazamiento 74HC595. Al configurar los pines y dispositivos del microcontrolador en el programa debemos inicializar la pantalla, llamando la función “lcd.initSPI()”, ya que está función indica que se va a trabajar con el estándar de comunicación “SPI”(en inglés, “Serial Peripheral Interface”) y la librerı́a con esto trabajar en conjunto con el registro de desplazamiento. 3.5. Diseño del Botón para el interior del laboratorio 3.5 27 Diseño del Botón para el interior del laboratorio El diseño de esta etapa del proyecto es necesario para ofrecer una salida a las personas que ya pasaron previamente por el control de acceso. El botón se diseña como una interrupción al procesador del microcontrolador, ya que la interrupción se debe dar en cualquier momento y circunstancia, para ası́ asegurar que en cualquier eventualidad la puerta abrirá sin importar la situación. Figura 3.11: Configuración de Botón de Emergencia El circuito de la imagen 3.11 se diseñó para realizar la función de botonera, cuenta con un botón tipo normalmente abierto, por lo que el pin A7, que está configurado como entrada en el código del micro controlador, está recibiendo una cantidad muy pequeña de corriente, ası́ que el pin se encuentra un estado en alto o un uno lógico. Al cerrar el botón el pin A7 estará conectado directamente a la tierra (GND) por lo que el micro controlador lee un cambio, ya que el estado pasa de alto a bajo. Se utiliza una resistencia de 10k Ohm para que no exista un corto circuito al tocar el interruptor. A nivel de código, se utiliza la función “attachInterrupt()”, esta función se encarga de activar una sub rutina o función cuando ocurre una interrupción externa, en el Spark Core, las interrupciones se pueden configurar en los pines D0, D1, D2, D3, D4 A0, A1, A3, A4, A5, A6, y A7. La función “attachInterrupt()recibe tres parámetros, el primero es el pin donde lee la interrupción, el segundo debe ser la función que debe ejecutarse, la misma no puede recibir ningún parámetro ni devolver ningún dato. El tercer parámetro es llamado “Modo”, e indica cuando debe ser activada la interrupción, donde existen tres modos, el primero es si el pin cambio de valor sin importar cual, el segundo es solamente cuando pasa de alto a bajo y el tercero es cuando pasa de bajo a alto. 28 3.6 3 Desarrollo Diseño del Relé Usando la información comercial de un cerrojo magnético, se diseñó esta etapa para que pueda adaptarse a este tipo de cierres que se usan en puertas controladas. Los cerrojos magnéticos son comúnmente controlados por relés, usando la información del SAXXON ZKYM350M, un cerrojo magnético usado para control de acceso, se puede simular su funcionamiento para que posteriormente se use junto al control de acceso que se diseñó. Figura 3.12: SAXXON ZKYM350M, un cerrojo magnético usado. [TVC, 2013] En esta etapa lo que se realizó fue verificar el funcionamiento de un relé, JZC–11F–05VDC–1Z (En la figura 3.13 está representado como RL1), al que se le conectaron dos LEDS, uno en la salida NC (En inglés “Normally Closed”, en español, Normalmente Cerrada) y otro en la NO (En inglés “Normally Open”, en español, Normalmente Abierta) ambos conectados directamente a tierra, y en el pin COM (En inglés “Common”) conectado a una resistencia de 330 Ohms y la fuente de alimentación. Para activar y desactivar la bobina del relé, se usa un transistor 2N2222 para utilizarlo como interruptor controlado por el pin A1, junto a una resistencia de 330 Ohm, que se configura como salida en la programación del Spark Core. Para adaptarse a un cerrojo magnético, solamente se debe conectar los pines NC o NO según lo solicite el cerrojo a usar. 3.6. Diseño del Relé Figura 3.13: Diseño del funcionamiento planteado del relé 29 30 3 Desarrollo 3.7 Programación El desarrollo del proyecto se realizo haciendo el diseño fı́sico de una etapa de la mano de su correspondiente etapa de programación y configuración. La programación del Spark Core es en base de “Wiring”, que es una forma de programación de código abierto para microcontroladores. “Wiring”permite escribir software multiplataforma para controlar los dispositivos conectados a una amplia gama de placas. Cuando escribimos el código se debe respetar tres partes básicas en la estructura del programa, como: • declaración de variables • setup() • loop() La función setup() es la parte donde se inicializa y se realiza la configuración de los diferentes elementos del sistema, como por ejemplo, la inicialización de la pantalla LCD, los pines a usar para manejar los leds, el relé y el teclado numérico. La void setup() sólo se ejecuta en el inicio y no se vuelve a ejecutar. La función loop() se lleva a cabo en el segundo paso, aquı́ es donde el ciclo del programa se ejecuta. Por el nombre, sabemos que es un ciclo que estará trabajando hasta que sea apagado, o se de una interrupción. El programa está diseñado para que al inicio todas las variables necesarias sean declaradas e inicializadas, inmediatamente se ingresa a la función setup() donde se realiza las configuración inicial y después se ejecuta el ciclo de trabajo, loop(), donde se pueden identificar cuatro etapas, el inicio, ingreso de datos, envı́o y recepción de datos y por último ejecutar. Figura 3.14: Diagrama de bloques general 3.7. Programación 31 Inicio En pantalla se muestra un mensaje de bienvenida y además de las instrucciones a seguir. El flujo del programa está diseñado para que esté esperando hasta que el usuario siga las instrucciones, en este caso que deje oprimido la tecla asterisco (*) hasta que cambie la información en pantalla. En cada ciclo, al iniciar se verifica que la puerta esté cerrada. Figura 3.15: Diagrama de bloques, etapa inicial 32 3 Desarrollo Ingreso de datos A continuación el programa le indica que debe ingresar el usuario, se solicita el número de la identificación (número de cédula), deben ser nueve dı́gitos, al terminar de ingresar la identificación se espera la confirmación del usuario o se puede borrar para que se corrija algún error. Si se borra, debe empezar de nuevo. Al terminar de ingresar el usuario y confirmarlo se pasa a ingresar la contraseña, son cuatro dı́gitos. La identificación y la contraseña están separadas por un punto y coma, para que cuando sea enviada al servidor se pueda revisar autentificar. Figura 3.16: Diagrama de bloques general, recepción de datos 3.7. Programación 33 Envı́o de datos La siguiente etapa se encarga de enviar los datos al servidor, primero se verifica si el sistema está conectado. Si está conectado se envı́an los datos al servidor y se avanza a la siguiente etapa. Si se pierde la conexión o no se conectó al servidor, se verifica si es el usuario es el super usuario si lo es se abre la puerta, si no queda cerrada y se inicia el ciclo de trabajo. Este usuario es en caso de emergencia, o para realizar algún tipo de mantenimiento. Figura 3.17: Diagrama de bloques general, envio de datos 34 3 Desarrollo Respuesta del servidor La etapa final del ciclo de trabajo, si el servidor responde afirmativamente, el micro controlador abre la puerta y deja pasar al usuario. Si la respuesta es negativa simplemente no se abre y se regresa al inicio del ciclo a la espera de un nuevo usuario. Puede existir la posibilidad de que el micro controlador pierda la conexión, el programa verificará si es el super usuario, si no volverá al inicio. Figura 3.18: Diagrama de bloques general, respuesta del servidor 4 Pruebas Durante el proyecto se realizaron distintos tipos de pruebas, verificando varios tipos de usos al sistema y condiciones que se podrı́an dar durante su funcionamiento. Prueba de Ingreso de datos • El sistema recibe datos desde el teclado, en distintas etapas del funcionamiento. 1. Al inicio, si no se oprime la tecla asterisco (*) no continua, no sucede ningún mal funcionamiento si se oprime otra tecla. 2. Durante el funcionamiento del sistema, mientras no se solicite ingreso de datos y si se oprime alguna tecla no incurrira en ningún mal funcionamiento o error. Prueba de Conexión • El sistema se conecto en distintas redes para probar conectividad y funcionalidad. 1. Las primeras pruebas se realizaron usando el programa Netcat, una computadora portátil Lenovo G580 y una red local con un Router D-Link Dir-600. Esta prueba se hizo conectando el sistema a la computadora y mediante Netcat para ası́ leer todo lo enviado por el sistema al socket e IP de la computadora. Todo lo enviado se observo en la consola donde estaba corriendo Netcat. Además se uso para enviar información al sistema, donde reaccionó como estaba programado, si se le enviaba una afirmación abrı́a la puerta, si se le enviaba un negación indicaba en la pantalla que habı́a sido rechazado, si se le enviaba otra información la ignoraba e indicaba que existio un error en la comunicación. 2. Las siguientes pruebas se realizaron en la escuela de Ingenierı́a Eléctrica de la Universidad de Costa Rica, usando la infraestructura de red que está instalado en el edificio. Está vez se comunicó el sistema con una otra computadora portátil, que tenı́a corriendo un servidor y el programa que se usó para el funcionamiento final del 35 36 4 Pruebas sistema. Las pruebas obtuvieron resultados positivos, a pesar de que al principio no se logró establecer una conexión entre ambos. 3. Las últimas pruebas se realizaron con el servidor final, e igual que en la prueba anterior, se realizó en el laboratorio Licit usando la infraestructura del edificio. La comunicación se dı́o sin ningún problema. Ya que se hicieron las pruebas previas al montar la prueba final está se llevo a cabo sin mucho problema. 5 Conclusiones y Recomendaciones 5.1 Conclusiones • Al terminar el proyecto se obtuvo un sistema funcional que cumple la función de control de acceso mediante una autentificación remota que se dio al conectarse por Wifi con el servidor TCP, instalado en la red local de computadoras del edificio de Ingenierı́a Eléctrica de la Universidad de Costa Rica. • La comunicación se dio de forma bastante simple, al establecer la comunicación con el servidor, se le envı́a un paquete de bytes, que contiene un número de identificación numérica de nueve dı́gitos de longitud, y una contraseña numérica, de 4 dı́gitos, separados por medio de un punto y coma. • El microcontrolador Spark Core se programa de una forma bastante simple, y ya que cuenta con la capacidad para conectarse a una red Wifi, permitió desarrollar el proyecto de una forma fácil y simple. Se usaron las librerı́as que están a disposición general, por lo que enviar y recibir información se da mediante rutinas sencillas. • El diseño del teclado y botón de emergencia usados en el proyecto cumplen las funciones necesarias para que el sistema lea la información que el usuario necesita ingresar. Se uso la menor cantidad de pines con el fin de dejar la posibilidad de agregarle más etapas al proyecto. 37 38 5 Conclusiones y Recomendaciones 5.2 Recomendaciones • Se recomienda conectar una fuente de poder al sistema, por ejemplo una baterı́a, de 5 V y una corriente de salida de por lo menos 1 A, con el fin de que funcione de forma aut ?onoma e independiente de una conexión que pueda fallar. • Se recomienda usar el sistema en una red confiable, que la seguridad de la infraestructura de red sea proporcionada por la conexión de red local donde se conecta el sistema. • Se recomienda realizar una tarjeta con el circuito impreso, con el fin de tener un producto terminado y que se pueda usar como un producto final, y no que este desarrollado en una placa de pruebas. Bibliografı́a Spark Docs (2014). Spark. http://docs.spark.io/. Andrew S., Tanenbaum (2004). Redes de Computadoras. John, Rittinghouse, PhD, CISM, & James F.Ransome, D. T. (2004). Wireless Operational Security. Magneto para Puerta (2014). technobly http://soporte.tvc.mx/ Ingenieria/YLI/YM350M/mi.html. Libreria LCD SPI (2014). technobly https://github.com/technobly/ SparkCore-LiquidCrystalSPI. Arduino Platform - Working with Shift Registers (2011). Dave Auld http://www.codeproject.com/Articles/144606/ Arduino-Platform-Working-with-Shift-Registers. Teclado numerico 4x3 (2013). http://www.ebay.com/itm/ PA-New-1Pc-4X3-Matrix-Array-12-Key-Membrane-Switch-Keypad-Keyboard-SCA-1711-/ 291308526289?pt=LH_DefaultDomain_3&hash=item43d3575ad1. Control de Personal con Lectores Externos (2014). Kaba. http: //www.kaba.es/Soluciones/Cerraduras-electronicas/625702/ lectores-de-tarjetas.html. Control de Personal con Lectores Externos (2013). dointech. http://www. dointech.com.co/control-personal.html . Lector de Huella Digital ZK5000 (2014). Frax. http://www.biometricos.cl. IEEE 802.11TM WIRELESS LOCAL AREA NETWORKS (2013). IEEE. http://www.ieee802.org/11/. Wifi (2014). Wifi Alliance http://www.wi-fi.org/. 39 A Acrónimos • SPI: Serial Peripheral Interface. • LED: Light-Emitting Diode, o en español Diodo Emisor de Luz. • CPU: Central Processing Unit, o en español Unidad de Procesamiento Central. • RAM: Random Access Memory, o en español Memoria de Acceso Aleatorio. • WEP: Wired Equivalent Privacy o en español Privacidad Equivalente a Cableado. • WPA: Wi-Fi Protected Access, o en español Acceso Wi-Fi Protegido. • USB: Universal Serial Bus, o en español Bus Universal en Serie. • PWM: Pulse Width Modulation, o en español Modulación por ancho de pulsos. • UART: Universal Asynchronous Receiver-Transmitter o en español TransmisorReceptor Ası́ncrono Universal • MAC: Media Access Control, o en español Control de Acceso al Medio. • TCP: Transmission Control Protocol, o en español Protocolo de Control de Transmisión. • IP: Internet Protocol, o en español Protocolo de Internet. • IDE: Integrated Development Environment, o en español Entorno de Desarrollo Integrado. • LCD: Liquid Crystal Display, o en español Pantalla de cristal lı́quido. 41 B Materiales En la siguiente tabla, se encuetra la lista de materiales usados en el proyecto. Parte SparkCore Character LCD Microchip Teclado Numerico LED LED LED Botón Trimmer Potenciometro Resistencia Resistencia Resistencia Resistencia Resistencia Resistencia Resistencia Capacitor Relé Diodo Transistor Tipo Chip Antenna Basic 16x2 74HC595 Matriz 4 x 3 Rojo Amarillo RGB 10 k Ohm 10 k Ohm 330 Ohm 10 k Ohm 1 k Ohm 680 Ohm 1,3 k Ohm 230 Ohm 150 Ohm 1 uF JZC-11F 1n4148 2N2222AG Cantidad 1 1 1 1 1 1 1 1 2 1 3 1 2 2 1 1 1 1 1 1 1 Cuadro B.1: Lista de Materiales Usados en el Proyecto 43 C Código 1 // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 2 #include ” l i q u i d −c r y s t a l −s p i . h ” 3 // F i r s t , we c o n s t r u c t t h e c l i e n t t h a t w i l l c o n n e c t t o our l o c a l server . 4 TCPClient c l i e n t ; 5 S t r i n g messageToSend ; 6 char s t r i n g 1 [ 1 ] = ” ” ; 7 byte ∗ msg ; 8 in t l e n g t h ; 9 // IP a d d r e s s o f t h e S e r v e r TCP 10 byte s e r v e r [ ] = { 1 9 2 , 1 6 8 , 1 , 3 } ; 11 // URL o f t h e S e r v e r TCP 12 const char∗ serverURL = ” h t t p s : / /www. a c c e s o l i c i t . e i e . u c r . ac . c r ” ; 13 in t p o r t = 1 0 0 1 0 ; 14 //−−−−−−−−−−−−−−−−−−−−−−−−−− 15 in t keyboardPin = A0 ; 16 // Analog i n p u t p i n t h a t t h e keypad i s a t t a c h e d t o 17 in t P i n R e l a y = A1 ; 18 // D i g i t a l Output p i n f o r t h e r e l a y ’ s c o n t r o l 19 in t Pin ledRIGHT = A6 ; 20 // D i g i t a l / Analog Output p i n f o r LED f o r i n f o r m a t i o n 21 in t Pin ledWRONG = A5 ; 22 // D i g i t a l / Analog Output p i n f o r LED f o r i n f o r m a t i o n 23 in t Pin buttonEXIT = A7 ; 24 // I n p u t Pin t h a t t h e I n t e r r u p t i s a t t a c h e d t o 25 26 in t v a r l o n g I D =9; 27 in t var longPASS =4; 28 S t r i n g SUPERUSERR = ”1 1 3 7 9 0 6 8 6 ; 7 7 9 9 ” ; 29 30 in t v a r k e y p r e s s e d = 1 2 ; // D e f a u l t Value f o r t h e Keypad 31 in t v a r k e y b o a r d V a l u e = 0 ; // v a l u e r e a d from t h e k e y b o a r d 32 in t j , i , k ; // Counters 33 b o o l e a n f l a g u s e r p a s s c o m p l e t e , ok ; 34 35 unsigned long SERVERTimeSecond , SERVERTimeFirst ; 36 //−−−−−−−−−−−−−−−−−−−−−−−−−−−− 37 38 L i q u i d C r y s t a l l c d (D2 , D3 , D4) ; 39 40 // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 41 42 void s e t u p ( ) { 43 lcd . initSPI () ; 45 46 C Código 44 // i n i t i a l i z e t h e SPI 45 // Must c a l l t h i s b e f o r e b e g i n ( ) 46 lcd . begin (16 , 2) ; 47 // s e t up t h e LCD ’ s number o f columns and rows : 48 49 pinMode ( Pin Relay , OUTPUT) ; 50 pinMode ( Pin ledRIGHT , OUTPUT) ; 51 pinMode ( Pin ledWRONG , OUTPUT) ; 52 53 a t t a c h I n t e r r u p t ( Pin buttonEXIT , interr Exit OPEN , CHANGE) ; 54 f o r ( k=0;k <4;k++){ 55 delay (500) ; 56 } 57 connectToMyServer ( ) ; 58 } 59 60 void l o o p ( ) { 61 62 interr Exit CLOSE ( ) ; 63 funtion printWelcome () ; 64 f l a g u s e r p a s s c o m p l e t e=f a l s e ; 65 i f ( ( v a r k e y p r e s s e d=f u n t i o n r e a d K e y b o a r d ( ) ) ==10){ 66 p r i n t F u n c t i o n ( 1 , 0 , 0 , ” I n g r e s e User ID ” , 0 ) ; 67 j =0; 68 while ( j<=v a r l o n g I D ) { //Read ID Number from user , 9 numbers 69 ok = true ; 70 v a r k e y p r e s s e d=f u n t i o n r e a d K e y b o a r d ( ) ; 71 i f ( ( v a r k e y p r e s s e d <v a r l o n g I D +1) && ( j <v a r l o n g I D ) ) { 72 s p r i n t f ( s t r i n g 1 , ” %d ” , v a r k e y p r e s s e d ) ; 73 // Composes a s t r i n g w i t h t h e same t e x t t h a t would 74 // be p r i n t e d i f f o r m a t was used on p r i n t f 75 // b u t i n s t e a d o f b e i n g p r i n t e d , t h e c o n t e n t 76 // i s s t o r e d as a C s t r i n g i n t h e b u f f e r p o i n t e d by string1 77 messageToSend+=s t r i n g 1 ; 78 p r i n t F u n c t i o n ( 0 , 0 , 1 , messageToSend , 5 0 ) ; 79 j ++; 80 } 81 i f ( j==v a r l o n g I D ) { 82 // I f t h e ID i s c o m p l e t e , i t i s c o n f i r m e d 83 // by t h e u s e r or i s d e l e t e d t o c o r r e c t 84 p r i n t F u n c t i o n ( 1 , 0 , 0 , ”User ” , 0 ) ; 85 p r i n t F u n c t i o n ( 0 , 5 , 0 , messageToSend , 9 0 0 ) ; 86 lcd . clear () ; 87 while ( ok ) { 88 v a r k e y p r e s s e d=f u n t i o n r e a d K e y b o a r d ( ) ; 89 p r i n t F u n c t i o n ( 1 , 0 , 0 , ”∗ Para Continuar ” , 0 ) ; 90 p r i n t F u n c t i o n ( 0 , 0 , 1 , ”# Para B o r r a r ” ,0) ; 91 i f ( v a r k e y p r e s s e d ==11){ 92 messageToSend = ” ” ; C Código 47 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 p r i n t F u n c t i o n ( 1 , 0 , 0 , ” I n g r e s e User ID ” , 0 ) ; j =0; ok=f a l s e ; } i f ( v a r k e y p r e s s e d ==10){ j ++; ok=f a l s e ; } } } } messageToSend+=” ; ” ; //Add t h e s e p a r a t o r printFunction (1 , 0 , 0 , ”Ingresar pass ” ,0) ; i =0; while ( i <var longPASS ) { //Read Pass Number from user , 4 numbers v a r k e y p r e s s e d=f u n t i o n r e a d K e y b o a r d ( ) ; i f ( v a r k e y p r e s s e d <10){ s p r i n t f ( s t r i n g 1 , ” %d ” , v a r k e y p r e s s e d ) ; messageToSend+=s t r i n g 1 ; p r i n t F u n c t i o n ( 0 , i , 1 , ”∗ ” , 5 0 ) ; i ++; } } //END GET USER/PASS i f ( messageToSend . l e n g t h ( ) ==(var longPASS+v a r l o n g I D +1) ) { f l a g u s e r p a s s c o m p l e t e=true ; } //SEND INFO TO SERVER i f ( c l i e n t . connected ( ) ) { i f ( messageToSend != ” ”) { l e n g t h=messageToSend . l e n g t h ( ) ; c l i e n t . w r i t e ( ( u i n t 8 t ∗ ) messageToSend . c s t r ( ) , l e n g t h +1) ; messageToSend=” ” ; } SERVERTimeFirst = m i l l i s ( ) ; while ( f l a g u s e r p a s s c o m p l e t e ) { SERVERTimeSecond = m i l l i s ( ) ; i f ( ( SERVERTimeSecond − SERVERTimeFirst ) > 5 0 0 0 ) { break ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; p r i n t F u n c t i o n ( 1 , 0 , 0 , ”SERVER” , 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”ERROR” , 9 0 0 ) ; } // R e c e i v i n g i n f o r m a t i o n from t h e s e r v e r i f ( c l i e n t . connected ( ) ) { // Gets a v a l u e i n d i c a t i n g w h e t h e r t h e u n d e r l y i n g Socket 48 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 C Código // f o r a T c p C l i e n t i s c o n n e c t e d t o a remote h o s t . True or f a l s e . p r i n t F u n c t i o n ( 1 , 0 , 0 , ”E spe r e . . . ” , 5 0 ) ; f u n t i o n b l i n k ( Pin ledRIGHT , 2 0 0 ) ; if ( client . available () ) { // Gets t h e amount o f d a t a t h a t has been r e c e i v e d from // t h e n e t w o r k and i s a v a i l a b l e t o be r e a d . char charANSWER = c l i e n t . r e a d ( ) ; // Reads t h e n e x t b y t e r e c e i v e d from t h e s e r v e r // t o which t h e c l i e n t i s c o n n e c t e d , and r e t u r n s t h e v a l u e i f (charANSWER==’ 1 ’ ) { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”Aceptado ” , 0 ) ; funtion openDOOR ( ) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; } else { i f (charANSWER==’ 0 ’ ) { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”Rechazado ” , 9 0 0 ) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; } else { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”SERVER” , 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”ERROR” , 9 0 0 ) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; } } } } // I f S e r v e r i s down , c h e c k t h e Super User else { f u n t i o n b l i n k ( Pin ledWRONG , 2 0 0 ) ; i f ( messageToSend==SUPERUSERR) { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”Super User ” , 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”ACEPTADO” , 5 0 0 ) ; funtion openDOOR ( ) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; messageToSend=” ” ; } else { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”Rechazado ” , 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”ERROR NO SERVER” , 9 0 0 ) ; delay (400) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; messageToSend=” ” ; } // Reconnect t o t h e s e r v e r connectToMyServer ( ) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; } } } e l s e { // I f S e r v e r i s down , c h e c k t h e Super User C Código 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 49 f u n t i o n b l i n k ( Pin ledWRONG , 2 0 0 ) ; // Reconnect t o t h e s e r v e r i f ( messageToSend==SUPERUSERR) { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”Super User ” , 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”ACEPTADO” , 6 0 0 ) ; funtion openDOOR ( ) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; messageToSend=” ” ; } else { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”Rechazado ” , 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”ERROR NO SERVER” , 9 0 0 ) ; delay (600) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; messageToSend=” ” ; } connectToMyServer ( ) ; f l a g u s e r p a s s c o m p l e t e=f a l s e ; } } } //END LOOP( ) // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ // Func tion t o c o n n e c t t o l o c a l s e r v e r TCP, // u s i n g IP/URL and a number o f p o r t void connectToMyServer ( /∗ S t r i n g i p ∗/ ) { i f ( c l i e n t . c o n n e c t ( serverURL , p o r t ) ) { // Connects t h e c l i e n t t o t h e s p e c i f i e d p o r t on t h e s p e c i f i e d h o s t . f u n t i o n b l i n k ( Pin ledRIGHT , 9 0 0 ) // I f S e r v e r i s up , D i s c o n n e c t Spark F u n c t i o n s Spark . d i s c o n n e c t ( ) ; } else { f u n t i o n b l i n k ( Pin ledWRONG , 9 0 0 ) Spark . c o n n e c t ( ) ; } delay (50) ; } void p r i n t F u n c t i o n ( in t I n t c l e a r , in t IntAxisX , in t IntAxisY , S t r i n g message , in t r e t r a s o ) { 235 // c l e a r , a x i s X, a x i s Y, Message , Delay 236 i f ( I n t c l e a r ==1){ 237 lcd . clear () ; 238 l c d . p r i n t ( message ) ; 50 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 C Código delay ( retraso ) ; } i f ( I n t c l e a r ==0){ l c d . s e t C u r s o r ( IntAxisX , IntAxisY ) ; l c d . p r i n t ( message ) ; delay ( retraso ) ; } } // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ void f u n t i o n p r i n t W e l c o m e ( ) { p r i n t F u n c t i o n ( 1 , 0 , 0 , ”P r o y e c t o EIE ” , 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”C o n t r o l Acceso ” , 900) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”∗ Para Continuar ” , 9 0 0 ) ; p r i n t F u n c t i o n ( 0 , 0 , 1 , ”C o n t r o l Acceso ” , 900) ; } // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ int funtion readKeyboard ( ) { i n t temp =12; i n t v a r k e y b o a r d V a l u e = 0 ; // v a l u e r e a d from t h e k e y b o a r d // −−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− v a r k e y b o a r d V a l u e = analogRead ( keyboardPin ) ; // r e a d t h e value delay (200) ; v a r k e y b o a r d V a l u e = in t ( v a r k e y b o a r d V a l u e ) ; i f ( var keyboardValue > 500) { if ( v a r k e y b o a r d V a l u e >=3700) {temp = 1 ; } i f ( ( v a r k e y b o a r d V a l u e >=3500) && ( v a r k e y b o a r d V a l u e 3 7 0 0 ) ) {temp = 2 ; } i f ( ( v a r k e y b o a r d V a l u e >=3200) && ( v a r k e y b o a r d V a l u e 3 5 0 0 ) ) {temp = 3 ; } i f ( ( v a r k e y b o a r d V a l u e >=3000) && ( v a r k e y b o a r d V a l u e 3 2 0 0 ) ) {temp = 4 ; } i f ( ( v a r k e y b o a r d V a l u e >=2500) && ( v a r k e y b o a r d V a l u e 3 0 0 0 ) ) {temp = 5 ; } i f ( ( v a r k e y b o a r d V a l u e >=2000) && ( v a r k e y b o a r d V a l u e 2 5 0 0 ) ) {temp = 6 ; } i f ( ( v a r k e y b o a r d V a l u e >=1500) && ( v a r k e y b o a r d V a l u e 2 0 0 0 ) ) {temp = 7 ; } i f ( ( v a r k e y b o a r d V a l u e >=1300) && ( v a r k e y b o a r d V a l u e 1 5 0 0 ) ) {temp = 1 0 ; } // A s t e r i s c o ∗ i f ( ( v a r k e y b o a r d V a l u e >=1100) && ( v a r k e y b o a r d V a l u e 1 3 0 0 ) ) {temp = 8 ; } i f ( ( v a r k e y b o a r d V a l u e >= 9 0 0 ) && ( v a r k e y b o a r d V a l u e 1 1 0 0 ) ) {temp = 0 ; } pot < < < < < < < < < C Código 277 i f ( ( v a r k e y b o a r d V a l u e >= 7 0 0 ) && ( v a r k e y b o a r d V a l u e < 9 0 0 ) ) {temp = 9 ; } i f ( ( v a r k e y b o a r d V a l u e > 5 0 0 ) && ( v a r k e y b o a r d V a l u e < 7 0 0 ) ) {temp = 1 1 ; } // Numeral # 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 } else { temp =12; } return temp ; } // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ void f u n t i o n b l i n k ( in t l e d , in t r e t r a s o ) { in t k ; i f ( r e t r a s o <255) { f o r ( k=0;k<r e t r a s o ; k++){ analogWrite ( led , k ) ; delay ( r e t r a s o /5) ; } f o r ( k=r e t r a s o ; k==0;k−−){ analogWrite ( led , k ) ; delay ( r e t r a s o /10) ; } analogWrite ( led , 0) ; } else { d i g i t a l W r i t e ( l e d , HIGH) ; delay ( retraso ) ; d i g i t a l W r i t e ( l e d , LOW) ; } } // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ void funtion openDOOR ( ) { // d i g i t a l W r i t e ( Pin Relay , HIGH) ; f o r ( k=0;k <10; k++){ //Time 5 s e c delay (500) ; } d i g i t a l W r i t e ( Pin Relay , LOW) ; } // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ void interr Exit OPEN ( ) { //Open t h e door , from i n s i d e d i g i t a l W r i t e ( Pin Relay , HIGH) ; } // ∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗∗ 51 52 326 327 void interr Exit CLOSE ( ) { 328 // C l o s e t h e door 329 d i g i t a l W r i t e ( Pin Relay , LOW) ; 330 } C Código D Librerı́a liquid-crystal-spi liquid-crystal-spi.h 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 #i f n d e f L i q u i d C r y s t a l S P I h #define L i q u i d C r y s t a l S P I h /∗ ∗ HARDWARE AND SOFTWARE LIQUIDCRYSTAL SPI ∗ 74HC595 LIBRARY FOR SPARK CORE ∗ ======================================================= ∗ Author : BDub ∗ Website : h t t p : / / t e c h n o b l y . com ∗ Date : Feb 24 t h 2014 ∗ ======================================================= ∗ h t t p s : / / g i t h u b . com/ t e c h n o b l y / SparkCore−L i q u i d C r y s t a l S P I ∗/ /∗ ========= INCLUDES ==================== ∗/ #include ” a p p l i c a t i o n . h ” /∗ ========= Arduino . h =================== ∗/ #define #define #define bit ) b i t S e t ( v a l u e , b i t ) ( ( v a l u e ) |= ( 1UL << ( b i t ) ) ) b i t C l e a r ( v a l u e , b i t ) ( ( v a l u e ) &= ˜ ( 1UL << ( b i t ) ) ) bitWrite ( value , bit , b i t v a l u e ) ( b i t v a l u e ? b i t S e t ( value , : b i t C l e a r ( value , b i t ) ) /∗ ========= L i q u i d C r y s t a l S P I . h ========== ∗/ // commands #define LCD CLEARDISPLAY 0 x01 #define LCD RETURNHOME 0 x02 #define LCD ENTRYMODESET 0 x04 #define LCD DISPLAYCONTROL 0 x08 #define LCD CURSORSHIFT 0 x10 #define LCD FUNCTIONSET 0 x20 #define LCD SETCGRAMADDR 0 x40 #define LCD SETDDRAMADDR 0 x80 // f l a g s f o r d i s p l a y e n t r y mode #define LCD ENTRYRIGHT 0 x00 #define LCD ENTRYLEFT 0 x02 #define LCD ENTRYSHIFTINCREMENT 0 x01 #define LCD ENTRYSHIFTDECREMENT 0 x00 53 54 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 D Librerı́a liquid-crystal-spi // f l a g s f o r d i s p l a y on/ o f f c o n t r o l #define LCD DISPLAYON 0 x04 #define LCD DISPLAYOFF 0 x00 #define LCD CURSORON 0 x02 #define LCD CURSOROFF 0 x00 #define LCD BLINKON 0 x01 #define LCD BLINKOFF 0 x00 // f l a g s f o r d i s p l a y / c u r s o r s h i f t #define LCD DISPLAYMOVE 0 x08 #define LCD CURSORMOVE 0 x00 #define LCD MOVERIGHT 0 x04 #define LCD MOVELEFT 0 x00 // f l a g s f o r f u n c t i o n s e t #define LCD 8BITMODE 0 x10 #define LCD 4BITMODE 0 x00 #define LCD 2LINE 0 x08 #define LCD 1LINE 0 x00 #define LCD 5x10DOTS 0 x04 #define LCD 5x8DOTS 0 x00 c l a s s L i q u i d C r y s t a l : public P r i n t { public : LiquidCrystal ( u i n t 8 t rs , u i n t 8 t enable , u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 , u i n t 8 t d4 , u i n t 8 t d5 , u i n t 8 t d6 , u i n t 8 t d7 ) ; L i q u i d C r y s t a l ( u i n t 8 t r s , u i n t 8 t rw , u i n t 8 t e n a b l e , u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 , u i n t 8 t d4 , u i n t 8 t d5 , u i n t 8 t d6 , u i n t 8 t d7 ) ; L i q u i d C r y s t a l ( u i n t 8 t r s , u i n t 8 t rw , u i n t 8 t e n a b l e , u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 ) ; LiquidCrystal ( u i n t 8 t rs , u i n t 8 t enable , u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 ) ; L i q u i d C r y s t a l ( u i n t 8 t s s , u i n t 8 t s c l k =255 , u i n t 8 t s d a t =255) ; // SPI t o S h i f t R e g i s t e r 74HC595 ########## void i n i t S P I ( void ) ; // SPI ################################## void i n i t ( u i n t 8 t f o u r b i t m o d e , u i n t 8 t r s , u i n t 8 t rw , u i n t 8 t enable , u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 , u i n t 8 t d4 , u i n t 8 t d5 , u i n t 8 t d6 , u i n t 8 t d7 , u i n t 8 t backlight ) ; void b e g i n ( u i n t 8 t c o l s , u i n t 8 t rows , u i n t 8 t c h a r s i z e = LCD 5x8DOTS) ; void c l e a r ( ) ; void home ( ) ; D Librerı́a liquid-crystal-spi 55 90 void n o D i s p l a y ( ) ; 91 void d i s p l a y ( ) ; 92 void n o B l i n k ( ) ; 93 void b l i n k ( ) ; 94 void noCursor ( ) ; 95 void c u r s o r ( ) ; 96 void s c r o l l D i s p l a y L e f t ( ) ; 97 void s c r o l l D i s p l a y R i g h t ( ) ; 98 void l e f t T o R i g h t ( ) ; 99 void r i g h t T o L e f t ( ) ; 100 void a u t o s c r o l l ( ) ; 101 void n o A u t o s c r o l l ( ) ; 102 void b a c k l i g h t ( ) ; 103 void n o B a c k l i g h t ( ) ; 104 105 void c r e a t e C h a r ( u i n t 8 t , u i n t 8 t [ ] ) ; 106 void s e t C u r s o r ( u i n t 8 t , u i n t 8 t ) ; 107 virtual s i z e t write ( u i n t 8 t ) ; 108 void command ( u i n t 8 t ) ; 109 private : 110 void send ( u i n t 8 t , u i n t 8 t ) ; 111 void spiSendOut ( ) ; // SPI 112 void w r i t e 4 b i t s ( u i n t 8 t ) ; 113 void w r i t e 8 b i t s ( u i n t 8 t ) ; 114 void p u l s e E n a b l e ( ) ; 115 void w r i t e S l o w ( u i n t 8 t ) ; 116 void w r i t e F a s t ( u i n t 8 t ) ; 117 118 uint8 t rs pin ; // LOW: command . HIGH : c h a r a c t e r . 119 uint8 t rw pin ; // LOW: w r i t e t o LCD. HIGH : r e a d from LCD. 120 uint8 t enable pin ; // a c t i v a t e d by a HIGH p u l s e . 121 u i n t 8 t b a c k l i g h t p i n ; // a c t i v a t e d by a HIGH p u l s e ( a d a f r u i t SPI/I2C LCD Backpack o n l y ) 122 uint8 t data pins [ 8 ] ; 123 124 // SPI 125 u i n t 8 t b a c k l i g h t ; // 1 = b a c k l i g h t on , 0 = b a c k l i g h t o f f 126 u i n t 8 t b i t S t r i n g ; // f o r SPI b i t 0=n o t used , b i t 1=RS , b i t 2=RW, b i t 3=Enable , b i t s 4 −7 = DB4−7 127 bool u s i n g S p i ; // t o l e t send and w r i t e f u n c t i o n s know we a r e u s i n g SPI 128 bool softSpi ; // t o l e t send and w r i t e f u n c t i o n s know we a r e u s i n g SPI 129 uint8 t latchPin ; 130 uint8 t sclkPin ; 131 uint8 t sdatPin ; 132 uint8 t clockDivider ; 133 u i n t 8 t dataMode ; 134 u i n t 8 t b i t O r d e r ; // SPI 135 56 D Librerı́a liquid-crystal-spi 136 uint8 137 uint8 138 uint8 139 140 uint8 141 142 uint8 143 } ; 144 145 #endif t t t displayfunction ; displaycontrol ; displaymode ; t initialized ; t numlines , c u r r l i n e ; liquid-crystal-spi.cpp 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 /∗ ∗ HARDWARE AND SOFTWARE LIQUIDCRYSTAL SPI ∗ 74HC595 LIBRARY FOR SPARK CORE ∗ ========================== ∗ Author : BDub ∗ W ebsite : h t t p : / / t e c h n o b l y . com ∗ Date : Feb 24 t h 2014 ∗ ============================ ∗ h t t p s : / / g i t h u b . com/ t e c h n o b l y / SparkCore−L i q u i d C r y s t a l S P I ∗/ // // // // // // // // // // // // // // // // When t h e d i s p l a y powers up , i t i s c o n f i g u r e d as f o l l o w s : 1. Display clear 2 . F un ction s e t : DL = 1 ; 8− b i t i n t e r f a c e d a t a N = 0 ; 1− l i n e d i s p l a y F = 0 ; 5 x8 d o t c h a r a c t e r f o n t 3 . D i s p l a y on/ o f f c o n t r o l : D = 0; Display o f f C = 0 ; Cursor o f f B = 0; Blinking o f f 4 . Entry mode s e t : I /D = 1 ; Increment by 1 S = 0 ; No s h i f t Note , however , t h a t r e s e t t i n g t h e Arduino doesn ’ t r e s e t t h e LCD , so we 28 // can ’ t assume t h a t i t s i n t h a t s t a t e when a s k e t c h s t a r t s ( and the 29 // L i q u i d C r y s t a l c o n s t r u c t o r i s c a l l e d ) . 30 31 /∗ ========= INCLUDES ==================== ∗/ 32 33 #include ” l i q u i d −c r y s t a l −s p i . h ” 34 35 /∗ ========= L i q u i d C r y s t a l S P I . cpp ======== ∗/ 36 D Librerı́a liquid-crystal-spi 57 37 L i q u i d C r y s t a l : : L i q u i d C r y s t a l ( u i n t 8 t r s , u i n t 8 t rw , u i n t 8 t enable , 38 u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 , 39 u i n t 8 t d4 , u i n t 8 t d5 , u i n t 8 t d6 , u i n t 8 t d7 ) 40 { 41 i n i t ( 0 , r s , rw , e n a b l e , d0 , d1 , d2 , d3 , d4 , d5 , d6 , d7 , 2 5 5 ) ; 42 } 43 44 L i q u i d C r y s t a l : : L i q u i d C r y s t a l ( u i n t 8 t r s , u i n t 8 t e n a b l e , 45 u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 , 46 u i n t 8 t d4 , u i n t 8 t d5 , u i n t 8 t d6 , u i n t 8 t d7 ) 47 { 48 i n i t ( 0 , r s , 2 5 5 , e n a b l e , d0 , d1 , d2 , d3 , d4 , d5 , d6 , d7 , 2 5 5 ) ; 49 } 50 51 L i q u i d C r y s t a l : : L i q u i d C r y s t a l ( u i n t 8 t r s , u i n t 8 t rw , u i n t 8 t enable , 52 u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 ) 53 { 54 i n i t ( 1 , r s , rw , e n a b l e , d0 , d1 , d2 , d3 , 0 , 0 , 0 , 0 , 2 5 5 ) ; 55 } 56 57 L i q u i d C r y s t a l : : L i q u i d C r y s t a l ( u i n t 8 t r s , u i n t 8 t enable , 58 u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 ) 59 { 60 i n i t ( 1 , r s , 2 5 5 , e n a b l e , d0 , d1 , d2 , d3 , 0 , 0 , 0 , 0 , 2 5 5 ) ; 61 } 62 63 L i q u i d C r y s t a l : : L i q u i d C r y s t a l ( u i n t 8 t s s , u i n t 8 t s c l k , u i n t 8 t s d a t ) // SPI 64 { 65 latchPin = ss ; 66 s o f t S p i = f a l s e ; // assume we a r e u s i n g hardware SPI 67 i f ( s c l k != 255 && s d a t != 2 5 5 ) { 68 s o f t S p i = true ; // on se c on d t h o u g h t , l e t ’ s u s e s o f t w a r e SPI 69 } 70 sclkPin = sclk ; 71 sdatPin = sdat ; 72 73 /∗ 74 initSPI ( ssPin ) ; 75 // s h i f t R e g i s t e r p i n s 1 , 2 , 3 , 4 , 5 , 6 , 7 r e p r e s e n t rs , rw , e n a b l e , d4 −7 i n t h a t o r d e r 76 // b u t we a r e n ot u s i n g RW so RW i t ’ s z e r o or 255 77 i n i t ( 1 , 1 , 255 , 3 , 0 , 0 , 0 , 0 , 4 , 5 , 6 , 7 , 255) ; 78 ∗/ 79 } 80 81 void L i q u i d C r y s t a l : : i n i t S P I ( void ) // SPI 82 { 83 // i n i t i a l i z e SPI : 58 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 D Librerı́a liquid-crystal-spi u s i n g S p i = true ; pinMode ( l a t c h P i n , OUTPUT) ; // s e t u p and s o f t w a r e SPI d i g i t a l W r i t e ( l a t c h P i n , HIGH) ; // I f we ’ r e u s i n g s o f t w a r e SPI , s e t u p t h e c l o c k and d a t a p i n s . if ( softSpi ) { pinMode ( s c l k P i n , OUTPUT) ; pinMode ( s d a t P i n , OUTPUT) ; d i g i t a l W r i t e ( s c l k P i n , LOW) ; d i g i t a l W r i t e ( s d a t P i n , LOW) ; } e l s e { // E l s e s e t up t h e hardware SPI SPI . b e g i n ( ) ; // c l o c k D i v i d e r = SPI CLOCK DIV4 ; // 72MHz / 4 = 18MHz ( works b u t t a k e s j u s t as l o n g as 9MHz) c l o c k D i v i d e r = SPI CLOCK DIV8 ; // 72MHz / 8 = 9MHz ( R e a l l y i s a b o u t t w i c e as f a s t as 4 . 5MHz) // c l o c k D i v i d e r = SPI CLOCK DIV16 ; // 72MHz / 16 = 4 . 5MHz SPI . s e t C l o c k D i v i d e r ( c l o c k D i v i d e r ) ; // FYI : S o f t w a r e SPI i s a b o u t t h e same s p e e d as SPI CLOCK DIV8 ! :) 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 l a t c h P i n used i n hardware // S e t d a t a mode t o SPI MODE0 by d e f a u l t dataMode = SPI MODE0 ; SPI . setDataMode ( dataMode ) ; // S e t b i t O r d e r t o MSBFIRST by d e f a u l t b i t O r d e r = MSBFIRST ; SPI . s e t B i t O r d e r ( b i t O r d e r ) ; } // A d a f r u i t SPI/I2C LCD Backpack or D i s c r e t e hookup t o 74HC595 // p i n s r e p r e s e n t : f o u r b i t m o d e , rs , rw , e n a b l e , d0 , d1 , d2 , d3 , d4 , d5 , d6 , d7 , b a c k l i g h t i n i t (1 , 1 , 255 , 2 , 0 , 0 , 0 , 0 , 6 , 5 , 4 , 3 , 7) ; 116 117 } 118 119 void L i q u i d C r y s t a l : : i n i t ( u i n t 8 t f o u r b i t m o d e , u i n t 8 t r s , u i n t 8 t rw , u i n t 8 t e n a b l e , 120 u i n t 8 t d0 , u i n t 8 t d1 , u i n t 8 t d2 , u i n t 8 t d3 , 121 u i n t 8 t d4 , u i n t 8 t d5 , u i n t 8 t d6 , u i n t 8 t d7 , u i n t 8 t backlight ) 122 { 123 rs pin = rs ; 124 r w p i n = rw ; 125 enable pin = enable ; 126 backlight pin = backlight ; 127 b a c k l i g h t = 0 ; // o f f by d e f a u l t D Librerı́a liquid-crystal-spi 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 data data data data data data data data pins pins pins pins pins pins pins pins [0] [1] [2] [3] [4] [5] [6] [7] = = = = = = = = 59 d0 ; d1 ; d2 ; d3 ; d4 ; d5 ; d6 ; d7 ; pinMode ( r s p i n , OUTPUT) ; // we can s a v e 1 p i n by n o t u s i n g RW. I n d i c a t e by p a s s i n g 255 i n s t e a d o f p i n# i f ( r w p i n != 2 5 5 ) { pinMode ( r w p i n , OUTPUT) ; } pinMode ( e n a b l e p i n , OUTPUT) ; // Always 4− b i t mode , don ’ t w a s t e p i n s ! // // i f ( f o u r b i t m o d e ) d i s p l a y f u n c t i o n = LCD 4BITMODE | LCD 1LINE | LCD 5x8DOTS ; // e l s e // d i s p l a y f u n c t i o n = LCD 8BITMODE | LCD 1LINE | LCD 5x8DOTS ; // b e g i n ( 1 6 , 2) ; // commented out , make s u r e you c a l l t h i s i n code ! // s i n c e i n i n i t S P I c o n s t r u c t o r we s e t u s i n g S P I t o t r u e and we run i t f i r s t // from SPI c o n s t r u c t o r , we do n o t h i n g h e r e o t h e r w i s e we s e t i t to f a l s e i f ( u s i n g S p i ) // SPI { ; } else { usingSpi = false ; } 156 157 158 159 160 161 162 163 164 } 165 166 void L i q u i d C r y s t a l : : b e g i n ( u i n t 8 t c o l s , u i n t 8 t l i n e s , u i n t 8 t dotsize ) { 167 i f ( l i n e s > 1) { 168 d i s p l a y f u n c t i o n |= LCD 2LINE ; 169 } 170 numlines = l i n e s ; 171 currline = 0; 172 173 // f o r some 1 l i n e d i s p l a y s you can s e l e c t a 10 p i x e l h i g h f o n t 60 i f ( ( d o t s i z e != 0 ) && ( l i n e s == 1 ) ) { d i s p l a y f u n c t i o n |= LCD 5x10DOTS ; } 174 175 176 177 178 179 // SEE PAGE 45/46 FOR INITIALIZATION SPECIFICATION ! // a c c o r d i n g t o d a t a s h e e t , we need a t l e a s t 40ms a f t e r power r i s e s a b o v e 2 . 7V // b e f o r e s e n d i n g commands . Arduino can t u r n on way b e f e r 4 . 5V so we ’ l l w a i t 50 delayMicroseconds (50000) ; // Now we p u l l b o t h RS and R/W low t o b e g i n commands d i g i t a l W r i t e ( r s p i n , LOW) ; d i g i t a l W r i t e ( e n a b l e p i n , LOW) ; i f ( r w p i n != 2 5 5 ) { d i g i t a l W r i t e ( r w p i n , LOW) ; } 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 // 4−B i t i n i t i a l i z a t i o n s e q u e n c e from Te c hn o bl y w r i t e 4 b i t s ( 0 x03 ) ; // Put b a c k i n t o 8− b i t mode delayMicroseconds (5000) ; w r i t e 4 b i t s ( 0 x08 ) ; delayMicroseconds (5000) ; // Comment t h i s o u t f o r V1 OLED // Comment t h i s o u t f o r V1 OLED w r i t e 4 b i t s ( 0 x02 ) ; delayMicroseconds (5000) ; w r i t e 4 b i t s ( 0 x02 ) ; delayMicroseconds (5000) ; w r i t e 4 b i t s ( 0 x08 ) ; delayMicroseconds (5000) ; // Put i n t o 4− b i t mode command (LCD DISPLAYCONTROL) ; delayMicroseconds (5000) ; command (LCD FUNCTIONSET | d i s p l a y f u n c t i o n ) ; font size , etc . delayMicroseconds (5000) ; clear () ; command (LCD ENTRYMODESET | LCD ENTRYLEFT) ; delayMicroseconds (5000) ; home ( ) ; delayMicroseconds (5000) ; command (LCD DISPLAYCONTROL | LCD DISPLAYON) ; enable cursor & b l i n k delayMicroseconds (5000) ; 206 207 208 209 210 211 212 213 214 215 216 217 218 219 D Librerı́a liquid-crystal-spi // Turn O f f // S e t # l i n e s , // C l e a r D i s p l a y // S e t Entry Mode // Home Cursor // Turn On − } /∗ ∗∗∗∗∗∗∗∗∗ h i g h l e v e l commands , f o r t h e u s e r ! ∗/ void L i q u i d C r y s t a l : : c l e a r ( ) { command (LCD CLEARDISPLAY) ; // c l e a r d i s p l a y , s e t c u r s o r position to zero D Librerı́a liquid-crystal-spi 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 delayMicroseconds (5000) ; 61 // t h i s command t a k e s a l o n g time ! } void L i q u i d C r y s t a l : : home ( ) { command (LCD RETURNHOME) ; delayMicroseconds (5000) ; } // s e t c u r s o r p o s i t i o n t o z e r o // t h i s command t a k e s a l o n g time ! void L i q u i d C r y s t a l : : s e t C u r s o r ( u i n t 8 t c o l , u i n t 8 t row ) { in t r o w o f f s e t s [ ] = { 0 x00 , 0 x40 , 0 x14 , 0 x54 } ; i f ( row > n u m l i n e s ) { row = n u m l i n e s −1; // we c o u n t rows s t a r t i n g w/0 } command (LCD SETDDRAMADDR | ( c o l + r o w o f f s e t s [ row ] ) ) ; } // Turn t h e d i s p l a y on/ o f f ( q u i c k l y ) void L i q u i d C r y s t a l : : n o D i s p l a y ( ) { d i s p l a y c o n t r o l &= ˜LCD DISPLAYON ; command (LCD DISPLAYCONTROL | d i s p l a y c o n t r o l ) ; } void L i q u i d C r y s t a l : : d i s p l a y ( ) { d i s p l a y c o n t r o l |= LCD DISPLAYON ; command (LCD DISPLAYCONTROL | d i s p l a y c o n t r o l ) ; } // Turns t h e u n d e r l i n e c u r s o r on/ o f f void L i q u i d C r y s t a l : : noCursor ( ) { d i s p l a y c o n t r o l &= ˜LCD CURSORON; command (LCD DISPLAYCONTROL | d i s p l a y c o n t r o l ) ; } void L i q u i d C r y s t a l : : c u r s o r ( ) { d i s p l a y c o n t r o l |= LCD CURSORON; command (LCD DISPLAYCONTROL | d i s p l a y c o n t r o l ) ; } // Turn on and o f f t h e b l i n k i n g c u r s o r void L i q u i d C r y s t a l : : n o B l i n k ( ) { d i s p l a y c o n t r o l &= ˜LCD BLINKON ; command (LCD DISPLAYCONTROL | d i s p l a y c o n t r o l ) ; } void L i q u i d C r y s t a l : : b l i n k ( ) { d i s p l a y c o n t r o l |= LCD BLINKON ; command (LCD DISPLAYCONTROL | d i s p l a y c o n t r o l ) ; } // These commands s c r o l l t h e d i s p l a y w i t h o u t c h a n g i n g t h e RAM void L i q u i d C r y s t a l : : s c r o l l D i s p l a y L e f t ( void ) { 62 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 D Librerı́a liquid-crystal-spi command (LCD CURSORSHIFT | LCD DISPLAYMOVE | LCD MOVELEFT) ; } void L i q u i d C r y s t a l : : s c r o l l D i s p l a y R i g h t ( void ) { command (LCD CURSORSHIFT | LCD DISPLAYMOVE | LCD MOVERIGHT) ; } // This i s f o r t e x t t h a t f l o w s L e f t t o R i g h t void L i q u i d C r y s t a l : : l e f t T o R i g h t ( void ) { d i s p l a y m o d e |= LCD ENTRYLEFT; command (LCD ENTRYMODESET | d i s p l a y m o d e ) ; } // This i s f o r t e x t t h a t f l o w s R i g h t t o L e f t void L i q u i d C r y s t a l : : r i g h t T o L e f t ( void ) { d i s p l a y m o d e &= ˜LCD ENTRYLEFT; command (LCD ENTRYMODESET | d i s p l a y m o d e ) ; } // This w i l l ’ r i g h t j u s t i f y ’ t e x t from t h e c u r s o r void L i q u i d C r y s t a l : : a u t o s c r o l l ( void ) { d i s p l a y m o d e |= LCD ENTRYSHIFTINCREMENT; command (LCD ENTRYMODESET | d i s p l a y m o d e ) ; } // This w i l l ’ l e f t j u s t i f y ’ t e x t from t h e c u r s o r void L i q u i d C r y s t a l : : n o A u t o s c r o l l ( void ) { d i s p l a y m o d e &= ˜LCD ENTRYSHIFTINCREMENT; command (LCD ENTRYMODESET | d i s p l a y m o d e ) ; } // A l l o w s us t o f i l l t h e f i r s t 8 CGRAM l o c a t i o n s // w i t h custom c h a r a c t e r s void L i q u i d C r y s t a l : : c r e a t e C h a r ( u i n t 8 t l o c a t i o n , u i n t 8 t charmap []) { l o c a t i o n &= 0 x7 ; // we o n l y have 8 l o c a t i o n s 0−7 command (LCD SETCGRAMADDR | ( l o c a t i o n << 3 ) ) ; f o r ( in t i =0; i <8; i ++) { w r i t e ( charmap [ i ] ) ; } } // Turn t h e b a c k l i g h t on/ o f f // B a c k l i g h t w i l l t u r n on or o f f i m m e d i a t e l y void L i q u i d C r y s t a l : : b a c k l i g h t ( void ) { backlight = 1; // add t h e b a c k l i g h t b i t on a l l t r a n s f e r s bitWrite ( b i t S t r i n g , b a c k l i g h t p i n , 1) ; // and send i t o u t spiSendOut ( ) ; } void L i q u i d C r y s t a l : : n o B a c k l i g h t ( void ) { D Librerı́a liquid-crystal-spi 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 63 backlight = 0; // add t h e b a c k l i g h t b i t on a l l t r a n s f e r s bitWrite ( b i t S t r i n g , b a c k l i g h t p i n , 0) ; // and send i t o u t spiSendOut ( ) ; } /∗ ∗∗∗∗∗∗∗∗∗∗ mid l e v e l commands , f o r s e n d i n g d a t a /cmds ∗/ i n l i n e void L i q u i d C r y s t a l : : command ( u i n t 8 t v a l u e ) { send ( v a l u e , LOW) ; } inline s i z e t LiquidCrystal : : write ( uint8 t value ) { send ( v a l u e , HIGH) ; return 1 ; // assume s u c e s s } /∗ ∗∗∗∗∗∗∗∗∗∗∗ low l e v e l d a t a p u s h i n g commands ∗∗∗∗∗∗∗∗∗ ∗/ // w r i t e e i t h e r command or data , w i t h a u t o m a t i c 4/8− b i t s e l e c t i o n void L i q u i d C r y s t a l : : send ( u i n t 8 t v a l u e , u i n t 8 t mode ) { i f ( u s i n g S p i == f a l s e ) { d i g i t a l W r i t e ( r s p i n , mode ) ; // i f t h e r e i s a RW p i n i n d i c a t e d , s e t i t low t o Write i f ( r w p i n != 2 5 5 ) { d i g i t a l W r i t e ( r w p i n , LOW) ; } i f ( d i s p l a y f u n c t i o n & LCD 8BITMODE) { w r i t e 8 b i t s ( value ) ; } else { w r i t e 4 b i t s ( v a l u e >>4) ; w r i t e 4 b i t s ( value ) ; } } e l s e //we u s e SPI { bitWrite ( bitString , spiSendOut ( ) ; r s p i n , mode ) ; // s e t RS t o mode // we a r e n o t u s i n g RW w i t h SPI so we a r e n o t even b o t h e r i n g // or 8BITMODE so we go s t r a i g h t t o w r i t e 4 b i t s w r i t e 4 b i t s ( v a l u e >>4) ; w r i t e 4 b i t s ( value ) ; } } void L i q u i d C r y s t a l : : p u l s e E n a b l e ( void ) { 64 D Librerı́a liquid-crystal-spi 372 i f ( u s i n g S p i == f a l s e ) 373 { 374 d i g i t a l W r i t e ( e n a b l e p i n , LOW) ; 375 delayMicroseconds (1) ; 376 d i g i t a l W r i t e ( e n a b l e p i n , HIGH) ; 377 delayMicroseconds (1) ; // e n a b l e p u l s e must be >450ns 378 d i g i t a l W r i t e ( e n a b l e p i n , LOW) ; 379 delayMicroseconds (100) ; // commands need > 37 us t o s e t t l e 380 } 381 e l s e //we u s e SPI 382 { 383 b i t W r i t e ( b i t S t r i n g , e n a b l e p i n , LOW) ; 384 spiSendOut ( ) ; 385 delayMicroseconds (1) ; 386 b i t W r i t e ( b i t S t r i n g , e n a b l e p i n , HIGH) ; 387 spiSendOut ( ) ; 388 delayMicroseconds (1) ; // e n a b l e p u l s e must be >450ns 389 b i t W r i t e ( b i t S t r i n g , e n a b l e p i n , LOW) ; 390 spiSendOut ( ) ; 391 delayMicroseconds (40) ; // commands need > 37 us t o s e t t l e 392 } 393 } 394 395 void L i q u i d C r y s t a l : : w r i t e 4 b i t s ( u i n t 8 t v a l u e ) { 396 i f ( u s i n g S p i == f a l s e ) 397 { 398 f o r ( in t i = 0 ; i < 4 ; i ++) { 399 pinMode ( d a t a p i n s [ i ] , OUTPUT) ; 400 d i g i t a l W r i t e ( d a t a p i n s [ i ] , ( v a l u e >> i ) & 0 x01 ) ; 401 } 402 } 403 e l s e //we u s e SPI 404 { 405 f o r ( in t i = 4 ; i < 8 ; i ++) { 406 //we p u t t h e f o u r b i t s i n t o t h e b i t S t r i n g 407 b i t W r i t e ( b i t S t r i n g , d a t a p i n s [ i ] , ( ( v a l u e >> ( i − 4 ) ) & 0 x01 ) ) ; 408 } 409 // add t h e b a c k l i g h t b i t on a l l t r a n s f e r s 410 b i t W r i t e ( b i t S t r i n g , b a c k l i g h t p i n , ( b a c k l i g h t & 0 x01 ) ) ; 411 412 // and send i t o u t 413 spiSendOut ( ) ; 414 } 415 pulseEnable () ; 416 } 417 418 void L i q u i d C r y s t a l : : w r i t e 8 b i t s ( u i n t 8 t v a l u e ) { 419 f o r ( in t i = 0 ; i < 8 ; i ++) { 420 pinMode ( d a t a p i n s [ i ] , OUTPUT) ; 421 d i g i t a l W r i t e ( d a t a p i n s [ i ] , ( v a l u e >> i ) & 0 x01 ) ; D Librerı́a liquid-crystal-spi 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 65 } pulseEnable () ; } void L i q u i d C r y s t a l : : spiSendOut ( ) // SPI { if ( softSpi ) { writeFast ( bitString ) ; } else { d i g i t a l W r i t e ( l a t c h P i n , LOW) ; SPI . t r a n s f e r ( b i t S t r i n g ) ; d i g i t a l W r i t e ( l a t c h P i n , HIGH) ; } } void L i q u i d C r y s t a l : : w r i t e S l o w ( u i n t 8 t v a l u e ) { d i g i t a l W r i t e ( l a t c h P i n , LOW) ; s h i f t O u t ( s d a t P i n , s c l k P i n , MSBFIRST, v a l u e ) ; d i g i t a l W r i t e ( l a t c h P i n , HIGH) ; } i n l i n e void L i q u i d C r y s t a l : : w r i t e F a s t ( u i n t 8 t v a l u e ) { PIN MAP [ l a t c h P i n ] . g p i o p e r i p h e r a l −>BRR = PIN MAP [ l a t c h P i n ] . g p i o p i n ; // Latch Low f o r ( u i n t 8 t i = 0 ; i < 8 ; i ++) { i f ( v a l u e & ( 1 << (7− i ) ) ) { // w a l k s down mask from b i t 7 t o bit 0 PIN MAP [ s d a t P i n ] . g p i o p e r i p h e r a l −>BSRR = PIN MAP [ s d a t P i n ] . g p i o p i n ; // Data High } else { PIN MAP [ s d a t P i n ] . g p i o p e r i p h e r a l −>BRR = PIN MAP [ s d a t P i n ] . g p i o p i n ; // Data Low } asm v o l a t i l e ( ”mov r0 , r 0 ” ”\n\ t ” ”nop ” ”\n\ t ” ”nop ” ”\n\ t ” ” nop ” ”\n\ t ” : : : ”r 0 ” , ”c c ” , ”memory ”) ; PIN MAP [ s c l k P i n ] . g p i o p e r i p h e r a l −>BSRR = PIN MAP [ s c l k P i n ] . g p i o p i n ; // C l o c k High ( Data S h i f t e d In ) asm v o l a t i l e ( ”mov r0 , r 0 ” ”\n\ t ” ”nop ” ”\n\ t ” ”nop ” ”\n\ t ” ” nop ” ”\n\ t ” : : : ”r 0 ” , ”c c ” , ”memory ”) ; PIN MAP [ s c l k P i n ] . g p i o p e r i p h e r a l −>BRR = PIN MAP [ s c l k P i n ] . g p i o p i n ; // C l o c k Low } asm v o l a t i l e ( ”mov r0 , r 0 ” ”\n\ t ” ”nop ” ”\n\ t ” ”nop ” ”\n\ t ” ”nop ” ”\n\ t ” : : : ”r 0 ” , ”c c ” , ”memory ”) ; PIN MAP [ l a t c h P i n ] . g p i o p e r i p h e r a l −>BSRR = PIN MAP [ l a t c h P i n ] . g p i o p i n ; // Latch High ( Data L a t c h e d ) }