Informe - Escuela de Ingeniería Eléctrica

Anuncio
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
Descargar