Universidad de Costa Rica Facultad de Ingenierı́a Escuela de Ingenierı́a Eléctrica Controlador lógico con enlace Wi-Fi para acceso remoto desde dispositivos iOS Por: Ileine Solano Ocampo Ciudad Universitaria “Rodrigo Facio”, Costa Rica Julio del 2013 Controlador lógico con enlace Wi-Fi para acceso remoto desde dispositivos iOS Por: Ileine Solano Ocampo IE-0499 Proyecto eléctrico Aprobado por el Tribunal: Ing. Geovanny Delgado M.Sc.E.E. Profesor guı́a Ing. Marco Antonio Vásquez M.Sc. Profesor lector Ing. Juan Ramón Rodrı́guez Profesor lector Resumen El proyecto presentado consiste en el desarrollo de un dispositivo controlador, el cual pueda ser accesado de forma remota por medio de una red IEEE 802.11 y a través de un dispositivo iOS. Para esto, se hizo uso de un microcontrolador HCS12 de Freescale, y de un módulo llamado Xbee Wi-Fi el cual se comunica por medio de una comunicación serial con el microcontrolador. De esta forma se logra la conexión del microcontrolador a una red Wi-Fi. Todo esto se realizó con una tarjeta de desarrollo llamada Dragon12-Plus2 como plataforma de hardware. Se presentan los procesos seguidos para el desarrollo de la aplicación de comunicación. En donde se explican los procedimientos utilizados para realizar el manejo del bloque de comunicación serial asincrónica del microcontrolador, de modo que se realice una comunicación efectiva entre el microcontrolador y el módulo Xbee Wi-Fi. Sumado al lograr enviar y recibir datos del módulo Xbee Wi-Fi, también es posible darle instrucciones al módulo gracias a las rutinas implementadas. Con la comunicación lograda, se realizaron rutinas de control lógico de entradas y salidas por medio de instrucciones remotas. De este modo, por medio de una aplicación en un dispositivo iOS, fue posible realizar el control de encendido y apagado de 8 LEDs. Además de esto, se implementó un sistema alterno de control de los LEDs por medio de botones pulsadores. Estos botones se encuentran en una configuración matricial 4x4 conectada al puerto A, la cual se controló por medio del bloque RTI. Y por último, se habilitó un botón pulsador, conectado al puerto H, el cual se encarga de realizar la asociación del módulo Xbee Wi-Fi a un Access Point. Una vez lograda la comunicación entre el dispositivo controlador y un dispositivo móvil (en este caso un dispositivo iOS), es posible realizar diferentes acciones de control. El alcance del proyecto fue realizar la comunicación y sentar las bases para las rutinas de control lógico de entradas y salidas. Con estas bases, es posible implementar en futuros proyectos un sistema de domótica que permita controlar, por ejemplo la iluminación de un hogar, desde un dispositivo móvil. iii Índice general Índice de figuras vii Índice de cuadros ix Nomenclatura x 1 Introducción 1 1.1 Objetivos . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1.2 Metodologı́a . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 2 1.3 Cronograma . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3 2 Marco Teórico 4 2.1 El microcontrolador MC9S12DG256 . . . . . . . . . . . . . . . 4 2.2 La herramienta de programación CodeWarrior IDE . . . . . . . 6 2.3 La plataforma de hardware Dragon12-Plus2 . . . . . . . . . . . 7 2.4 Módulo Xbee Wi-Fi . . . . . . . . . . . . . . . . . . . . . . . . 8 3 Diseño de la aplicación 10 3.1 Manejo del SCI del 68HCS12 . . . . . . . . . . . . . . . . . . . 11 3.2 Manejo del módulo Xbee Wi-Fi . . . . . . . . . . . . . . . . . . 19 3.3 Manejo de los periféricos . . . . . . . . . . . . . . . . . . . . . . 28 3.4 Etapa de Inicialización . . . . . . . . . . . . . . . . . . . . . . . 37 3.5 El programa principal . . . . . . . . . . . . . . . . . . . . . . . 47 3.6 La aplicación para los dispositivos iOS . . . . . . . . . . . . . . 47 4 Pruebas y Resultados 50 4.1 Prueba del manejo del SCI del 68HCS12 . . . . . . . . . . . . . 50 4.2 Prueba del manejo de los periféricos . . . . . . . . . . . . . . . 52 4.3 Prueba del programa principal . . . . . . . . . . . . . . . . . . 54 4.4 La aplicación para los dispositivos iOS . . . . . . . . . . . . . . 54 iv 5 Conclusiones y Recomendaciones 58 Bibliografı́a 61 A Microcontrolador MC9S12DG256 62 B SCI del MC9S12DG256 67 C CRG del MC9S12DG256 70 D Puerto H del MC9S12DG256 72 E RTI del MC9S12DG256 74 F Proceso de desarrollo de CodeWarrior 76 G Dragon12-Plus2 78 H Pines del Xbee 81 I 82 Comandos AT del Xbee J API Frames del Xbee Wi-Fi 87 K Comparación Xbee - WiFly 90 L Código en C de las rutinas implementadas para pruebas 92 L.1 Rutina de prueba para el bloque SCI . . . . . . . . . . . . . . . M Código en C de las rutinas implementadas 92 94 M.1 Rutina de inicialización del bloque SCI . . . . . . . . . . . . . . 94 M.2 Rutina de atención de interrupciones del bloque SCI . . . . . . 95 M.3 Rutina de manejo de datos recibidos por el bloque SCI . . . . . 96 M.4 Rutina de manejo de datos transmitidos por el bloque SCI . . . 96 M.5 Rutina de transmisión de tramas del Xbee . . . . . . . . . . . . 97 M.6 Rutinas de envı́o de comandos al Xbee . . . . . . . . . . . . . . 98 M.7 Rutina de recepción de tramas . . . . . . . . . . . . . . . . . . 100 M.8 Rutina de inicialización del módulo Xbee WiFi . . . . . . . . . 103 M.9 Rutina de verificación de la asociación del módulo Xbee WiFi . 105 v M.10 Rutina para revisar la suma de verificación . . . . . . . . . . . 106 M.11 Rutina de inicialización del Puerto H . . . . . . . . . . . . . . . 106 M.12 Rutina de atención de interrupciones del Puerto H . . . . . . . 107 M.13 Rutina de inicialización del Puerto A . . . . . . . . . . . . . . . 107 M.14 Rutina de reconocimiento de teclas presionadas . . . . . . . . . 108 M.15 Rutina de ejecución de acciones de acuerdo a la tecla presionada 109 M.16 Rutina de manejo del teclado conectado al Puerto A . . . . . . 109 M.17 Rutina de inicialización del bloque RTI . . . . . . . . . . . . . . 110 M.18 Rutina de atención de interrupciones del bloque RTI . . . . . . 111 M.19 Rutina de inicialización del PLL . . . . . . . . . . . . . . . . . 111 M.20 Programa principal . . . . . . . . . . . . . . . . . . . . . . . . . 112 vi Índice de figuras 3.1 Diagrama de bloques de la aplicación . . . . . . . . . . . . . . . . . 10 3.2 Diagrama del ”buffer”de transmisión . . . . . . . . . . . . . . . . . 12 3.3 Diagrama del ”buffer”de recepción . . . . . . . . . . . . . . . . . . 12 3.4 Diagrama de flujo de la rutina SCI1_isr . . . . . . . . . . . . . . . 14 3.5 Diagrama de flujo de la rutina SCI1_InChar . . . . . . . . . . . . . 16 3.6 Diagrama de flujo de la rutina SCI1_OutChar . . . . . . . . . . . . 18 3.7 Estructura básica de una trama API . . . . . . . . . . . . . . . . . 19 3.8 Estructura básica de una trama API TxIPv4 . . . . . . . . . . . . 20 3.9 Diagrama de flujo de la rutina Xbee_TxIPv4 . . . . . . . . . . . . . 22 3.10 Estructura básica de una trama API AT Command . . . . . . . . 23 3.11 Diagrama de flujo de la rutina Xbee_ATCommand . . . . . . . . . . . 24 3.12 Diagrama de flujo de la rutina Xbee_ATCommandStr . . . . . . . . . 25 3.13 Estructura básica de una trama API RxIPv4 . . . . . . . . . . . . 26 3.14 Estructura básica de una trama API AT Command Response . . . 26 3.15 Diagrama de flujo de la rutina Xbee_Rx . . . . . . . . . . . . . . . 27 3.16 Conexión del teclado 4x4 de la Dragon12-Plus2 . . . . . . . . . . . 29 3.17 Diagrama de flujo de la rutina PORTA_Scan . . . . . . . . . . . . . 30 3.18 Diagrama de flujo de la rutina SearchKey . . . . . . . . . . . . . . 32 3.19 Diagrama de flujo de la rutina PORTA_Action . . . . . . . . . . . . 33 3.20 Diagrama de flujo de la rutina RTI_isr . . . . . . . . . . . . . . . 34 3.21 Diagrama de flujo de la rutina PortH_isr . . . . . . . . . . . . . . 36 3.22 Diagrama de flujo de la rutina PLL_Init . . . . . . . . . . . . . . . 38 3.23 Diagrama de flujo de la rutina PORTA_Init . . . . . . . . . . . . . 40 3.24 Diagrama de flujo de la rutina PORTH_Init . . . . . . . . . . . . . 41 3.25 Diagrama de flujo de la rutina RTI_Init . . . . . . . . . . . . . . . 42 3.26 Diagrama de flujo de la rutina SCI1_Init . . . . . . . . . . . . . . 43 3.27 Diagrama de flujo de la rutina Xbee_Init . . . . . . . . . . . . . . 46 3.28 Diagrama de flujo del programa principal . . . . . . . . . . . . . . 48 vii 4.1 Pantalla de la configuración del componente Terminal de CodeWarrior utilizado para la simulación . . . . . . . . . . . . . . . . . . . 4.2 51 Pantalla del componente Terminal de CodeWarrior luego de la simulación . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 52 4.3 Prueba realizada para el teclado 4x4 del Puerto A . . . . . . . . . 53 4.4 Prueba realizada al programa principal . . . . . . . . . . . . . . . . 55 4.5 Prueba realizada con la aplicación para iPad . . . . . . . . . . . . 57 A.1 Diagrama de bloques del MC9S12DP256B . . . . . . . . . . . . . . 63 A.2 Mapa de memoria del MC9S12DG256B . . . . . . . . . . . . . . . 65 B.1 Diagrama de bloques del SCI . . . . . . . . . . . . . . . . . . . . . 67 B.2 Diagrama de bloques del transmisor del SCI . . . . . . . . . . . . . 68 B.3 Diagrama de bloques del recepctor del SCI . . . . . . . . . . . . . 69 B.4 Registros del SCI . . . . . . . . . . . . . . . . . . . . . . . . . . . . 69 C.1 Registro SYNR . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 C.2 Registro REFDV . . . . . . . . . . . . . . . . . . . . . . . . . . . . 70 C.3 Registro CLCKSEL . . . . . . . . . . . . . . . . . . . . . . . . . . 71 C.4 Registro PLLCTL . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 C.5 Registro CRGFLG . . . . . . . . . . . . . . . . . . . . . . . . . . . 71 D.1 Registro DDRH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 D.2 Registro PTH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 D.3 Registro PPSH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72 D.4 Registro PIEH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 D.5 Registro PIFH . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 73 E.1 Registro CRGINT . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 E.2 Registro RTICTL . . . . . . . . . . . . . . . . . . . . . . . . . . . . 74 F.1 Diagrama del Ciclo de Desarrollo en CodeWarrior . . . . . . . . . 77 J.1 Estructura del API frame TxIPv4 . . . . . . . . . . . . . . . . . . 87 J.2 Estructura del API frame RxIPv4 . . . . . . . . . . . . . . . . . . 88 J.3 Estructura del API frame para enviar comandos AT . . . . . . . . 89 J.4 Estructura del API frame de respuesta de comandos . . . . . . . . 89 viii Índice de cuadros A.1 Mapa de memoria de los dispositivos . . . . . . . . . . . . . . . . . 64 A.2 Vectores de interrupción del MC9S12DP256 . . . . . . . . . . . . . 66 E.1 Valores de los posibles divisores de frecuencia para RTI . . . . . . 75 G.1 Uso de los puertos de entrada y salida en la tarjeta Dragon12, lista 1 79 G.2 Uso de los puertos de entrada y salida en la tarjeta Dragon12, lista 2 80 H.1 Asignación de pines en el Xbee Wi-Fi . . . . . . . . . . . . . . . . 81 I.1 Comandos AT para Direccionamiento . . . . . . . . . . . . . . . . 82 I.2 Comandos AT para Networking . . . . . . . . . . . . . . . . . . . . 82 I.3 Comandos AT para Seguridad . . . . . . . . . . . . . . . . . . . . . 83 I.4 Comandos AT para la interfaz RF . . . . . . . . . . . . . . . . . . 83 I.5 Comandos AT para la interfaz Serial . . . . . . . . . . . . . . . . . 84 I.6 Comandos AT de Diagnóstico . . . . . . . . . . . . . . . . . . . . . 85 I.7 Comandos AT para Ejecución . . . . . . . . . . . . . . . . . . . . . 86 K.1 Comparación entre el módulo Xbee Wi-Fi y el módulo WiFly GSX 91 ix Nomenclatura AP Access Point. API Application Programming Interface. BDLC Byte Data Link Controller. BSS Basic Service Set. CAN Controller Area Network. CLKSEL CRG Clock Select Register. CPU Central Processing Unit. CRG Clocks and Reset Generator. CRGFLG CRG Flags Register. CRGINT CRG Interrupt Enable Register. DDRx Port x Data Direction Register. DNS Domain Name System. EEPROM Electrically Erasable Programmable Read-Only Memory. IDE Integrated Development Environment. IIC Inter-IC Bus. IP Internet Protocol. MCU Microcontroller Unit. OSCCLK Valor de la frecuencia de referencia del microcontrolador. PIEH Port H Interrupt Enable Register. x PLL Phase Locked Loop. PLLCLK Valor de la frecuencia del PLL. PLLCTL CRG PLL Control Register. PPSH Port H Polarity Select Register. PWM Pulse-Width Modulator. RAM Random Access Memory. RDRF Receive Data Register Full Flag. REFVD CRG Reference Divider Register. RF Radio Frecuency. RTI Real Time Interruption. RTICTL CRG RTI Control Register. RTIF Real Time Interruption Flag. SCI Serial Communication Interface. SCI1BR SCI1 Baud Registers. SCI1CR1 SCI1 Control Register 1. SCI1CR2 SCI1 Control Register 2. SCI1DRL SCI1 Data Register Low. SPI Serial Peripheral Interface. SSID Service Set Identifier. SYNR CRG Synthesizer Register. TCP Transmission Control Protocol. TDRE Transmit Data Register Empty Flag. UART Universal Asynchronous Receiver/Transmitter. UDP User Datagram Protocol. xi 1 Introducción Se cuenta actualmente con un sistema de control lógico, aplicado fundamentalmente para control de iluminación inteligente. Este está desarrollado sobre una plataforma de PLC, programado en lenguaje ladder. Se desea dar un cambio cualitativo a la aplicación migrando su plataforma de hardware y de software. El concepto general de la aplicación a desarrollar consiste en el control remoto, vı́a Wi-Fi, de todas las funcionalidades del controlador y desde dispositivos Apple-iOS (iPod, iPhone y iPad). Todo el desarrollo de la aplicación en iOS será desarrollado por un tercero. Desde el punto de vista del hardware, se va a desarrollar un controlador con base en el 68HCS12 de Freescale, dicho desarrollo de hardware NO es parte del alcance del proyecto. En su lugar, se utilizará como plataforma de hardware la tarjeta Dragon12-Plus2 de Wytec. Además, se utilizará el módulo Xbee Wi-Fi para proveer conexión IEEE 802.11 al 68HCS12. Desde el punto de vista del software, se tiene una serie de objetivos especı́ficos, los cuales consisten principalmente en la implementación de subrutinas de control lógico por Wi-Fi. Estas se utilizarán para el control de las salidas del microcontrolador. 1.1 Objetivos Objetivo General • Implementar un control por Wi-Fi en la tarjeta Dragon12-Plus2 de Wytec, para accesarlo desde dispositivos iOS. Objetivos Especı́ficos • Aprender sobre la arquitectura y programación del microcontrolador 68HCS12 de Freescale. • Aprender el entorno de programación CodeWarrior para HCS12. 1 2 1 Introducción • Desarrollar la aplicación de enlace entre un dispositivo iOS y la tarjeta Dragon12-Plus2 de Wytec. • Desarrollar y probar las subrutinas de control lógico por Wi-Fi. 1.2 Metodologı́a Para lograr los objetivos planteados, el desarrollo del trabajo incluyó los siguientes pasos y procedimientos: 1. Entrenamiento en la CPU del HSC12. a) Aprendizaje sobre la arquitectura del HSC12. b) Realización del pequeños programas de práctica en el AsmIDE. c) Realización de pequeños programas utilizando el simulador de la tarjeta Dragon12-Plus. 2. Entrenamiento en el ambiente de programación CodeWarrior. 3. Entrenamiento con la tarjeta Dragon12-Plus2. 4. Entrenamiento con el módulo Xbee Wi-Fi. 5. Desarrollo de la aplicación de control lógico por Wi-Fi de salidas y entradas. 1.3. Cronograma 1.3 3 Cronograma Marzo Actividades Actividades técnicas Entrenamiento en la CPU del HCS12. Aprender sobre la arquitectura del HCS12. Realizar pequeños programas de práctica en el AsmIDE. Realizar pequeños programas de práctica utilizando el simulador. Entrenamiento en el ambiente de programación CodeWarrior. Entrenamiento con la tarjeta Dragon12Plus Entrenamiento con el dispositivo Xbee Wi-Fi. Desarrollo de la aplicación de comunicación por Wi-Fi. Desarrollo de la aplicación de control de salidas. Actividades del informe Desarrollo del Capítulo 1: Introducción. Desarrollo del Capítulo 2: Marco Teórico. Desarrollo del Capítulo 3: Diseño de la aplicación. Desarrollo del Capítulo 4: Pruebas y Resultados. Desarrollo del Capítulo 5: Conclusiones. Entrega del informe final escrito. Preparación de la presentación oral del informe. Corrección del informe final. Abril Meses Mayo Junio Julio Del Del Del Del Del Del Del Del Del Del Del Del Del Del Del Del Del Del Del Del Del 11 al 18 al 25 al 1 al 8 al 15 al 22 al 29 al 6 al 13 al 20 al 27 al 3 al 10 al 17 al 24 al 1 al 8 al 15 al 22 al 29 al 15 22 29 5 12 19 26 3 10 17 24 31 7 14 21 28 5 12 19 26 31 2 Marco Teórico Para el desarrollo del proyecto se contó básicamente con cuatro grandes recursos: la tarjeta de desarrollo Dragon12-Plus2, la cual tiene un microcontrolador MC9S12DG256 de Freescale Semiconductor, el IDE (Integrated Development Environment) llamado CodeWarrior, y el módulo Xbee Wi-Fi. Por esta razón, se da una breve descripción de las principales caracterı́sticas de estos recursos utilizados. 2.1 El microcontrolador MC9S12DG256 Como parte de la familia de los microcontroladores HCS12, se utilizó el MCU (Microcontroller Unit) MC9S12DG256CVPE el cual es el que incluye la tarjeta de desarrollo Dragon12-Plus2. Dentro de las principales caracterı́sticas que tiene este dispositivo, se encuentran: (Freescale Semiconductor, 2005) • Una CPU (Central Processing Unit) HCS12 de 16 bit. • Memoria: 256K bytes de Flash EEPROM, 12K bytes de RAM, 4K bytes de EEPROM. • Interfaces seriales: dos ası́ncronas SCI (Serial Communication Interface) y tres sincrónicas SPI (Serial Peripheral Interface). • Convertidores Analógico-Digital: dos de 8 canales con una resolución de 10 bit. • 29 canales discretos de entrada/salida. • 20 lı́neas digitales discretas de entrada/salida con capacidad de interrupción. • Temporizadores: ocho canales. • Ocho Canales PWM (Pulse-Width Modulator). 4 2.1. El microcontrolador MC9S12DG256 5 • Un BDLC (Byte Data Link Controller). • Un IIC (Inter-IC Bus). • Un circuito PLL (Phase Locked Loop) que permite ajustar el reloj del microcontrolador. En el Apéndice A se muestran el mapa de memoria y el diagrama de bloques del microcontrolador. Para información sobre la estructura y el modelo de programación de los microcontroladores HCS12 se recomienda consultar el libro de Almy (2011) y el de Pack y Barrett (2001). El Bloque SCI A la hora de realizar el proyecto, el bloque SCI correspondió a uno de los bloques más importantes dentro del MCU. Por lo tanto, se mencionan algunas de las caracterı́sticas importantes de este bloque: (Freescale Semiconductor, 2004) • Permite una comunicación serial asincrónica con dispositivos periféricos o con otros CPUs. • Permite una operación Full-Duplex. • Tiene 13 bit para la selección del baud rate. • Se puede elegir entre formato de 8 bit o de 9 bit. • El transmisor y el receptor se habilitan de forma separada. • Se puede programar la paridad para el transmisor, ya sea par, impar o ninguna. • Permite la operación por medio de interrupciones, gracias a ocho banderas. • Tiene detección de errores de entramado, y revisión de paridad por medio del hardware. 6 2 Marco Teórico En el Apéndice B se encuentran los diagramas de bloques del SCI del microcontrolador utilizado, además, se encuentra la referencia de los registros que utiliza. Para mayor información sobre el funcionamiento se este bloque, se recomienda revisar el manual de fabricante Freescale Semiconductor (2004). 2.2 La herramienta de programación CodeWarrior IDE CodeWarrior es un IDE profesional de Freescale, el cual provee una plataforma de software flexible para el desarrollo de aplicaciones. Este tiene la ventaja que permite programar tanto en ensamblador como en C y C++. Tiene herramientas que permiten realizar la inicialización de los dispositivos, además de componentes que ayudan a la hora de la simulación. Las principales herramientas que tiene CodeWarrior son: (Freescale Semiconductor, 2009a) • Administrador de proyectos: entre las funciones que tiene, es el que se encarga de realizar a alto nivel el manejo de los archivos del proyecto. Esto incluye organizar los objetos del proyecto en archivos y en targets. Determina el orden en el que se va a realizar el proceso de construcción. • Editor: es el ambiente en el que se crean y se modifican los códigos fuente. • Motor de búsqueda: provee las opciones de buscar y reemplazar, pero además, se tiene que se pueden comparar códigos fuente. • Navegador de fuente: es el que permite el manejo de sı́mbolos, como variables y funciones. • Sistema de construcción: es el que se encarga de convertir los códigos fuente en archivos ejecutables. • Debugger: es el que permite resolver errores. CodeWarrior, al ser un IDE trabaja por proyectos, por lo que se generan una gran cantidad de archivos los cuales conforman el proyecto. Los archivos 2.3. La plataforma de hardware Dragon12-Plus2 7 en la carpeta Source son lo que contienen los archivos de código fuente. Pero también, se generan otros archivos que son necesarios para la la correcta creación del proyecto, como por ejemplo los archivos .prm los cuales definen el arreglo de memoria que se va a utilzar. Para mayor información sobre las herramientas de CodeWarrior, se recomienda consultar los respectivos manuales. Para los detalles del ensamblador consultar el manual de Freescale Semiconductor (2009b), para el debugger consultar el de Freescale Semiconductor (2009c), y para las herramientas de construcción consultar el de Freescale Semiconductor (2010). 2.3 La plataforma de hardware Dragon12-Plus2 Como plataforma de hardware, se utilizó la tarjeta de desarrollo Dragon12Plus2. Esta plataforma permite el rápido desarrollo de aplicaciones, además, tiene gran cantidad de dispositivos periféricos que permiten realizar pruebas de mejor forma. Esta viene con un microcontrolador de la familia HCS12 de Freescale, especı́ficamente, el MC9S12DG256CVPE. Esta tarjeta se encuentra en dos posibles opciones, una que viene preinstalada con un bootloader y con D-Bug12 monitor, y la otra opción que trae pre-instalado serial monitor. Para realizar el proyecto se utilizó la tarjeta con serial monitor de Freescale, la cual permite usar CodeWarrior. Dentro de las caracterı́sticas y facilidades que presenta esta tarjeta se mencionan algunas de ellas: (EVBplus, 2012) • Interfaz USB seleccionable para utilizar con SCI0 o SCI1. • LED RGB. • Puerto de comunicación RS485. • Dos convertidores analógico digital. • Visualizador de 7 segmentos de 4 dı́gitos. • Un DIP switch de 8 posiciones. • 4 botones pulsadores. 8 2 Marco Teórico • Reguladores de 3,3 V y 5 V. • Switch para abortar cuando el programa se encuentra enciclado. • Teclado 4x4 • Detector IR, sensor de luz, sensor de temperatura. • Sockets para Xbee. Para la lista completa consultar el manual del fabricante EVBplus (2012). En el Apéndice G se encuentra cómo se utilizan los pines de entrada y salida del microcontrolador para la conexión con los periféricos que tiene la Dragon12. 2.4 Módulo Xbee Wi-Fi R Wi-Fi proveen conexión inalámbrica a dispositivos fiLos módulos RF Xbee nales dentro de una red 802.11. Estos utilizan el protocolo 802.11 para comunicarse con otros dispositivos 802.11 bgn, aunque sean dispositivos de diferentes fabricantes (Digi International, 2011b). El Xbee tiene interfaz de comunicación serial, tanto UART (Universal Asynchronous Receiver/Transmitter) como conexiones SPI en modo esclavo. Además, provee servicios IP por medio de comunicación serial. Lo que hace es conectar un puerto IP directamente a la interfaz de comunicación serial del Xbee, ya sea UART o SPI. Dentro de este servicio de comunicación serial, se tienen dos modos de funcionamiento: el modo transparente y el modo API (Application Programming Interface). El modo API provee más capacidades y soporta TCP (Tranmission Control Protocol) y UDP (User Datagram Protocol) al mismo tiempo. Se utilizan las tramas TxIPv4 para transmitir datos desde el módulo, y se utiliza la trama RxIPv4 cuando se reciben datos en el módulo. En el Apéndice J se encuentra la estructura de estas tramas. Usando los modos de operación descritos (modo API), el funcionamiento básico es: • Transmisión: Para lograr la transmisión de datos desde el Xbee hasta otro host en una red 802.11, el Xbee necesita recibir por medio de la 2.4. Módulo Xbee Wi-Fi 9 interfaz serial los bytes correspondientes a la trama API llamada TxIPv4. Una vez que el Xbee recibe esta trama, transmite por medio de su módulo RF los datos y se encarga de crear las tramas correspondientes con los protocolos de comunicaciones utilizados. • Recepción: A la hora de recibir datos desde un dispositivo 802.11 , estos datos se reciben por medio de la interfaz RF del Xbee. El Xbee crea una trama API RxIPv4 que la transmite al microcontrolador por medio de su interfaz de comunicación serial. Las configuraciones del Xbee se realizan por medio de comandos, los comandos de mayor importancia para el proyecto se muestran en el Apéndice I. El fabricante del Xbee provee una herramienta de software llamada X-CTU la cual permite la configuración de los módulos y la prueba de los mismos, se recomienda revisar el manual de este software de Digi International (2008). Para iniciar utilizando estos módulos, en la guı́a rápida de Digi International (2011a) se muestra cómo hacerlo. Además, para mayor información sobre el funcionamiento del Xbee, consultar el manual de Digi International (2011b). 3 Diseño de la aplicación El principal objetivo del proyecto es el desarrollo de un dispositivo controlador, el cual pueda ser accesado de forma remota por medio de una red IEEE 802.11 y a través de un dispositivo iOS. El diagrama de bloques básico de la aplicación se muestra en la Figura 3.1. Access Point (AP) Tx Rx Módulo Xbee Wi-Fi Microcontrolador HCS12 Rx Dispositivo iOS Tx Figura 3.1: Diagrama de bloques de la aplicación Se observa en la Figura 3.1 que el dispositivo controlador consta de un microcontrolador HCS12, el cual se comunica por medio de una comunicación serial con el módulo Xbee. El módulo Xbee Wi-Fi es el encargado de proveer conexión IEEE 802.11. Del otro lado del sistema de comunicación se encuentra un dispositivo iOS, el cual cuenta con una aplicación desarrollada por un tercero. Esta aplicación se encarga de conectarse al módulo Xbee y enviar instrucciones de forma remota. Todo esto se realiza bajo una infraestructura de red conocida como BSS (Basic Service Set), en la cual los dispositivos de la red hablan por medio de un dispositivo maestro conocido como Access Point (AP). A continuación se explica cómo se realizó el manejo de cada uno de los bloques mencionados anteriormente. 10 3.1. Manejo del SCI del 68HCS12 3.1 11 Manejo del SCI del 68HCS12 Para la aplicación desarrollada en el proyecto, el manejo de los periféricos del microcontrolador se realizó por medio de interrupciones. Por lo tanto, son las rutinas de atención de interrupciones las encargadas de realizar todo el manejo de datos para luego retornar al programa principal, el cual no hace más que esperar a que haya interrupciones. En el futuro, será desde este programa principal que se hagan las invocaciones a las subrutinas de aplicación del controlador. Tal como se mencionó en el Marco Teórico, el microcontrolador MC9S12DG256 consta de dos unidades SCI (Serial Communication Interface). En la tarjeta de desarrollo utilizada, la Dragon12-Plus2, el bloque SCI0 se utiliza para la comunicación con el puerto USB. Por lo tanto, se utilizó el bloque SCI1 para la aplicación desarrollada. Se usó un formato de 8-bit, sin paridad, y una velocidad de transmisión de 9600 bps. Las interrupciones del bloque SCI se habilitan e inhabilitan por medio del registro SCI1CR2 ( SCI1 Control Register 2). Para la aplicación realizada, se utilizaron dos tipos de interrupciones, las interrupciones generadas por las banderas RDRF (Receive Data Register Full Flag) y TDRE (Transmit Data Register Empty Flag). Estas banderas se ponen en alto cuando hay un dato recibido, o cuando se está libre para transmitir, respectivamente. Para mayor información sobre estos registros consultar el Apéndice B. Para el manejo de los datos, tanto los recibidos como los datos a enviar, se utilizó un sistema de “buffer”, a cómo se describe en la sección SCI del libro de Almy (2011). Sin embargo, cabe mencionar que se hizo un trato diferente para los datos recibidos y para los datos a enviar. Para la transmisión de datos se utilizó un “buffer” tal como se muestra en la Figura 3.2. Este es un “buffer” cı́clico, de modo que cuando se llega a la última posición, el próximo dato se debe guardar en la primera posición del “buffer”, y ası́ sucesivamente. Se utilizan dos punteros, uno lleva la dirección donde se va a guardar el próximo dato, y el otro lleva la dirección del próximo dato a extraer. Una vez que estos punteros apunten a la misma dirección, se dice que el “buffer” está vacı́o y no hay más datos para transmitir. Para el “buffer” de recepción de datos, se utilizó una configuración como la que se muestra en la Figura 3.3. El manejo de este “buffer” no es cı́clico como 12 3 Diseño de la aplicación txBuffer txBufout 0x01 txBufin 0x02 txBuffer+BUFSIZE Figura 3.2: Diagrama del ”buffer”de transmisión el de transmisión, sino que se trata como una lı́nea. Esto facilita el manejo de datos y el análisis posterior de los mismos, ya que se sabe de antemano que los datos recibidos forman una trama de longitud conocida. Entonces, cada vez que se recibe el primer dato de una trama, este se coloca siempre en la primera posición del “buffer”. Es por esta razón que sólo es necesario un puntero, el cual me dice cuál es la posición en la que se va a guardar el siguiente dato. El programa es el que se encarga de procesar los datos trama por trama. i=0 0x7E i=1 0x00 i=2 0x05 i=BUFSIZE-1 rxBuffer rxBuffer[i=3] rxBuffer+BUFSIZE Figura 3.3: Diagrama del ”buffer”de recepción Para mayor explicación sobre este sistema, se recomienda consultar el libro de Almy (2011). 3.1. Manejo del SCI del 68HCS12 13 Tomando en cuenta lo mencionado, el manejo del SCI se puede dividir en tres grandes partes: la rutina de atención de interrupciones, la rutina de manejo del receptor y la rutina de manejo del transmisor. Estas se describen a continuación. Rutina de atención de interrupciones del SCI La rutina de atención de interrupciones del SCI es la encargada de recibir datos y guardarlos en el “buffer” de recepción, y además, es también la encargada de extraer datos, del “buffer” de transmisión, para transmitirlos. En la Figura 3.4 se muestra el diagrama de flujo de la rutina SCI_isr implementada para el manejo de datos. Lo primero que se hace es guardar el estado del registro del control SCI1CR2 con el cual se entró a la rutina de atención de interrupciones. Una vez hecho esto, se inhabilitan las interrupciones tanto del receptor como del transmisor, esto evita que se entre a la rutina antes de haber hecho el respectivo manejo de los datos. Y por último, se habilitan las interrupciones de mayor prioridad por medio de la directiva en ensamblador CLI. Como tanto el receptor (por medio de la bandera RDRF) y el transmisor (por medio de la bandera TDRE) pueden generar interrupciones, inicialmente hay que revisar cuál de los dos fue el que generó una interrupción (esto se hace con el estado inicial del registro SCI1CR2 con el que se entró a la rutina de atención de interrupciones), ya que el HCS12 tiene un único vector de para ambas interrupciones. Pero además, antes de realizar esto, es más eficiente revisar si inicialmente las interrupciones de estos estaban habilitadas. Si las interrupciones de alguno de los dos no estaban habilitadas, se sabe que ese no fue quién llamó a la rutina de atención de interrupciones. Si la bandera RDRF está en alto, quiere decir que hay un dato recibido (un byte en nuestro caso), por medio de una comunicación serial, y que este ya está en el registro de datos recibidos. Lo que debe hacer la rutina de atención de interrupciones es leer este dato del registro de datos SCI1DRL (SCI1 Data Register Low), y al hacer esto, automáticamente se limpia la bandera RDRF. Luego, para el manejo de datos se llama a la función SCI1_InChar, la cual se encarga de hacer el manejo de datos recibidos de acuerdo al sistema del “buffer” de la Figura 3.3 mencionado anteriormente. 14 3 Diseño de la aplicación SCI1_isr Guardar el estado del registro de control SCI1CR2 como initSCI1CR2. Deshabilitar la interrupciones del transmisor y las del receptor. Habilitar las interrupciones del microcontrolador (CLI). ¿Interrupciones del receptor habilitadas en initSCI1CR2? SI ¿RDRF está en alto? SI Guardar datos de SCI1DRL en variable dataIn. NO NO ¿TDRE está en alto? SI SI SCI_InChar(dataIn) ¿Interrupciones del transmisor habilitadas en initSCI1CR2? NO NO ¿txBufin == txBufout? SI Deshabilitar las interrupciones del transmisor. NO Transmitir a SCI1DRL el valor en la posición que apunta el puntero txBufout, e incrementar en uno el puntero. ¿txBufout apunta al final del buffer? NO SI Reiniciar puntero txBufout para que apunte al inicio del buffer. Restaurar los valores iniciales del registro SC1CR2: SCI1CR2 = initSCI1CR2 Habilitar las interrupciones del receptor. Fin Figura 3.4: Diagrama de flujo de la rutina SCI1_isr 3.1. Manejo del SCI del 68HCS12 15 Por otro lado, si es la bandera TDRE la que está en alto, la rutina de atención de interrupciones debe extraer los datos del “buffer” de transmisión, que sigue un principio de funcionamiento como el mostrado en la Figura 3.2, y colocarlos en el registro de transmisión de datos del SCI1. Para hacer esto, se tiene el puntero txBufout, el cual contiene la dirección donde se encuentra el dato a transmitir. Una vez que se pasa el dato al registro SCI1DRL para ser transmitido, se aumenta en 1 el puntero. El funcionamiento básico de la atención de interrupciones para el transmisor es el mencionado, sin embargo, hay que tomar en cuenta algunos casos especiales, en los cuales hay que tomar medidas de control adicionales para el “buffer”. Por ejemplo: • Si se tiene que el puntero txBufin (puntero que contiene la dirección donde se debe guardar el próximo dato en el “buffer”) y el puntero txBufout apuntan a la misma dirección, quiere decir que no hay datos para transmitir. Por esto, se inhabilitan las interrupciones del transmisor, para que no se esté entrando a la rutina de atención de interrupciones de forma innecesaria. • Si el puntero txBufout apunta al final del “buffer”, se debe reiniciarlo y fijarlo para que apunte al inicio nuevamente. Una vez hecho el respectivo manejo de datos, se restaura el estado del registro de control SCI1CR2 y se habilitan las interrupciones del receptor. En el Apéndice M se encuentra el código utilizado para implementar esta rutina. Rutina de manejo del receptor Se creó una rutina llamada SCI1_InChar cuyo diagrama de bloques se muestra en la Figura 3.5. Esta rutina es llamada por la rutina de atención de interrupciones cuando se da la recepción de un dato por medio del bloque SCI1 y recibe el dato que se leyó del registro de datos del SCI1. La rutina SCI1_InChar está hecha especialmente para realizar el manejo de datos necesario para formar las tramas API del módulo Xbee Wi-Fi, y además, se guardan los datos en forma de “buffer” de lı́nea como el mostrado en la Figura 3.3. Para realizar esto, se define un arreglo de caracteres de 16 3 Diseño de la aplicación SCI1_InChar Se recibe un caracter llamado rxData Sumar uno al índice (rxIndx) del buffer de entrada (rxBuffer). NO ¿rxData es el caracter de inicio? SI Fijar en 0 el valor del índice (rxIndx) del buffer de entrada (rxBuffer). Guardar rxData en la posición rxIndx del buffer de entrada rxBuffer. ¿rxIndx == 2? Asignar a la variable len (longitud de la trama) el valor actual más 3. SI NO ¿Se está en el final de la trama? SI Xbee_Rx(rxBuffer) NO Fin Figura 3.5: Diagrama de flujo de la rutina SCI1_InChar 3.1. Manejo del SCI del 68HCS12 17 tamaño BUFSIZE, en el caso de la aplicación se definió de 64 bytes, ya que se sabe de antemano que no se van a tener tramas mayores, sin embargo, esto puede ser modificado fácilmente. Cuando se recibe el dato 0x7E se sabe que es el inicio de una trama, inmediatamente se inicializa el puntero para que se guarde este dato en la primera posición (posición 0). Los siguientes dos datos que se reciben conforman la parte alta y parte baja de la longitud de la trama (como se conoce de antemano el tamaño aproximado de las tramas que se van a utilizar, sólo se trabaja con el dato de la parte baja que corresponde al dato en la posición 2). Conociendo la longitud de la trama, se sabe cuándo es que se llega al final de la misma. Una vez que se llegue al final de la trama, se envı́a la trama a la función Xbee_Rx que es la que se encarga del análisis de los datos. El código utilizado para implementar esta rutina se encuentra en el Apéndice M. Rutina de manejo del transmisor Se implementó una rutina que hace el manejo de datos a transmitir en forma de un “buffer”, ası́ como se mostró en la Figura 3.2. Para esto, se tienen dos punteros, txBufin y txBufout, que respectivamente, son los que llevan las direcciones del siguiente dato a guardar y el siguiente dato a extraer del “buffer”. Una vez que las posiciones a las que apuntan los punteros sean iguales, se dice que el “buffer” está vacı́o y no hay más datos para transmitir. En la Figura 3.6 se muestra el diagrama de flujo de la función implementada. La función SCI1_OutChar es la encargada de guardar los datos en el buffer por medio del puntero txBufin. Tal como se vio anteriormente, es la rutina de atención de interrupciones la que se encarga de extraer los datos del “buffer” y de transmitirlos al registro de datos del SCI1. Por esta razón, cuando se añaden datos al “buffer” por medio de la rutina SCI1_OutChar, es cuando se habilitan las interrupciones del transmisor, ya que ahora sı́ hay datos para transmitir. Al tratarse de un “buffer” de forma cı́clica, hay que tener ciertas consideraciones a la hora de controlarlo. Por ejemplo: • A la hora de introducir datos, hay que controlar que siempre haya una 18 3 Diseño de la aplicación SCI1_OutChar Se recibe un caracter llamado txData. Definir variable used: used = txBufin-txBufout ¿used < 0? Sumar el valor del tamaño del buffer de transmisión a la variable used. SI NO ¿used < ((BUFSIZE+ extrabuf)-1)? NO txBUFULL = 0xFF SI ¿txBUFULL == 0xFF? SI Incrementar en 1 la variable extraBuf y poner en cero la variable txBUFULL NO Transferir txData a la posición del buffer de transmisión (txBuffer) apuntada por txBufin. Incrementar txBufin en 1. ¿txBufin apunta al fin del buffer? SI Reiniciar puntero txBufin al inicio del buffer de transmisión (txBuffer). NO Habilitar interrupciones del transmisor del SCI1. Fin Figura 3.6: Diagrama de flujo de la rutina SCI1_OutChar 3.2. Manejo del módulo Xbee Wi-Fi 19 posición libre en el “buffer”, no se puede llenar completamente porque sino se cae en una posición errónea en la que se cree que está vacı́o. • Si no hay espacio en el “buffer” para guardar datos, se cambia el estado a la variable global llamada txBUFULL, con esto, se indica que el buffer está lleno. Con esto, es posible realizar una acción de control. En el caso de la rutina implementada, se aumenta el tamaño del “buffer” en 1 posición, la cual permite que se guarde en esta posición el dato. • Si el puntero txBufin apunta al final del “buffer”, se debe fijar para que apunte al inicio nuevamente. El código utilizado para implementar esta rutina se encuentra en el Apéndice M. 3.2 Manejo del módulo Xbee Wi-Fi Tal como se mencionó en el marco teórico, el módulo Xbee tiene dos modos de operación, el modo transparente y el modo API. Se utilizó el modo API. Al configurar el módulo para que trabaje de este modo, se tiene que la comunicación con el mismo debe realizarse por medio de tramas estructuradas conocidas como tramas API. En la Figura 3.7 se muestra la estructura básica que tienen estas tramas, que constan de un delimitador de inicio, dos bytes que especifican la longitud de la trama, un campo de datos que depende del API que se utilice, y un byte para la suma de verificación (checksum). La Figura 3.7 fue hecha con base en el manual de Digi International (2011b). En el Apéndice J se muestra la estructura especı́fica de las tramas API utilizadas en el proyecto. Delimitador de inicio (Byte 1) 0x7E Longitud (Byte 2 y 3) MSB LSB Trama de datos (Byte 4 hasta n) Checksum (Byte n+1) Estructura específica de cada API Frame 1 Byte Figura 3.7: Estructura básica de una trama API 20 3 Diseño de la aplicación Es importante mencionar que el cálculo de la suma de verificación se hace según se muestra en la ecuación 3.1, siguiendo la notación de la Figura 3.7, en donde el resultado final es el byte menos significativo luego de hacer la operación. checksum = 0xF F − (SumaDeBytesDeT ramaDeDatos) (3.1) Tomando esto en cuenta, el manejo del Xbee consiste en realizar una rutina para que, por medio de comunicación serial, el microcontrolador pueda enviar, recibir, e identificar tramas correspondientes a las tramas API. La comunicación serial se describió anteriormente. Por su parte, las rutinas implementadas para el manejo de tramas se clasifican en tres grandes ramas: rutina de transmisión de tramas, rutina de envı́o de comandos, rutina recepción de tramas. Se describe el desarrollo realizado para cada rutina. Rutina de transmisión de tramas Para la transmisión de datos por Wi-Fi, el módulo Xbee hace uso del API frame llamado TxIPv4. En la Figura 3.8 se muestra la estructura básica de esta trama, además, en el Cuadro J.1 del Apéndice J se muestra un ejemplo de la misma. Delimitador de inicio (Byte 1) 0x7E Longitud (Byte 2 y 3) MSB LSB Checksum (Byte n+1) Trama de datos (Byte 4 hasta n) 0x20 Identificador del API Frame 0x00 Frame ID Dirección IP destino Puerto de destino Puerto de fuente 4 bytes 2 bytes 2 bytes Protocolo 0x00 0- UDP 1- TCP Opciones de transmisión Datos 1 Byte Hasta 1400 bytes Figura 3.8: Estructura básica de una trama API TxIPv4 Por lo tanto, para lograr una transmisión de datos, se necesita enviar los bytes correspondientes a la trama TxIPv4 hacia el pin Rx del Xbee. El Xbee recibe esta trama por medio de una comunicación serial, y haciendo uso de su módulo RF, la envı́a hacia el host vı́a Wi-Fi. Con base en esto, se tiene que la información necesaria para realizar la transmisión es básicamente: • Dirección IPv4 del dispositivo de destino (32 bit). • Puerto de destino, número del puerto TCP (Transmission Control Protocol) o UDP (User Datagram Protocol) (16 bit). 3.2. Manejo del módulo Xbee Wi-Fi 21 • Puerto de la fuente, número del puerto TCP o UDP. (16 bit). • Protocolo, ya sea TCP o UDP. • Datos a transmitir (Hasta 1400 bytes). Con estos datos conocidos, es posible hacer la transmisión de datos. En la Figura 3.9 se muestra el diagrama de flujo de la rutina implementada para la transmisión, de nombre Xbee_TxIPv4. Esta rutina lo que hace es recibir los datos mencionados anteriormente como información necesaria, y con base en esa información, se envı́an byte por byte (por medio del SCI del microcontrolador) los datos necesarios para crear una trama según la trama API TxIPv4 mostrada en la Figura 3.8. El código utilizado se encuentra en el Apéndice M. Rutina de envı́o de comandos El envı́o de comandos al Xbee se hace por medio de la trama API conocida como AT Command. En la Figura 3.10 se muestra la estructura básica de esta trama, además, en el Cuadro J.3 del Apéndice J se muestra un ejemplo de la misma. Para fijar o leer parámetros sobre la configuración del Xbee, es necesario enviar los bytes correspondientes a la trama AT Command hacia el pin Rx del Xbee. El Xbee recibe esta trama por medio de una comunicación serial, y por medio del identificador de trama (0x08), sabe que es un API AT Command. La lista de comandos disponibles se encuentra en el Apéndice I. En virtud de que algunos comandos reciben un arreglo de caracteres (String) de entrada, mientras que otros reciben un único byte de control, o ninguno, se implementaron dos rutinas, una para cada caso. La primera tiene nombre Xbee_ATCommand, cuyo diagrama de flujo se muestra en la Figura 3.11. Esta es la que se encarga de enviar comandos cuyos parámetros son un sólo byte, o ninguno. Esta rutina se encarga de enviar, byte por byte (por medio del SCI del microcontrolador) hacia el módulo Xbee, las bytes necesarios para armar una trama de la forma mostrada en la Figura 3.10. Análogamente, se tiene la rutina llamada Xbee_ATCommandStr, cuyo diagrama de flujo se muestra en la Figura 3.12. El principio de funcionamiento de 22 3 Diseño de la aplicación Xbee_TxIPv4 Se reciben variables: - ipDA: el valor de la dirección IP del destino, se da byte por byte desde ipDA1 hasta ipDA4. - destPort: puerto de destino, se da en parte alta (destPortH) y parte baja (destPortL) en hex. - sourcePort: puerto de fuente en hexadecimal. - protocol: 0-UDP o 1-TCP. - data: arreglo de caracteres a ser transmitidos Se obtiene parte alta (sourcePortH) y parte baja (sourcePortL) de la variable de entrada sourcePort. Se guardan los valores de data en memoria en un arreglo de caracteres de nombre dataOut. Se declara variable length, que corresponde a los índices del arreglo. Se encuentra la suma de los caracteres. Se obtienen los valores de parte alta (lengthH) y parte baja (lengthL) de la variable de longitud, tomando en cuenta que hay que sumar 12 a la variable length para tener la longitud real de la trama. Se obtiene el valor de la suma de verificación (checksum). SCI1_OutChar(0x7E) SCI1_OutChar(lengthH) SCI1_OutChar(lengthL) SCI1_OutChar(0x20) SCI1_OutChar(0x00) SCI1_OutChar(ipDA1) SCI1_OutChar(ipDA2) SCI1_OutChar(ipDA3) SCI1_OutChar(ipDA4) SCI1_OutChar(destPortH) SCI1_OutChar(destPortL) SCI1_OutChar(sourcePortH) SCI1_OutChar(sourcePortL) SCI1_OutChar(protocol) SCI1_OutChar(0x00) Se define variable de control j = 0. SCI1_OutChar(dataOut[j]) j++ SI ¿j < length? NO SCI1_OutChar(checksum) Fin Figura 3.9: Diagrama de flujo de la rutina Xbee_TxIPv4 3.2. Manejo del módulo Xbee Wi-Fi Delimitador de inicio (Byte 1) 0x7E 23 Longitud (Byte 2 y 3) MSB LSB Checksum (Byte n+1) Trama de datos (Byte 4 hasta n) 0x08 0x01 Identificador del API Frame Frame ID AT Command Valor del parámetro 1 Byte 2 bytes (ASCII) Figura 3.10: Estructura básica de una trama API AT Command esta rutina es el mismo que el mencionado para la rutina Xbee_ATCommandStr, con la diferencia que para el valor del parámetro hay que hacer un manejo de un arreglo de caracteres. El código utilizado para ambas rutinas se encuentra en el Apéndice M. Rutina de recepción de tramas Para la recepción de tramas, se realizó una sola rutina, la cual cual recibe un arreglo de caracteres correspondiente a una trama completa. Por medio del identificador, se sabe si fue una trama correspondiente a una recepción por Wi-Fi (RxIPv4 - 0xB0) o una respuesta del Xbee luego de recibir una trama API AT Command (AT Command Response - 0x88). Tal y como se explicó en la sección del manejo del SCI, la rutina de atención se interrupciones del SCI es la encargada de armar las tramas, y una vez armada, esta es enviada a la rutina Xbee_Rx. En la Figura 3.13 se muestra la forma general de una trama API de recepción por Wi-Fi (RxIPv4), mientras que en la Figura 3.14 se muestra la estructura de la trama enviada por el Xbee a través de su UART como respuesta ante la ejecución de un comando. En el diagrama de flujos de la Figura 3.15 corresponde a la rutina implementada, de nombre Xbee_Rx. Esta revisa el identificador de la trama para saber de qué tipo de trama se trata. Con base en esto, se realiza la acción correspondiente. Se implementó una rutina que se encarga de revisar el valor de la suma de verificación de los datos recibidos desde el Xbee correspondientes a una trama RxIPv4. Para hacer la verificación de esta suma, se suman los valores de cada uno de los bytes dentro del espacio de la trama que corresponde a los datos, y a este resultado se le suma el valor del byte correspondiente al campo de 24 3 Diseño de la aplicación Xbee_ATCommand Se reciben dos variables: - atCommand: El valor en hexadecimal del AT Command. - paramValue: valor del parámetro, si lo hay. Se definen variables, parte alta y parte baja de la longitud: lengthL = 0x05 y lengthH = 0. Se obtiene parte alta (atCommandH) y parte baja (atCommandL) de la variable de entrada atCommand. Se obtiene el valor de la suma de verificación (checksum). ¿Es paramValue nulo? SI Restar 1 al valor de lengthL. NO SCI1_OutChar(0x7E) SCI1_OutChar(lengthH) SCI1_OutChar(lengthL) SCI1_OutChar(0x08) SCI1_OutChar(0x01) SCI1_OutChar(atCommandH) SCI1_OutChar(atCommandL) SCI1_OutChar(paramValue) NO ¿Es paramValue nulo? SI SCI1_OutChar(checksum) Fin Figura 3.11: Diagrama de flujo de la rutina Xbee_ATCommand 3.2. Manejo del módulo Xbee Wi-Fi 25 Xbee_ATCommandStr Se reciben dos variables: - atCommand: El valor en hexadecimal del AT Command. - paramValue: valor del parámetro, este es un arreglo de caracteres. Se obtiene parte alta (atCommandH) y parte baja (atCommandL) de la variable de entrada atCommand. Se guardan los valores de paramValue en memoria en un arreglo de caracteres de nombre paramValueIn. Se declara variable length, que corresponde a los índices del arreglo. Se encuentra la suma de los caracteres. Se obtienen los valores de parte alta (lengthH) y parte baja (lengthL) de la variable de longitud, tomando en cuenta que hay que sumar 4 a la variable length para tener la longitud real de la trama. Se obtiene el valor de la suma de verificación (checksum). SCI1_OutChar(0x7E) SCI1_OutChar(lengthH) SCI1_OutChar(lengthL) SCI1_OutChar(0x08) SCI1_OutChar(0x01) SCI1_OutChar(atCommandH) SCI1_OutChar(atCommandL) Se define variable de control j = 0. SCI1_OutChar(paramValueIn[j]) j++ SI ¿j < length? NO SCI1_OutChar(checksum) Fin Figura 3.12: Diagrama de flujo de la rutina Xbee_ATCommandStr 26 3 Diseño de la aplicación Delimitador de inicio (Byte 1) 0x7E Longitud (Byte 2 y 3) LSB MSB Checksum (Byte n+1) Trama de datos (Byte 4 hasta n) Dirección IP Puerto de Puerto de de la fuente destino fuente 0xB0 Identificador del API Frame 4 bytes 2 bytes Protocolo Reservado Datos 2 bytes 0- UDP 1- TCP 1 byte 1 Byte Hasta 1400 bytes Figura 3.13: Estructura básica de una trama API RxIPv4 Delimitador de inicio (Byte 1) 0x7E Longitud (Byte 2 y 3) MSB LSB Checksum (Byte n+1) Trama de datos (Byte 4 hasta n) 0x88 Identificador del API Frame 0x01 Frame ID AT Command Estado 2 bytes (ASCII) 1 byte Valor del parámetro 1 Byte Figura 3.14: Estructura básica de una trama API AT Command Response la suma de verificación. Si la suma es igual a 0xFF entonces quiere decir que los datos recibidos están correctos. En el Apéndice M se encuentra esta rutina llamada Checksum. Cuando se recibe una de trama API RxIPv4, se llama a la rutina que verifica el valor de la suma de verificación. Si la suma es incorrecta entonces se ignora la trama, si por el contrario la suma es correcta, se guardan los datos de la dirección IP y el puerto de la fuente. Luego, se revisa el campo que contiene especı́ficamente los datos enviados, si corresponde a alguno de los códigos correctos, se realiza una acción. Para el caso de la aplicación realizada en el proyecto, los códigos permitidos son los códigos ASCII del 0 hasta el 7, además de la letra R. Cuando se recibe el código de un número, se cambia de estado al LED del puerto B correspondiente al número recibido. Además, por medio de la rutina Xbee_TxIPv4, se envı́a al dispositivo que envió la orden, un dato de confirmación de la acción realizada. Para esto último, se utilizan la dirección IP y el puerto guardados inicialmente. Al recibirse una R, se responde con la transmisión, uno por uno, de los estados actuales de cada LED del puerto B por medio de la rutina Xbee_TxIPv4. Cuando se recibe una trama API AT Command Response, se cambia el valor de una variable global llamada stat, de acuerdo al campo de datos recibido. Esta variable podrá ser utilizada por otras rutinas del programa según convenga. Los posibles valores que se pueden recibir de esta trama son: 3.2. Manejo del módulo Xbee Wi-Fi 27 Xbee_Rx Se recibe una trama de caracteres llamada frame, la cual es armada por la subrutina SCI1_InChar(). Se tienen las variables globales stat = 0xFF, param=0xFF. checksum=Checksum(frame) NO ¿frame[3] == 0x88? NO ¿frame[3] == 0xB0? SI SI ¿checksum == 0xFF? SI Se definen variables: ipDA1 = frame[4] ipDA2 = frame[5] ipDA3 = frame[6] ipDA4 = frame[7] sourcePortH = frame[10] sourcePortH = frame[11] NO SI Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF0); stat = frame[7] ¿frame[14] == ’0’? SI Hacer toggle en el LED correspondiente: PORTB ^= 0x1 ¿(PORTB & 0x1) == 0? param = frame[8] NO NO SI ¿frame[14] == ’1’? SI Hacer toggle en el LED correspondiente: PORTB ^= 0x2 SI ¿frame[14] == ’2’? SI Hacer toggle en el LED correspondiente: PORTB ^= 0x4 NO SI SI Hacer toggle en el LED correspondiente: PORTB ^= 0x8 NO SI SI Hacer toggle en el LED correspondiente: PORTB ^= 0x10 NO SI SI Hacer toggle en el LED correspondiente: PORTB ^= 0x20 SI Hacer toggle en el LED correspondiente: PORTB ^= 0x40 SI Hacer toggle en el LED correspondiente: PORTB ^= 0x80 Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON4); Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF5); SI Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF6); ¿(PORTB & 0x40) == 0? Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON6); Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF7); ¿(PORTB & 0x80) == 0? NO NO ¿frame[14] == ’R’? Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF4); Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON5); SI ¿frame[14] == ’7’? Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON3); NO NO NO Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF3); ¿(PORTB & 0x20) == 0? NO ¿frame[14] == ’6’? Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON2); ¿(PORTB & 0x10) == 0? NO ¿frame[14] == ’5’? Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF2); ¿(PORTB & 0x8) == 0? NO ¿frame[14] == ’4’? Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON1); ¿(PORTB & 0x4) == 0? NO ¿frame[14] == ’3’? Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, OF1); ¿(PORTB & 0x2) == 0? NO NO Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON0); Xbee_TxIPv4 (ipAd1, ipAd2, ipAd3, ipAd4, sourcePortH, sourcePortL, 0x2616, 0x01, ON7); Se envía, uno por uno, el estado actual de cada LED de acuerdo al estado de PORTB y por medio de la subrutina Xbee_TxIPv4(), a como se hace en los casos individuales. NO Fin Figura 3.15: Diagrama de flujo de la rutina Xbee_Rx 28 3 Diseño de la aplicación • 0x0: OK • 0x1: ERROR • 0x2: Comando inválido • 0x3: Parámetro inválido El código utilizado para implementar esta rutina se encuentra en el Apén- dice M. 3.3 Manejo de los periféricos El Puerto B En la tarjeta de desarrollo Dragon12-Plus2, hay 8 LEDs conectados al puerto B. Para poder utilizarlos, se fija el registro de dirección DDRB en alto, para que funcione como salidas. Por medio del registro de datos PORTB, es posible encender o apagar los LEDs, dependiendo si el registro está en alto o en bajo respectivamente. El manejo que se hace de los LEDs en la aplicación es para que funcionen de forma “toggle”. Es decir, al presionar un botón, se cambia de estado el LED. Esto se logra al realizar la operación lógica XOR (O-exclusiva) al registro de datos PORTB, con la máscara del LED al que se le desea cambiar de estado. El módulo RTI y el Puerto A Para implementar un control alterno de los LEDs, de modo que sea posible encenderlos y apagarlos de una forma alternativa al manejo por Wi-Fi, se utilizaron los botones pulsadores del teclado 4x4 que trae la tarjeta de desarrollo Dargon12-Plus2. En la Figura 3.16 se muestra cómo se encuentra conectado este teclado al puerto A. Hay que recordar que el puerto A no genera interrupciones, y que el programa en general se trabaja por medio de interrupciones. Es por esta razón que se utilizó el módulo RTI (Real Time Interruption) para hacer el manejo del teclado. De esta forma, el RTI genera una interrupción de forma periódica, y en cada interrupción, se realiza un escaneo del teclado para ver si se presionó 3.3. Manejo de los periféricos 29 Figura 3.16: Conexión del teclado 4x4 de la Dragon12-Plus2 alguna tecla. A continuación se explica el manejo tanto del teclado, como el de módulo RTI. Manejo del teclado 4x4 del Puerto A Para el manejo del teclado 4x4, se definen las columnas (PA0-PA3) como salidas y las filas (PA4-PA7) como entradas. Se observa de la Figura 3.16 que si por ejemplo uno fija la columna PA1 en alto, esto no va a generar cambios en PA4-PA7, ya que los interruptores están todos abiertos, por lo que PA4-PA7 tendrán todos un valor de 0 lógico en el registro de datos. Sin embargo, si se presiona la tecla 9 (según la notación de la Figura 3.16), se cierra el circuito, haciendo que en PA6 se observe un 1 lógico. Al tomar en cuenta este comportamiento, la rutina de escaneo del teclado consiste en fijar una columna en alto, y leer los estados de las filas en busca de que haya alguna fila en alto, ya que esto significa que hay alguna tecla presionada. Y esto se repite para las 4 columnas que se tienen. En la Figura 3.17 se muestra el diagrama de flujo de la función implementada. Para mejorar el rendimiento de la lectura del teclado, se siguieron los consejos mencionados en el libro de Almy (2011). Donde se realiza el escaneo de forma más lenta, para evitar lecturas erróneas por la vibración que generan los dispositivos mecánicos. Sin embargo, también hay que encontrar un balance y la lectura no puede ser muy lenta, porque sino el sistema tiene una mala respuesta ante las presiones de los botones. Además, se buscan las presiones 30 3 Diseño de la aplicación PORTA_Scan Se tienen las siguientes constantes: COLS = 4, ROWS = 4, PTACOL = 0xF0, PTAROW = 0x0F, ONE = 0x1, TEN = 0x10 Se tiene la variable global: keybuf1 = 0 Se definen las variables de control: setCol, readRow, i = 0, j =0, status = 0, key = 0, temp NO ¿i < COLS? SI Se define el estado base de las columnas: PORTA &= PTACOL Para ver cual columna va en alto: setCol = (ONE<<i) Se pone columna en alto: PORTA |= setCol NO ¿j < ROWS? SI Se guarda estado del puerto A: pta = PORTA Para ver cual fila se va a leer: readRow = (TEN<<j) Se lee la fila: status= pta & readRow ¿status != 0? SI key = SearchKey(PORTA) NO keybuf1 = key status = 0 ¿keybuf1 != key? SI Se guarda estado valor de keybuf1: temp = keybuf1 Se inicializa keybuf1: keybuf1 = 0 NO Se retorna 0. Se retorna variable temp. Fin Figura 3.17: Diagrama de flujo de la rutina PORTA_Scan 3.3. Manejo de los periféricos 31 y depresiones del teclado, no sólo cuando hay una presión. Cuando se encuentra que hay una presión de una tecla, se analiza el estado del puerto A para saber cuál fue la tecla presionada. Por esta razón, se implementó la rutina SearchKey cuyo diagrama de flujo se muestra en la Figura 3.18. Esta devuelve el valor ASCII de la tecla presionada. En la Figura 3.19 se muestra en diagrama de flujo de la función que realiza acciones con base en el resultado de la tecla presionada. Básicamente, con base en el valor ASCII de la tecla presionada, se sabe a cuál LED hay que cambiarle el estado. El código implementado para las rutinas del manejo del teclado 4x4 se encuentra en el Apéndice M. Manejo del módulo RTI Para hacer el manejo de las interrupciones del módulo RTI, se implementó la rutina de atención de interrupciones llamada RTI_isr, cuyo diagrama de flujo se muestra en la Figura 3.20. Esta rutina se accesa de forma periódica, ya que el módulo RTI genera interrupciones periódicamente. Para el proyecto se configuró el módulo RTI de modo que se dieran interrupciones cada 13,65 ms, esto con el propósito de cumplir con el requisito de tener un tiempo de lectura del teclado idóneo, el cual lea lo suficientemente rápido para que el sistema tenga una buena respuesta ante una presión de un botón, pero que no sea tan rápida que el ruido generado por los dispositivos mecánicos pueda dar una lectura errónea. En el apartado de la etapa de inicialización del módulo se describe cómo se fijó este valor. Al accesar esta rutina, se guarda el estado inicial del registro de banderas de interrupción CRGFLG (CRG Flags Register), se inhabilitan las interrupciones del RTI, y se habilitan las interrupciones de mayor prioridad por medio del comando CLI. Una vez hecho esto, se revisa si la bandera del interrupción RTIF (Real Time Interruption Flag) está en alto (en el estado inicial del registro CRGFLG). Si la bandera está en alto, se llama a la función PORTA_Scan, la cual se encarga de realizar el escaneo del teclado del puerto A y devuelve el valor ASCII de la tecla presionada, si la hubo, sino se devuelve un 0. Si hubo una presión de 32 3 Diseño de la aplicación SearchKey Se recibe un caracter (keyIn) que representa el estado de PORTA cuando se ha presionado una tecla. ¿keyIn == 0x82? SI Se devuelve variable de salida: result = ’0’ SI Se devuelve variable de salida: result = ’1’ SI Se devuelve variable de salida: result = ’2’ NO ¿keyIn == 0x11? NO ¿keyIn == 0x12? NO ¿keyIn == 0x14? SI Se devuelve variable de salida: result = ’3’ NO ¿keyIn == 0x21? SI Se devuelve variable de salida: result = ’4’ SI Se devuelve variable de salida: result = ’5’ SI Se devuelve variable de salida: result = ’6’ NO ¿keyIn == 0x22? NO ¿keyIn == 0x24? NO ¿keyIn == 0x41? SI Se devuelve variable de salida: result = ’7’ NO Se devuelve variable de salida: return = 0 Fin Figura 3.18: Diagrama de flujo de la rutina SearchKey 3.3. Manejo de los periféricos 33 PORTA_Action Se recibe un caracter (key) que representa el número ASCII de la tecla presionada ¿key == ’0’? SI Se hace toggle en el LED correspondiente: PORTB ^= 0x1 SI Se hace toggle en el LED correspondiente: PORTB ^= 0x2 SI Se hace toggle en el LED correspondiente: PORTB ^= 0x4 NO ¿key == ’1’? NO ¿key == ’2’? NO ¿key == ’3’? SI Se hace toggle en el LED correspondiente: PORTB ^= 0x8 SI Se hace toggle en el LED correspondiente: PORTB ^= 0x10 SI Se hace toggle en el LED correspondiente: PORTB ^= 0x20 SI Se hace toggle en el LED correspondiente: PORTB ^= 0x40 SI Se hace toggle en el LED correspondiente: PORTB ^= 0x80 NO ¿key == ’4’? NO ¿key == ’5’? NO ¿key == ’6’? NO ¿key == ’7’? NO Fin Figura 3.19: Diagrama de flujo de la rutina PORTA_Action 34 3 Diseño de la aplicación RTI_isr Se guarda el estado inicial de las banderas de interrupción: initCRGFLG = CRGFLG Se deshabilitan las interrupciones de RTI: CRGINT &= ~0x80 Habilitar las interrupciones de mayor prioridad (CLI). ¿RTIF == 1? SI key = PORTA_Scan() NO ¿key == 0? NO PORTA_Action(key) SI ¿PTH7 == 1? NO ¿cont == 1000? SI cont++ SI NO Se limpia la bandera RTIF: CRFLG |= 0x80 Se habilitan las interrupciones de RTI: CRGINT |= RTIE Fin Figura 3.20: Diagrama de flujo de la rutina RTI_isr Xbee_Assoc() 3.3. Manejo de los periféricos 35 alguna tecla, se realiza una acción de acuerdo a la tecla presionada, por medio de la función PORTA_Action. Además, se incorporó una funcionalidad la cual periódicamente revisa si el módulo Xbee está asociado o no al AP. Si no está asociado, se llama a la rutina de inicialización nuevamente. Para hacer esto se hace uso del módulo RTI y de un contador. Si el valor de PH7 es 1, es decir, si se está trabajando en el modo de red de infraestructura, se aumenta un contado cada vez que se genera la interrupción del RTI. Cuando dicho contador llega al valor deseado, entonces se llama a la rutina llamada Xbee_Assoc, la cual es la encargada de hacer esta revisión. Una vez hecho esto, se limpia la bandera RTIF, y luego, se habilitan nuevamente las interrupciones del bloque RTI. En el Apéndice M se muestra el código en C utilizado para la implementación de la rutina RTI_isr. El Puerto H Se utilizaron tres de los botones pulsadores que en la tarjeta Dragon12-Plus2 se encuentran conectados al puerto H, ası́ como uno de los interruptores que forman parte del “DIP Switch” también conectado a este puerto. Dos de estos botones se utilizan para hacer la asociación del módulo Xbee Wi-Fi, ya sea a un AP o ya sea para configurarlo como creador de una red Ad Hoc. El tercer botón se utiliza para hacer el proceso de des-asociación del módulo. El puerto H genera interrupciones, por lo tanto, se realizó una rutina de atención de interrupciones de la forma mostrada en el diagrama de flujo de la Figura 3.21. La interrupción se genera cuando hay un flanco negativo. Cuando se da esto, se guarda el estado de las banderas de interrupción PIFH (Port H Interruption Flags), se inhabilitan las interrupciones del puerto H, y se habilitan las interrupciones de mayor prioridad (CLI). Luego, se revisan las banderas para ver quién generó la interrupción. Si el botón SW5 conectado al PH0 se presionó y además el interruptor en PH7 está en alto, se llama a la rutina de inicialización del Xbee, Xbee_Init. Una vez realizada la asociación, se limpia la bandera y se habilitan las interrupciones del puerto H. Por el contrario, si el botón SW4 conectado al PH1 se presionó y además el interruptor en PH7 está en bajo, se llama a la rutina de inicialización del Xbee en modo Ad Hoc, Xbee_AdHoc. Una vez terminada la respectiva rutina, se limpia la bandera y 36 3 Diseño de la aplicación PORTH_isr Se guarda el estado inicial de las banderas de interrupción: initPIFH = PIFH Inhabilitar las interrupciones del puerto H: PIEH = 0 Habilitar las interrupciones de mayor prioridad (CLI). ¿((initPIFH &01) == 1) && (PTH7 == 1)? SI Xbee_Init("AP", ee, "clave") Se limpia la bandera de interrupción: PIFH |= 0x1 NO ¿((initPIFH &02) == 1) && (PTH7 == 0)? SI Xbee_AdHoc Se limpia la bandera de interrupción: PIFH |= 0x2 NO ¿(initPIFH &04) == 1)? SI Xbee_ATCommand(0x4E52, ’’) Se limpia la bandera de interrupción: PIFH |= 0x4 NO Se habilitan las interrupciones del puerto H: PIEH = 0x7 Fin Figura 3.21: Diagrama de flujo de la rutina PortH_isr 3.4. Etapa de Inicialización 37 se habilitan las interrupciones del puerto H. Cuando se presiona el botón SW3, se envı́a el comando “NR” (Network Reset), el cual hace que se reinicien los valores necesarios para una asociación, esto causa que el módulo Xbee pierda asociación. En el Apéndice M se encuentra el código utilizado para implementar la rutina PortH_isr. 3.4 Etapa de Inicialización En esta etapa se hace la inicialización del microcontrolador y sus puertos, del SCI y del Xbee. Inicialización del microcontrolador La inicialización del microcontrolador consiste en inicializar el PLL (Phase Locked Loop) para ajustar la frecuencia del sistema a 48 MHz. Además, se hace la inicialización de los puertos y módulos a utilizar, estos son el puerto A, el puerto H y el módulo RTI (Real Time Interruption). Una vez hecho esto, se deben habilitar las interrupciones por medio de la directiva en ensamblador CLI. Se explican en detalle cada una de las inicializaciones mencionadas. Inicialización del PLL El diagrama de flujo de la rutina de inicialización del PLL se muestra en la Figura 3.22, mientras que el código de la misma se encuentra en el Apéndice M. Esta rutina se hizo con base en la rutina encontrada en el manual de la tarjeta Dragon12-Plus2 de EVBplus (2012). Lo que se hace es que se inicializan los registros CLCKSEL (CRG Clock Select Register) y PLLCTL (CRG PLL Control Register). Primero se inicializa CLKSEL igual a 0x7F, con lo que se logra que el bit PLLSEL (PLL Select Bit) esté en bajo, haciendo que el reloj sea el del sistema. Luego, se pone en alto el bit PLLON del registro PLLCTL, lo que activa el PLL. En el Apéndice C se muestra el detalle de estos registros. Según el manual de Freescale Semiconductor (2002a) sobre el bloque CRG, la frecuencia del PLL se obtiene por medio de 3.2. Donde PLLCLK es el valor de la frecuencia del PLL. Con OSCCLK igual a 8 MHz, se necesita que el 38 3 Diseño de la aplicación PLL_Init Fijar el valor del registro CLKSEL: CLKSEL &= 0x7F Fijar el valor del registro PLLCTL: PLLCTL |= 0x40 Fijar el valor de SYN y REFV: Para 48 MHz: SYN = 0x05 y REFV = 0x01 Para 8 MHz: SYN = 0 y REFV = 0 ¿LOCK == 1? NO SI Cambiar el valor de PLLSEL a 1: CLKSEL |= 0x80 Fin Figura 3.22: Diagrama de flujo de la rutina PLL_Init 3.4. Etapa de Inicialización 39 registro SYNR (CRG Synthesizer Register) tenga un valor de 0x05 y que el registro REFDV (CRG Reference Divider Register) sea igual a 0x01. P LLCLK = 2 ∗ OSCCLK ∗ (SY N R + 1) (REF DV + 1) (3.2) Una vez que se hace esto, hay que esperar que el bit LOCK del registro CRGFLG (CRG Flags Register) se ponga en alto, lo cual indica que el PLL está dentro del rango de tolerancia permitido para la frecuencia deseada. Cuando sucede esto, se cambia el bit PLLSEL a un 1 lógico, lo que provoca que se pase a utilizar el PLL y ahora la frecuencia del sistema es de 48 MHz. En el Apéndice M se encuentra el código de la rutina implementada para realizar esto. Inicialización del Puerto A En la tarjeta Dragon12-Plus2 se encuentra conectado un teclado 4x4 al puerto A del microcontrolador, cuya conexión se muestra en la Figura 3.16. Para leer este tipo de teclados, es necesario fijar las columnas como salidas y las filas como entradas (o viceversa). Además, inicialmente se fijan las salidas todas en bajo. La rutina de inicialización PORTA_Init hace esto, lo cual se muestra en el diagrama de flujo de la Figura 3.23. Inicialización del Puerto H En la tarjeta Dragon12-Plus2 hay 4 botones pulsadores conectados a los bits menos significativos del Puerto H. Para la aplicación del proyecto se utilizan los botones localizados en PH0 y PH1. Para la inicialización del puerto H hay que tomar en cuenta que este genera interrupciones, por lo tanto, hay que habilitarlas. En la Figura 3.24 se muestra el diagrama de flujo de la rutina PORTH_Init implementada. Esta lo que hace es fijar el puerto H como entradas por medio del registro DDRH (Port H Data Direction Register), al poner el registro PPSH (Port H Polarity Select Register) en bajo se fija que sea un flanco negativo el que va a accionar las interrupciones. Además, al poner en alto el registro PIEH (Port H Interrupt Enable Register) se habilitan las interrupciones. Para el detalle de estos registros, consultar el Apéndice D. 40 3 Diseño de la aplicación PORTA_Init Fijar PA0-PA3 (columnas) como salidas y PA4-PA7 (filas) como entradas: DDRA = 0x0F Fijar el valor de las columnas en bajo: PORTA |= 0xF0 Fin Figura 3.23: Diagrama de flujo de la rutina PORTA_Init El código de la rutina implementada se muestra en el Apéndice M. Inicialización del bloque RTI La inicialización del bloque RTI (Real Time Interruption) consiste en fijar el valor del perı́odo para el bloque, y además, habilitar las interrupciones del mismo. Con base en esto, se hizo la rutina RTI_Init, cuyo diagrama de bloques se muestra en la Figura 3.25. Para una frecuencia de 48 MHz, con un valor del registro RTICTL (CRG RTI Control Register) de 0x79 se logra que el perı́odo del RTI sea de aproximadamente 13,65 ms. Este valor se escogió siguiendo las recomendaciones que se encuentran en el libro de Almy (2011) para el manejo del teclado 4x4, en donde se recomienda realizar una lectura lenta (cada 10 ms aproximadamente) para evitar falsas lecturas del teclado debido a la vibración natural que tienen los dispositivos mecánicos. En el Cuadro E.1 del Apéndice E se muestra en detalle los posibles valores de este registro, además del detalle de otros registros relacionados al bloque RTI. 3.4. Etapa de Inicialización 41 PORTH_Init Fijar el puerto H como entradas: DDRH = 0; Fijar que un flanco negativo active las interrupciones: PPSH = 0 Habilitar las interrupciones del puerto H: PIEH = 0x7 Fin Figura 3.24: Diagrama de flujo de la rutina PORTH_Init Una vez hecho esto, hay que habilitar las interrupciones del bloque RTI, lo cual se hace por medio del bit más significativo del registro CRGINT (CRG Interrupt Enable Register). En el Apéndice M se muestra el código utilizado para implementar esta rutina. Inicialización del bloque SCI La inicialización del bloque SCI consiste en fijar el valor de la velocidad a la que se va a llevar a cabo la comunicación serial (baud rate), y además, fijar los registros de control SCI1CR1 (SCI1 Control Register 1) y SCI1CR2 (SCI 42 3 Diseño de la aplicación RTI_Init Se fija el tiempo para RTI a 13,65 ms para un reloj de 48 MHz: RTICTL = 0x79. Se habilitan las interrupciones de RTI: CRGINT |= 0x80 Fin Figura 3.25: Diagrama de flujo de la rutina RTI_Init Control Register 2). En la Figura 3.26 se muestra el diagrama de bloques de la rutina utilizada para realizar este proceso. Se tiene que BR es el valor que hay que fijar en los registros SCI1BRH/L (SCI Baud Rate Registers) para obtener el “baud rate” deseado, siguiendo la relación de 3.3. BR = M oduleClock 16 ∗ BaudRate (3.3) Luego de fijar el valor de los registros SCI1BRH/L, se fijan los registros de control. Para la aplicación desarrollada en el proyecto, se fijó el SCI1CR1 a un valor de 0, mientras que se fijó un valor de 0x2C para el registro SCI1CR2. Con esto, se trabaja la comunicación en un formato de 8-bit y sin paridad. Se habilitan el receptor y el transmisor, y además, se habilitan las interrupciones del receptor. En el Apéndice B se muestra mayor detalle de estos registros. El código de la rutina SCI1_Init implementada se encuentra en el Apéndice M. 3.4. Etapa de Inicialización 43 SCI1_Init Fijar el valor del baud rate por medio de los registros SCI1BDH y SCI1BDL. Fijar el valor inicial para el registro de control 1: SCI1CR1 = 0 Fijar el valor inicial para el registro de control 2, habilitando la transmisión y la recepción de datos, además de las interrupciones del receptor: SCI1CR1 = 0x2C Fin Figura 3.26: Diagrama de flujo de la rutina SCI1_Init Inicialización del módulo Xbee Wi-Fi La inicialización del Xbee consiste en realizar el proceso de asociación del módulo con un Access Point (AP). Para realizar esto, hay que fijar los siguientes parámetros: 1. SSID (Service Set Identifier) del AP. 2. Tipo de seguridad. 3. Clave de seguridad en caso de haberla. 44 3 Diseño de la aplicación Una vez fijos estos parámetros, si se graban en la memoria no volátil del Xbee, el módulo se asociará automáticamente al AP cada vez que se encienda. Para fijar los parámetros, se hace uso del API frame de comandos de la Figura 3.10. Los respectivos comandos son: (Digi International, 2011b) 1. ID (SSID): Se usa para leer o fijar el nombre del AP, puede ser hasta 31 caracteres ASCII. 2. EE (Encryption Enable): Permite leer o fijar el tipo de seguridad del AP. Los posibles parámetros pueden ser: • 0: sin seguridad. • 1: WPA. • 2: WPA2. • 3: WEP. 3. PK (Security Key): Permite fijar la clave de seguridad necesaria para accesar al AP. Este comando es sólo de escritura. Se realizó una rutina de inicialización, llamada Xbee_Init, que se encarga de enviar las tramas API correspondientes a los pasos mencionados anteriormente. Para esto, se hace uso de las rutinas de envı́o de comandos implementadas anteriormente. El diagrama de flujo de esta rutina se muestra en la Figura 3.27, en donde se observa que se espera hasta que el Xbee de una respuesta de OK cuando el comando fue fijado válidamente. De igual forma, se pide que dé el estado de la asociación, hasta que la asociación se realice de forma exitosa, se retorna al funcionamiento normal del microcontrolador. Para verificar si el módulo Xbee está asociado o no a un AP, se utiliza el comando llamado AI (Association Indicator). Por medio de una trama API “AT Command”, se envı́a este comando y el módulo Xbee da la respuesta de su estado actual. Cuando el módulo está asociado correctamente se obtiene como respuesta un valor de 0. Por lo tanto, a la hora llamar a la rutina de inicialización Xbee_Init, se envı́a este comando hasta recibir un valor de 0. Esto se hace durante 5 veces (valor escogido para cubrir el tiempo aproximado de una asociación exitosa, puede ser fácilmente cambiado), separadas por aproximadamente 1 s, luego se da el retorno de la subrutina si no se obtuvo 3.4. Etapa de Inicialización 45 el valor esperado de la asociación antes de cumplir el ciclo. Esto se hace para evitar que el programa quede en un ciclo infinito en el caso en el que se dé un error y no se obtenga el valor esperado de la asociación exitosa. Además de esto, se implementó una rutina que revisa el estado de la asociación (por medio del comando AI), y si el módulo Xbee no está asociado, entonces se llama a la rutina de inicialización nuevamente para que se realice el proceso correspondiente. Ahora, esta revisión se hace cı́clicamente por medio del bloque RTI cuando el valor de PH7 es un 1. Se tiene un contador el cual se incrementa cada vez que se da la interrupción del bloque RTI, cuando se llega a la cantidad de tiempo deseada, se llama a la rutina mencionada. En el Apéndice M se encuentra el código de esta rutina llamada Xbee_Assoc. De forma alternativa para la inicialización del Xbee, se implementó una rutina la cual permite utilizar el módulo Xbee como un creador de una red Ad Hoc. Para esto, se hace uso del botón pulsador SW4 conectado a PH1, el cual llama a la subrutina de inicialización del módulo para que funcione en este modo. Además de esto, se utilizó el DIP Switch 7 para controlar cuándo se trabaja en una red de infraestructura y cuándo en una red Ad Hoc. De este modo, cuando el PH7 está en alto se trabaja en una red infraestructura y se deshabilita la función del botón pulsador SW4. Y de otra manera, cuando el valor de PH7 está en bajo, se trabaja en una red Ad Hoc y se deshabilita la función del botón pulsador SW5. Cuando se llama a la rutina del creador de la red Ad Hoc, se mandan los respectivos comandos, en el Apéndice M se encuentra la rutina implementada. Además de esto, hay que configurar el dispositivo iOS para que funcione de manera correcta. Primero, por medio de la configuraciones de las redes WiFi, hay que conectarlo al Xbee. Luego, hay que fijar que la dirección IP sea estática, y fijarla al valor de 192.168.1.2, ya que esta es la que se fija por defecto en la rutina para el nodo adjunto. Y además, hay que fijar el valor de la máscara como 0.0.0.0. Una vez hecho esto, ya es posible utilizar la aplicación, en donde la dirección IP del módulo Xbee se fijó como 192.168.1.1. 46 3 Diseño de la aplicación Xbee_Init Se reciben las sirguientes variables: - ssid: cadena de caracteres con el nombre del AP a conectarse. - ee: (0-Sin seguridad, 1-WPA, 2-WPA2, 3-WEP). - pk: cadena de caracteres con la clave de seguridad. Además, se tiene la variable global de control stat. Xbee_ATCommandStr(0x4944, ssid) ¿stat == 0? NO SI stat = 0xFF Xbee_ATCommandStr(0x4545, ee) ¿stat == 0? NO SI stat = 0xFF Xbee_ATCommandStr(0x504B, pk) ¿stat == 0? NO SI stat = 0xFF Xbee_ATCommandStr(0x4149, ’’) ¿stat == 0? NO SI stat = 0xFF Fin Figura 3.27: Diagrama de flujo de la rutina Xbee_Init 3.5. El programa principal 3.5 47 El programa principal El programa principal es sencillo, ya que el manejo de los periféricos del microcontrolador se hace por medio de interrupciones. Por lo tanto, el programa principal básicamente se encarga de realizar las rutinas de inicialización mencionadas anteriormente, y luego, espera hasta que se de una interrupción. En la Figura 3.28 se muestra el diagrama de flujo del programa principal. El código implementado se encuentra en el Apéndice M, en donde el programa principal corresponde a la función main(). Se observa cómo después de realizar las rutinas de inicialización, se habilitan las interrupciones y luego el programa cae en un ciclo infinito. Este ciclo se encarga únicamente encender y apagar un LED (LED RGB de la tarjeta Dragon12-Plus2), el cual da una señal de que el dispositivo está en funcionamiento. Cuando se da alguna interrupción, esta es atendida y luego se regresa de nuevo al ciclo infinito. 3.6 La aplicación para los dispositivos iOS Aunque la aplicación fue desarrollada por un tercero, se explica el funcionamiento básico de la misma. Inicialmente, el dispositivo iOS debe estar conectado al mismpo AP al que se encuentra conectado el controlador. La aplicación tiene la opción de conectarse al controlador, esto se logra introduciendo la dirección IP que el AP asignó al módulo Xbee Wi-Fi. A la hora de realizar el proyecto, el Xbee Wi-Fi no soportaba DNS (Domain Name System), por lo que no fue posible realizar esta conexión por medio del nombre del “host”, sino que es necesario conocer la dirección IP del controlador. Se espera que el Xbee Wi-Fi soporte DNS en futuras actualizaciones del firmware. Una vez conectados, el usuario tiene la opción de presionar botones, los cuales tienen un código asociado el cual es enviado por Wi-Fi al controlador. El controlador se encarga de decodificar la información y realizar la acción correspondiente al código. Para el caso especı́fico del proyecto, se tienen 8 LEDs numerados del 0 al 7, y la aplicación consta de la misma cantidad de botones con la misma numeración. Cuando en la aplicación se presiona un 48 3 Diseño de la aplicación Inicio PLL_Init() Se inicializan los puertos B, J, M y P para el manejo de los LEDs. PORTA_Init() PORTH_Init() RTI_Init() SCI1_Init(BAUD_9600) Se habilitan las interrupciones: CLI Se hace toggle al bit PM2: PTM ^= 0x4 msDelay() Figura 3.28: Diagrama de flujo del programa principal 3.6. La aplicación para los dispositivos iOS 49 botón, se envı́a una orden por Wi-Fi al sistema controlador, lo que provoca que se de un cambio de estado del LED correspondiente, pero además, se muestra el cambio en la aplicación una vez que se tiene la retroalimentación del controlador. 4 Pruebas y Resultados Se presentan a continuación algunas pruebas representativas que se realizaron y sus respectivos resultados obtenidos, los cuales ilustran el correcto funcionamiento de las etapas desarrolladas en el proyecto. Para esto, se presentan en un orden similar al presentado en el capı́tulo del Diseño de la aplicación. 4.1 Prueba del manejo del SCI del 68HCS12 Para observar el funcionamiento del bloque SCI del microcontrolador, se utilizó el componente Terminal que tiene el simulador de CodeWarrior. Para utilizar este componente, es necesario activarlo por medio de las opciones del simulador en Component >Open>Terminal. Una vez activado, en los ajustes del componente hay que fijar el que sea el SCI1 el que se esté simulando. Para mayor detalle sobre este componente, consultar el manual del “Debugger” de CodeWarrior en el manual de Freescale Semiconductor (2009c). En la Figura 4.1 se muestra el detalle de la pantalla utilizada para la configuración de dicho componente. Para la prueba del bloque SCI, se realizó un programa sencillo el cual utiliza las rutinas implementadas anteriormente (SCI1_Init, SCI1_InChar y SCI1_OutChar). Se modificó levemente la rutina SCI1_InChar para que funcione de acuerdo a la prueba a realizar. En el Apéndice L se presenta la rutina utilizada. El componente Terminal simula los caracteres digitados en el teclado como entradas al bloque SCI. Sin embargo, aunque recibe la información, no se despliega en pantalla. Es por esto que por medio del programa hay que hacer que se muestre el pantalla lo que se digita. Esto se logra transmitiendo, por medio de la función SCI1_OutChar implementada, el caracter que se recibe por comunicación serial. El hecho de lograr que se desplieguen en pantalla los caracteres digitados quiere decir que se está enviando y recibiendo información por medio del puerto serial de forma correcta. Sin embargo, se hizo una 50 4.1. Prueba del manejo del SCI del 68HCS12 51 Figura 4.1: Pantalla de la configuración del componente Terminal de CodeWarrior utilizado para la simulación pequeña prueba para probar no sólo la recepción y transmisión de datos, sino también el manejo de datos que es lo que se necesitaba para el proyecto. El programa básicamente consiste en identificar una secuencia predeterminada y enviar un mensaje de acuerdo a los datos digitados. En el momento que se recibe hola (se digita por medio del teclado) y se presiona la tecla “Enter”, el programa verifica las cuatro letras, y envı́a, por medio del bloque SCI1, una respuesta HOLA MUNDO la cual es desplegada en pantalla. De lo contrario, si se presiona “Enter” y el mensaje es otro, se despliega en pantalla “ERROR”. En la Figura 4.2 se muestra la pantalla del componente Terminal utilizado durante la prueba. En rojo y minúsculas son los datos digitados por el usuario (datos recibidos por el SCI1), y en azul y mayúsculas son los datos enviados por el programa (datos transmitidos por medio del bloque SCI). Se observa que al digitar “hi”, como no es la secuencia permitida, se devuelve un mensaje de “ERROR”. La respuesta “HOLA MUNDO” se da únicamente después de recibir “hola”. Por medio de esta prueba se comprobó que el manejo del SCI1 se hace de forma correcta, ya que envı́a, recibe, y se hace manejo de datos de forma efectiva. 52 4 Pruebas y Resultados Figura 4.2: Pantalla del componente Terminal de CodeWarrior luego de la simulación 4.2 Prueba del manejo de los periféricos La prueba del manejo de los periféricos consistió básicamente en probar las funcionalidades de los botones y que estos trabajaran correctamente. Para el caso de los botones pulsadores en el teclado 4x4, se probó que funcionaran de modo que al presionar los botones numerados del 0 al 7, se encendiera el LED con el respectivo número. Al presionar alguno de los otros botones que no son los numerados del 0 al 7, entonces no hay acción observable. En la Figura 4.3 se observa una serie de imágenes que demuestran cómo al presionar el botón “3” se enciende el LED de igual numeración. Al presionar nuevamente el botón, se apaga dicho LED. Al presionar una de las teclas no válidas, el botón “C”, no se da acción alguna. Se inicia de un estado en el que todos los LEDs están apagados como se muestra en la Figura 4.3a. Luego, se presiona el botón “3” y el resultado es el mostrado en la Figura 4.3b en donde se enciende dicho LED. Para demostrar el funcionamiento “toggle” del programa, se presiona nuevamente el botón “3”. Esto provoca que se apague según se muestra en la Figura 4.3c. Por último, para corroborar que sólo los botones entre 0 y 7 tienen efecto, se presiona el botón “C”, lo que no provoca cambio alguno como se muestra en la Figura 4.3d. 4.2. Prueba del manejo de los periféricos (a) Estado inicial: LEDs apagados, luego se presiona el botón “3” (b) Se enciende el LED “3”, luego se presiona nuevamente el botón “3” (c) Se apaga el LED “3”, se presiona el botón “C” (d) Se mantienen los LEDs apagados Figura 4.3: Prueba realizada para el teclado 4x4 del Puerto A 53 54 4 Pruebas y Resultados 4.3 Prueba del programa principal Para probar el funcionamiento de todo el programa en general, en especial para la sección del manejo de instrucciones por Wi-Fi, se realizó una prueba con una PC. La idea es observar la interacción Microcontrolador-Xbee, y enviar órdenes por medio de Wi-Fi para observar los datos que envı́a el Xbee al recibir las órdenes. Pero además, observar que se den las acciones correspondientes en la tarjeta Dragon12-Plus2. Para esto, se utilizó el comando de la terminal llamado netcat (esto funciona en Linux y MAC OS). Para hacer la conexión de la PC con el módulo Xbee se introduce el siguiente comando: nc direccionIP puerto. Esto se hace una vez que tanto la PC como el Xbee estén conectados al mismo AP. Y donde direccionIP es la dirección IP del módulo Xbee y puerto es 9750 que es el puerto 0x2616 que se utilizó por defecto en el proyecto. Por medio de este comando es posible crear una conexión con el host con la dirección IP y por medio del puerto indicados. En la Figura 4.4 se observa una secuencia de imágenes donde se muestra la pantalla de la terminal con los comandos introducidos en la terminal (en rojo) y los recibidos del Xbee (en azul). Y además, se muestra la imagen de los LEDs en la tarjeta. Se observa en la Figura 4.4a que al enviar un “5”, se enciende el LED 5 y se envı́a a la PC “ON5”, indicando que el LED está ahora encendido. De igual forma sucede si se envı́a desde un 0 hasta un 7, tal como se observa en la Figura 4.4b al enviar un “0”. Luego, cuando se envı́a nuevamente un “5”, se apaga el LED y se envı́a un “OF5” indicando que ahora el estado es apagado, esto se muestra en la Figura 4.4d. Cuando se envı́a “R” se envı́an uno por uno los estados actuales de los LEDs tal y como se muestra en la terminal de la Figura 4.4e. Si se envı́a algún código diferente a los predeterminados, se envı́a el mensaje de “ERROR”, esto es lo que se muestra en la Figura 4.4c. 4.4 La aplicación para los dispositivos iOS Como se mencionó, la aplicación para los dispositivos iOS fue desarrollada por un tercero. Sin embargo, se muestra en la Figura 4.5 una secuencia de imágenes tomadas al realizar pruebas con la aplicación. 4.4. La aplicación para los dispositivos iOS (a) LEDs apagados y se envı́a comando “5” (b) LED “5” encendido y se envı́a comando “0” (c) LEDs “0” y “5” encendidos, se envı́a comando “8” (d) LEDs “0” y “5” encendidos, se envı́a comando “5” (e) LED “0” encendido y se envı́a comando “R” Figura 4.4: Prueba realizada al programa principal 55 56 4 Pruebas y Resultados Se observa cómo al presionar los botones de la aplicación que corresponden a cada uno de los LEDs, estos se encienden o apagan de acuerdo al estado actual. En la Figura 4.5a se observa que el estado de los LEDs corresponde a la imagen mostrada en la aplicación. Luego, se apagan los LEDs “4” y “7” por medio de los botones pulsadores, sin embargo, la aplicación muestra la misma imagen anterior tal y como se observa en 4.5b. Ahora, al presionar el botón “Refresh” de la aplicación, se envı́a al Xbee una orden para que reenvı́e el estado de los LEDs, con base en esto se actualiza la aplicación, lo cual se muestra en 4.5c. Con esto se corrobora el correcto funcionamiento de la aplicación implementada. 4.4. La aplicación para los dispositivos iOS (a) Estado inicial: LEDs “0”, “2”, “4” y “7” encendidos (b) Se apagan LEDs “4” y “7” por medio de los botones pulsadores (c) Se actualiza la aplicación Figura 4.5: Prueba realizada con la aplicación para iPad 57 5 Conclusiones y Recomendaciones Al finalizar el proyecto, se logra el objetivo del mismo, el cual consistió en el desarrollo de un dispositivo controlador, el cual pueda ser accesado de forma remota por medio de una red IEEE 802.11 y a través de un dispositivo iOS. Para esto, se hizo uso de un microcontrolador HCS12 de Freescale, y de un módulo llamado Xbee Wi-Fi el cual se comunica por medio de una comunicación serial con el microcontrolador, y ası́ es como se logra la conexión a una red Wi-Fi del microcontrolador. Para realizar el proyecto y cumplir con el objetivo general del mismo, fue necesario aprender sobre la arquitectura y el modelo de programación que tienen los microcontroladores HCS12 de Freescale. Una vez aprendido esto, se tuvo que investigar y aprender sobre cómo funciona el CodeWarrior IDE, ya que esta fue la herramienta utilizada para la programación. Como plataforma de hardware se utilizó la tarjeta Dragon12-Plus2 de Wytec, la cual contiene un microcontrolador 68HCS12. Por lo tanto, fue necesario también el estudio de cómo funciona esta tarjeta y cómo está hecha la conexión de los diferentes dispositivos periféricos utilizados. Una vez que se tenı́an las bases, se procedió a realizar la aplicación de comunicación. Para esto, fue necesario aprender sobre comunicaciones seriales asincrónicas y sobre el módulo Xbee Wi-Fi. La interfaz entre el microcontrolador y el módulo Xbee se realizó de forma exitosa, en donde fue posible recibir y enviar datos al módulo por medio de una comunicación serial. Además, por medio de las tramas API que son caracterı́sticas del módulo Xbee, fue posible hacer un manejo de datos el cual permitió realizar rutinas de control lógico. Con estas rutinas se controlaron 8 LEDs, a los cuales se les implementó también un sistema alterno de control por medio de botones pulsadores. Ya lograda la comunicación entre el dispositivo controlador y un dispositivo móvil (en este caso un dispositivo iOS), es posible realizar diferentes acciones 58 5 Conclusiones y Recomendaciones 59 de control. El alcance del proyecto fue realizar la comunicación y sentar las bases para las rutinas de control lógico de entradas y salidas. Con estas bases, en un futuro es posible implementar un sistema de domótica que permita controlar, por ejemplo la iluminación de un hogar, desde un dispositivo móvil. En cuanto a los problemas encontrados al realizar el proyecto, se tiene que el módulo Xbee Wi-Fi no soporta DNS. Esto representa un inconveniente para futuras aplicaciones que utilicen como base este proyecto, ya que el hecho de tener que saber la dirección IP del dispositivo controlador provoca que la aplicación sea poco amigable con el usuario. Se investigó con el fabricante de este módulo, y se espera que en actualizaciones futuras del firmware se implemente esta caracterı́stica. Sin embargo, como solución a este problema, se presenta una alternativa al módulo Xbee Wi-Fi, este es el módulo WiFly GSX de Roving Networks. Este módulo sı́ soporta DNS y tiene algunas ventajas en comparación con el módulo Xbee Wi-Fi, sin embargo, también tiene sus desventajas. En el Apéndice K se presenta un cuadro comparativo que se realizó con base en los manuales de usuario, en el cual se comparan algunas caracterı́sticas importantes de cada módulo. Con base en esto, sabiendo las ventajas y desventajas de cada módulo, se puede hacer la elección que más se ajuste a las necesidades de la aplicación a realizar. Como una recomendación más para mejorar el programa, se propone utilizar un “Watchdog”. De esta forma, se puede eliminar el LED que parpadea infinitamente en el programa principal, y se cambia por un LED controlado por las interrupciones generadas por el “Watchdog”. De esta forma, se sabe que el programa está funcionando correctamente. Por último, se presentan dos recomendaciones para mejorar a la aplicación del dispositivo iOS, las cuales ayudarı́an a que el rendimiento general del programa sea mejor. La primera recomendación es realizar el proceso de conexión y desconexión de forma automática. Es decir, cuando se presiona alguno de los botones, la aplicación hace el proceso de conexión, y una vez recibida la respuesta del Xbee y aplicados los cambios en la interfaz de la aplicación, se termina la conexión. Este cambio es el que hace posible que varios dispositivos se puedan conectar al mismo tiempo, ya que a como se trabajó durante el proyecto, la conexión se hace manualmente y se mantiene hasta que se cie- 60 5 Conclusiones y Recomendaciones rre la aplicación. Por lo tanto, al no cerrarse el socket, los demás dispositivos no pueden conectarse al módulo Xbee. Por otra parte, la configuración del módulo Xbee está hecha para cerrar el socket poco tiempo después de enviar información (el tiempo es definido por el comando de TCP “timeout”), y también está configurado para enviar información hacia cualquier dispositivo que inicie una comunicación con el módulo Xbee. Por lo tanto, al tomar en cuenta estas configuraciones se puede lograr la conexión de varios dispositivos. La segunda recomendación para mejorar la aplicación es realizar el proceso de actualizar la aplicación (Refresh) de forma automática. Es decir, enviar al Xbee el dato “R” de forma periódica, de modo que la aplicación siempre esté actualizada. Con las recomendaciones mencionadas, no sólo posible mejorar el rendimiento del programa, sino que también permiten hacerlo más funcional y más la amigable con el usuario. Bibliografı́a Almy, T. (2011). Designing with Microcontrollers - The 68HCS12. 2011 edición. Digi International, I. (2008). X-CTU: Configuration & Test Utility Software. Digi International, I. (2011a). Xbee Wi-Fi Development Kit Getting Started Guide. R Wi-Fi RF Module. Digi International, I. (2011b). Xbee EVBplus, L. (2012). Dragon12-Plus2 Trainer User’s Manual, 1.01 edición. Freescale Semiconductor, I. (2002a). CRG Block User Guide, 2.07 edición. Freescale Semiconductor, I. (2002b). MC9S12DP256 Port Integration Module (PIM) Block User Guide, 2.07 edición. Freescale Semiconductor, I. (2004). HCS12 Serial Communications Interface (SCI) Block Guide. Freescale Semiconductor, I. (2005). MC9S12DP256 Device User Guide, 02.15 edición. Freescale Semiconductor, I. (2009a). CodeWarrior Development Studio 8/16Bit IDE User’s Guide. Freescale Semiconductor, I. (2009b). S12(X) Assembler Manual. Freescale Semiconductor, I. (2009c). S12(X) Debugger Manual. Freescale Semiconductor, I. (2010). S12(X) Build Tools Reference Manual. Pack, D. J. y Barrett, S. F. (2001). 68HC12 Microcontroller Theory and Applications. Prentice Hall. Roving Networks, I. (2013). WiFly Command Reference, Advance Features & Applications User’s Guide, 1.2r edición. 61 A Microcontrolador MC9S12DG256 Se muestra el diagrama de bloques y el mapa de memoria de estos microcontroladores, extraı́dos de Freescale Semiconductor (2005). Es importante aclarar que el microcontrolador MC9S12DG256 tiene las mismas caracterı́sticas que el MC9S13DP256. La mayor diferencia entre ellos es que el DG256 tiene 2 puertos CAN, mientras que el DP256 tiene 5 puertos CAN. 62 63 A Microcontrolador MC9S12DG256 ! !! 9 % 8 $ !!9 !! !! !!% !!8 !! !! !!$ !9 ! ! !% !8 ! ! !$ *8 ## #' !-= !! '! .= > ., ,. @ ( !! ., ,. > #' !! # # ! (< $ (< (< (< 9 ($ ( ( (8 (% ( ( (9 ($ ( ( (8 (% ( ( (9 # # # # (6$ (6 (6 (68 (6% (6 (6 (69 !! !! $ 8 $ ' $ 8 % ' , , < < 9 $ 8 % 9 (")$ (") (") (")' (")% (") * -, .4 - . =-? . ;$ - 2, 9 % 8 $ !! !!% !!8 !! !! !!$ !!: !!; *% * * * * * * * * * * * ! 7 *$ * # .,- 7 !!" " ! /< ;$0 ! !% !8 ! ! !$ !: !; # # -5 *.4 !! !9 ! ! !% !8 ! ! !$ -5 (- !! #$ # -5 '! $ 8 % 9 ! ! ! ! #$ !! -+ & & & &# &$ & &' #) #) + '( #,-. . /#0 ! ! *' #$ # # #8 #% # # #9 !! -.- # (., .2 .-. 2.- #$ # # #8 #% # "% " " " " "# "$ " < .2 &-. . & !!< 1 6 !! $ 8 % 9 !! -,34- 2,. !?, . !! &! ., ,. *$ * * *8 *% * * *9 !$$ !$ !$ !$8 !$% !$ !$ !$9 !! !! &* !!" " 6 !! + + + 6 *$ * * *8 *% * * *9 % ! !!6 6 !! . . . .-, !$ !$ +# +$ + + +' Figura A.1: Diagrama de bloques del MC9S12DP256B 64 A Microcontrolador MC9S12DG256 ! " #$ " !!"# $%&&&& ' %&())* + Cuadro A.1:! Mapa memoria de los dispositivos " de ! " # $ %$& % ' % ( ) * + ! $ " " ( ,&-' %.' " / // 0 1 /! /( &- , 0, 22 ! ! ( 3,& ,4 5 6. " &3, 6! " #( ,' %', $ . " &3, % / 7 3 , ". " &3, 7 ! " ( , 5 5&, 8,& " % % , 5 5&, 8,& " %" %( , 43, 8,& " " " ( %,, 2- %2 " ( ( , 43, 8,& " (" (( , 43, 8,& " ( (,3 ' 6 ' ( $ /( ,' %', $ . " &3, % / ! ( , &,,. , 9 6! ! " ( , &,,. , 9 6! (( , &,,. , 9 6! /( , &,,. , 9/ 6! ! ( ', 6! " ( , &,,. , 9! 6! /(( $ ((( ,, /((( ,, 6/"! / !#6 "" ! ((( (: (,3 " ((( (,3 ,' 7 ; 6/"! (((( (: (,3 6/"! A Microcontrolador MC9S12DG256 65 ! % " - ,& # " % & / 0 1 23 4053 6 728 7 4 1 " " ) % $ / 0 1 40538 7 2 4 1 % / 0 1 9 00 8 9 : 0 ) 7" ; 92 /# 6 %$ . 8 9 ) < 9 : 9 0 " " ) % $ "'#"%( 4 9 : 0 ) 7 ; 97 !"#$%& !"#$%& !"#$%& "')(*"* ($%+ &,(-+" .,) &)",+ &,(-+" .,) 4* /6 5 8 Figura A.2: Mapa de memoria del MC9S12DG256B !" 66 A Microcontrolador MC9S12DG256 #$% #$% & Cuadro A.2: Vectores de interrupción del MC9S12DP256 #$% & ' ) !!!" !!!! # $ $ % !!!" !!!& ' ( $ ))*) +(" (, % ( '% *$% +! % *% !!!-" !!!. / $ / % !!!0" !!!1 $ $ % % !!!2" !!! 34 $ $ !!!5" !!!6 74#8 79. $ !!!" !!!: 4#8 49. 4#8# +4#8$, % ! !!!;" !!! # * 4 49. #4$* +#*4, !; !!" !!! * ; 49. *4 +;4, !!" !!& * 49. *4 +4, !!-" !!. * 49. *4 +4, - !!0" !!1 * : 49. *4 +:4, 0 !!2" !! * 5 49. *4 +54, 2 !!5" !!6 * 6 49. *4 +64, 5 !!" !!: * 2 49. *4 +24, !!;" !! * 49. *4 +4, ; !!&" !!&! * <= 49. *# +*/!, & !!&" !!&& - <= 49. -*) +-/>4, & !!&-" !!&. 49. -*) +-4, &- !!&0" !!&1 4; 49. ;# +4" *4, &0 !!&2" !!& 4; 49. ;# +*4" *4" #4" 4)4, &2 !!&5" !!&6 4 49. # +*4" *4" #4" 4)4, &5 !!&" !!&: -*&; 49. -*&;*) +-4, & !!&;" !!& -*& 49. -*&*) +-4, &; !!" !!! ? 49. *? 4! +*? 4, !!" !!& !!-" !!. +,, +,,- ( &= <= ) & ./ 49. *4!+*4, 49. (*)+(@4, - * ) 012) .3*4 + +5 +,,5 +,, ! )11 * !*6021.(*'4 +,,7 +,,8 ! # * !*60 2#*'4 +7 +,,% +,,9 :1 * :1 $2*'4 +% +,,; +,,$ ** * * 2* *'4 +; +,, ' +,, , #)*$ * #)$$ 2#)*' #)0*'4 + ' +,, +,, : #)*% * #)%$ 2#)*' #)0*'4 + ''). * ''012*' '*'4 + & +,, +,, - ,1&#" * ,012*' '*'4 + +,, 5 +,, &6; * &6;*' 2)*'4 + 5 +,, 7 +,, 8 &6; * &6;*' 2#*' .3*'4 + 7 +,, % +,, 9 &6; * &6;*' 2<,*'4 + % +,, ; +,, $ &6; * &6;0*' 20<'*'%0<'*';4 + ; +,,&' +,,&, &6$ * &6$*' 2)*'4 +&' +,,& +,,&: &6$ * &6$*' 2#*' .3*'4 +& +,,&& +,,& &6$ * &6$*' 2<,*'4 +&& +,,& +,,&- &6$ * &6$0*' 20<'*'%0<'*';4 +& +,,&5 +,,& &6% * &6%*' 2)*'4 +&5 +,,&7 +,,&8 &6% * &6%*' 2#*' .3*'4 +&7 +,,&% +,,&9 &6% * &6%*' 2<,*'4 +&% +,,&; +,,&$ &6% * &6%0*' 20<'*'%0<'*';4 +&; +,,-' +,,-, &69 * &69*' 2)*'4 +-' +,,- +,,-: &69 * &69*' 20<'*'%0<'*';4 +- +,,-& +,,- &69 * &69*' 2<,*'4 +-& +,,- +,,-- &69 * &690*' 20<'*'%0<'*';4 +- +,,-5 +,,- &67 * &67*' 2)*'4 +-5 +,,-7 +,,-8 &67 * &67*' 2#*' .3*'4 +-7 +,,-% +,,-9 &67 * &67*' 2<,*'4 +-% +,,-; +,,-$ &67 * &670*' 20<'*'%0<'*';4 +-; +,, & +,, +,,' +,,, ) ) * * )0)*, 2)0)*'4 +' +,, +,,: ) '= # * )#:6 2)*'4 + +,,; +,, ! !" #$ B Serial Communication Interface (SCI) del microcontrolador " # MC9S12DG256 Se muestran los diagramas del SCI del microcontrolador de bloque MC9S12DG256, ademásde los registros del mismo. fueron extraı́dosde Freescale Ambos Se miconductor (2004). !" ( #$ ÷&' $ * " % $( Figura B.1: Diagrama de bloques del SCI ! ! "# " $ % & % '( )*+ 67 $ % &'" (# ) !!!% " ) " # % 68 B SCI del MC9S12DG256 ' ! $ ! # " & ' ! & ! %! ! %! Figura B.2: de bloques del transmisor del SCI Diagrama !" # $ # ! "# # ! $ % "#&"'! %( ( ( %&! ) % ))%) ( ) * # +' , ---) ! " # B SCI del MC9S12DG256 69 # $ $ ! &$ %'( ) ' ! " ! # '( Figura B.3: Diagrama de bloques del recepctor del SCI !" # $" $% # '( # $ # $%%& # # # *) # # # $ # * !" !" ' #() $* &) &* !" #+ ( !" -, ,) &, ( *. ! * '+ %$(' ' ,& - () ( ) ...+ &$ % *) $) *) ) *) * , $) % * * * * * * * * !" !" !" !" #$% / 0 1 23 ! del Figura B.4: Registros SCI " # # 0 1"#2 3" C Clocks and Reset Generator (CRG) del microcontrolador MC9S12DG256 ( 3 4 )) %& 1$%%&666666666666666666666666666666666666 ( )) 0 - ./ )) # , - . 1"#2 3" / 0 1 2 ( 3 4 )) Se muestran de los correspondientes a este34 bloque,342 utiliza2 el detalle 2 %& registros 1$%%& 34. 34/66666666666666666666666666666666666 340 6 341 ( )) dos en el proyecto. Las imágenes fueron tomadas de Freescale Semiconductor 2 2 2 2 2 2 2 2 (2002a). 5" 0 0 1"#2 3" 1"#2 3" - )) # ./ , - 2 2 2 !"#$ % # & '( . / 0 1 2 34. 34/ 340 341 34 342 2 2 2 2 2 2 2 5" !"#$ % # & '( )" *+ # &*( Figura C.1: Registro SYNR !" !" " # ! $%%& '! ( )# - )) # ./ , . / 0 1 2 2 2 2 2 0 1 2 )" *+ # &*( 2 2 2 2 2 2 2 2 !" !" " # ! 5" $%%& '! ( )# - )) # ./ )" *+ # &*( , - 2 2 Figura C.2: Registro REFDV . / 0 1 2 * 2 2 2 2 2 2 0 1 2 2 2 2 2 5" )" *+ # &*( + # &,( %+ !" "(" " # * 70 + # &,( %+ !" "(" " # 4 3")10#" " $ 5#2 # 666) 01 '1 #$%& #"'( #$%& #$%& )%* )! %"'( *" )%* )%* C CRG del MC9S12DG256 & ' +,"()'(% * . 71 + '" " %, '"'( ' " * +,, - ./ . / 0 1 2 ! " # $ %#$ # -##)# -))4)5 $55 -##5 %5 5 %$-5 ) &' &' 3 " * +,- . % *+,., ( ) & 'CLCKSEL "()'(% Figura C.3: Registro ! &' " #&' $ %#$ # &' % *+,- ., ! " ' !" '" " & -##)# -##!'' # )' () # -#'** + . / 0 1 2 % %3% "&& $ '() 1 2 3 4 &4 '**&( 5& 6 ' 3 ,1 + $4 52 666, 1 -)- ! ! ! ! ! '- )- ! 5 $ Figura C.4: Registro PLLCTL !"# # , + $ % $+ % - -, - , # . %# ) ! ! , ) % % / ) + & !'' # () , . / 0 1 2 5,6 76 38 !" +," 5,6!" 38!" !"#$ %3% !" #"$ % &4 9,%3 +," 4 *+, '**&( '#* * & $ % '**&( #'** ) + 0 #'** 0 ,#'**&( , Figura C.5: %# Registro CRGFLG # # $ . '**)-* ! !" # ! " / .&,* " 0 - $ 111& *, !" ! ! $!%&'( !" ) &! * &! * +," # + " +," ! "# $%& * /0(1 ( ! + #,,- .' % & +#,& ' +#,' +#, ( +#,( +#, ) +#,) +#, % * +#,* D Puerto H del microcontrolador MC9S12DG256 !' () $%& . . . . . . . . - Se muestran el detalle de los registros " ! correspondientes a este bloque, utilizados en! el proyecto. Las imágenes fueron tomadas de Freescale Semiconductor # $ # (2002b). + #,,- . % & ' ( ) % * //,& //,' //, //,( //, //,) //, //,* * * * * * * * * - * /0(1 ( ! ** ( $& Figura D.1: Registro DDRH + #,,-. % & ' +#,& +#,' * * ( ) % * +#, +#,( +#, +#,) +#, +#,* * * (,0*( #( %2 1 * - 333,*0 * * * - ! #0'1 ' ! "# $%& * ( 1 /0(1 ' Figura D.2: Registro PTH + ,--. / 0 1 2 3 4 0 ! $% $%1 $%2 $%3 $% $%4 $% $% + #,,- .' % & +#,& ' ( +#,' +#, +#,( +#, . . ) +#,) +#, % * +#,* . . . !" # $ %# & Figura D.3: Registro PPSH . . . - !' 72 () $%& ! " " # " " # $%&' (! $ " % " " % #" )*% " # ! $ # # % + " % # *" " % #" )*% " !" # $ %# & ! #0'1 ' ! " " # " " D Puerto H del MC9S12DG256 73 # $%&' ( $ % " " % #" )*% " % + # " % # *" " % #" )*% " % + # " % # + ,--. / 0 1 2 3 4 0 )% )%1 )%2 )%3 )% )%4 )% )% '( )'!* $ %) & Figura D.4: Registro PIEH ! " ", % )%&' ( ) % ) ) - #" ./ # 01!2 ! '-0!' ,' 23 1 . 444-!0 , *--. / 6 * 7 8 9 : $ 6 ( &' * &' 7 &' 8 &' 9 &' &' : &' $ &' ( ( ( ( ( ( ( ( ( - !" # $ % & Figura D.5: Registro PIFH 1!2 ! ! "#$% &' #(% &' )*(+ , & ' $ - . " / #$% ( -0 #(% ' $ E Real Time Interruption (RTI) del microcontrolador MC9S12DG256 Se muestran el detalle de los registros correspondientes a este bloque, utilizados en el proyecto. Las imágenes fueron tomadas de Freescale Semiconductor '12 (2002a). * +,, - ./0 . ) / 0 1 2 #$%& )%* 3 " ! "#$% Figura E.1: Registro CRGINT & 9:; 9:; '12 ( #)) % *+ . # $ # !" 00 $ $ $ $ $ / $ / $ $ $ $ #$%& #"'( #$%& 12 ! ( #$%& ! )%* )! %"'( *" Figura E.2: Registro RTICTL )%* )%* & ' "()'(% "#$% + '" " %, '"'( ' " ! " &' " * +,, - ./ #$ . / %! 0 &! 1 2 !! ' ( ! !( ! ' "&' !) -##)# -))4)5 $55 -##5 %5 5 %$-5 !(( &* 74 ' " !!+ ! ,&&*-" ) 3 " &' ,- ./ & 0%1 02%31 4 "()'(% & ' #! 5 5! 5 55! 55 5! 5 5! 55 53! 55 56! 555 52! & 9:; ( #)) % *+ . $ E RTI del MC9S12DG256 00 $ $ # / $ # / $ $ $ $ $ $ $ 75 12 ! ( ! & 9:; "#$% ! " &' " #$ %! &! !! ' ( ! !( ! ' "&' !) !(( &* ' " !!+ ! ,&&*-" Cuadro E.1: Valores de los posibles divisores de frecuencia para RTI &' ,- ./ & 0%1 02%31 4 #! 5 5! 5 55! 55 5! 5 5! 55 53! 55 56! 555 52! ÷5! ,337 /$ // / /# / / / 5 ÷! ,337 4/$ 4// 4/ 4/# 4/ 4/ 4/ 5 ÷! ,337 #4/$ #4// #4/ #4/# #4/ #4/ #4/ 55 ÷3! ,337 4/$ 4// 4/ 4/# 4/ 4/ 4/ 5 ÷6! ,337 4/$ 4// 4/ 4/# 4/ 4/ 4/ 55 ÷2! ,337 4/$ 4// 4/ 4/# 4/ 4/ 4/ 55 ÷! ,337 .4/$ .4// .4/ .4/# .4/ .4/ .4/ 555 ÷! ,337 54/$ 54// 54/ 54/# 54/ 54/ 54/ 5 ÷8! ,337 64/$ 64// 64/ 64/# 64/ 64/ 64/ 55 ÷5! ,337 /$4/$ /$4// /$4/ /$4/# /$4/ /$4/ /$4/ < ):& # = >; % ???) &: F Proceso de desarrollo de CodeWarrior Se muestra el diagrama de flujo que representa el proceso de desarrollo que sigue el IDE CodeWarrior, este se extrajo de Freescale Semiconductor (2009a). 76 F Proceso de desarrollo de CodeWarrior 77 # !" # $ # % & $ $ ' %( Figura F.1: Diagrama del Ciclo de Desarrollo en CodeWarrior G Dragon12-Plus2 Se muestra la asignación de pines de entrada y salida que tiene la tarjeta de desarrollo Dragon12-Plus2, esta información fue extraı́da de EVBplus (2012). 78 G Dragon12-Plus2 79 Cuadro G.1: Uso de los puertos de entrada y salida en la tarjeta Dragon12, lista 1 " $ & % ! # % % %" %$ %& " $ '( '( '(" '($ ) ) )" )$ )& ) )% ) "& " "% " "! "# $ $ *+, - ./0- *+, - ./0- *+," - ./0- *+,$ - ./0- *+,& *+, *+,% *+, + + +" +$ +& + +% + % & $ $# $! $ $% 0- (12 34! ' . . ." .$ .& . .% . " &# $ $& $$ $" , (12 - 20 (12 34 , (12 " - 20 (12 34& , (12 $ - 20 (12 34$ , (12 & - 20 (12 34" , (12 , (12 % , (12 , (12 ! 5 5 5% 5 "" " ## #! ,' '3&! *+, 0 3, - ,3 $ 3* - ,3 $ 7 7 7" 7$ 7& 7 7 ! % " # ! '3 *, + *, ,)& *, 0/-1 ,) *, 0/-1 ,)% *, 0/-1 ,) *, 0/-1 ' 4 *, - 6- " 5" - 6- " 5" 80 G Dragon12-Plus2 Cuadro G.2: Uso de los puertos de entrada y salida en la tarjeta Dragon12, lista 2 ) . ** *. !" # $ $ !" # ! !" # ! %&'( ! '+)) ," /$ 6 " .1 $0# 21$ " .1 $0# 21$ " .1 $0# " .1 $0# !3 %45 '" !3 %45 '" !3 %45 '" !3 ! ! ! ! ! ! !) !. *6 6 6 6 6 6 6 6) ! / 7 %8 ,"56 ! / 7 9+ ,"56 ! / 00 7 %87 $ # : ! / 00 7 9+ ! '+))7 !" # $ ; ! ,:! '+))7 !" # $ ; ! ,:!'< '+))7 !" # $ ; ! ,: !! ; ! ,:-7 %&'( $/ =$ + + + + + + +) +. 6 ) . * /$ /$ /$ % $ 0 3 / = > = !0? ,/0/5"/ ,/$ " $ #5"/ $ ,1$ 7 /$ " $ #- ). )6 . . . .. .6 * )* . . . .) .* * * "1/ $ 7 !. "1/ $ 7 !. /$ /$ '= ,0= @+0/ ,7 ' /$ + 0 8% 9 ; 0/ # " 0/ 4" A ; 0/ # " 0/ 4" B ; 0/ # " 0/ 4" /$ /$ /$ /$ /$ ) . ,/0/,/0/,/0/,/0/,/0/,/0/,/0/,/0/- ,0/,/0/,/0/,/0/- " " " " " " ") ". "* "6 " " " " " " H Pines del Xbee ! " #$ Se muestra la distribución de pines en el módulo Xbee Wi-Fi, esto fue extraı́do ?. de H.1: Asignación de pines en el Xbee Wi-Fi Cuadro %&!" $ "$" & & ' $ ( 8 = * ) 0 + 1 @ 7 9 : #;3<#,;= #<$<#,;* #,;<(,>.,; 223 #,;7<( .7 #,;<( . " #3<%22(>/<#,;1 ?9# #,;*<#*<(,>.;, # ! , ! ! 3<#,;+ ; !!" & <?(,; = * ) ;>%22(<#,;@ :2 <#,;) ; , ; ! ; ." ,"<?(,; 9 ,"<?(,; 0 3<#,;0 , !!" & <?(,; + #=<#,;=<(,>2% 1 #<#,;<(,>%A @ #<#,;<(,>339 7 #7<#,;7 # ! ; , ; #'" , ! # (& 3 # 3 # , ?(,;< (, ." ?(,; ?(,; # 9 ( <?(,; ?" ?(,;<(, , $ ,<?(,;<(, $ ,<?(,;<(, 4 $ ,<?(,;<(, $ ,<?(,; 81 I Comandos AT del Xbee Se muestra la lista de los AT Commands disponibles para el Xbee Wi-Fi. Esta lista se extrajo de Digi International (2011b). Cuadro I.1: Comandos AT para Direccionamiento /0 /5 7 4 ! ? + !"# $ " % & '(')*+'++, 1 23 2 4 " 2 ! 6 2 4 6 2 4 ') 8 9 #*1 2 8 9 #*1 6 !! ! / = 2 2 6 2 & 6 " $ " ! " " 2 6 ! 2 $ ! "# " 6 " " @> 1 " " + 1 +&:::::: $ %& ' " & : 6 6 A & " % +&.#= 9" *# 6 , ++++ - ........ ++++ - ........ ........ ++++ ++++ - ........ ++++ ++++ - ........ ++++ + 1 +&:::::::: ; 16< 61 + 1 +&:::::::: ; 16< 61 +1>6 !! !! %+&+, + 1 +&:::: +&)') + - +&:::: +&)') +1+&:::::::: +&.++++ + 1 +&:::: ; 16< Cuadro I.2: Comandos AT para Networking !" % & & ' ( ')( . * 0 0 & * & # !" *+) , "+) - + * / # " + * / % " / *+*122 31 "** 4 #$$ * * *1* 82 I Comandos AT del Xbee 83 Cuadro I.3: Comandos AT para Seguridad 55 & 65 6 6- 8 7 7 * / " / 6 - / 6! + 65 * +!"+ 6 6- 5 9 "! 65 & ':; "-< . ( * Cuadro I.4: Comandos AT para la interfaz RF $ ! . 2 " *122 % . # $ % # 0*+= <*-"" :9 0 :90 * '+ ( . ) % ) */ = ) "+= ) -+ = ) !+ "* ) ;+ "9 ) ; "+*15 3 4 *+ + "+ " 0 - / - 0 ! / 99 0 ; / "" 0 9 / : 0 : / > 0 = / "- 0 < / "< 0 > / -; 0 *1* / !: 0 *1*) / ;< 0 * 84 I Comandos AT del Xbee Cuadro I.5: Comandos AT para la interfaz Serial ! ' & !( ' 0 ' -" . & $ $ % , . %& & . ' 1 2&% 2 3 ,&& %& % ' 4. 2&% 2 3 5 . & $ 1 . % . 0 # ' 0 ' -" . & 1 # . %&' ' - . % $ $ . 9"' +, % $ 7 1 &'/ ' -" % $ . $ *. & :% $ 7 ; ' +"8)/ . .1 2 $ %$$# . " 7 ' "#& $ ., && "8 5 . *. & :% ## $ . % ' ! * ,. 1 . 9" 2 %$$ "# $ ' & -" $ . (8 & $ . " %&' "% $ ! $#% $ . (8 & $ . " %&' 0 "8 ! "# ) ) !(*& ) !(*& +,- & . / * + % / ) ) ) 3 ) 6 ) 6 ) 3 ) ) 3) * +* % 67 / ) 1 ) 2 1 ) 8 1 ) ) * < . = 3 ) & ) &, & ) # & % ) # & % % 5 &, ) # & % % 5 .#. ) "*3 & +&, &/ ) "*3 & +.#. &/ ) & ) " $&, & ) # & % ) # & % % 5 &, ) # & % % 5 .#. $%& I Comandos AT del Xbee 85 Cuadro I.6: Comandos AT de Diagnóstico + 0 3 !" # $%$ % ! ! $%$ & ! !" , " !" -% .( &/( + 1 , 2 &&& ' 3 " 1 4 ! 0 0 5 &&/ 6 .( 7 " ! &/8 ' & 6 3 330 & 8 6 330 # & 9 6 330 4 ! 1 &/ 6 : 1 5 0 4 " + & 6 : 1 4 0 4 5 ! &((6 : " 330 2 '7 0 " ! 0 &&&4 3 " " ! 330 ;<<4 ! !" 0 330 ;<<4 " ! 0 0 4 2 &/ 6 0 " =& // (( 6 3 6 3 " " 2 &&> 4 &/>.4 & >. 4 &8>.? 3 6 330 # 0 > 330 & ' &(((( ) ' "* ("' & ' &(((( ) ' "* ("' &' "* ' ' ' ' '& =@ ' . 4 ! " 4 ! 300 . 0 4 # " &== ! !" A B % ! " 330 1 & 1 # 330 % 4 ! 4 5 !" 8/ 8C & 6 & ' ' 86 I Comandos AT del Xbee Cuadro I.7: Comandos AT para Ejecución " ! " ! # $ # % ! # &&' ( ! ) ) ) ) ) ) ) ) & ) ) ! * + ! ,+-., ! ! ! # +- ! !# / #0 " " ! 11( %22 ! # # ! & J API Frames del Xbee Wi-Fi la Se muestra lista de los API Frames del Xbee Wi-Fi que se utilizaron en el proyecto. Esta lista extrajo de Digi International (2011b). se ! "# % &' $ & '' + ! , ' , + ) ! $ '1 & ! ! '1 ) 6 & 9 ! . % &- . 1 2 " 2 1, () ) )* * ) ) ) / ) * /! '0'12 ' % &0 1 $ & ' '1 % & '' 1 $ & ' '1 '+ 3 /!4 '3 . 5 ', & & ' 3 ' 5 5 $ 7 . 8 ) /! ) ) '- ,27:;<8 '1 1-7:<8 '" 1.7:<8 '2 1.7=<8 '0 17==8 1 /! . ) /! . ) / ', ) 2 ) ) + ) Figura J.1: Estructura del API frame TxIPv4 87 88 J API Frames del Xbee Wi-Fi ! " #$% %$& ' ( ) *# $%! *$ %$ +,-!+./! !+ 0 123 +,-!+./! !+ &! 7 #$% % #$% $4 %$& 0- # +. $ #$% +. $ $ 4 56 8 + 7 - + 0 9 4 8 & : #/ . 5 ./ 8 / -. 7 , +. 8 + -. 7 ++ +. 8 +- ; *$' +; $ < $ +0 +& &/ =2= +: .: == +. . == +5 . == +/ . == +, +0 +,-!+./! !+ & ! * +& / 0 ! Figura J.2: Estructura del API frame RxIPv4 J API Frames del Xbee Wi-Fi 89 ! " # $% % & ' ( )* ,'- . +'- / 0 1 ( 2 " + ' ( ! 6 !" &$ $ $% " . ,'- 0 2* &# +'- 4 25 # ! & 3 % '! 7 7 3 3 ) 0* $ $ 1 $ J.3: Estructura del API frame para enviar comandos AT Figura ! " #" #$ % % &' $ " ' " ( " " # $% $ ' , ) " ) )! ' ) " ' *+ -& ( ,& / 0 1 2 ! 2/ #&% ,& 4 22 #'% . " ! . 3 " 5 67 ( 5 +6 / 5 $ 1 5 $ ) " " " * ( -& 0 ) 8 " " "" 1 Figura J.4: Estructura del API frame de respuesta de comandos K Comparación Xbee - WiFly Se presenta un cuadro comparativo entra las caracterı́sticas del módulo Xbee Wi-Fi y el módulo WiFly GSX. Solamente se mencionan algunas de las caracterı́sticas, para mayor detalle se recomienta revisar los manuales de usuario de Digi International (2011b) y de Roving Networks (2013). 90 K Comparación Xbee - WiFly 91 Cuadro K.1: Comparación entre el módulo Xbee Wi-Fi y el módulo WiFly GSX Caracterı́stica Xbee Wi-Fi WiFly GSX Certificaciones FCC, IC, ETSI, C-tick, TELEC FCC, CE, IC Estándares IEEE 802.11 soportados b, g y n byg Aplicaciones de red incorporadas DHCP client, UDP y TCP DHCP client, DNS client, ARP, ICMP ping, FTP client, TELNET, HTTP, UDP y TCP Software especializado para configuración del módulo X-CTU de Digi No tiene, se utilizan programas terminales como TeraTerm (Windows OS) o CoolTerm (Mac OS-X) Tipos de red Infraestructura y Ad Hoc Infraestructura, Ad Hoc y “Soft A” (Access Point con funcionalidades limitadas) Modos de interfaz serial Modo transparente y modo API Modo transparente L Código en C de las rutinas implementadas para pruebas L.1 Rutina de prueba para el bloque SCI //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−SCI1 InChar Prb−−−−−−−−−−−−−−−−−−−−−− // M o d i f i c a t i o n o f SCI1 InChar f o r t e s t i n g // I n p u t : c h a r r e c e i v e d by SCI // Output : none void Hi ( void ) { SCI1 SCI1 SCI1 SCI1 SCI1 SCI1 SCI1 SCI1 SCI1 SCI1 SCI1 // Send ”HOLA MUNDO” OutChar ( ’H ’ ) ; OutChar ( ’O ’ ) ; OutChar ( ’ L ’ ) ; OutChar ( ’A ’ ) ; OutChar ( ’ ’ ) ; OutChar ( ’M’ ) ; OutChar ( ’U ’ ) ; OutChar ( ’N ’ ) ; OutChar ( ’D ’ ) ; OutChar ( ’O ’ ) ; OutChar ( 1 3 ) ; // Enter } void E r r o r ( void ) { SCI1 SCI1 SCI1 SCI1 SCI1 SCI1 // Send ”ERROR” OutChar ( ’E ’ ) ; OutChar ( ’R ’ ) ; OutChar ( ’R ’ ) ; OutChar ( ’O ’ ) ; OutChar ( ’R ’ ) ; OutChar ( 1 3 ) ; // Enter } void SCI1 InChar ( char rxData ) { SCI1 OutChar ( rxData ) ; // D i s p l a y I n p u t i f ( rxData == 1 3 ) r x I n d x = 0 ; e l s e r x I n d x++; // I n c r e a s e r x B u f f e r i n d e x r x B u f f e r [ r x I n d x ] = rxData ; // Save d a t a I n i n b u f f e r i f ( r x B u f f e r [ r x I n d x ] == 1 3 ) { // When ENTER p r e s s e d i f ( r x B u f f e r [ 1 ] == ’ h ’ ) { rxBuffer [1]=0; // Find i f ” h o l a ” was p r e s s e d // C l e a r d a t a i n b u f f e r 92 L.1. Rutina de prueba para el bloque SCI 93 c o n t++; } i f ( r x B u f f e r [ 2 ] == ’ o ’ ) { rxBuffer [2]=0; c o n t++; } i f ( r x B u f f e r [ 3 ] == ’ l ’ ) { rxBuffer [3]=0; c o n t++; } i f ( r x B u f f e r [ 4 ] == ’ a ’ ) { rxBuffer [4]=0; c o n t++; } i f ( c o n t == 4 ) Hi ( ) ; MUNDO” else Error () ; cont = 0 ; } } // I f ” h o l a ” was r e c e i v e d , r e t u r n ”HOLA // I f not , send ”ERROR” M Código en C de las rutinas implementadas M.1 Rutina de inicialización del bloque SCI //−−−−−−−−−−−−−−−−−−−−−−−−−−−−S C I 1 I n i t −−−−−−−−−−−−−−−−−−−−−−−−−−−−− // I n i t i a l i z e S e r i a l p o r t SCI1 // I n p u t : baudRate i s t h e baud r a t e i n b i t s / s e c // Output : none void S C I 1 I n i t ( unsigned short baudRate ) { SCI1BDH = 0 ; // BR=MCLK/(16∗ baudRate ) // Check i f b u s f r e q u e n c y i s 24 MHz #i f BUSCLOCK == 24 // For 24 MHz b u s f r e q u e n c y switch ( baudRate ) { case BAUD 2400 : SCI1BDL=113; SCI1BDH=2; case BAUD 4800 : SCI1BDL=56; SCI1BDH=1; SCI1BDL=156; case BAUD 9600 : case BAUD 19200 : SCI1BDL=78; case BAUD 38400 : SCI1BDL=39; case BAUD 57600 : SCI1BDL=26; case BAUD 115200 : SCI1BDL=13; default : SCI1BDL=156; } break ; break ; break ; break ; break ; break ; break ; // d e f a u l t : 9600 b p s #e l s e // For 4 MHz b u s f r e q u e n c y switch ( baudRate ) { case BAUD 1200 : SCI1BDL=208; case BAUD 2400 : SCI1BDL=104; case BAUD 4800 : SCI1BDL=52; case BAUD 9600 : SCI1BDL=26; case BAUD 19200 : SCI1BDL=13; case BAUD 38400 : SCI1BDL=6; case BAUD 57600 : SCI1BDL=4; case BAUD 115200 : SCI1BDL=2; default : SCI1BDL=26; } break ; break ; break ; break ; break ; break ; break ; break ; // d e f a u l t : 9600 b p s #e n d i f 94 M.2. Rutina de atención de interrupciones del bloque SCI 95 SCI1CR1 = 0 ; /∗ b i t names 7 0 LOOPS 6 0 SCISWAI 5 0 RSRC 4 0 M 3 0 WAKE 2 0 ILT 1 0 PE 0 0 PT ∗/ SCI1CR2 = 0x2C ; /∗ b i t names 7 0 TIE 6 0 TCIE 5 1 RIE 4 0 ILIE 3 1 TE 2 1 RE 1 0 RWU 0 0 SBK ∗/ } M.2 Rutina de atención de interrupciones del bloque SCI //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−S C I 1 i s r −−−−−−−−−−−−−−−−−−−−−−−−−−−− // I n t e r r u p t S e r v i c e Routine f o r SCI1 // I n p u t : none // Output : none i n t e r r u p t void S C I 1 i s r ( void ) { unsigned char dataIn , initSCI1CR2 ; initSCI1CR2 = SCI1CR2 ; SCI1CR2 &= ˜TIEB ; SCI1CR2 &= ˜RIE ; asm CLI ; // // // // Save s t a t u s o f SCI1CR2 Disable Transmitter i n t e r r u p t s Disable Receiver i n t e r r u p t s Enable h i g h e r p r i o r i t y i n t e r r u p t s i f ( initSCI1CR2 & RIE ) { enabled i f ( SCI1SR1 & RDRF) { d a t a I n = SCI1DRL ; SCI1 InChar ( d a t a I n ) ; } } // Check i f R e c e i v e r I n t e r r u p t i o n s were i f ( initSCI1CR2 & TIEB) { enabled // Check i f T r a n s m i t t e r I n t e r r u p t i o n e s were // I f RDRF i s s e t // Read data , i t c l e a r s RDRF F l a g // S t o r e d a t a i f ( SCI1SR1 & TDRE) { i f ( t x B u f i n == t x B u f o u t ) { initSCI1CR2 &= ˜TIEB ; } else { SCI1DRL = ∗ t x B u f o u t++; // I f TRDE i s s e t // I f b u f f e r i s empty , done // D i s a b l e T r a n s m i t t e r i n t e r r u p t s // Send d a t a t o SCI 96 M Código en C de las rutinas implementadas } } i f ( t x B u f o u t == ( t x B u f f e r+BUFSIZE+e x t r a B u f ) ) { // Check i f end o f b u f f e r txBufout = t x B u f f e r ; // Go t o s t a r t o f buffer } } // End o f TDRE i f // End o f TIEB i f SCI1CR2 = initSCI1CR2 ; SCI1CR2 |= RIE ; // R e s t o r e SCI1CR2 // Enable R e c e i v e r i n t e r r u p t s } M.3 Rutina de manejo de datos recibidos por el bloque SCI //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−SCI1 InChar−−−−−−−−−−−−−−−−−−−−−−−−−− // Handles c h a r a c t e r s r e c e i v e d i n o r d e r t o make an API Frame f o r Xbee // I n p u t : c h a r r e c e i v e d by SCI // Output : none void SCI1 InChar ( char rxData ) { i f ( rxData == 0x7E ) r x I n d x = 0 ; e l s e r x I n d x ++; index // Check i f s t a r t o f frame // I f not , i n c r e a s e r x B u f f e r r x B u f f e r [ r x I n d x ] = rxData ; // Save d a t a I n i n b u f f e r // Check f o r v a l u e o f l e n g t h i f ( r x I n d x == 2 ) l e n = r x B u f f e r [ r x I n d x ] + 3 ; i f ( ( r x I n d x == l e n ) && ( r x B u f f e r [ r x I n d x ] != 0x7E ) ) { // Check i f end o f frame Xbee Rx ( r x B u f f e r ) ; // Send d a t a t o Xbee f u n c t i o n len = 0; // S e t v a l u e o f l e n g t h i n z e r o f o r incoming frames } } M.4 Rutina de manejo de datos transmitidos por el bloque SCI //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−SCI1 OutChar−−−−−−−−−−−−−−−−−−−−−−−− // Send d a t a t o t r a n s m i s s i o n b u f f e r // I n p u t : c h a r d a t a t o be t r a n s f e r r e d // Output : none void SCI1 OutChar ( char t x d a t a ) { i n t used = t x B u f i n − t x B u f o u t ; i f ( used < 0 ) used += (BUFSIZE+e x t r a B u f ) ; fix it // I f used i s n e g a t i v e , M.5. Rutina de transmisión de tramas del Xbee 97 i f ( used >= (BUFSIZE+e x t r a B u f ) −1){ // Check i f t h e r e i s s p a c e i n buffer txBUFULL = 0xFF ; // S e t i n d i c a t o r i f t h e r e i s no s p a c e } i f (txBUFULL == 0xFF ) { e x t r a B u f ++; txBUFULL = 0 ; } // I f t h e i n d i c a t o r o f f u l l b u f f e r i s s e t // I n c r e a s e b u f f e r s i z e // R e s e t i n d i c a t o r ∗ t x B u f i n++ = t x d a t a ; // T r a n s f e r d a t a t o b u f f e r , i n c r e a s e txBufin i f ( t x B u f i n == ( t x B u f f e r+BUFSIZE+e x t r a B u f ) ) { // I f p o i n t e r i s a t t h e end o f b u f f e r txBufin = txBuffer ; // R e e s t a b l i s h i t } SCI1CR2 |= TIEB ; // Enable t r a n s m i s s i o n i n t e r r u p t s } M.5 Rutina de transmisión de tramas del Xbee //−−−−−−−−−−−−−−−−−−−−−−−−−−−−Xbee TxIPv4−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− // Transmit d a t a from SCI1 t o Xbee ’ s RF u s i n g TxIPv4 frame // I n p u t : ipDA i s t h e i p d e s t i n a t i o n a d d r e s s i n h e x a d e c i m a l // d e s t P o r t i s t h e d e s t i n a t i o n UDP or TCP p o r t number i n hexadecimal // s o u r c e P o r t i s t h e s o u r c e UDP or TCP p o r t number i n h e x a d e c i m a l // p r o t o c o l (0−UDP, 1−TCP) // d a t a i s t h e d a t a t o be t r a n s m i t t e d // Output : none void Xbee TxIPv4 ( char ipDA1 , char ipDA2 , char ipDA3 , char ipDA4 , char destPortH , char de s tP or tL , i n t s o u r c e P o r t , char p r o t o c o l , char ∗ data ) { char ∗ dataOut ; char checksum ; long i n t sumData =0; char sourcePortH , s o u r c e P o r t L ; i n t l e n g t h =0 , j =0; char l e n g t h L , lengthH ; s o u r c e P o r t H = s o u r c e P o r t >> 8 ; s o u r c e P o r t L = s o u r c e P o r t & 0xFF ; dataOut = m a l l o c ( 1 0 0 ∗ s i z e o f ( char ) ) ; while ( ∗ data ) { d a t a and sum o f d a t a dataOut [ l e n g t h ] = ∗ data ; sumData += dataOut [ l e n g t h ] ; data++; l e n g t h ++; // Save d a t a and o b t a i n l e n g t h o f 98 M Código en C de las rutinas implementadas } lengthH = ( l e n g t h +12) >> 8 ; transmit l e n g t h L = ( l e n g t h +12) & 0xFF ; // Obtain b y t e s o f l e n g t h t o // C a l c u l a t e checksum checksum = 0xFF − ( 0 x20+0x00+ipDA1+ipDA2+ipDA3+ipDA4+destPortH+ d e s t P o r t L+ s o u r c e P o r t H+s o u r c e P o r t L+p r o t o c o l +0x00+sumData ) ; // Transmit frame SCI1 OutChar ( 0 x7E ) ; SCI1 OutChar ( lengthH ) ; and checksum SCI1 OutChar ( l e n g t h L ) ; SCI1 OutChar ( 0 x20 ) ; SCI1 OutChar ( 0 x00 ) ; SCI1 OutChar ( ipDA1 ) ; SCI1 OutChar ( ipDA2 ) ; SCI1 OutChar ( ipDA3 ) ; SCI1 OutChar ( ipDA4 ) ; SCI1 OutChar ( destPortH ) ; SCI1 OutChar ( d e s t P o r t L ) ; SCI1 OutChar ( s o u r c e P o r t H ) ; SCI1 OutChar ( s o u r c e P o r t L ) ; SCI1 OutChar ( p r o t o c o l ) ; SCI1 OutChar ( 0 x0 ) ; f o r ( j =0; j <l e n g t h ; j ++){ SCI1 OutChar ( dataOut [ j ] ) ; } SCI1 OutChar ( checksum ) ; // S t a r t D e l i m i t e r // Length b e t w e e n API Frame D e l i m i t e r // API Frame D e l i m i t e r : TxIPv4 // 0 d i s a b l e s Tx s t a t u s frame // IP D e s t i n a t i o n Address // D e s t i n a t i o n Port // Source Port // P r o t o c o l // Transmit o p t i o n s b i t f i e l d 1 = 1 , // terminate socket a f t e r tx complete // RF Data // Checksum f r e e ( dataOut ) ; } M.6 Rutinas de envı́o de comandos al Xbee //−−−−−−−−−−−−−−−−−−−−−−−−−−−−Xbee ATCommand−−−−−−−−−−−−−−−−−−−−−−−−−−− // Used t o s e t or q u e r y d e v i c e p a r a m e t e r s on t h e l o c a l d e v i c e // I n p u t : atCommand i s t h e AT Command Name i n h e x a d e c i m a l // paramValue i s t h e parameter v a l u e i f needed , i f not , e n t e r ’ ’ // Output : none void Xbee ATCommand ( i n t atCommand , char paramValue ) { char checksum ; char atCommandH , atCommandL ; char l e n g t h L=0x05 , lengthH =0; atCommandH = atCommand >> 8 ; atCommandL = atCommand & 0xFF ; // Obtain b y t e s o f AT Command // C a l c u l a t e checksum checksum = 0xFF − ( 0 x08+0x01+atCommandH+atCommandL+paramValue ) ; M.6. Rutinas de envı́o de comandos al Xbee 99 i f ( paramValue == ’ ’ ) { l e n g t h L −−; } // Transmit frame SCI1 OutChar ( 0 x7E ) ; SCI1 OutChar ( lengthH ) ; and checksum SCI1 OutChar ( l e n g t h L ) ; SCI1 OutChar ( 0 x08 ) ; SCI1 OutChar ( 0 x01 ) ; SCI1 OutChar (atCommandH) ; SCI1 OutChar ( atCommandL ) ; i f ( paramValue != ’ ’ ) { SCI1 OutChar ( paramValue ) ; } SCI1 OutChar ( checksum ) ; // S t a r t D e l i m i t e r // Length b e t w e e n API Frame D e l i m i t e r // API Frame D e l i m i t e r : AT Command // Frame ID // AT Command // Parameter Value i f p r e s e n t // Checksum } //−−−−−−−−−−−−−−−−−−−−−−−−−−−−Xbee ATCommandStr−−−−−−−−−−−−−−−−−−−−−− // Used t o s e t or q u e r y d e v i c e p a r a m e t e r s on t h e l o c a l d e v i c e // I n p u t : atCommand i s t h e AT Command Name i n h e x a d e c i m a l // paramValue i s s t r i n g parameter v a l u e // Output : none void Xbee ATCommandStr ( i n t atCommand , char ∗ paramValue ) { char ∗ paramValueIn ; char checksum ; long i n t sumData =0; char atCommandH , atCommandL ; i n t l e n g t h =0 , j =0; char l e n g t h L , lengthH ; atCommandH = atCommand >> 8 ; Command atCommandL = atCommand & 0xFF ; // Obtain b y t e s o f AT paramValueIn = m a l l o c ( 1 0 0 ∗ s i z e o f ( char ) ) ; while ( ∗ paramValue ) { // Save d a t a and o b t a i n l e n g t h o f d a t a and sum o f d a t a paramValueIn [ l e n g t h ] = ∗ paramValue ; sumData += paramValueIn [ l e n g t h ] ; paramValue++; l e n g t h ++; } if } ( ! ( ∗ paramValue ) ) { // NULL c h a r a c t e r a t t h e end o f string paramValueIn [ l e n g t h ] = ∗ paramValue ; l e n g t h ++; 100 M Código en C de las rutinas implementadas lengthH = ( l e n g t h +4) >> 8 ; transmit l e n g t h L = ( l e n g t h +4) & 0xFF ; // Obtain b y t e s o f l e n g t h t o checksum = 0xFF − ( 0 x08+0x01+atCommandH+atCommandL+sumData ) ; // Transmit frame SCI1 OutChar ( 0 x7E ) ; SCI1 OutChar ( lengthH ) ; and checksum SCI1 OutChar ( l e n g t h L ) ; SCI1 OutChar ( 0 x08 ) ; SCI1 OutChar ( 0 x01 ) ; SCI1 OutChar (atCommandH) ; SCI1 OutChar ( atCommandL ) ; // S t a r t D e l i m i t e r // Length b e t w e e n API Frame D e l i m i t e r // API Frame D e l i m i t e r : AT Command // Frame ID // AT Command f o r ( j =0; j <l e n g t h ; j ++){ // Parameter Value SCI1 OutChar ( paramValueIn [ j ] ) ; } SCI1 OutChar ( checksum ) ; // Checksum f r e e ( paramValueIn ) ; } M.7 Rutina de recepción de tramas //−−−−−−−−−−−−−−−−−−−−−−−−−−−−Xbee Rx−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− // When Xbee d a t a i s r e c e i v e d u s i n g S e r i a l Data S e r v i c e // I n p u t : Frame r e c e i v e d by SCI // Output : none void Xbee Rx ( unsigned char ∗ frame ) { char ptp = 0 ; char ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , checksum ; checksum = Checksum ( frame ) ; switch ( frame [ 3 ] ) { case 0xB0 : // S w i t c h on API I d e n t i f i e r // Api Frame RxIPv4 i f ( checksum=0xFF ) { ipAd1 = frame [ 4 ] ; ipAd2 = frame [ 5 ] ; ipAd3 = frame [ 6 ] ; ipAd4 = frame [ 7 ] ; s o u r c e P o r t H = frame [ 1 0 ] ; s o u r c e P o r t L = frame [ 1 1 ] ; switch ( frame [ 1 4 ] ) { case ’ 0 ’ : // Check c h a r a c t e r r e c e i v e d M.7. Rutina de recepción de tramas PORTB ˆ= 0 x1 ; // T o g g l e on c o r r e s p o n d i n g LED msDelay ( 1 ) ; // Send S t a t u s o f t h e LED i f (PORTB & 0 x1 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON0” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF0” ) ; msDelay ( 1 ) ; break ; case ’ 1 ’ : PORTB ˆ= 0 x2 ; msDelay ( 1 ) ; i f (PORTB & 0 x2 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON1” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF1” ) ; msDelay ( 1 ) ; break ; case ’ 2 ’ : PORTB ˆ= 0 x4 ; msDelay ( 1 ) ; i f (PORTB & 0 x4 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON2” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF2” ) ; msDelay ( 1 ) ; break ; case ’ 3 ’ : PORTB ˆ= 0 x8 ; msDelay ( 1 ) ; i f (PORTB & 0 x8 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON3” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF3” ) ; msDelay ( 1 ) ; break ; case ’ 4 ’ : PORTB ˆ= 0 x10 ; msDelay ( 1 ) ; i f (PORTB & 0 x10 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON4” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF4” ) ; msDelay ( 1 ) ; break ; case ’ 5 ’ : PORTB ˆ= 0 x20 ; msDelay ( 1 ) ; i f (PORTB & 0 x20 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON5” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF5” ) ; msDelay ( 1 ) ; break ; 101 102 M Código en C de las rutinas implementadas case ’ 6 ’ : PORTB ˆ= 0 x40 ; msDelay ( 1 ) ; i f (PORTB & 0 x40 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON6” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF6” ) ; msDelay ( 1 ) ; break ; case ’ 7 ’ : PORTB ˆ= 0 x80 ; msDelay ( 1 ) ; i f (PORTB & 0 x80 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON7” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF7” ) ; msDelay ( 1 ) ; break ; case ’R ’ : LED // For a p p l i c a t i o n r e f r e s h , send s t a t u s o f e v e r y i f (PORTB & 0 x1 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON0” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF0” ) ; msDelay ( 0 . 1 ) ; i f (PORTB & 0 x2 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON1” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF1” ) ; msDelay ( 0 . 1 ) ; i f (PORTB & 0 x4 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON2” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF2” ) ; msDelay ( 0 . 1 ) ; i f (PORTB & 0 x8 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON3” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF3” ) ; msDelay ( 0 . 1 ) ; i f (PORTB & 0 x10 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON4” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF4” ) ; msDelay ( 0 . 1 ) ; i f (PORTB & 0 x20 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON5” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF5” ) ; msDelay ( 0 . 1 ) ; i f (PORTB & 0 x40 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON6” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF6” ) ; msDelay ( 0 . 1 ) ; M.8. Rutina de inicialización del módulo Xbee WiFi 103 i f (PORTB & 0 x80 ) Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ON7” ) ; e l s e Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”OF7” ) ; msDelay ( 0 . 1 ) ; break ; default : // Send ERROR i f r e c e i v e d d a t a i s n o t valid msDelay ( 1 ) ; Xbee TxIPv4 ( ipAd1 , ipAd2 , ipAd3 , ipAd4 , sourcePortH , s o u r c e P o r t L , 0 x2616 , 0 x01 , ”ERROR” ) ; msDelay ( 1 ) ; break ; } break ; } case 0 x88 : // Api Frame AT Command Response s t a t = frame [ 7 ] ; /∗ P o s i b l e v a l u e s o f s t a t : 0 : OK 1 : ERROR 2 : I n v a l i d Command 3 : I n v a l i d Parameter ∗/ param = frame [ 8 ] ; // Value o f parameter r e t u r n e d when i t ’ s an s t a t u s AT Command break ; default : break ; } // End s w i t c h } M.8 Rutina de inicialización del módulo Xbee WiFi //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−X b e e I n i t −−−−−−−−−−−−−−−−−−−−−−−−−− // I n i t i a l i z e Xbee // I n p u t : s s i d i s t h e name o f AP t o c o n n e c t to , // ee i s t h e E n c r i p t i o n Enable (0−No S e c u r i t y , 1−WPA, 2−WPA2, 3− WEP) // pk i s t h e s e c u r i t y k e y // Output : none void X b e e I n i t ( char ∗ s s i d , char ee , char ∗pk ) { char i ; Xbee ATCommand ( 0 x4148 , 0 x2 ) ; type while ( s t a t ) ; msDelay ( 1 ) ; // AH Command : I n f r a s t r u c t u r e n e tw o r k 104 M Código en C de las rutinas implementadas s t a t = 0xFF ; Xbee ATCommand ( 0 x4D41 , 0 x0 ) ; DHCP while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // MA Command : S e t a d d r e s s i n g mode as Xbee ATCommand ( 0 x4348 , 0 x0 ) ; while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // CH Command : A u t o r a t e c h a n n e l Xbee ATCommandStr ( 0 x4944 , s s i d ) ; AP while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // ID Command : S e t t h e SSID o f t h e Xbee ATCommand ( 0 x4545 , e e ) ; Enable while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // EE Command : S e t t h e E n c r y p t i o n Xbee ATCommandStr ( 0 x504B , pk ) ; while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // PK Command : S e t t h e s e c u r i t y k e y param = 0xFF ; f o r ( i =0; i <5; i ++){ Xbee ATCommand ( 0 x4149 , while ( s t a t ) ; i f ( param == 0 ) { param=0xFF ; break ; } s t a t = 0xFF ; msDelay ( 5 ) ; } ’ ’); // AI Command : a s s o c i a t i o n i n d i c a t i o n // Wait f o r OK i n a s s o c i a t i o n msDelay ( 1 ) ; } //−−−−−−−−−−−−−−−−−−−−−−−−−−−Xbee AdHoc−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− // C o n f i g u r e s Xbee as an Ad Hoc n et w o rk c r e a t o r // I n p u t : none // Output : none void Xbee AdHoc ( ) { Xbee ATCommand ( 0 x4148 , 0 x1 ) ; node while ( s t a t ) ; // AH Command : S e t s Xbee as c r e a t o r // o f an Ad Hoc Network M.9. Rutina de verificación de la asociación del módulo Xbee WiFi 105 msDelay ( 1 ) ; s t a t = 0xFF ; Xbee ATCommand ( 0 x4D41 , 0 x1 ) ; static while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // MA Command : S e t a d d r e s s i n g mode as Xbee ATCommand ( 0 x4545 , 0 ) ; Enable while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // EE Command : S e t t h e E n c r y p t i o n Xbee ATCommand ( 0 x4348 , 0 x1 ) ; while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // CH Command : S e t c h a n n e l Xbee ATCommand ( 0 x4252 , 0xB ) ; creator while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // BR Command : S e t b i t r a t e o f IBSS // parameter as no s e c u r i t y Xbee ATCommandStr ( 0 x4944 , ” X b e e C o n t r o l l e r ” ) ; SSID while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // ID Command : S e t t h e Xbee ATCommandStr ( 0 x4D59 , ” 1 9 2 . 1 6 8 . 1 . 1 ” ) ; module IP a d d r e s s while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // MY Command : S e t t h e Xbee Xbee ATCommandStr ( 0 x444C , ” 1 9 2 . 1 6 8 . 1 . 2 ” ) ; j o i n e r IP a d d r e s s while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // DL Command : S e t t h e IBSS Xbee ATCommandStr ( 0 x4D4B , ” 0 . 0 . 0 . 0 ” ) ; mask while ( s t a t ) ; msDelay ( 1 ) ; s t a t = 0xFF ; // MK Command : S e t v a l u e o f } M.9 Rutina de verificación de la asociación del módulo Xbee WiFi //−−−−−−−−−−−−−−−−−−−−−−−−−−Xbee Assoc−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− 106 M Código en C de las rutinas implementadas // V e r i f i e s a s s o c i a t i o n o f module , i f // Xbee Init routine again . // I n p u t : none // Output : none i t ’ s not a s s o c i a t e d , c a l l s void Xbee Assoc ( ) { param = 0xFF ; Xbee ATCommand ( 0 x4149 , indication while ( s t a t ) ; ’ ’); // AI Command : a s s o c i a t i o n i f ( param ) { X b e e I n i t ( ”AndroidAP ” , 0x2 , ”password ” ) ; I n i t i a l i z e Xbee param = 0xFF ; } // s t a t = 0xFF ; } M.10 Rutina para revisar la suma de verificación //−−−−−−−−−−−−−−−−−−−−−−−−−−Checksum−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− // V e r i f i e s t h e v a l u e o f t h e checksum o f an API frame // I n p u t : ∗ frame i s t h e API frame // Output : sum i s 0xFF i f t h e checksum i s c o r r e c t unsigned char Checksum ( unsigned char ∗ frame ) { unsigned char i , r e s u l t =0 , l e n g t h =0 , sum=0; l e n g t h = frame [ 2 ] ; // Save v a l u e o f l e n g t h o f frame d a t a f o r ( i =0; i <l e n g t h +1; i ++){ sum += frame [3+ i ] ; } sum &= 0xFF ; return sum ; // Add t h e v a l u e s o f each b y t e i n d a t a // frame and t h e v a l u e o f checksum // Only l a s t b y t e // Return v a l u e o f t h e sum } M.11 Rutina de inicialización del Puerto H //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−P o r t H I n i t −−−−−−−−−−−−−−−−−−− // I n i c i a l i z a t i o n r o u t i n e f o r Port H // I n p u t : none // Output : none void P o r t H I n i t ( void ) { DDRH = 0 x0 ; // Port as i n p u t PPSH = 0 ; // S e t f a l l i n g e d g e f o r i n t e r r u p t i o n PIEH = 0 x7 ; // I n t e r r u p t i o n s e n a b l e d M.12. Rutina de atención de interrupciones del Puerto H } M.12 Rutina de atención de interrupciones del Puerto H //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−P o r t H i s r −−−−−−−−−−−−−−−−−−−−− // I n t e r r u p t S e r v i c e Routine f o r Port H // I n p u t : none // Output : none i n t e r r u p t void P o r t H i s r ( void ) { char i n i t P I F H ; i n i t P I F H = PIFH ; PIEH = 0 ; asm CLI ; // Save s t a t e i f i n t e r r u p t f l a g s // D i s a b l e PortH i n t e r r u p t i o n s // Enable h i g h e r l e v e l i n t e r r u p t i o n s i f ( i n i t P I F H & 0 x1 ) { // Check which f l a g s e t t h e i n t e r r u p t i o n i f (PTH&0x80 ) { X b e e I n i t ( ”AndroidAP ” , 0x2 , ”password ” ) ; // I n i t i a l i z e Xbee } PIFH |= 0 x1 ; // C l e a r i n t e r r u p t i o n f l a g } i f ( i n i t P I F H & 0 x2 ) { i f ( ! ( PTH&0x80 ) ) { Xbee AdHoc ( ) ; } PIFH |= 0 x2 ; } i f ( i n i t P I F H & 0 x4 ) { Xbee ATCommand ( 0 x4E52 , PIFH |= 0 x4 ; } PIEH = 0 x7 ; // Check which f l a g s e t t h e i n t e r r u p t i o n // I n i t i a l i z e Xbee as Ad Hoc C r e a t o r // C l e a r i n t e r r u p t i o n f l a g // Check which f l a g s e t t h e i n t e r r u p t i o n ’ ’); // Network R e s e t // C l e a r i n t e r r u p t i o n f l a g // Enable PortH i n t e r r u p t i o n s } M.13 Rutina de inicialización del Puerto A //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−PORTA Init−−−−−−−−−−−−−−−−−−−−−−−−−− // I n i c i a l i z a t i o n r o u t i n e f o r Port A // I n p u t : none // Output : none void PORTA Init ( void ) { DDRA = 0x0F ; PORTA &= 0xF0 ; // PA0−PA3 as o u t p u t s , PA4−PA7 as i n p u t s // S e t PA0−P03 low 107 108 M Código en C de las rutinas implementadas } M.14 Rutina de reconocimiento de teclas presionadas //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−SearchKey−−−−−−−−−−−−−−−−−−−−−−−−−−− // R e c e i v e s s t a t u s o f PORTA and t e l l s which k e y was p r e s s e d // I n p u t : none // Output : ASCII c h a r a c t e r o f c o r r e s p o n d i n g k e y b o a r d i n p u t unsigned char SearchKey ( unsigned char k e y I n ) { unsigned char r e s u l t ; switch ( k e y I n ) { case 0 x82 : return r e s u l t = ’ 0 ’ ; break ; // A1 and A7 h i g h case 0 x11 : return r e s u l t = ’ 1 ’ ; break ; // A0 and A4 h i g h case 0 x12 : return r e s u l t = ’ 2 ’ ; break ; // A1 and A4 h i g h case 0 x14 : return r e s u l t = ’ 3 ’ ; break ; // A2 and A4 h i g h case 0 x21 : return r e s u l t = ’ 4 ’ ; break ; // A0 and A5 h i g h case 0 x22 : return r e s u l t = ’ 5 ’ ; break ; // A1 and A5 h i g h case 0 x24 : return r e s u l t = ’ 6 ’ ; break ; // A2 and A5 h i g h case 0 x41 : return r e s u l t = ’ 7 ’ ; break ; // A0 and A6 h i g h default : return r e s u l t = 0 ; break ; } } M.15. Rutina de ejecución de acciones de acuerdo a la tecla presionada 109 M.15 Rutina de ejecución de acciones de acuerdo a la tecla presionada //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−PORTA Action−−−−−−−−−−−−−−−−−−−−−−−− // Performs an a c t i o n a c c o r d i n g t o i n p u t // I n p u t : ASCII c h a r a c t e r o f c o r r e s p o n d i n g k e y p r e s s e d // Output : none void PORTA Action ( unsigned char key ) { switch ( key ) { case ’ 0 ’ : PORTB ˆ= 0 x1 ; break ; // T o g g l e on PORTB’ s c o r r e s p o n d i n g LED case ’ 1 ’ : PORTB ˆ= 0 x2 ; break ; case ’ 2 ’ : PORTB ˆ= 0 x4 ; break ; case ’ 3 ’ : PORTB ˆ= 0 x8 ; break ; case ’ 4 ’ : PORTB ˆ= 0 x10 ; break ; case ’ 5 ’ : PORTB ˆ= 0 x20 ; break ; case ’ 6 ’ : PORTB ˆ= 0 x40 ; break ; case ’ 7 ’ : PORTB ˆ= 0 x80 ; break ; default : break ; } } M.16 Rutina de manejo del teclado conectado al Puerto A //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−PORTA Scan−−−−−−−−−−−−−−−−−−−−−−−−−− // Scans t h e COLSxROWS k e y b o a r d s e a r c h i n g f o r i n p u t // I n p u t : none // Output : ASCII c h a r a c t e r o f c o r r e s p o n d i n g k e y b o a r d i n p u t 110 M Código en C de las rutinas implementadas unsigned char PORTA Scan ( void ) { int i , j ; unsigned char s e t C o l =0 , readRow=0 , pta =0 , s t a t u s = 0 , key = 0 , temp =0; f o r ( i =0; i <COLS ; i ++){ // Scan Columns PORTA &= PTACOL; columns ( low ) s e t C o l = (ONE<<i ) ; high PORTA |= s e t C o l ; // S e t d e f a u l t s t a t e o f f o r ( j =0; j <ROWS; j ++){ // Scan Rows // S e t which column t o s e t // S e t column h i g h pta = PORTA; readRow = (TEN<<j ) ; // S e t which row t o read s t a t u s = pta & readRow ; // Read row if ( status ){ // I f s t a t u s i s d i f f e r e n t from z e r o , k e y was p r e s s e d key = SearchKey ( pta ) ; // Search which k e y was p r e s s e d k e y b u f 1 = key ; // S t o r e v a l u e o f key status = 0; // C l e a r status } } } i f ( k e y b u f 1 != key ) { // Wait u n t i l k e y i s d e p r e s s e d t o r e t u r n value temp = k e y b u f 1 ; keybuf1 = 0 ; return temp ; } e l s e return 0 ; // Otherwise , r e t u r n 0 } M.17 Rutina de inicialización del bloque RTI //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−R T I I n i t −−−−−−−−−−−−−−−−−−−−−−−−−−− // I n i c i a l i z a t i o n r o u t i n e f o r Real Time I n t e r r u p t i o n // I n p u t : none // Output : none void R T I I n i t ( void ) { RTICTL = 0 x79 ; clock CRGINT |= RTIE ; } // S e t RTI time a t 13 ,65 ms w i t h 48 MHz cpu // Enable RTI I n t e r r u p t i o n s M.18. Rutina de atención de interrupciones del bloque RTI M.18 111 Rutina de atención de interrupciones del bloque RTI //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−RTI isr −−−−−−−−−−−−−−−−−−−−−−−−−−−− // I n t e r r u p t S e r v i c e Routine f o r RTI // I n p u t : none // Output : none i n t e r r u p t void R T I i s r ( void ) { unsigned char initCRGFLG ; unsigned char key =0; initCRGFLG = CRGFLG; CRGINT &= ˜RTIE ; asm CLI ; // Save s t a t e o f i n t e r r u p t f l a g s // D i s a b l e RTI i n t e r r u p t i o n s // Enable h i g h e r l e v e l i n t e r r u p t i o n s i f ( initCRGFLG & RTIF) { key = PORTA Scan ( ) ; i f ( key ) PORTA Action ( key ) ; make an a c t i o n // Scan PORTA // I f k e y was p r e s s e d and umpressed , i f (PTH&0x80 ) { c o n t++; i f ( c o n t ==1000){ Xbee Assoc ( ) ; cont = 0 ; } } CRGFLG |= RTIF ; // C l e a r RTIF f l a g by s e t t i n g 1 t o i t } CRGINT |= RTIE ; // Enable RTI I n t e r r u p t i o n s } M.19 Rutina de inicialización del PLL //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−PLL Init−−−−−−−−−−−−−−−−−−−−−−−−−−−−− // S e t PLL c l o c k t o 48 MHz or 8 MHz a c c o r d i n g t o BUSCLOCK // I n p u t : none // Output : none void P L L I n i t ( void ) { CLKSEL &= 0x7F ; /∗ 7 6 5 4 3 Bits of PLLSEL PSTP SYSWAI ROAWAI PLLWAI CLKSEL: 0 1 1 1 1 112 M Código en C de las rutinas implementadas 2 CWAI 1 RTIWAI 0 COPWAI ∗/ 1 1 1 PLLCTL |= 0 x40 ; /∗ 7 6 5 4 3 2 1 0 ∗/ B i t s o f PLLCTL: CME x PLLON 1 AUTO x ACQ x Not used PRE x PCE x SCME x x : default state /∗ To c a l c u l a t e PLL o s c f r e c u e n c y : PLLCLK = 2 ∗ OSCCLK ∗ (SYNR + 1) / (REFDV + 1) For PLLCLK = 48 MHz: SYNR = 0 x5 , REFDV = 0 x1 , w i t h OSCCLK = 8 MHz ∗/ // S e t PLL c l o c k s p e e d #i f BUSCLOCK == 24 SYNR = 0 x05 ; // For PLLCLK = 48 MHz REFDV = 0 x01 ; #e l s e SYNR = 0 x00 ; // For PLLCLK = 8 MHz REFDV = 0 x00 ; #e n d i f while ( ! (CRGFLG&0x08 ) ) ; CLKSEL |= 0 x80 ; // Wait f o r PLLCLK t o s t a b i l i z e // S w i t c h t o PLL c l o c k } M.20 Programa principal // f i l e n a m e ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ main . c ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ ∗ // U n i v e r s i d a d de Costa Rica − E s c u e l a de I n g e n i e r i a E l e c t r i c a // I l e i n e S ola no //−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−−− #include <h i d e f . h> #include <mc9s12dg256 . h> #include < s t d l i b . h> #include #include #include #include ”p l l . h” ”sci1 . h” ”api . h” ”porta . h” M.20. Programa principal 113 #include ”p o r t h . h ” #include ” r t i . h ” void main ( void ) { // S e t sy ste m c l o c k f r e q u e n c y t o PLL Init ( ) ; msDelay ( 1 ) ; BUSCLOCK MHz (24 or 4) LCD Init ( ) ; DDRB = 0xFF ; DDRJ = 0xFF ; DDRP = 0xFF ; DDRM = 0xFF ; PTP = 0x4F ; PORTB = 0 x0 ; // // // // // // PORTB as o u t p u t PTJ as o u t p u t PTP as o u t p u t PTM as o u t p u t For Green i n RGB LED Turn o f f LEDs EIE−UCR IE −0499 writeLine ( ” writeLine ( ” ” , 0) ; ” , 1) ; // I n i t i a l i z e Port A PORTA Init ( ) ; msDelay ( 1 ) ; // I n i t i a l i z e Port H PortH Init () ; msDelay ( 1 ) ; // I n i t i a l i z e Real Time I n t e r r u p t i o n RTI RTI Init () ; msDelay ( 1 ) ; // I n i t i a l i z e s e r i a l communication i n t e r f a c e SCI1 S C I 1 I n i t ( BAUD 9600 ) ; asm CLI ; // Enable i n t e r r u p t i o n s msDelay ( 1 ) ; while ( 1 ) { PTM ˆ= 0 x4 ; msDelay ( 0 . 8 ) ; } } // RGB LED b l i n k i n g