scieee AI-readable full text Open interactive document viewer

Control remoto mediante microcontrolador de los accesorios de un vehículo

Casas Rustarazo, Jaime

Full text

UNIVERSIDAD POLITÉCNICA DE VALENCIA ESCUELA TÉCNICA SUPERIOR DE INGENIERÍA INFORMÁTICA PROYECTO FINAL DE CARRERA CONTROL REMOTO MEDIANTE MICROCONTROLADOR DE LOS ACCESORIOS DE UN VEHICULO. ALUMNO: JAIME CASAS RUSTARAZO DIRECTOR: ÁNGEL RODAS JORDÁ Fecha: 5-9-2011 2 INDICE DE CONTENIDOS 1.- Introducción ……………………………………………………………………… 3 2.- Objetivos. Descripción del proyecto …………………………………………….. 4 3.- Hardware ………………………………………………………………………… 5 3.1.- Emisor………………………………………………………………….. 5 3.1.1.- Componentes ………………………………………………… 5 3.1.1.1.- PIC 16F628 …………………………………….…... 5 3.1.1.2.- Módulo RF TX433N ……………………………….. 7 3.1.2.- Desarrollo y construcción ……………………………………. 7 3.2.- Receptor …………………………………………………………….….. 18 3.2.1.- Componentes…………………………………………………. 19 3.2.1.1.- PIC 18F2550 ……………………………………….. 19 3.2.1.2.- EEPROM 24LC1025 ………………………………. 20 3.2.1.3.- Timer RTC DS1307 ………………………………… 28 3.2.1.4.- Módulo RF RX433N ………………………………. 33 3.2.2.- Desarrollo y construcción ….………………………………… 34 4.- Software …………………………………………………………………………. 46 4.1.- Librerías de componentes desarrolladas …………………………….…. 46 4.1.1.- Memoria 24LC1025 ………………………………………….. 46 4.1.2.- Timer RTC DS1307 ………………………………………..… 54 4.2.- Pruebas de componentes ……………………………………………….. 68 4.2.1.- USART …………………………………………………….… 69 4.2.2.- Memoria 24LC1025 ……………………………………….… 73 4.2.3.- Timer RTC DS1307 ……………………………………….… 80 4.2.4.- Conexión USB CDC ………………………………………... 93 4.3.- Tramas de datos ……………………………………………………….. 105 4.4.- Firmware …………..…………………………………………………... 108 4.4.1.- Emisor ……………………………………………………..… 108 4.4.2.- Receptor ………………………...…………………………….. 115 5.- Eclipse Telecontrol. Grabación de secuencias …………………………………. 137 6.- Conclusiones y agradecimientos ……………………………………………....... 143 7.- Anexos - Manual de usuario. - Datasheets de todos los componentes. - El protocolo rs232. - El protocolo i2c. - El protocolo USB CDC detallado. - “Microchip Application Notes” oportunas. - Firmware y documentación del cargador de secuencias. - Proyectos en MPLab, Proteus y Visual Studio. 3 1.- Introducción. Preliminares: Se dispone de un Mitsubishi Eclipse 2.0i 210cv el cual posee ciertas modificaciones como resultado de un costoso proceso de personalización con la finalidad de servir de espectáculo en las concentraciones automovilísticas tuning a nivel nacional e internacional habilitadas al efecto. En el maletero de dicho vehículo se ha llevado a cabo la instalación de un equipo de audio de alta fidelidad, así como los dispositivos mostrados a continuación: - Subida y bajada de portón automático. Posee un cilindro neumático de simple efecto capaz de elevar y bajar automáticamente el portón del maletero. - Cerradura electrónica del portón. Debido a la automatización de la subida y bajada del portón, se ha sustituido la tradicional apertura de cerradura mecánica mediante llave por una cerradura servocontrolada. - Subida y bajada de altavoces. En el interior del maletero se halla una plataforma horizontal en la cual se encuentran 4 altavoces, sujetada por dos pistones neumáticos mediante los cuales es posible elevar o descender dicha plataforma - Entrada y salida de las etapas. Situada debajo de la plataforma de los altavoces se halla una base que contiene las 4 etapas de audio encargadas de alimentar los altavoces del equipo Hi-Fi. Dicha base también está controlada por pistones neumáticos de simple efecto de forma que actuando sobre ellos es posible ocultar o mostrar las etapas. Con el fin de etapas la base describe una trayectoria horizontal deslizándose hacia el interior del vehículo, quedando totalmente colocada sobre los asientos traseros, y para mostrarlas se lleva a cabo el mismo movimiento en sentido contrario, extrayéndolas y haciéndolas accesibles desde el maletero. - Sirena acústica. El vehículo posee una sirena en el maletero cuya finalidad es la de avisar unos segundos antes y después de la apertura o cierre del portón, 4 evitando de esta manera en la medida de lo posible accidentes derivados con las partes móviles y los espectadores que se encuentren en las inmediaciones del vehículo. Además de los elementos descritos del maletero del automóvil, sobre este también se han instalado los siguientes elementos: - Suspensión neumática en las 4 ruedas. Se ha sustituido la suspensión mecánica tradicional por suspensión neumática en las 4 ruedas del vehículo. Ello significa que la suspensión está provista de cilindros neumáticos que posibilitan la acción de regular en altura cada una de las ruedas en todo momento de manera independiente. Dichos pistones neumáticos se accionan, igual que los demás mecanismos descritos, mediante electroválvulas. - El coche dispone de iluminación tuning en el maletero, interior del habitáculo y bajos exteriores, haciendo uso para ello de diodos LED, flashes y tubos de neón. 2.- Objetivos. Descripción del proyecto: El proyecto desarrollado consiste en el diseño y construcción de un controlador lógico programable controlado por radiofrecuencia, con la finalidad de hacer posible el control automatizado de todos y cada uno de los elementos descritos del vehículo. Dicho sistema se compone de dos unidades claramente diferenciadas. La primera de ellas, el emisor, consiste en un telemando de reducido tamaño provisto de 9 botones, cada uno de ellos con una finalidad definida. El emisor envía el estado de los mismos a través de ondas de radiofrecuencia bajo un protocolo previamente establecido. 5 La segunda unidad, el receptor, es el encargado de recibir y reconocer los comandos emitidos por el telemando y actuar en consecuencia controlando los mecanismos descritos del vehículo, siguiendo los patrones que previamente le haya sido asignado a cada pulsación. El receptor permite programar el comportamiento asociado a cada tecla del emisor pulsada, de forma que es posible, además de asignar un único movimiento por pulsación (ejemplo, subir portón o encender neones), asignar a una pulsación una secuencia de movimientos preestablecidos. Con el fin de llevar a cabo la programación de secuencias en el receptor se ha dotado al mismo de conexión USB y se ha desarrollado un programa de ordenador en el cual se muestra gráficamente el vehículo y sus actuadores de forma que hace posible la programación del receptor de una forma muy sencilla e intuitiva para el usuario. 3.- Hardware. Se describirá a continuación el hardware de ambos elementos, primeramente del emisor y seguidamente del receptor. 3.1.- Emisor Con el fin de facilitar la comprensión del funcionamiento del emisor previamente seguirá un esquema descriptivo ascendente. Se comenzará mostrando primeramente los componentes que componen el sistema y posteriormente se analizará el desarrollo y la construcción del emisor propiamente dicho. 3.1.1.- Componentes Existen dos componentes fundamentales dentro del emisor que necesitan ser analizados. Estos componentes son, por una parte, el microcontrolador que gobierna el circuito. Por la otra, el módulo de radiofrecuencia encargado de emitir las ondas electromagnéticas. 3.1.1.1.- Microcontrolador PIC 16F628 El diseño del emisor se realiza en torno al microcontrolador PIC16F628, de la empresa Microchip. Dicho microcontrolador es el encargado de componer las tramas de datos en base al estado de los interruptores y llevar a cabo el envío a través del módulo de radiofrecuencia. El pinout o distribución de pines del circuito integrado se muestra en la siguiente figura. 6 Las características más notables de dicho microcontrolador se enumeran a continuación. - Juego de instrucciones RISC. El hecho de poseer instrucciones sencillas hace posible que éstas se ejecuten a una velocidad relativamente grande en comparación con los sistemas CISC, que exigen mayor tiempo por instrucción y segmentaciones del procesador complejas. - Oscilador de hasta 20 MHz. Por una parte dispone de un oscilador interno, al mismo tiempo que permite el uso de un oscilador interno de una frecuencia de hasta 20 MHz. El oscilador interno es inadecuado para esta aplicación ya que a pesar de que es útil en muchos otros proyectos, éste hace uso de la UART del PIC y esto requiere un oscilador externo de cuarzo para lograr una estabilidad adecuada en la onda. Se ha utilizado un cristal de 4 MHz por disponibilidad, ya que es suficiente para nuestros propósitos y no se justifica la necesidad de uno de mayor velocidad. - Memoria de programa flash de 2k-palabras. Posee una memoria flash capaz de alojar 2k instrucciones de programa, suficiente para nuestros propósitos. - Memoria RAM de 224 bytes. Los 224 bytes de memoria volátil suplen los requisitos de esta aplicación. - Memoria EEPROM de 128 bytes. Posee 128 bytes de memoria persistente o no volátil, sin embargo en este proyecto no se utiliza. - Pila de 8 niveles. Posee una pila interna 8 niveles, necesaria para llevar a cabo la llamada a subrutinas (funciones). - 16 terminales genéricos de I/O con una intensidad máxima de 25 mA. - 3 temporizadores internos. - Módulo UART, comparadores analógicos, módulo PWM. En este caso se ha hecho uso de la UART para establecer la conexión con el módulo de radiofrecuencia. La señal se envía a este módulo a través de una conexión serie RS232 implementada en hardware por el propio microcontrolador. - Entrada de interrupción externa. Existe una patilla mediante la cual es posible controlar interrupciones externas por flanco de subida o de bajada (configurable). No se utiliza en este proyecto. 7 3.1.1.2.- Módulo RF TX433N Con el fin de hacer posible la transmisión de ondas electromagnéticas por parte del receptor se hace uso de un módulo emisor de radiofrecuencia de la empresa Velleman. Dicho módulo responde a la referencia tx433n. La imagen y el pinout del mismo es el siguiente: Funciona a una tensión variable dentro del rango desde 3 hasta 12V, a mayor voltaje mayor será la potencia de la onda irradiada. Utiliza el modo de modulación SAW y trabaja en la frecuencia de 433,92 MHz. Se obtienen buenos resultados hasta una velocidad de transmisión de 2.4kbps, bastante lejana de la utilizada en este proyecto. No requiere ningún ajuste y se adquiere listo para su funcionamiento, el fabricante asegura distancias de hasta 100 metros en visión directa con el módulo receptor utilizando una antena de cuarto de onda. Sin embargo y debido a las reducidas dimensiones del mando emisor se ha optado por una antena en bucle. La reducción de alcance no es de importancia ya que aun así presenta una potencia de salida adecuada para las necesidades que nos ocupan. 3.1.2.- Desarrollo y construcción El trazado de esquema del emisor así como las simulaciones del mismo han sido llevados a cabo utilizando para ello el paquete informático de aplicaciones Proteus. Se incluye como anexo los esquemas y el proyecto para su testeo en dicho programa. La siguiente captura de pantalla muestra el entorno de trabajo durante la edición del esquema electrónico del mando emisor. 8 Haciendo uso de la opción “exportar” del menú “File -> Export Graphics -> Export Bitmap” es posible extraer exportar el esquema y obtener así una representación gráfica del circuito electrónico una vez concluido su desarrollo. 9 16 Frente y reverso: Obsérvese en la anterior imagen la colocación del diodo LED azul en la parte inferior derecha de la placa, ya soldada y cableada. Una vez hecho ello se pasará a montar la placa de los componentes activos propiamente dichos. En ella se situará el módulo emisor de radiofrecuencia, el microcontrolador PIC, el transistor de alimentación del módulo, el regulador de tensión 7805, los condensadores de desacoplo de frecuencias de cada integrado y las resistencias de apoyo del circuito. La parte posterior de dicha placa se muestra a continuación. La cara mostrada es la cara posterior de los componentes, la cara que colinda con la placa de los microinterruptores. Se puede observar la mecanización circular de la placa para el correcto acople del módulo emisor 17 En la siguiente imagen puede observarse esta misma placa en su parte superior, con el cableado de los interruptores conectado al PIC de forma provisional para llevar a acabo pruebas de programación de firwmare y ajuste del funcionamiento. Préstese atención a esta imagen: 18 En ella queda claro el procedimiento de ensamblaje. La placa de la izquierda se coloca sobre la primera, y el conjunto formado por ambas se introduce en la caja plástica. El anclaje de estos tres componentes es exacto. En la parte inferior del interior del mando se colocará la pila de 12 voltios. En la imagen se muestra el cableado provisional durante la fase de pruebas, sin embargo una vez afinado el firmware y programada la placa de forma definitiva, se cortarán los cables (los cables rojos de la figura) lo más cortos posibles y se soldarán de nuevo una vez encajadas ambas placas, obteniendo así un conjunto compacto y reducido. Tras el cableado definitivo entre ambas placas y su montaje dentro de la carcasa plástica, el mando presenta el siguiente aspecto: 3.2.- Receptor Del mismo modo que se realizó durante la descripción del mando emisor, se va a proceder a describir previamente los componentes que conforman el receptor siguiendo de este modo un enfoque ascendente. Se partirá del conocimiento del funcionamiento de los componentes que forman el circuito receptor para después poder entender el funcionamiento como conjunto. 19 3.2.1.- Componentes El receptor está compuesto por diversos componentes electrónicos clave. Uno de ellos, y el principal, es el microcontrolador PIC18F2550 que da vida al sistema. Tras ello, el módulo receptor de radiofrecuencia es el encargado de recibir las ondas emitidas por el emisor. Además el sistema incorpora una memoria EEPROM y un timer en tiempo real. Se procederá al análisis de cada uno de ellos. 3.2.1.1.- Microcontrolador PIC 18F2550 El microcontrolador PIC18F2550 es el que controla el receptor. En el se delegan todas las tareas de procesamiento que dan funcionalidad al sistema. Este microcontrolador se encuentra en encapsulados de 28, 40 y 44 patillas ya que debido al alto número de funciones de las que dispone algunas de ellas se encuentran multiplexadas. En el caso que nos ocupa es suficiente con el encapsulado de 28 patillas. El pinout del mismo se muestra a continuación: Las características más notables del mismo son las siguientes: - Frecuencia de reloj de hasta 48 MHz. Del mismo modo que el PIC16F628 utilizado en el receptor este microcontrolador también implementa un oscilador interno. Sin embargo y debido a la necesidad de hacer uso de la UART del mismo se ha optado por el uso de un cristal de cuarzo externo de 20 MHz, dotando al sistema de un oscilador estable y de onda simétrica. - Soporte USB 2.0. Incorpora un módulo hardware que implementa las funciones y mecanismos necesarios para dotar al microcontrolador de conexión USB en el papel de dispositivo (no host). - Modos Idle y Sleep. Permiten inducir el circuito integrado en modos especiales de bajo consumo. El modo Idle desactiva la unidad central de proceso y las partes asociadas al mismo, permaneciendo únicamente activos aquellos dispositivos de E/S mediante los cuales es posible devolver al procesador a su estado normal ante un evento predeterminado. 20 - Interrupciones externas. Se dispone de la posibilidad de configuración de varios pines de entrada del microcontrolador como patillas de entrada de interrupción activa por flanco ascendente o descendente (configurable por software). - PWM, entradas analógicas, UART. En este caso concreto de aplicación se hace uso de la UART del chip para establecer la comunicación con el módulo receptor de radiofrecuencia. - Módulo MSSP. Se utiliza para establecer la comunicación por i2c con la memoria EEPROM y el timer RTC. - Memoria de programa de 32k-instrucciones. Está dotado con una memoria flash capaz de alojar una cantidad de 32k instrucciones, más que suficiente para nuestros propósitos. - Memoria RAM de 2KB. Se dispone de un banco de 2KB de memoria volátil RAM y acceso aleatorio. - Memoria EEPROM de 256 bytes. El dispositivo pone a disposición del desarrollador 256 bytes de memoria no volátil o persistente. Las razones de elección de este microcontrolador y no otro de la familia de chips que Microchip pone a disposición es el hecho de que está dotado de módulo USB, al mismo tiempo que ofrece los recursos necesarios no siendo requerido otro de categoría superior. 3.2.1.2.- Memoria EEPROM 24LC1025 El receptor hace uso de una memoria EEPROM 24LC1025 de microchip, cuya finalidad es posibilitar el guardado de secuencias y las acciones asignadas a los pulsadores. Dicha memoria comparte el bus i2c con el timer DS1307, y es el microcontrolador el encargado iniciar la comunicación con los dispositivos cuando así sea necesario y llevar a cabo el correcto direccionamiento de los mismos con el fin de discernir entre uno u otro. De la misma forma que se ha implementado el driver que ofrece acceso a las funciones del timer también se ha programado una API que ofrece toda la funcionalidad de la memoria EEPROM mencionada. Para ello, y como es proceso habitual durante la programación de drivers de dispositivo, se ha comenzado estudiando el datasheet del circuito integrado con la finalidad de conocer los aspectos importantes, secuencias de transferencias de datos, modos de funcionamiento, direccionamiento, acceso, mapeado interno, rangos de direcciones, etc. Y todo lo necesario para llevar a cabo exitosamente la implementación que permita la usabilidad de éste dispositivo. Constitución interna La memoria EEPROM 24LC1025 posee 1Mbit de capacidad organizada en 128 K-palabras de 8 bits (1024 Kbits), siendo necesario 16 bits para poder direccionar todo el rango disponible. Debido a la arquitectura interna del dispositivo se encuentra organizada como si de dos memorias de 512 Kb se tratase, estableciendo dos bloques lógicos de 512 Kb y habilitando un bit de selección de bloque con el fin de acceder a uno u otro durante las operaciones de lectura y escritura. Dicho bit puede considerarse como si del bit de dirección número de mayor peso de la dirección se tratase. 21 22 Direccionamiento del dispositivo Primeramente se prestará atención al subconjunto destacad en la siguiente tabla, extraída de la página 5 del datasheet. Se puede observar que se dispone de dos patillas mediante las cuales puede establecerse la dirección física del dispositivo en el bus, A0 y A1. A pesar de que primeramente pudiera parecer que se dispone de tres patillas, la tabla indica que la pata A2 no se trata de una pata de configuración y que debe dejarse fija a valor lógico 1 para que el dispositivo funcione correctamente. Por lo tanto, disponiendo de dos patillas para configurar la dirección del dispositivo es posible conectar hasta 4 memorias EEPROM en el mismo bus, permitiendo una capacidad total de 4Mbit. Formato del byte de direccionamiento: 23 Observando el diagrama del byte de dirección puede observarse que está compuesto por una serie de cuatro bits fijos, seguidos de 3 bits de dirección (de los cuales internamente el más significativo se corresponde al bit de selección de bloque) y un bit de lectura/escritura en la posición del bit de menos peso. El valor de A1 y A0 debe corresponderse con el valor cableado eléctricamente en las patillas 1 y del chip. Una vez direccionado el chip, el siguiente paso consiste en enviar la dirección de trabajo sobre la cual se quiere operar. Para ello se fracciona la dirección en dos mitades, enviando primeramente el byte más significativo de la misma (bits15 a 8) y posteriormente el byte menos significativo (bits 7 a 0). Hasta aquí puede considerarse el máximo común divisor a la hora de llevar a cabo cualquiera de las operaciones posibles sobre la memoria. Volviendo a la misma tabla, préstese ahora atención a la línea enmarcada en rojo: 24 Como se puede observar el circuito integrado posee también de una patilla de habilitación de escritura la cual queda habilitada a nivel bajo. En caso de colocarla a nivel alto, las operaciones de escritura quedan inhibidas a pesar de que las de lectura no se ven afectadas (página 5 del datasheet). “This pin must be connected to either VSS or VCC. If tied to VSS, write operations are enabled. If tied to VCC, write operations are inhibited, but read operations are not affected” Según la tabla de la página 3 del datasheet, se tiempo de setup mínimo de dicha patilla (TW setup min) es de 600 nanosegundos, y el tiempo de mantenimiento (TW hold min) es de 1300 ns. Se tiene por tanto, que antes de iniciar cualquier transferencia de escritura será necesario colocar la patilla 7 del chip a nivel bajo durante al menos 600 ns. antes, y será necesario mantener dicho nivel al menos 1300 ns. tras la última operación de escritura llevada a cabo. Operaciones de escritura Obsérvese el siguiente diagrama, extraído de la página 7 del datasheet. 25 En él se refleja el fujo de datos de una operación de escritura aleatoria, esto es, a una dirección cualquiera dentro del rango direccionable por la memoria. Como se puede ver, la comunicación se inicia cuando el microcontrolador coloca el bit de START en el bus. Acto seguido, envía el byte de dirección de dispositivo constituido por una parte fija, el bit de bloque, la dirección configurada según los pines A1 y A0, y el bit de lectura/escritura, que al tratarse de un caso de escritura será 0. A continuación se envía el byte más significativo de la dirección seguida del byte menos significativo de la misma. A cada envío, el chip responde con un bit de reconocimiento ACK. Una vez seleccionada la dirección, sucesivas escrituras escribirán posiciones consecutivas de la memoria hasta que el microcontrolador de por finalizada la comunicación escribiendo el bit de STOP en el bus. El dispositivo permite también el acceso a bloque de datos en modo página. El siguiente diagrama representa una instancia de dicho modo de escritura. Como se puede observar el modo de acceso no difiere del modo aleatorio. Simplemente hay que tener en cuenta una serie de consideraciones a la hora de llevar a cabo la operación. - El tamaño de la página es fijo e igual a 128. Deberán realizarse por lo tanto 128 accesos consecutivos a una dirección 128*n donde n es un numero entero. - La dirección de la página deberá ser múltiplo de 128, y al ser de tamaño 128 bits acabará en una posición inmediatamente anterior al principio de la siguiente página. Esto es, la dirección de página que comience en 12*n acabará en 128*(n+1)-1. - Los datos se copian a un buffer intermedio y son actualizados una vez recibido el último byte. En caso de que la línea de habilitación de escritura WP se ponga a nivel alto deshabilitando la escritura durante un proceso de escritura de página, el dispositivo reconocerá las operaciones (enviará ACKs) pero no actualizará los datos al finalizar la recepción. 32 La figura muestra el orden de los datos durante un flujo de datos de un proceso de escritura de los registros del timer. Primeramente el microcontrolador debe generar el bit de START. Acto seguido debe direccionar el dispositivo escribiendo la dirección del mismo en el bus. La dirección del dispositivo está formada por 8 bits, de los cuales los 7 bits de mayor peso conforman la dirección física fija del mismo. El bit de menos peso indica si se está solicitando una operación de escritura o de lectura. Tanto si este bit vale 0 como 1, el dispositivo queda direccionado si los 7 bits de mayor peso de la dirección se corresponden con el valor en binario “1101000”. Es decir, el dispositivo se puede direccionar a través de la dirección 0xD0 para una operación de escritura y con la dirección 0xD1 para una operación de lectura. El siguiente byte hace referencia a la dirección del registro sobre el cual se va a realizar la operación de escritura. Una vez especificado el registro, una posterior escritura actualizará el valor del registro apuntado. El registro apuntador es autoincremental, esto significa que posteriores valores escritos en el bus actualizarán cada vez el registro inmediatamente posterior. Esta característica, presente en muchos dispositivos, permite agilizar el intercambio de información permitiendo llevar a cabo escrituras sobre registros consecutivos sin necesidad de iniciar una nueva transferencia y direccionamiento por separado. Tras cada byte enviado, el dispositivo receptor del mismo ha de responder con un bit de reconocimiento ACK (Acknowledgment). Tras escribir el último valor del último registro deseado, el microcontrolador debe generar el bit de STOP dando por concluido el intercambio de información y liberando el bus. Lectura de los registros del timer. De manera análoga al proceso de escritura en el dispositivo, el intercambio de información deberá comenzar colocando el bit de START en el bus i2c para, acto seguido, escribir en el mismo la dirección del timer en modo lectura, esto es, con el bit menos significativo a 1. El archivo será direccionado para una operación de lectura, por tanto, escribiendo el valor 0xD1 en el bus i2c. A continuación una lectura del bus i2c 33 por parte del microcontrolador obtendrá el valor del registro seleccionado en ese momento. Sucesivas lecturas obtendrán valores de los registros inmediatamente consecutivos, de igual forma que sucedía durante el proceso de escritura. Cada vez que el microcontrolador recibe un byte debe indicarlo mediante el bit de reconocimiento ACK, excepto cuando se dispone a leer el último valor en cuyo caso debe responderse con No-Acknowledgement, o bit NACK, haciendo saber de este modo al timer que la operación de lectura ha finalizado y no ha de volcar más datos al bus. Acto seguido, el microcontrolador finalizará el intercambio de datos mediante la escritura en el bus del bit de STOP. Viendo el esquema del flujo de datos. Viendo la figura que indica el orden de los datos durante el proceso de lectura se puede observar que en ningún momento durante la orden de lectura se indica el valor del registro sobre el cual se desea llevar a cabo la operación. De ello se deduce, que a la hora de realizar una operación de lectura deberá anteponerse una operación de escritura, en la cual el microcontrolador escribe el registro apuntador del timer, para posteriormente iniciar la secuencia de lectura sobre el registro previamente indicado. El datasheet del dispositivo pone a disposición del desarrollador más información sobre aspectos de timing de bus, electricidad, dimensiones, disipación de calor, características eléctricas, etc. Sin embargo con la información comentada hasta ahora se dispone del suficiente conocimiento como para llevar a cabo la implementación del driver del chip. 3.2.1.4.- Módulo RF RX433N De igual modo que la transmisión por parte del mando emisor se delega en el módulo de radiofrecuencia tx433n, para la recepción se hace uso del módulo complementario, el cual responde a la referencia rx433n, también de la empresa Velleman. La asignación de pines de dicho módulo es la siguiente: De igual modo que el emisor, trabaja en la frecuencia de 433,92 MHz en modulación ASK. Posee una sensibilidad de -108 dBm y es efectivo en cuanto a recepción de datos sin corrupción hasta una tasa de transferencia de 3 KB/s. Para su correcto funcionamiento ha de ser alimentado con una tensión continua de 5 voltios. 34 3.2.2.- Desarrollo y construcción Siguiendo con las herramientas utilizadas para el desarrollo de emisor, se ha llevado a cabo del mismo modo el diseño y simulación del receptor. Se incluye como anexo todo el proyecto en Proteus, con los esquemas y archivos necesarios para las simulaciones pertinentes. La siguiente captura de pantalla muestra un pantallaza de la suite de desarrollo electrónico durante el proceso de diseño del esquema del receptor. Existen sin embargo algunos componentes que no se han incluido dentro del proyecto en Proteus. Posteriormente se hablará de ellos y los motivos. Haremos uso de la opción “exportar” del menú “File -> Export Graphics -> Export Bitmap” con el fin de exportar el esquema y obtener una imagen del mismo en formato habitual. En la siguiente imagen puede verse el esquema del receptor una vez exportado: 35 36 Como se ha mencionado existen diversos componentes que no aparecen en el esquema. El motivo de ello es la falta de espacio en la superficie de trabajo de Proteus, y el hecho de que su ausencia no tiene consecuencias en la simulación práctica de los circuitos por ordenador. Los elementos que no aparecen en los esquemas son los siguientes: • Leds rojos y resistencias limitadoras de intensidad asociadas. Un conjunto LEDresistencia por cada relé. Cada vez que un LED está activo se enciende su resistencia indicadora. • Conjunto Resistencia-Condensador. Una resistencia de 10Khz en serie con un condensador de 100nF, y cada conjunto resistencia-condensador descrito en paralelo con los contactos del relé. Esto evita los chispazos en los contactos mecánicos de los relés y evita su deterioro con el tiempo, al mismo tiempo que reduce considerablemente las emisiones electromagnéticas producidas como consecuencia del cierre/apertura de los contactos. 37 • Fuente de alimentación. Reduce la tensión a 5 voltios estabilizados para alimentar los circuitos integrados. La fuente de alimentación está constituida por un regulador integrado 7805 de 3 patillas, así como dos condensadores cerámicos de 100 nF y uno electrolítico de 2200 uF. • Un condensador de 100 nF en paralelo con la alimentación lo más cerca posible de cada circuito integrado. Ayuda a reducir transitorios de alta frecuencia en las líneas de alimentación que podrían ocasionar un funcionamiento erróneo de los componentes o el cuelgue del microcontrolador. 38 Toda la circuitería tiene como epicentro el microcontrolador PIC18F2550. Como fuente de oscilación se ha utilizado un cristal de cuarzo de 20 MHz, acompañado de dos condensadores cerámicos de 22pF. Para llevar a cabo el trazado de la conexión del bus i2c, que une el microcontrolador con la memoria EEPROM y el Timer RTC, se han colocado estos tres elementos lo más cerca posible entre sí de forma que la longitud de las líneas sea lo más corta posible. Tal y como marca el estándar se han colocado dos resistencias de pull-up de 4,7 Kohm a positivo, ello es debido a que los dispositivos que hacen uso de este bus implementan la salida en configuración de colector abierto para permitir el acceso compartido a las líneas de datos por lo que únicamente pueden colocar la línea a nivel bajo, siendo necesario fijar las líneas a nivel alto de forma externa mediante resistencias cuando ninguno de los dispositivos anclados al bus está manteniendo la línea a nivel bajo. Esta es la función de las resistencias de pull-up. El módulo DS1307 funciona a dúo con un cristal de 32.768 KHz, siendo éste la base de tiempos de onda cuadrada que el circuito integrado utiliza de forma interna. Es necesario soldar el cristal de cuarzo lo más cerca posible al circuito integrado, asimismo el fabricante recomienda el uso de planos de masa para el cristal. Sin embargo a nivel práctico esto no es necesario. Se ha soldado un cable proveniente de masa la carcasa metálica del cristal de cuarzo haciendo el efecto de Jaula de Faraday (obsérvese el reducido tamaño del cristal en las imágenes del receptor). La finalidad de la incorporación de un chip cuya capacidad es la de ofrecer la hora en todo momento cobra sentido a la hora de la reproducción de secuencias preprogramadas. Cada secuencia preprogramada lleva asociado un tiempo, codificado en la propia instrucción, que indica la duración mediante la cual tiene validez dicha instrucción. Es decir, si una instrucción bajo ejecución de la secuencia indica que sendas ruedas delanteras deben elevarse, también se indica el tiempo durante el cual debe llevarse a cabo. Es decir, el tiempo que se estarán elevando antes de dar por concluida la instrucción y pasar a leer la siguiente orden programada en la memoria. Con el fin de controlar el tiempo transcurrido desde que se inicia la ejecución de la instrucción se incorpora en el circuito del receptor este timer. Mediante diversas consultas sucesivas (espera activa) es posible conocer el momento exacto en el cual ha 39 transcurrido el tiempo deseado y se debe dar por concluida la ejecución de la instrucción, pasando a la siguiente. La conexión de la memoria EEPROM tampoco presenta mayores complicaciones, únicamente es necesario tener en cuenta la conexión de las patillas del bus i2c y el cableado de la patilla de protección de escritura WP a la patilla correspondiente a RB2 del microcontrolador. El motivo de la incorporación de una memoria EEPROM en el circuito es dotar al mismo de la capacidad de almacenar una cantidad relativamente elevada de datos. El PIC también posee una zona de memoria regrabable por el firmware y accesible al programador, sin embargo está limitada a 256 bytes, una capacidad muy reducida para este caso. Por ello se opta por el uso de una memoria externa, la finalidad de la misma es servir de almacén regrabable de las secuencias de instrucciones programadas por el usuario. El diodo LED amarillo D1 está controlado por dos transistores PNP BC557 en paralelo. Ello permite ser activado al mismo tiempo por el microcontrolador cuando se habilita la escritura en la EEPOM a través de la patilla WP de la misma, y por el timer DS1307 en una de sus patillas que ofrece una señal cuadrada. La finalidad de ello es hacer posible que el led esté apagado, fijo o parpadeando a una frecuencia de 1 Hz (en este último caso se aprovecha de la patilla de salida que habilita el timer). Ello ofrece la posibilidad de ser usado para mostrar visualmente la actividad interna del receptor, utilizando este LED como elemento indicador según el caso. Por otra parte se dota al sistema de un conector USB de tipo B, cableado directamente al microcontrolador a través de las patillas habilitadas al efecto en él. El condensador cerámico de 470 nF es necesario para asegurar el correcto funcionamiento del bus. La resistencia de 10k conectada a positivo entrega un nivel alto a la entrada MCLR del PIC. Esta entrada resetea el microcontrolador cuando se encuentra a nivel bajo, mediante esta resistencia se asegura el correcto funcionamiento del mismo evitando situaciones de inestabilidad, si se deja esta patilla al aire sin conexión el 40 funcionamiento del microcontrolador no será el esperado. En algunos casos puede no llegar a funcionar directamente. Los dos integrados ULN2803 conforman la etapa de potencia que separa la parte lógica del receptor de la parte destinada al control de los dispositivos, motivo de la existencia del circuito. Cada uno de estos circuitos incorpora en su interior 8 drivers de corriente capaces de servir para el control de cargas de un consumo relativamente alto. Cada uno de estos drivers está constituido en base a un transistor Darlington en corte/saturación. En el modo de saturación es capaz de soportar una intensidad máxima de 500 mA, suficiente para el caso que nos ocupa, teniendo en cuenta que la intensidad consumida por cada relé ronda los 30 mA. Hay que tener en cuenta que el ULN2803 no entrega corriente, sino que cierra a masa la la carga conectada a él. Pasar por alto esta consideración durante un diseño electrónico que haga uso de estos integrados puede derivar en fallas difíciles de detectar. La salida de cada uno de los drivers de corriente internos del chip incorpora un diodo en paralelo a una línea de masa común. En la figura superior puede observarse la conexión. Se trata de un diodo con una tensión inversa de ruptura bastante alta, idóneo para el empleo de relés, motores, solenoides y otras cargas inductivas que puedan producir corrientes inversas durante su funcionamiento. De este modo nos ahorramos también el diodo que de otro modo habría que colocar por cada relé de forma externa. Una vez descrita la visión general del circuito electrónico del receptor se pasará a mostrar los pasos de montaje llevados a cabo. Primeramente se ha cortado la placa de circuito impreso al tamaño adecuado y se han soldado los relés. Posteriormente se ha procedido del mismo modo con las regletas de conexión de los actuadotes y los LEDs señalizadores de estado, uno por cada LED. Cada LED va emparejado de una resistencia de 1k, la cual debe ser colocada en serie. 41 Del mismo modo, se han soldado también el conjunto condensador-resistencia en paralelo entre los contactos de salida de cada uno de los relés. Aquí se muestra otro ángulo de la placa: Como siguiente paso se colocarán los zócalos de todos los integrados, así como el conector RJ-12 para el programador ICD2 y el conector USB de tipo B en su localización correspondiente. 48 mismo modo se definen dos constantes cuya función es ser especificadas como parámetro en algunas funciones de la API (líneas 43 a 45). void EEPROM_24LC1025_init(): función de inicialización del dispositivo. Debe ser llamada antes que cualquier otra función de la API. void EEPROM_24LC1025_write(int32 addr, byte data, byte wait): permite la escritura aleatoria del dispositivo. “addr” contiene la dirección en una variable de 32 bits, “data” contiene el dato en un valor de 8 bits a escribir y “wait” hace referencia a si la función debe bloquearse hasta que esté actualizado el dato o debe retornar de inmediato (valor EEPROM24_LC1205_WAIT o EEPROM24LC1025_NOWAIT). byte EEPROM_24LC1025_read(int32 addr): lleva a cabo una operación de lectura aleatoria en memoria. Lee el valor apuntado por la dirección de 32 bits contenida en “addr”. int 24LC1025_page_write(int32 addr, byte *buffer, byte wait): Escribe la página de 128 bits de tamaño de datos de tipo byte en la dirección especificada por “addr”. El parámetro “wait” permite controlar, del mismo modo que su análoga para acceso aleatorio, si debe esperar a que el proceso de escritura haya concluido o si el retorno de la función es inmediato tras finalizar la transferencia i2c con el dispositivo. En caso de que la dirección especificada no sea múltiplo de 128 y no sea por tanto una dirección válida no se lleva a cabo ninguna operación y devuelve “1”. En caso de que la dirección sea correcta, se lleva a cabo la operación y se devuelve “0”. Se transferirán exactamente 128 bits, en caso de que el buffer sea mayor solo se transferirán los 128 primeros bits y en caso de que sea menor se transferirán los datos de las posiciones de memoria siguientes fuera del rango del tamaño del buffer. int 24LC1025_page_read(int32 addr, byte *buffer): Lee una página de 128 bits de tamaño de datos de tipo byte en la dirección especificada por “addr” y los coloca en “buffer”. En caso de que la dirección especificada no sea múltiplo de 128 no se lleva a cabo ninguna operación y se devuelve “1”, en caso de que sea válida se lleva a cabo la lectura de página y devuelve “0”. En caso de que el buffer sea de mayor tamaño solo se rellenarán con datos los 128 primeros bytes, y en caso de que sea menor el resultado es impredecible corrompiendo las direcciones de memoria adyacentes al buffer. Finalmente, en la línea 54 se incluye el archivo de código que implementa las funciones definidas y se cierra el bloque condicional del preprocesador dando por concluido de este modo el archivo de definiciones. A continuación se estudiará el archivo 24LC1025.c por partes: EEPROM_24LC1025_init(): 49 La función de inicialización únicamente controla la patilla de habilitación / deshabilitación de escritura, inhabilitándola. EEPROM_24LC1025_write() El primer paso consiste en determinar si el acceso se va a producir en el banco 0 o el banco 1. En caso de que la dirección sea menor que los primeros 65535 bits, se encontrará en el banco 1. En caso de que sea mayor, el banco seleccionado deberá ser el 1 (líneas 58 y 59). Posteriormente se habilita la escritura del dispositivo y se espera 1 ms con el fin de cumplir el tiempo de set-up. Volvamos a echar un vistazo al datasheet: 50 El tiempo mínimo de set-up de la señal de protección es de 600 ns. Con 1 ms superamos con creces dicho tiempo. A pesar de que puede reducirse bastante, no es conveniente apurar el timing de las señales, con 1 ms es suficiente para nuestro cometido y no supone una pérdida de tiempo considerable. Acto seguido se deshabilitan las interrupciones en caso de estar habilitadas, como viene siendo habitual en las operaciones con el bus i2c, y después se inicia la transferencia . Primeramente se lanza el bit de START, acto seguido la dirección del dispositivo, la parte alta de la dirección, la parte baja, se escribe el dato de 8 bits y se envía al bus el bit de STOP (líneas 68 a 73). En caso de que haya sido seleccionada la opción de llevar a cabo una espera activa con el fin de no retornar hasta que haya sido finalizado el proceso de escritura interno de la memoria, el algoritmo entra en un bucle, contenido entre las líneas 75 y 83. Dicho bucle comienza tratando de iniciar una nueva operación de escritura, escribiendo el bit de START y posteriormente la dirección del dispositivo en modo escritura. Si no devuelve el bit de reconocimiento ACK, sigue iterando hasta que éste sea devuelto, considerando que el dispositivo se encuentra listo para una nueva operación de escritura y que por tanto la operación anterior ha sido finalizada. Finalmente, se deshabilita la escritura del dispositivo y se lleva a cabo una espera de 2 ms. Con el fin de cumplir con el timing de las especificaciones. Volviendo al datasheet: Del mismo modo y aunque un tiempo de hold de 1.3 ms es suficiente para garantizar el correcto funcionamiento, se le dará un margen adecuado y se pondrá una espera de 2 ms. 51 EEPROM_24LC1025_read() Esta función realiza una operación de lectura aleatoria sobre la dirección indicada. Para ello y de igual modo que su homóloga de escritura, primeramente comprueba el valor de la dirección y establece un banco de trabajo u otro (líneas 107 y 108). Acto seguido, deshabilita las interrupciones y comienza la lectura de la dirección. Para ello, primeramente inicia una operación de escritura sobre el dispositivo, envía la dirección fraccionada en dos partes, y posteriormente inicia una nueva transferencia sin cerrar la anterior (sin poner el bit de STOP) en la cual direcciona de nuevo el dispositivo en modo lectura (con el bit menos significativo a 1) para posteriormente leer un byte del bus sin enviar el bit de ACK, indicando al dispositivo que únicamente se va a leer una dirección. Tras ello, se cierra la conexión con el bit de STOP (líneas 114 a 121). EEPROM_24LC1025_page_write() 52 Este algoritmo realiza una operación de escritura de página. Para ello primeramente comprueba si la dirección especificada es múltiplo de 128, en caso contrario devuelve “1” y finaliza (línea 149). En caso contrario, del mismo modo que el resto de operaciones primeramente comprueba el banco de acceso (líneas 151 y 152), tras ello habilita la patilla de habilitación de escritura y comienza la transferencia. 53 Se escribe el bit de START, se pone en el bus la dirección del dispositivo direccionado como escritura, se pasa la dirección de inicio de página en dos mitades, y se llevan a cabo 128 operaciones de escritura en el bus tomando para ello los datos del buffer de manera consecutiva (línea 165). Tras ello, y si el parámetro “wait” así lo indica, se lleva a cabo una espera activa hasta que el ciclo de escritura finalice tal y como se ha explicado anteriormente en la función de escritura aleatoria. Acto seguido, se habilitan de nuevo las interrupciones y finaliza la función. EEPROM_24LC1025_page_read() Función complementaria a EEPROM_24LC1025_page_write(), lee una página completa de 128 bits de la dirección especificada en memoria y la almacena en la dirección del buffer especificado como parámetro. Para ello primeramente comprueba si la dirección de página es válida, esto es, múltiplo de 128. En caso contrario devuelve “1” y el algoritmo finaliza. En caso de tratarse de una dirección válida se inicia la operación. Para ello primeramente, y al igual que en el resto de operaciones, se comprueba a que banco hace referencia dicha dirección (líneas 207 y 208). Acto seguido se deshabilitan 54 las interrupciones y se comienza una operación de escritura para especificar la dirección sobre la que se leerá. Para ello se envía el bit de START, la dirección del dispositivo en modo escritura, y tras ello la dirección de la página fraccionada en dos mitades como ya se ha visto anteriormente. Después se inicia una nueva transferencia sin cerrar la anterior, direccionando ahora el dispositivo en modo lectura colocando para ello el bit menos significativo a 1 (línea 219) y se entra en un bucle “for” que lleva a cabo 128 lecturas consecutivas (línea 220). La última lectura se efectúa fuera del bucle ya que ésta deberá enviar el bit de no reconocimiento NAK, esto se consigue pasando como parámetro el valor “0” a la función “i2c_read()”. Una vez hecho esto, se escribe el bit de STOP y se da por concluida la operación de escritura de página. 4.1.2.- Timer RTC DS1307. El driver está compuesto, siguiendo con la metodología de desarrollo del lenguaje C, de un archivo cabecera .h que contiene las definiciones y prototipos de las funciones y el archivo del driver propiamente dicho de extensión .c, que implementa la API previamente definida en el archivo de cabecera. El archivo DS1307.h Se procederá a analizar primeramente el archivo DS1307.h por partes: Primeramente se hace uso del juego de directivas de preprocesador del compilador #ifndef-#endif para llevar a cabo el control de inclusión de la librería. Esto permite evitar errores cuando se incluye una librería mas de una vez en un mismo proyecto, debido a inclusiones simultaneas desde diversos archivos fuente diferentes lo que daría lugar a errores debido a duplicidad de definiciones. Cuando se hace uso de este driver en un proyecto es necesario haber definido previamente el pinout del dispositivo, el control de ello se lleva a cabo obligando al desarrollador a definir la macro “DS1307_pinout” cuando define el pinout del dispositivo. En caso de que no esté definida, se da por hecho que no se ha definido el pinout del dispositivo y el compilador muestra el error “DS1307: Pinout no definido.”. 55 El siguiente bloque de sentencias define la API del dispositivo, que serán implementadas en el archivo de código de extensión .c, se incluyen las siguientes funciones: DS1307_init(): Función que debe ser llamada primeramente con el fin de inicializar los registros internos y llevar al dispositivo a un estado conocido. Cualquier función que se llame de la API debe situarse posteriormente a esta función. Opera sobre el registro de configuración. DS1307_set_date_time(): establece la fecha y la hora del dispositivo. DS1307_get_date_time(): obtiene la fecha y la hora del dispositivo. DS1307_set_date(): establece solo la fecha del dispositivo. DS1307_get_date(): obtiene solo la fecha del dispositivo. DS1307_set_time(): establece solo la hora del dispositivo. DS1307_get_time(): obtiene solo la hora del dispositivo. DS1307_get_day_of_week(): obtiene un string con el nombre del dia de la semana. DS1307_out_osc_conf(): cambia la configuración de la patilla 7 de salida de onda cuadrada. Permite reconfigurar el dispositivo operando sobre el registro de configuración. DS1307_out_pause(): pausa el timer. Inhabilita el paso del tiempo. DS1307_out_resume(): reanuda la ejecución del timer. DS1307_out_out_osc_on(): habilita la salida de onda cuadrada por la patilla 7, según la configuración previamente establecida mediante DS1307_out_osc_conf() o DS1307_init(). DS1307_out_osc_off(): deshabilita la salida de onda cuadrada por la patilla 7. 56 Asimismo, también se definen dos funciones internas que no forman parte de la API del chip. DS1307_bcd2bin(): Convierte un valor BCD en su representación en binario natural. DS1307_bcd2bin(): Convierte un valor en binario natural en su representación en BCD. A continuación se lleva a cabo la definición del mapeado de registros internos del dispositivo, con el fin de asignar un alias a cada dirección de registro y facilitar la legibilidad y mantenimiento del código. El siguiente bloque de código del archivo define los parámetros de configuración que serán utilizados durante la llamada a las funciones DS1307_init() y DS1307_osc_conf(). Pueden ser empleados conjuntamente mediante el operador “or”, representado en C por el símbolo “|”. 57 Finalmente, se define un array de strings conteniendo los días de la semana para hacer posible la implementación de la función DS1307_get_day_of_week(). Tras ello, se incluye el archivo de código y se cierra el bloque condicional del preprocesador mediante la sentencia “#endif”. El archivo DS1307.c El archivo DS1307.c contiene la implementación de las funciones del driver definidas en el archivo de cabecera. Función DS1307_init(): 64 DS1307_pause() La función D1307_pause() detiene el funcionamiento del timer. Tras la llamada a esta función el paso del tiempo se deshabilitará y el timer quedará pausado hasta la llamada de la función de reanudación DS1307_resume(). Con el fin de llevar a cabo el pausado del dispositivo, la función modifica el bit de mayor peso del registro del segundero. Si se pone dicho bit a 0, se habilita el funcionamiento del timer. Si se pone a 1, se deshabilita. Hay que tener en cuenta que los demás bits del registro deben permanecer inalterados, para ello se deberá leer previamente su valor (líneas 347 a 351) para posteriormente modificar el bit sobre el valor leído mediante una operación OR (“|”) y la máscara 0x80, con lo cual se consigue poner a uno dicho bit manteniendo inalterados el resto de ellos. Una vez puesto a uno el bit de mayor peso se procederá a actualizar el registro de los segundos con dicho valor modificado, siguiendo para ello el procedimiento habitual. DS1307_resume() 65 Función complementaria a la función DS1307_pause(), reanuda el paso del tiempo del timer. Para ello, siguiendo el proceso análogo a la función pause(), obtiene el valor del registro de los segundos (líneas 378 a 383), pone a cero el bit de mayor peso mediante la operación AND (“&”) y la máscara 0x7F, y actualiza el valor del mismo (línea 387). Función DS1307_out_osc_off() 66 Deshabilita la salida de onda cuadrada de la patilla 7 del chip. Como se vio anteriormente, ello se lleva a cabo mediante la escritura del bit 4 del registro de control. SQWE = 1 Æ Salida habilitada. SQWE = 0 Æ Salida deshabilitada. A la hora de modificar un bit del registro hay que tener en cuenta que no es posible la modificación individual a nivel de bit, la modificación de un registro supone la escritura de nuevo del registro completo de 8 bits. Para conservar el valor de los demás bits durante la actualización, se lleva previamente a cabo una operación de lectura sobre el registro y se guarda su valor (lineas 443 a 448). Acto seguido, y sobre el valor leido, se pone a 0 el bit correspondiente mediante la operación AND (&) junto con una máscara de bits, que resetea el bit 4 permaneciendo inalterados el resto de los bits del registro, para posteriormente escribir de nuevo el valor del registro de configuración (linea 452). Función DS1307_out_osc_on() 67 Opera de la misma manera que la función DS1307_out_osc_off(), solo que en lugar de poner a 0 el bit SQWE lo pone a 1 con el fin de hacer accesible la onda cuadrada a través d la patilla 7 del dispositivo. Para ello primeramente obtiene el valor del registro de configuración (lineas 410 a 415), posteriormente pone a 1 el bit 4 del mismo mediante la operación lógica a nivel de bit OR (“|”), para finalmente iniciar una operación de escritura y actualizar el valor del registro el el timer (lineas 417 a 419). Una vez finalizado el proceso, finaliza la transferencia de la forma habitual escribiendo en el bus el bit de STOP. Función DS1307_bcd2bin() Realiza la conversión del número en formato BCD especificado como parámetro en su correspondiente valor en representación en binario natural. En un número representado en BCD, el nibble (conjunto de 4 bits) superior del byte representa el valor de las decenas y el nibble inferior el valor de las unidades. Teniendo esto en cuenta, el algoritmo se basa en el aislamiento de ambos nibbles para su tratamiento por separado. Primeramente se obtiene el valor de las decenas. Ello se consigue desplazando el valor 4 bits hacia le derecha, debido a que la instrucción de desplazamiento rellena por la izquierda con ceros. Acto seguido se multiplica por 10 para obtener el valor de dicho número (linea 473). 68 Se procede de forma similar con las unidades, para ello se realiza la operación AND con la máscara 0x0F de forma que se pone a cero el nibble de mayor peso. El valor obtenido es el valor de las unidades (linea 474). Finalmente, se suman ambos valores y se obtiene el valor esperado en binario natural (linea 475). Función DS1307_bin2bcd() Esta opera de manera inversa que la función presentada anteriormente, realizando la conversión de un valor en binario natural pasado como parámetro a su representación en BCD, con el fin de ser utilizado durante las funciones de escritura del timer. Para ello primeramente obtiene el valor de las decenas, haciendo uso de la divisón entera y despreciando de este modo el resto de la operación (linea 497). Acto seguido, se obtiene el valor de las unidades. Para ello, al valor inicial se le resta el valor ya obtenido de las decenas (previa multipliación por 10) y el resultado es el valor esperado (linea 493). Otra forma de hacerlo sería realizando la operación módulo (“%”) la cual obtiene el resto de una división: realizando la operación módulo de la forma “bin % 10” obtenemos el valor de las unidades del número en representación binaria. 4.2.- Pruebas de componentes. Una vez implementados los dirvers de los componentes necesarios se han llevado a cabo ciertas pruebas sobre ellos con el fin de verificar su correcto funcionamiento y la correcta implementación del código de dichos drivers. Del mismo modo el hecho de llevar a cabo inicialmente pruebas sencillas sobre cada uno de los componentes permite familiarizarse con su uso y aprender el manejo concreto y los pormenores de cada uno de ellos. Se pasará posteriormente, por tanto, a explicar las pruebas realizadas sobre cada uno de los componentes que así se ha considerado conveniente llevar a cabo. 69 4.2.1.- USART En el presente proyecto es de vital importancia el correcto funcionamiento de la USART de ambos microcontroladores, el PIC16F628 y el PIC18F4550, del emisor y receptor respectivamente, debido a que a través de su conexión directa con los módulos de radiofrecuencia de emisor y receptor, suponen la apertura al canal de comunicación inalámbrica. Con el fin de llevar a cabo un primer contacto con la USART de ambos pics se ha implementado un sencillo programa cuya única función es la de enviar el mismo carácter que recibe, dicho de otro modo, implementa la función “echo”. Hay que tener en cuenta que los PIC poseen lógica TTL y funcionan a niveles de tensión comprendidos entre 0 y 5 voltios, sin embargo los niveles de tensión de funcionamiento del PC operan en el rango entre -12 y 12 voltios. Para llevar a cabo la conversión de niveles de tensión y permitir la comunicación bidireccional entre el PIC y el ordenador, se hará uso del conversor de niveles desarrollado. El código de esta prueba no supone una alta complejidad y el código se encuentra autodocumentado, sin embargo se procederá a hacer una explicación del mismo: 70 Las líneas 28 y 29 se definen los pines utilizados como entrada y salida rs232. La creación de variables definición para llevar a cabo la configuración el pinout de los componentes supone una buena práctica de programación que mejora la legibilidad y mantenimiento futuro del código. Acto seguido se procede a inicializar la USART del PIC mediante la sentencia “use”, propia del compilador CCS. Esta sentencia inicializa la USART del microcontrolador en base a las opciones pasadas como parámetros, en este caso concreto se crea una conexión serie a una velocidad de 2400 baudios, usando como patilla de transmisión la patilla correspondiente al bit 6 del puerto C (patilla 17) y la correspondiente al bit 7 del mismo puerto como recepción (patilla 18) ya que son las que se corresponden con la USART. La unidad de envío de datos estará compuesta por 8 bits (1 byte) y no se utilizará control de errores mediante bit de paridad (opción parity=N). Es importante mencionar que el compilador CCS inicializará la USART hardware siempre y cuando la definición de pines de envío y recepción indicados se corresponda con los establecidos como entrada y salida de la misma, en caso contrario se creará una conexión RS232 por software y no se utilizará la USART del dispositivo. También es importante dejar constancia de que la definición del puerto serie deberá llevarse a cabo siempre posteriormente de la especificación de la frecuencia del microcontrolador (línea 25) ya que internamente el compilador CCS necesita conocer la base de tiempos para establecer la comunicación y cumplir con el timing de la señal de la transmisión serie. La sentencia “#int_rda” indica que la función descrita a continuación hace referencia al manejador de interrupción de la USART. Dicha función debe tener tipo de retorno nulo (void) y ser lo mas escueta posible, denominador común que debe cumplir toda aquella función software encargada de llevar a cabo el control de interrupciones de cualquier índole. Cada vez que se encuentre disponible un carácter en el buffer de lectura de la USART, se producirá una interrupción que delegará el control en la función indicada tras esta sentencia. 71 Acto seguido se pasa a la implementación del manejador de interrupción propiamente dicho en la línea 42, el cual únicamente lee un carácter a través de la función “getc()” y lo devuelve por el mismo canal de comunicación mediante la instrucción “printf()” previamente formateado con la inclusión de retorno de línea para mejorar la presentación de la aplicación. Seguidamente se procede a la implementación del “main” o función principal del programa, la cual únicamente activa las interrupciones del dispositivo con el fin de habilitar el manejador asociado previamente. Una vez escrito el código se procederá a su verificación. Para ello primeramente se simulará en Proteus, como circuito electrónico se utilizará el mismo del receptor. Haciendo doble click sobre el símbolo del terminal virtual se accede a su configuración, en la cual se especificarán las siguientes opciones: Haciendo doble click en el símbolo del microcontrolador se abrirá la ventana de propiedades del mismo mediante la cual se podrá seleccionar el firmware a cargar en el PIC, directamente de la carpeta del proyecto de MPLab previamente compilado. Una vez cargado el archivo rs232.hex se simulará el proyecto y se comprobará que a cada carácter pulsado en el terminal virtual, el microcontrolador devuelve el mismo carácter pulsado. 72 Tras llevar a cabo esta comprobación básica se procederá a llevar a cabo la comprobación sobre el hardware real. Para ello se abrirá MPLab y se seleccionará el programador IC2 en el menú “Programmer -> Select programmer”. Se conectará la alimentación del mismo y se conectará a la placa del circuito electrónico a través de la opción “Programmer -> Connect”. Acto seguido se programará el PIC con el firmware previamente compilado. Una vez hecho esto se procederá a alimentar el circuito electrónico se conectará la salida de la USART del microcontrolador al conversor de niveles de tensión mediante los pines habilitados al efecto en el circuito, y el conversor de niveles se conectará al ordenador directamente. Después de ello se definirá una nueva conexión serie mediante el Hyperterminal de Windows que deberá responder a la siguiente configuración: Baudios: 2400 Bits de datos: 8 Paridad: N Bits de parada: 1 Control de flujo: Ninguno Se ha guardado la conexión de Hyperterminal bajo el nombre “Prueba RS232.ht”, dicho archivo se encuentra en la carpeta “receptor\pruebas\rs232” y haciendo doble click sobre él se crea una nueva conexión automáticamente ya configurada. Es posible, por tanto, ejecutar este archivo para abrir automáticamente un Hyperterminal ya configurado para la prueba con la única salvedad de la necesidad de especificar el puerto que se utilizará para la comunicación a través de la opción “Archivo -> Propiedades”. En el caso que nos ocupa se ha utilizado un conversor serieusb de forma que es posible disponer de conexión serie en ordenadores que carecen de este puerto de forma nativa. Dicho conversor crea una conexión virtual RS232 que ofrece todas las funciones de un puerto serie real. Una vez programado el microcontrolador y encendido el circuito electrónico es posible verificar el correcto funcionamiento del hardware real y comprobar que la USART funciona correctamente, permitiendo interactuar con ella desde el PC y devolviendo el eco del carácter enviado. 73 4.2.2.- Memoria 24LC1025 El siguiente paso será la verificación del correcto funcionamiento de la memoria 24LC1025 de Microchip, así como del driver desarrollado para su manejo. Para llevar a cabo esta verificación se ha implementado un software que permite la prueba realizar operaciones de lectura y escritura de las direcciones de la memoria en modo acceso aleatorio, así como en modo página, el cual permite el acceso a bloques completos de memoria de tamaño de página de 128 bits. Siguiendo la misma metodología que las comprobaciones del timer RTC DS1307, se lleva a cabo a través de la conexión RS232 haciendo uso para ello del Hyperterminal de Windows, suponiendo un sistema cómodo y sencillo de interactuación con el microcontrolador durante las operaciones de verificación del dispositivo bajo análisis. De forma análoga a los casos ya estudiados, se indicará la velocidad de reloj como primer paso después de la inclusión del archivo de cabecera del dispositivo y la palabra de configuración del mismo (fuses). Acto seguido, se lleva a cabo la definición de los pines de interconexión de la conexión serie directa de la USART del microcontrolador así como del patillaje de la memoria EEPROM, que debido a que se accede a ella mediante el bus i2c al igual que al timer DS1307, el pinout permanece inalterado. Únicamente será necesario añadir una definición, la correspondiente a la patilla de habilitación y deshabilitación de escritura de la memoria (línea 41). 80 comprobación se lleva a cabo elemento a elemento a través de un bucle “for()” (línea 188), de forma que en el momento en que se encuentra una incoherencia entre ambos en alguno de sus elementos, se detiene la comprobación mediante la comprobación de la variable “error” en cada pasada del bucle. Una vez finalizado el bucle de comprobación y ya sea tanto en caso de éxito tanto como de error, la variable “error” contendrá el valor de la comprobación. En caso de haber resultado exitosa, el bucle habrá terminado porque la variable “i” habrá llegado al valor límite de tamaño de página pasado como parámetro (y fijado en 128 durante la llamada a la función) y la variable “error” valdrá 0 (no error). En caso de haber finalizado el bucle porque se haya producido un error en la comprobación, la variable “error” valdrá 1 y éste será el valor devuelto por la orden “return” (línea 191). Durante la comprobación de escritura en acceso aleatorio en memoria, se pide al usuario por un valor de tamaño 8 bits (tamaño de palabra de la memoria). La obtención de dicho valor queda delegada a la función “obtén_dato()”. 4.2.3.- Timer RTC DS1307. Con el fin de verificar el correcto funcionamiento del timer RTC DS1307 y su conexión con el microcontrolador a través de i2c así como el correcto funcionamiento del driver de dispositivo desarrollado, se ha programado una aplicación de prueba que permite operar sobre él y llevar a cabo la prueba de las operaciones básicas de puesta en hora y lectura de la misma. Como método de establecer una comunicación directa entre microcontrolador y usuario y poder en todo momento operar directamente con las funciones de lectura y escritura del timer, se ha hecho uso de la conexión RS232 de la USART del PIC de forma que una vez en ejecución es posible poner en hora el timer así como efectuar operaciones de lectura a conveniencia desde el Hyperterminal de Windows. 81 Primeramente se define la frecuencia de funcionamiento del cuarzo del PIC, 20 MHz. Esto es necesario especificarlo antes de la definición de la conexión serie e i2c ya que, como se ha especificado en la prueba anterior, estas funciones operan a nivel de señal directamente sobre las patillas de los buses y se hace necesario para la generación de ondas y timing de la comunicación. Acto seguido se define el pinout de la conexión I2C sobre la que se basa el DS1307 así como de la conexión serie que permitirá operar a través de Hyperterminal. Se define la macro “DS1307_PINOUT” con la finalidad de hacer saber a la librería desarrollada para el timer que se ha definido el pinout, en caso contrario mostrará un error haciendo notar que es necesaria la definición de las patillas del dispositivo. Tras ello, se definirán las conexiones i2c y rs232. La conexión rs232 será la misma que la definida en la prueba anterior, y la conexión i2c se especificará que el dispositivo es el máster, que la patilla de datos es la definida por I2C_SDA y la de reloj por I2C_SCL, y que se va a utilizar una velocidad de transmisión lenta, 100 KHz, ya que es la única velocidad soportada por el dispositivo (datasheet pág. 6, DS1307.pdf). “Within the 2-wire bus specifications a regular mode (100kHz clock rate) and a fast mode (400kHz clock rate) are defined. The DS1307 operates in the regular mode (100kHz) only. “ 82 Tras definir los pines de conexión y abrir las conexiones rs232 e i2c, el siguiente paso es la inclusión del archivo de cabecera del driver del timer (línea 43). El orden es importante ya que este archivo se basa en las definiciones previas. Se han definido 3 funciones, escribe_rtc() (línea 46), lee_rtc() (línea 47) y ascii2byte() (línea 48). Sobre la primera de ellas se delega el control de las operaciones de escritura, análogamente a ello el main pasa el control pasa a la segunda función cuando se trata de una operación de lectura, y la tercera operación tiene como finalidad la conversión de caracteres numéricos ASCII a sus correspondientes en binario natural. La función main de la prueba no supone una complejidad excesiva, primeramente fija a nivel alto la salida RB2 del microcontrolador y a nivel bajo el resto de salidas, ello tiene la finalidad de de apagar inicialmente el LED amarillo por una parte y de desactivar todos los relés de la placa. Es importante recordar que el diodo LED está gobernado por un transistor PNP BC557 operando en corte/saturación y que un nivel alto en su salida hace entrar al mismo en corte desactivando el LED. Contrariamente a lo que ocurre con los relés, las salidas del microcontrolador están 83 directamente cableadas a las etapas de potencia ULN2803 con lo que para desactivarlos es necesario establecer las salidas del microcontrolador asociadas a nivel bajo. Posteriormente se procede a inicializar el timer, para ello se llama a la función DS1307_init() en la línea 61 con los parámetros DS1307_OUT_ON y DS1307_OUT_1_HZ, que habilitan la salida 7 del timer haciendo accesible la onda cuadrada generada a una frecuencia de 1 Hz. Esta salida está directamente cableada a la base del transistor mencionado BC557 de forma que será posible verificar la oscilación del cuarzo de 16.768 KHz del timer viendo parpadear el LED a la frecuencia establecida de 1 Hz. Como se puede observar en la línea de código número 68, la parte principal del programa la conforma un bucle infinito el cual pregunta al usuario por la operación a llevar a cabo. Es posible leer la hora (opción “r”) y escribirla en la configuración del chip (opción “w), el programa se cerciora que la orden introducida sea la correcta mediante el while() condicional de la línea 69, el cual sigue iterando si la opción es errónea. Si la opción introducida hace referencia a una operación de lectura, se delega el control en la función “lee_rtc()” (línea 71), y en caso de tratarse de una operación de escritura se llama a la función “escribe_rtc()” (línea 72). La función de escritura del timer se muestra a continuación: 84 Primeramente la función pregunta al usuario la hora a introducir (línea 88). En todo momento se realiza un eco al Hyperterminal (línea 89) con la finalidad de mostrar el carácter que se está tecleando, en caso de no realizar esta operación el usuario no vería gráficamente la pulsación de las teclas sobre el terminal. 85 Acto seguido se realiza la conversión del carácter recibido a su correspondiente en binario natural ya que el Hyperterminal opera sobre caracteres ASCII. En caso de enviar un número sobre el terminal, éste envía su correspondiente en representación ASCII y no el número en binario real, que es lo deseado. Por ejemplo, en caso de introducir en el terminal el valor numérico “7”, el carácter recibido por el PIC no será el 0x07 como sería lo esperado sino su correspondiente en representación ASCII, en este caso el valor enviado por el Hyperterminal sería 0x37. Se hace necesario por tanto para la correcta interacción PCPIC cuando se va a llevar a cabo el intercambio de valores numéricos de la función de conversión de ASCII a binario durante la comunicación PC a PIC, y binario a ASCII durante la comunicación PIC a PC. Sin embargo en este último caso la operación se simplifica bastante ya que puede realizarse implícitamente mediante la función “printf()” con el parámetro %i, seguido del número a convertir. Por ejemplo, para imprimir por el Hyperterminal el número 9, contenido en la variable dato, basta con utilizar la siguiente orden de la biblioteca estándar de C: 86 printf(“%c”, dato); Una vez obtenido el valor de las unidades y las decenas, se construye el número completo (línea 94) multiplicando el valor de las decenas por 10 y sumándole las unidades. Es importante comentar que en caso de introducir valores erróneos, por ejemplo introducir como hora un número fuera del rango [0-23] dará lugar al erróneo funcionamiento del dispositivo. Es función del programador cerciorarse que los valores introducidos se encuentran dentro de los rangos establecidos, sería posible introducir en el código instrucciones de control de los valores fuera de rango sin embargo debido a que se trata de un programa de prueba, no supone un problema serio ya que el usuario es el encargado de introducir los valores adecuados y se evita introducir complejidad innecesaria al código. Del mismo modo, puede ser interesante como ejercicio adicional hacer pruebas con valores fuera de rango con el fin de observar el comportamiento del timer. El fragmento de código comprendido entre las líneas 97 a 105 repite el proceso para obtener los minutos, y el código contenido entre 107 y 115 realiza la misma operación nuevamente con el fin de obtener el valor de los segundos. En la línea 117 se llama a la función DS1307_set_time(), la cual actualiza el timer con la hora especificada. Tras ello, en la línea 118 se muestra un mensaje de retorno al ordenador que será mostrado por el Hyperterminal y confirma que se ha llevado a cabo la operación. El parámetro “%02i” de la función printf indica que el valor pasado es un entero, y que se mostrará siempre con dos cifras rellenando por la izquierda con ceros. La finalidad de ellos es mejorar la presentación y mostrar la hora de la forma habitual. La función lee_rtc() es mas sencilla que la anterior, y únicamente realiza una llamada a la función DS1307_get_time() con el fin de obtener la hora del dispositivo y acto seguido envía por la USART un mensaje con el resultado: 87 El último fragmento de código de el programa de prueba hace referencia a la función anteriormente nombrada ascii2byte() la cual se encarga de convertir el carácter ASCII pasado como parámetro en un valor de retorno entero correspondiente al valor en binario natural. Para ello la función la compone un bloque “swtich()” con un “case” por valor, de forma que dependiendo del valor obtenido la conversión es inmediata. En caso de un valor erróneo se ejecuta la cláusula por defecto “default”, la cual devuelve 0: 88 Una vez tratado el tema del código se simulará con el fin de verificar el correcto funcionamiento del mismo, así como del timer y la conexión i2c. Para ello se cargará en Proteus de forma análoga al procedimiento llevado a cabo durante la prueba de la USART del PIC, en este caso se hará doble click sobre el microcontrolador en el esquema y se seleccionará el firmware ya compilado bajo el nombre DS1307.hex. En este caso se hará uso también del monitor de actividad I2C del simulador, el cual se conectará directamente en paralelo a las líneas SDA y SCL como si se tratase de un dispositivo más y se configurará a velocidad de 100 KHz en el menú de propiedades desplegado al hacer doble click sobre él. Se iniciará la simulación y e inmediatamente se abrirá el terminal virtual de Proteus que simula una conexión RS232, así como el monitor de actividad del bus i2c. A continuación puede observarse el diálogo de prueba entre el microcontrolador y el usuario durante la prueba de verificación del timer: Dicho diálogo ha dado lugar a un intercambio de información directo PICDS1307 a través del bus I2C, información que puede ser analizada mediante el monitor i2c que Proteus pone a disposición del usuario para dicho cometido. Los datos capturados por el monitor son los siguientes. 89 Como puede observarse existe una correspondencia directa entre las órdenes enviadas al PIC a través del Hyperterminal y la actividad del puerto I2C llevada a cabo por el PIC. La primera línea (seg. 11.032) se corresponde con la inicialización del timer. La segunda con la puesta en hora. De aquí en adelante, cada una de las tramas de datos hace referencia a una operación de lectura del chip. Es posible comprobar como las instrucciones de código de acceso al bus I2C del driver desarrollado llevan a cabo su cometido, controlando la información enviada y recibida a través del bus con los datos adecuados y en el orden especificado tal y como se puede ver a continuación. Primeramente se analizará la función de inicialización. 96 Del mismo modo, podría ser que el cable se encontrara conectado pero todavía no hubiera sido enumerado por el PC. Esto es, que todavía no hubiera sido reconocido y su driver cargado y asociado, con lo cual seguiría estando inutilizable. De comprobar si el dispositivo se encuentra enumerado por el host, se encarga la función usb_enumerated(). Se hace necesario llevar a cabo comprobaciones continuas sobre el estado del bus con el fin de llevar a cabo las gestiones de funcionamiento internas del mismo. De ello se encarga la función usb_task(). Esta función debe ser llamada continuamente. Llamadas sucesivas a la misma es un acto benigno. Debe ser invocada en cada pasada del bucle. Las funciones usb_cdc_getc() y usb_cdc_putc() leen y escriben (respectivamente) un carácter del puerto serie virtual creado a través de la conexión USB. Una vez estudiadas las funciones que componen el programa, se explicará su funcionamiento. La función main ejecuta constantemente las mismas instrucciones. Básicamente, comprueba si hay algún carácter a la entrada y posteriormente lo devuelve. Sin embargo, y debido a la naturaleza impredecible y cambiante del bus USB, como se ha explicado anteriormente, se añaden algunas funciones extra de apoyo. En cada pasada del bucle, y antes de llevar a cabo ninguna otra operación, primeramente se comprueba que el cable se encuentra conectado. En ese caso se llama a la función usbtask() y posteriormente se comprueba si se encuentra enumerado. En caso negativo no se hace nada más y se vuelve a hacer lo mismo constantemente hasta que esté enumerado (reconocido por el driver). Una vez se encuentra enumerado, cada pasada del bucle llega hasta lo más profundo de la serie de llamadas de funciones y lee un carácter para posteriormente devolverlo (función “eco”). El firmware aquí mostrado es bastante sencillo ya que hace uso de las librerías que ocultan toda la complejidad del bus USB y la implementación de la clase CDC. Para que el correcto funcionamiento y comunicación entre el host (PC) y el dispositivo sea posible es necesario que exista un entendimiento mutuo entre ambos. Por ello es necesario personalizar algunos puntos del código concreto de las librerías del USB, así como también se hace necesario proporcionar un driver al PC para que reconozca el firmware del dispositivo bajo desarrollo. Para este último no será necesario desarrollarlo completamente, existe un template incluido en el propio compilador CCS que servirá para tener a punto un driver rápidamente en base a ciertas modificaciones ligeras de un archivo modelo. Primermante se mostrarán las modificaciones necesarias por parte de los archivos de código del firmware y finalmente se mencionarán los aspectos a personalizar en el driver proporcionado por CCS para el host. En lo relativo al firmware, en el archivo usb_cdc.h se modificará la función de inicio del CDC (obsérvese que es la función que se llama en el main del programa) para que configure las características del puerto RS232 virtual creado con los parámetros acordes a nuestras necesidades. Como se puede ver, esta función inicializa una estructura que contiene los parámetros de una conexión serie estándar. Se adecuarán por tanto a nuestras necesidades concretas en lo relativo a los baudios, paridad, etc. 97 Por otra parte, se hace necesario también la modificación del archivo usb_desc_cdc.h para que el dispositivo sea reconocido por el driver. Las líneas concretas a modificar son las que se muestran a continuación. Existe una tabla que contiene la descripción del dispositivo con la finalidad de mostrar información en el momento en el que éste se conecta al PC. Modificando a conveniencia los datos de dicha tabla se hace posible la personalización de las cadenas de identificación que servirán para dar nombre al dispositivo en el ordenador, visible en el administrador de dispositivos. La tabla USB_STRING_DESC contiene tres cadenas. Cada una de las cadenas comienza con un valor entero que contiene el tamaño de la misma (de la cadena en cuestión, incluyéndose el mismo valor como un elemento dentro del conteo). El segundo carácter de la cadena hace referencia al significado de la cadena, y se especifica haciendo uso de las macros definidas en las librerías. A continuación, el resto de caracteres de la cadena contiene la información propia de la misma. La primera cadena hace referencia al tipo de codificación utilizado. No se tocará, dejándose el valor por defecto. La segunda y tercera cadenas contienen ambas la descripción del hardware. Nótese que tras cada carácter se deberá colocar otro carácter “0” siempre, por lo que cada carácter supondrá un espacio de dos unidades durante el conteo de caracteres de la cadena para especificarlo en el primer elemento de la misma. Además de ello, deberá modificarse también la cadena USB_STRING_DESC_OFFSET que contendrá el offset, esto es, la posición de incio, de cada una de las cadenas de la tabla previamente nombrada. 98 Obsérvese las líneas 185 y 186 del mismo archivo. Contienen el VID y el PID (Vendor ID y Product ID), que identifican el vendedor y el producto. Cuando se conecta el dispositivo al ordenador se produce un intercambio de información entre ambos. El host “pregunta” al dispositivo sobre su configuración, el cual devuelve entre otros datos estos dos valores los cuales son usados para localizar el driver asociado al mismo y cargarlo en el sistema. En caso de no existir el driver en el sistema, lo pide al usuario de forma que lo guardará para posteriores usos del dispositivo (solo es necesario proporcionar el driver la primera vez que se conecta el dispositivo al ordenador). El VID es un número idealmente único entre empresas que desarrollan hardware bajo USB de forma que cada una de ellas posee un identificador único. El PID identifica al identificador de producto, y cada empresa es libre de utilizar los valores que considere oportunos para ello. En este caso concreto se dejará el VID y PID proporcionados por Microchip. El VID 0x04D8 se corresponde con el de Microchip (obsérvese que se indica primero el byte de menor peso y posteriormente el de mayor peso). 99 Una vez modificados los archivos usb_cdc.h y usb_desc_cdc.h pasará a escribirse el archivo del driver de la parte del PC. Dicho archivo posee la extensión .inf, y será necesario proporcionarlo al sistema la primera vez que se conecte el dispositivo bajo desarrollo. Se modificarán las siguientes líneas: El primer recuadro rojo indica el fabricante. El segundo recuadro es el más importante ya que en él se indica de nuevo el VID y el PID. El VID y el PID deberán ser idénticos tanto en los archivos ya nombrados en la parte del firmware, como en el archivo de extensión .inf de la parte del host. 100 Al final del archivo se pueden modificar las cadenas de texto con el fin de personalizar los mensajes de identificación del dispositivo en el ordenador. A continuación se mostrará el funcionamiento del dispositivo desarrollado. Se trata de un dispositivo muy sencillo pero funcional, que muestra la funcionalidad básica del bus USB en su modo CDC, y crea un puerto serie virtual a través de USB mediante el cual es posible llevar a cabo la conexión mediante Hyperterminal y probar el correcto funcionamiento haciendo uso de la función de “eco” implementada. Para ello conectaremos la alimentación de la placa de los relés (el receptor) con el firmware en este ejemplo descrito grabado en ella. Posteriormente se conectará al puerto USB haciendo uso del puerto habilitado para ello en la placa. Se mostrará el siguiente mensaje en la parte inferior derecha de la pantalla: Obsérvese que el nombre de identificación de dispositivo se corresponde con las cadenas especificadas en el archivo modificado usb_desc_cdc.h. En este momento, el host ha solicitado información al dispositivo y éste le ha respondido, entre otras cosas, con estas cadenas de identificación. Sin embargo a nivel práctico no tienen ninguna utilidad, para la identificación del dispositivo se utiliza, como se dijo anteriormente, la combinación VID-PID. Del mismo modo que se ha pasado la cadena “ECLIPSE TELECONTROL” entre muchos otros parámetros, también se ha recibido el VID-PID configurado en el firmware. En este momento el PC buscará en sus archivos si posee los drivers asociados a dicho binomio VID-PID. Al ser la primera vez que se conecta el dispositivo no se dispondrá del driver con lo cual se mostrará el siguiente mensaje: 101 Haremos click en “No por el momento” y acto seguido en “Instalar desde una lista o ubicación específica”. 102 Se seleccionará el directorio que contiene el archivo .inf del driver y se hará click en “Aceptar”. Se iniciará el proceso de instalación… 103 Y finalmente se mostrará el mensaje de fin del proceso. En este mismo momento el hardware se encontrará instalado y listo para funcionar. Este proceso solo será necesario llevarlo a cabo la primera vez que se conecte el dispositivo. De aquí en adelante y, al no ser que se desinstale intencionadamente el driver, cada vez que se conecte el dispositivo al sistema se cargará el driver de forma automática y transparente para el usuario. Haciendo click en el botón derecho en “Mi PC” y posteriormente en “Administrador de dispositivos” se podrá ver como el dispositivo se encuentra instalado correctamente en el sistema como un puerto serie virtual: 104 Una vez conectado el dispositivo e instalado el driver se procederá a llevar a cabo la prueba de funcionamiento del mismo. Para ello, se abrirá el Hyperterminal y se seleccionará el puerto serie virtual creado. En el administrador de dispositivos, como muestra la captura anterior, es posible observar el número asignado por el sistema. A la hora de configurar el Hyperterminal se tendrán en cuenta para ello los parámetros (baudios, paridad, bits de datos, etc.) especificados durante la modificación de la función usb_cdc_init() en el archivo usb_cdc.h. Una vez abierto el Hyperterminal será posible teclear sobre el, observando como efectivamente se produce el efecto de ECO de los caracteres teclados sobre el mismo. Quedará de este modo probado y demostrado el funcionamiento del bus USB sobre la placa. 105 4.3.- Tramas de datos. La transmisión por radiofrecuencia tiene asociados ciertos problemas inherentes a la misma que hacen tener en cuenta una serie de consideraciones para asegurar la correcta transmisión. Cuando una onda de radio se topa con un obstáculo, parte de la energía que posee es absorbida por el mismo y transformada en otro tipo de energía. El resto de la energía parte de ella puede ser reflejada y la otra parte traspasará el objeto y seguirá propagándose en su trayectoria. Sin embargo ello habrá conllevado la reducción de su potencia, es lo que se conoce como atenuación. La atenuación se da cuando la energía de una señal se reduce en el momento de la transmisión. La atenuación se mide en belios (Símbolo B) y equivale al logaritmo en base 10 de la intensidad de salida de la transmisión, dividida por la intensidad de entrada. Por lo general suelen usarse sin embargo los decibelios (símbolo dB) como unidad de medida, equivaliendo cada decibelio a un décimo de belio. 112 113 En las líneas 35 a 43 se crea el array de bytes destinado a servir de esqueleto durante la construcción de nuevas tramas. Los primeros 6 bytes contienen los bytes de identificación o direccionamiento del receptor, cuya finalidad ya ha sido indicada en apartados anteriores. Los tres bytes posteriores se corresponden con el primer byte de datos (maletero), segundo byte de datos (ruedas) y el checksum de ambos. En las líneas 44 y 45 se declaran dos variables que contendrán el estado de los interruptores en el momento actual y anterior con la finalidad de poder llevar a cabo comparaciones entre ellas y determinar cuando se han producido cambios de estado en las pulsaciones. El código comprendido entre las líneas 54 a 79 supone el bucle principal del programa. Primeramente se comprueba si hay algún interruptor pulsado (línea 57). Posteriormente y en caso afirmativo, se enciende el transmisor y se crea una trama partiendo del esqueleto base previamente definido y el estado actual de los pulsadores recién leído de los puertos del microcontrolador. El bucle do-while comprendido entre las líneas 59 y 63 asegura que la trama se reenvíe de forma continua mientras el estado de los pulsadores se mantenga. Tras ello, el código comprendido entre las líneas 71 y 77 de la función main se ejecuta si no hay ningún pulsador activado. En el caso de que esto suceda, se desactiva el módulo emisor y se procede a una nueva lectura de los interruptores con el fin de poder seguir con el bucle de comprobaciones. Función lee_interruptores(): 114 Esta función obtiene el estado actual de los interruptores conectados al puerto A y puerto B del microcontrolador y coloca el resultado de la lectura en la variable global “interruptores”. Dicha variable global es de tipo “long int”, esto es, de tipo entero de dos bytes de tamaño. El byte de menos peso (LSB, Less Significant Byte) contiene el estado de los pulsadores relativos a la suspensión neumática de las ruedas y el byte más significativo contiene el estado de los pulsadores destinados a controlar el maletero. Para poder acceder a ambos bytes por separado se crea una variable de tipo puntero a byte llamada “acceso_byte” a la cual primeramente se le asigna la dirección de la variable “interruptores”, haciendo posible de este modo la escritura del byte de menos peso de la misma con el estado del puerto B. Se utiliza la operación lógica AND (&) con la máscara 0xF9 para aislar los bits a tener en cuenta de aquellos cuyo valor no tiene ningún significado y por lo tanto no queremos obtener. Posteriormente se incrementa la variable “acceso_byte” y se accede al byte de mayor peso de la variable “interruptores”. En ella se guarda el estado de los interruptores asociados al maletero, se ha utilizado la consulta de estado bit a bit de forma independiente en lugar de proceder de manera análoga a como se ha llevado a cabo con el puerto B debido a que durante las pruebas se observó que la llamada a la función de consulta de estado del puerto A, el prototipo de la cual es “input_a()”, resetea el valor de todos los bits que se encuentran a 1 en dicho puerto. Esto puede ser debido a un modo de funcionamiento interno diferente de este tipo de puerto (el cual posee una naturaleza y una electrónica interna distinta ya que permite ser configurado como analógico o digital), o a un bug del compilador CCS. Una vez leídos los valores de ambos bytes, se devuelve el valor de 16 bits obtenido. Función TX433_on(): Enciende el emisor. En caso de que esté encendido no hace nada y en caso de que esté apagado lo enciende, esperando tras ello 50 ms con el fin de permitir la estabilización de tensiones en el mismo antes de comenzar a enviar las tramas de datos. 115 Función TX433N_off(): Envía la trama compuesta por el array de bytes cuya referencia es pasada como primer parámetro, de longitud “longitud”, pasado como segundo parámetro de tipo entero. Esta función está constituida por un bucle for, que recorre todo el array de datos desde principio a fin enviando por la USART del microcontrolador cada uno de ellos de forma sucesiva uno a uno. 4.4.2.- Receptor Antes de comenzar a analizar el firmware del receptor se explicará conceptualmente el funcionamiento del mismo. El código del aparato receptor es mucho más complejo que el del emisor, y en él entran en juego las interrupciones, los buses i2c, las temporizaciones y el protocolo USB, también presente en el proyecto y mediante el cual es posible la carga dinámica de secuencias preprogramadas. Primeramente es necesario disponer de un mecanismo de recepción y almacenaje. Los datos llegan a través del receptor de radiofrecuencia conectado a la patilla de entrada de la USART. Cada vez que se recibe un byte se genera una interrupción de atención que se encarga de manejar el evento y actuar en consecuencia. El tratamiento del dato en la propia función de interrupción es posible, sin embargo las interrupciones deben ser funciones de código rápidas, ligeras y que supongan una carga computacional ligera. Téngase en cuenta que la ejecución de una interrupción supone romper el flujo natural del programa para pasar a ejecutar el código del manejador asociado, hasta la finalización del cual no se retomará el flujo de ejecución interrumpido. Del mismo modo, durante la ejecución del manejador de interrupción puede llegar una nueva interrupción. En el mundo asíncrono e impredecible de las interrupciones deben tenerse en cuenta todas las posibilidades dentro del abanico de opciones posibles durante la ejecución del programa. Todos estos impedimentos llevan a concluir que debe utilizarse un método de almacenaje temporal de la información, de forma que se delega en una función externa el tratamiento de dicha información recibida, y la interrupción únicamente coloca en dicho almacén los datos recibidos de forma consecutiva según los va recibiendo. Si se incorpora la rutina de tratamiento de datos dentro de la propia interrupción se bloqueará la USART. Hágase la prueba si así se desea. El motivo de ello es que mientras está tratando un carácter recibido recibirá el siguiente, saltará de nuevo la interrupción y se saturarán los registros de recepción (únicamente tiene 2 registros de un byte cada uno). 116 Cuando se saturan los registros, la USART se bloquea completamente. Para evitar eso se hace uso de un buffer circular, o buffer en anillo. El funcionamiento es conceptualmente sencillo. Se dispone de una zona de memoria dedicada, el buffer propiamente dicho, destinada a almacenar información. Existen dos punteros que apuntan respectivamente hacia dos posiciones independientes dentro de este buffer. Uno de ellos está destinado al almacenaje de datos, e indica la posición del siguiente hueco libre en el buffer. El puntero de salida, sin embargo, apunta hacia la dirección del primer elemento extraíble del mismo. Cuando se llega a la última dirección del buffer, se vuelve a comenzar desde la primera. De ahí viene el nombre “buffer circular” o “buffer en anillo”. La naturaleza de este tipo de buffer ofrece una metodología de almacenaje FIFO (First In, First Out), en la cual los elementos se irán extrayendo por orden de llegada. Una variable dedicada guarda el número de elementos actuales en el buffer. Si el buffer está vacío no se efectúa ninguna operación de lectura (o se devuelve un valor nulo, o no válido, depende de la implementación concreta) y si el buffer está lleno se descarta el dato y no se almacena o se devuelve un mensaje de error (nuevamente, depende de la implementación en cuestión). El uso de un buffer intermedio de almacenaje de datos resuelve el problema de recepción y tratamiento de la información, liberando al manejador de interrupción de la elevada carga computacional que ello supone y permitiendo almacenar los datos recibidos para que la función de tratamiento opere con ellos durante el flujo natural de ejecución del programa. En el buffer circular se dispondrá por tanto de los datos recibidos por la USART, es decir por el módulo receptor de radiofrecuencia, en estricto orden de llegada. Existirá, por tanto, una función del programa cuyo objetivo será analizar la secuencia de datos recibidos y reconocer en ella tramas provenientes del receptor. Recuérdese el formato de la trama, ya tratado con anterioridad: 117 Para el reconocimiento de datos se ha llevado a cabo la implementación de una máquina de estados finitos. Primeramente se describirá que es una máquina de estados, para posteriormente y una vez comprendido, entender como se aplica la máquina de estados para el reconocimiento de tramas de datos preestablecidas. Una máquina de estados finitos (FSM = Finite State Machine) se basa en la idea de que hay un número de estados acotado y bien definido dentro de un sistema informático. Reduciéndose al ejemplo más elemental, cuando una aplicación apaga o enciende un LED existen dos estados, un estado es cuando dicho LED está apagado y el otro es cuando está encendido. Las máquinas de estado requieren una variable global de estado, la cual contiene el estado actual en el cual se halla el sistema. La variable de estado puede modificarse dentro de las propias funciones de la máquina de estados o desde funciones externas. Dependiendo del estado, conocido en todo momento, se dirige el flujo del programa hacia unos módulos de ejecución u otros dependiendo de las condiciones concretas de las que ello dependa. Las máquinas de estados tienen una característica muy importante: siempre se encuentran en un estado conocido. Esto es, no existe indeterminación, en caso de incertidumbre o según la situación lo requiera siempre se vuelve a un estado inicial conocido. El primer paso a la hora de implementar un reconocimiento de tramas de datos en base a una máquina de estados es identificar el conjunto de estados que la definen. En este caso concreto se pueden identificar varios estados. El primer de ellos será el estado inicial. Siempre habrá un estado inicial, punto de partida para los demás estados. El segundo estado será aquel en el que se ha leido correctamente el primer byte de la secuencia y éste coincide con el primer byte de identificación de trama. El siguiente estado será aquel en el que se han leido consecutivamente dos bytes correctos de identificación. Así sucesivamente. En el caso de que se rompa el flujo de lecturas correctas, se vuelve al estado inicial. El siguiente gráfico muestra los estados que se pueden identificar en el sistema de reconocimiento, así como las transiciones entre ellos: 118 Los círculos representan los estados. Las flechas las transiciones posibles entre ellos, y la información que acompaña a cada flecha indica la condición para que dicha transición suceada. Estado 1: Estado inicial. Estado por defecto punto de partida para los demás estados. Estado 2: Se llega tras leer el primer byte y cerciorarse de que éste coincide con el primer byte de identificación del dispositivo. Si estando en el estado dos se recibe otro byte y este coincide con el segundo byte de identificación del dispositivo, se pasa al estado 3. En caso contrario, se vuelve al estado 1. Estado 3: De manera análoga al estado dos, se han leido dos bytes consecutivos. Estado 4: Se han leído 3 bytes de identificación correctos. Estado 5: Se han leído 4 bytes de identificación correctos. Estado 6: Se han leído 5 bytes de identificación correctos. Estado 7: Se han leido 6 bytes y los 6 coinciden. Por lo tanto el dispositivo está diseccionado por el emisor. El siguiente byte recibido se guardará como primer byte de datos y se pasará al estado siguiente. 119 Estado 8: Se está esperando el segundo byte de datos. Cuando se reciba se pasará al estado 9. Estado 9: Esperando el último byte de la trama, correspondiente al checksum. Cuando se reciba se hará la suma y se comprobará que no hay errores. En caso de haber errores se descartará la información recibida y en caso de resultar satisfactoria la comprobación se actualizarán las variables globales del sistema pertinentes, reflejando la información recibida. En cualquiera de los casos, luego se pasará al estado 1. La máquina de estados mantiene en todo momento la información recibida en una variable global, que contiene el estado de los interruptores del emisor en todo momento. La máquina de estados actualiza dicha variable en función de los datos recibidos, cada vez que reconoce una trama enviada por el emisor. Esta variable global, que contiene el estado de los pulsadores, está disponible para que otras funciones del programa operen a conveniencia. Existirá pues, otra función que cada vez que es llamada actualiza el estado de los relés. Dicha función se encuentra dentro del bucle principal. El bucle principal también comprueba cíclicamente el estado del conector USB. Si se detecta conexión, se rompe la ejecución del bucle y se entra en modo programación. Todo ello queda delegado en otra función encargada de ello. A continuación pasa a describirse el código fuente del receptor, mediante lo cual se comprenderán ciertos aspectos y se hará mucho más comprensible los conceptos explicados aquí introducidos. Se han extraido las instrucciones al preprocesador, #defines, configuración de pines de dispositivos, etc. en un archivo auxiliar llamado config.h. Se analizará previamente este archivo. 120 Configuración de los fuses del microcontrolador. Debido a que se trata de un cristal de cuarzo de 20 MHz hay que colocar la cadena “HSPLL”, que junto con la cadena “PLL5” configuran el dispositivo para obtener los 48 MHz internos necesarios para hacer uso del USB. La sentencia #use especifica la velocidad del cristal. RX_BUFFER_SIZE define la capacidad en bytes del buffer circular previamente descrito. ID1…ID6 especifican los bytes de identificación del receptor. Obviamente para que el sistema funcione deberán ser los mismos que se especificaron en el mando emisor. MSEGS_SIRENA define el tiempo (en milisegundos) que deberá estar la sierena incorporada en el vehículo sonando antes de proceder a abrir o cerrar el portón del maletero. Esto tiene como finalidad avisar de forma acústica a los espectadores o 121 personas cercanas que se encuentren en las inmediaciones y evitar accidentes con las partes móviles del vehículo. Desde las líneas 40 a 42 se define el pinout del módulo receptor de radiofrecuencia. Las líneas 48 a 50 definen la conexión del timer RTC DS1307, y las líneas 52 y 53 lo relativo a la memoria EEPROM (las líneas i2c son las mismas que las del timer). Se configura la USART del pic a 9600 badios, con un tamaño de palabra de 8 bits y reseteando automáticamente la USART en caso de saturación. Ello se consigue especificando la cadena “ERRORS”. Se configura el bus i2c, que conecta la memoria y el timer con el PIC, según las patillas especificadas anteriormente y se inicializa a 100 KHz (parámetro “show”). Finalmente se indica el pinout (conexiones físicas) del microcontrolador con los relés que manejan los actuadores del vehículo. Una vez se ha descrito el archivo config.h pasará a analizarse el archivo principal del firmware del receptor propiamente dicho: 128 se aplica al caso de inversión, en el cual en lugar de subir los actuadores invierten su acción (INV=1). Se trata el caso de cada rueda por separado y los casos de INV=0 e INV=1 de forma aislada. Posteriormente se procede del mismo modo con los actuadores del maletero, aplicando las máscaras adecuadas con la operación AND (&) y actuando en consecuencia. Con la finalidad de evitar sobrecargar al procesador se ha añadido al sistema una variable “novedades”. Cada vez que la máquina de estados cambia el valor de la variable “interruptores” pone “novedades” a TRUE, con lo cual se entra en la función y se actualizan todos los relés. En caso de no haber novedades es innecesario perder ciclos de reloj en reescribir constantemente el estado de todos los relés con el mismo valor. La función mostrada en la siguiente página se corresponde con la máquina de estados reconocedora de tramas. Cada vez que se inicia su ejecución inicia un bucle en el cual recorre todos los elementos del buffer circular. Extrae del buffer cada elemento de forma secuencial, uno a uno. Comprueba cada dato extraído actualizando el estado en función del mismo. E caso de reconocer la trama de identificación, guarda los dos bytes consecutivos (bytes de datos) y en el último estado los suma y comprueba con el checksum recibido como último byte de la trama. En caso de éxito, si el estado de los interruptores recibido no presenta diferencias con el actual no hace nada (significa que se está manteniendo el pulsador). En caso de cambio de estado, actualiza la variable global “pulsadores” con el estado de los pulsadores, obtenidos de dato_D1 y dato_D2, y coloca a TRUE la variable “novedades”. 129 130 Inicializa la máquina de estados. Coloca la máquina en el estado inicial y establece a 0 el estado de los pulsadores (ningún interruptor pulsado en el emisor hasta que se de muestre lo contrario al recibir alguna trama indicadora de ello). Esta función añade un elemento de tipo entero de ocho bits sin signo (byte) al buffer circular. Para ello primeramente comprueba si hay sitio. En caso negativo el dato se descarta (se pierde). En caso de que haya sitio disponible, se introduce en la primera posición del buffer libre, apuntada por rx_in_pos, y se aumenta en una unidad dicho apuntador. Para ello se lleva a cabo la operación módulo (%) con el tamaño del buffer. De este modo se consigue volver al inicio una vez pasada la última posición del array. Posteriormente, se incrementa la variable indicadora del número de elementos y finaliza la función. Función complementaria a la anterior, extrae un elemento del buffer. Primeramente comprueba la disponibilidad de información, en caso de que no haya información disponible devuelve cero (hay que elegir un valor concreto que no tenga repercusión en el proceso que extrae los datos). Posteriormente se extra el dato del buffer, se actualiza el apuntador de lectura y se decrementa el número de elementos. 131 Devuelve 1 si el buffer está vacío, 0 en caso contrario. Inicializa el buffer. Establece el número de elementos a 0 y inicializa los apuntadores a la primera posición del array. Eleva la suspensión de la rueda delantera izquierda. Para ello desactiva la electroválvula que acciona la bajada del coche y activa la que hace subir la suspensión. Desciende la suspensión de la rueda delantera izquierda, de forma análoga a la función anterior. 132 Mantiene la posición de la rueda delantera izquierda. Para ello desactiva la electroválvula de subida y también la de bajada de la rueda. Estas funciones llevan a cabo las mismas operaciones, pero sobre la rueda delantera derecha. 133 Controles de la rueda trasera izquierda. Controles de la rueda trasera derecha. Encendido y apagado de los neones, respectivamente. 134 Control del movimiento de las etapas. Control del movimiento vertical de la plataforma de los altavoces. Apertura del portón del maletero. Primeramente activa la sirena durante el tiempo definido por MSEG_SIRENA (definido en el archivo config.h). Acto seguido acciona la apertura de la cerradura servocontrolada mientras la sirena aún está sonando, tras lo cual posteriormente abre el portón. 135 Cierra el portón del maletero. Primeramente activa la señal acústica de aviso durante el tiempo definido por MSEGS_SIRENA, para posteriormente comenzar el descenso del portón y cortar la sirena tres segundos después. Lleva a cabo la reproducción automática de la secuencia preprogramada a través del ordenador. Para ello se define una variable a la que primeramente se le asigna la dirección de inicio (definida en config.h). Se inicializa la memoria 24LC1025 y se entra en un bucle de ejecución de instrucciones. Dentro del bucle, como primer paso, se lee una orden, formada por 4 bytes, a partir de la dirección especificada. Posteriormente se comprueba el checksum de la orden y si éste no es válido se pone a TRUE la variable “fin”, con lo cual se sale del bucle y la reproducción se da por terminada. En caso de que el checksum sea correcto se comprueba si la orden indica un bucle. En caso afirmativo se reinicia la dirección de lectura con la dirección inicial, y se espera a la siguiente pasada del bucle. Como tercer caso se tiene una ejecución de instrucción normal. En este caso, se ejecuta la instrucción mediante la función “ejecuta_orden_secuencia()” y posteriormente se incrementa la dirección en 4 de forma que en la siguiente pasada del bucle se leerán los próximos 4 bytes al llamar a la función “lee_orden()”, ya que cada instrucción está compuesta por 4 bytes. El valor booleano que devuelve la función “ejecuta_orden_secuencia()” indica el motivo de la salida de la función. Si es FALSE significa final de ejecución de la instrucción. En caso de ser TRUE indica la pulsación del botón del emisor que indica la interrupción del proceso de reproducción, con lo cual la siguiente pasada saldrá del bucle y la reproducción de la secuencia se dará por concluida. 136 La función de lectura de órden de la memoria está implementada del siguiente modo: Lee los cuatro bytes de la memoria EEPROM. Las órdenes se almacenan como un conjunto consecutivo de 4 bytes. Esta instrucción lee las 4 posiciones consecutivas a partir de la dirección especificada como parámetro. La implementación de la función de comprobación de checksum se muestra a continuación. El motivo de la existencia de esta función es la comprobación de integridad de la orden. En la propia orden se encuentra implícito un valor de checksum el cual debe coincidir con el valor calculado. En caso negativo se toma la orden como errónea y se detendrá la ejecución del programa. Como se verá más adelante, la órden de fin de secuencia se aprovecha de esta propiedad introduciendo una orden vacía con un checksum inválido de forma que de esta manera se fuerza la detención de la ejecución. Se trata de un checksum de siete bits, el cual se almacena en los siete bits de menos peso del byte más significativo de la orden. Primeramente se calcula el checksum de los tres bytes inferiores que la componen. En caso de que el bit de mayor peso del byte más significativo sea uno, se sumará una unidad al checksum calculado. Esto es debido a que este bit es parte de la información codificada en la orden y no del checksum (el cual, como se ha dicho, solo ocupa los siete bits de menos peso). Acto seguido se aisla el checksum codificado en la propia orden a través de la máscara de bits y la operación lógica AND (linea 500) y se comprueba si coinciden. En caso afirmativo la orden es correcta y en caso negativo se asume un error de integridad, dando la orden por descartada. La siguiente función comprueba si una orden dada representa un bucle en la secuencia: 137 Para ello se aisla el bit de mayor peso del segundo byte de los cuatro que componen la orden. En caso de estar activado este bit la orden indica un cierre de bucle de la secuencia, en caso negativo se trata de una orden más de la lista. 5.- Eclipse Telecontrol. Grabación de secuencias. Con la finalidad de hacer posible la grabación de secuencias en el receptor, posteriormente reproducibles desde el mando emisor con tan solo pulsar una combinación preestablecida de teclas, se ha desarrollado un programa de ordenador en C# bajo Windows. Dicho programa responde al nombre de “Eclipse Telecontrol” y tiene el siguiente aspecto: El software desarrollado ofrece toda la funcionalidad necesaria para crear secuencias de órdenes en las cuales es posible controlar todos los actuadores del vehículo. Permite controlar la suspensión neumática de cada rueda haciendo posible