INSTITUTO TECNOLOGICO Y DE ESTUDIOS SUPERIORES DE MONTERREY CAMPUS TOLUCA ESTUDIO SOBRE LOS SISTEMAS DE ADQUISICIÓN DE DATOS PARA ESTACIONES DE MONITOREO REMOTO TESIS QUE PARA OBTENER EL GRADO DE: MAESTRIA EN CIENCIAS CON ESPECIALIDAD EN INGENIERIA ELECTRÓNICA (SISTEMAS ELECTRÓNICOS) PRESENTA: MIGUELANGEL FRAGA AGUILAR DIRECTOR DE TESIS: DR. LUCIANO CHIRINOS GAMBOA TOLUCA, EDO. DE MEXICO, MAYO DE 2006 ESTUDIO SOBRE LOS SISTEMAS DE ADQUISICIÓN DE DATOS PARA ESTACIONES DE MONITOREO REMOTO Examen de Grado Presentado por: Miguelangel Fraga Aguilar Fecha: 10 de mayo de 2006 _____________________________ Dr. José Armando Herrera Corral Presidente del Jurado Examinador ____________________________ Dr. Luciano Chirinos Gamboa Sinodal 1 ____________________________ Dr. Cesar A. Zamilpa Quiroz Sinodal 2 Veredicto: Aprobado por Unanimidad TOLUCA, EDO. DE MEXICO, MAYO DE 2006 Contenido Contenido.................................................................................................................................................... i Abstracto................................................................................................................................................... iii 1- Introducción........................................................................................................................................... 1 1.1- Antecedentes................................................................................................................................... 1 1.2- Planteamiento del problema............................................................................................................2 1.3- Justificación.................................................................................................................................... 3 1.4- Objetivos......................................................................................................................................... 3 1.5 Logros del proyecto......................................................................................................................... 4 2- Marco teórico......................................................................................................................................... 5 2.1 Introducción..................................................................................................................................... 5 2.2- Conversores analógico digital y acondicionamiento de señal........................................................ 5 2.2.1- Acondicionamiento de señal.................................................................................................... 5 2.2.1.1- Escalamiento .................................................................................................................... 5 2.2.1.2- Filtrado.............................................................................................................................. 6 2.2.2- Convertidores Analógico Digital............................................................................................. 7 2.2.2.1- Convertidor tipo aproximaciones sucesivas..................................................................... 7 2.2.2.2- Convertidor tipo Ráfaga y media Ráfaga......................................................................... 7 2.2.2.3- Convertidor por doble integración.................................................................................... 8 2.3 Técnicas para la programación de microcontroladores.................................................................... 9 2.3.1- Técnica del ciclo de por pasos (Paced Loop) ......................................................................... 9 3- Método................................................................................................................................................. 11 3.1- Introducción.................................................................................................................................. 11 3.2- Diseño del sistema........................................................................................................................ 11 3.2.1- Especificaciones de la estación meteorológica...................................................................... 11 3.2.2- Selección de los componentes............................................................................................... 12 3.2.3- Diagrama a bloques............................................................................................................... 13 3.2.4- Diagrama de flujo de la operación del sistema...................................................................... 14 3.3- Descripción del circuito ............................................................................................................... 16 3.3.1- Subsistema de alimentación................................................................................................... 16 3.3.2- Subsistema de acondicionamiento de señal........................................................................... 16 3.3.3- Medición de la temperatura interna....................................................................................... 18 3.3.4- Comunicación RS232............................................................................................................ 19 3.3.5- Conexiones del microcontrolador.......................................................................................... 20 3.4- Descripción del programa del sistema......................................................................................... 21 3.4.1- Programa de prueba............................................................................................................... 21 3.4.1.1- Subrutina principal.......................................................................................................... 21 3.4.2- Programa completo de aplicación ......................................................................................... 24 3.4.2.1- Subrutina principal.......................................................................................................... 24 3.4.2.2- Rutina de ajuste de la frecuencia del DCO..................................................................... 24 3.4.2.3- Rutina de Medición......................................................................................................... 25 3.4.2.4- Rutina de escritura a la memoria FLASH....................................................................... 26 3.4.2.5- Rutinas de la interfaz con el usuario .............................................................................. 27 3.4.2.6- Rutinas de transmisión de datos..................................................................................... 28 3.4.2.7- Rutinas para el manejo del puerto serie.......................................................................... 28 3.4.2.8- Rutinas para escribir en la pantalla LCD........................................................................ 28 3.5- Descripción del programa de recepción de datos......................................................................... 29 i 4- Resultados, conclusiones y trabajo futuro........................................................................................... 32 4.1 Introducción................................................................................................................................... 32 4.2- Resultados del programa de prueba.............................................................................................. 32 4.3- Resultados de la prueba a la intemperie. .............................................................................34 4.4- Conclusiones................................................................................................................................. 48 4.5- Trabajo Futuro.............................................................................................................................. 49 Bibliografía.............................................................................................................................................. 50 Índice de figuras....................................................................................................................................... 52 Índice de tablas......................................................................................................................................... 53 Apéndice A - Diagrama Eléctrico de la estación meteorológica............................................................. 54 Apéndice B – Circuito impreso de la estación meteorológica................................................................. 55 .................................................................................................................................................................. 56 Apéndice C – Listado del programa de la estación meteorológica.......................................................... 57 Modulo principal5.c............................................................................................................................. 57 Modulo interfaz2.c............................................................................................................................... 65 Modulo transmite.c.............................................................................................................................. 74 Modulo lcdadn2.c................................................................................................................................. 77 Modulo serie2.c.................................................................................................................................... 79 Modulo prueba6.c................................................................................................................................ 81 Modulo serie.h..................................................................................................................................... 87 Modulo lcdand.h.................................................................................................................................. 87 Modulo interfaz.h................................................................................................................................. 88 Modulo serialport.form........................................................................................................................ 88 Modulo serialport.class........................................................................................................................ 90 ii Abstracto Se presenta el proceso de diseño y desarrollo de una estación meteorológica de bajo costo para uso en investigación agrícola. La estación es capaz de monitorear cinco variables a diferentes velocidades de muestreo, almacenarlas y posteriormente transmitirlas por módem a las oficinas de los investigadores en agricultura. Esta diseñada para reducir el consumo de energía y permitir que sea alimentada a partir de un banco de baterías recargables y paneles solares. Se incluye un programa para la recepción de los datos capturados en una computadora personal. Abstract The design and development process of a meteorological station for use on agriculture research is presented. The station is able to log five variables at different sampling rates and to transmit the logged data to the researcher’s office later. It has been designed to reduce power consumption and allow it to be powered by rechargeable batteries and a solar panel. A personal computer program to receive the logged data is also included. iii 1- Introducción 1.1- Antecedentes Contar con información completa y confiable es indispensable para poder tomar decisiones o para realizar una investigación seria. Por esta razón, en las diferentes actividades humanas surge con frecuencia la necesidad de recopilar grandes cantidades de datos. Cuando dicha recopilación debe efectuarse en lugares remotos y durante largos periodos de tiempo, este proceso resulta muy costoso y complicado. Con el objeto de reducir costos y aumentar la confiabilidad de la recopilación, es frecuente utilizar sistemas automáticos, los cuales tienen que operar en condiciones muy diferentes los sistemas de monitoreo convencionales. Por el hecho de operar en lugares apartados, no siempre esta disponible la infraestructura necesaria para proporcionar un suministro de energía eléctrica constante al sistema. También, puede resultar difícil que el investigador visite con frecuencia al sistema para recoger los datos obtenidos. Así, el sistema debe ser capaz de almacenar grandes conjuntos de datos y de ser posible, comunicarlos a un centro de recopilación. Dos ejemplos en donde la adquisición de datos remota surge como una necesidad se dan en la sismología y la climatología. Para poder determinar correctamente las características de sismo o investigar el riesgo que presenta una falla geológica se deben colocar varios sismógrafos en puntos muy separados uno del otro. Los mejores lugares están fuera de las zonas urbanas, ya que las vibraciones producidas por los automóviles y la maquinaria pesada afectan las mediciones de los sismógrafos más sensibles. En climatología se requiere colocar estaciones climatológicas en todo tipo de lugares, por ejemplo, en la cima de las montañas para predecir el riesgo de avalanchas o en las llanuras desérticas para monitorear la formación de tornados. Los datos obtenidos por estas estaciones son reunidos para formar un mapa con la distribución de las diversas variables climáticas en el área geográfica de interés, el cual se utiliza para que los especialistas elaboren sus pronósticos. También en zonas de cultivo con superficie extensa, él poder conocer el microclima local permite a los agrónomos sugerir el mejor tipo de cultivo para la región y también indicar cuando es el mejor momento para irrigar o aplicar un pesticida sin que las lluvias lo dispersen y reduzcan su efectividad. 1 1.2- Planteamiento del problema México, es un país que se encuentra en el cinturón de fuego, una zona sísmica muy activa. También cuenta con un amplio territorio y una gran diversidad de climas. Por lo anterior, la investigación en sismología y meteorología son claves para prevenir desastres y para lograr un desarrollo óptimo de la agricultura del país. Sin embargo, en México no se fabrican equipos que sean útiles para la recolección automatizada de datos, tales como sismógrafos y estaciones meteorológicas. Esto limita la capacidad de los investigadores de obtener información de campo de manera continua y amplia, también aumenta la dependencia tecnológica. Desarrollar la capacidad de diseñar y construir equipos para el registro automático de variables ambientales a un bajo costo permitiría que se usaran más ampliamente y que la información obtenida sirviera para que se tomaran decisiones más informadas y acertadas. En particular, la Fundación PRODUCE de Michoacán, una asociación de productores agrícolas del valle de Apatzingan, se encuentra en el proceso de desarrollar técnicas de cultivo que utilizan información del microclima local para se apliquen a los cultivos menores cantidades de pesticidas y fertilizantes, evitando el desperdicio y determinando el momento en que su aplicación va a tener un mejor efecto. De llegarse a aplicar estas técnicas de forma masiva en todo el valle de Apatzingan, estas tendrían un gran impacto ecológico, económico y social, al ayudar a los a obtener mejores cosechas con menos agroquímicos. Sin embargo, para que estas técnicas puedan aplicarse masivamente en la producción es necesario contar con estaciones meteorológicas de bajo costo que puedan distribuirse entre los productores y que les permitan obtener la información del microclima local como para que los expertos en agricultura (o un sistema experto ejecutándose en la computadora que recopila la información meteorológica y entrenado para dicho propósito) pueda decirles en que momento es conveniente aplicar los agroquímicos y en que cantidades. Por esta razón, la fundación se puso en contacto con el autor de este documento y solicito que cooperáramos en el desarrollo de una estación meteorológica que fuera apta para este fin. El primer paso en este proceso es la construcción de un primer prototipo que pueda usado por los investigadores de la fundación para mejorar y validar las técnicas de cultivo propuestas. Con base en este prototipo se desarrollara una versión mejorada que se probaría en un programa piloto con un grupo selecto de productores para comprobar que cumple con sus necesidades y en caso de ser necesario mejorar algún aspecto del funcionamiento de la estación, considerarlo en el diseño del prototipo final que se pudiera distribuir entre los productores. 2 1.3- Justificación El poder diseñar equipo de adquisición de datos en el país, permitirá, entre otras ventajas, ahorrar en gastos de importación, reducir el precio final al usuario del equipo y ampliar su utilización, así como contar con equipo adaptado especialmente a las necesidades de los investigadores y productores nacionales. De llegar a desarrollarse un equipo adecuado para su uso en la producción agrícola, tendría un gran impacto social y económico al aumentar la productividad de los campesinos. El amplio desarrollo de la tecnología de microprocesadores y microcontroladores, donde ha habido grandes avances en capacidad de memoria, integración de periféricos y disminución en el consumo de energía, permite el diseño de equipos más económicos y con un menor número de partes de lo que era posible en el pasado. En el mercado internacional existen varios modelos de estaciones capaces de realizar este trabajo, pero miden una cantidad de variables mayor a la necesaria para poder aplicar las técnicas que consideran el microclima local y por lo tanto su costo es más elevado. Ejemplos de estaciones comerciales son la Lacrosse 2510 y la Davis Vantage Pro2. Ambas miden las variables medidas por la estación presentada en este trabajo y además incluyen un barómetro, un pluviómetro, y enlace por RF con rango máximo entre 60 y 120m. La estación Lacrosse 2510 tiene un costo de $699USD y la Davis Vantage Pro2 cuesta $599 USD, pero requiere de accesorios adicionales con un costo total de $176 USD extras para poder transmitir los datos a una PC. Con esto el precio de ambas estaciones seria muy superior al de las partes del prototipo descrito en el presente trabajo. 1.4- Objetivos • Desarrollar Un sistema electrónico de monitoreo para una estación meteorológica que cumpla con los requerimientos de investigadores en agricultura del estado de Michoacán. • Que la estación desarrollada cuente con la capacidad de almacenar los valores capturados por un periodo largo de tiempo y de comunicarlos a los investigadores. • Que sea de bajo costo para que pueda ser la base para una versión mejorada que pueda distribuirse entre los productores y que les permita tomar decisiones sobre sus cultivos de forma más informada y objetiva. • Documentar el proceso de diseño de la estación para que pueda servir como un ejemplo y una guía introductoria de cómo desarrollar equipos de monitoreo remoto similares a esta. 3 1.5 Logros del proyecto Se culmino el desarrollo de un primer prototipo de la estación meteorológica que pude comenzar a utilizarse en laboratorios de investigación en agronomía. Se valido el correcto funcionamiento de la estación tanto en la medición de las variables como en el almacenamiento y transmisión. El prototipo fue evaluado por los investigadores en agricultura de la fundación PRODUCE de Michoacán y en su opinión el prototipo puede usarse para la investigación de nuevas técnicas de riego y fumigado para las cuales es indispensable contar con información muy detallada sobre el microclima local. Además este prototipo tiene el potencial de ser la base para el desarrollo de una versión con una interfaz de usuario simplificada, comunicación vía RF y menor costo que pueda utilizarse para que los productores apliquen estas técnicas en sus cultivos. 4 2- Marco teórico 2.1 Introducción En este capitulo se presentan una breve descripción los conocimientos teóricos utilizados para el desarrollo de la estación meteorológica. 2.2- Conversores analógico digital y acondicionamiento de señal 2.2.1- Acondicionamiento de señal 2.2.1.1- Escalamiento Una de las tareas más frecuentes en el proceso de acondicionamiento de señal es el escalado de la señal de un sensor que entrega una salida en voltaje. El escalamiento consiste en llevar la señal del rango de voltaje entregado por el sensor al rango de voltaje que requiere la entrada del convertidor analógico digital. Este proceso normalmente se realiza por medio de algún amplificador sumador. La función de mapeo de un rango de voltaje a otro usualmente es una línea recta, de la forma Vo = m * Vi + b. El parámetro m correspondería con la ganancia del amplificador y el parámetro b con un voltaje de desplazamiento o polarización que el amplificador suma al voltaje de entrada. La configuración del amplificador dependerá de varios factores, principalmente de si el voltaje de entrada es unipolar o diferencial de si se dispone de fuentes de alimentación simétrica. Cuando la entrada sea unipolar se usara un simple amplificador sumador no inversor como el mostrado en al figura 2.1. Si es diferencial deberá usarse un amplificador sumador diferencial como el mostrado en la figura 2.2 Figura 2.1 Amplificador sumador no inversor Figura 2.2 Amplificador sumador con entrada diferencial 5 El diseño de cualquiera de estos dos amplificadores puede lograrse de una manera relativamente simple, logrando cualquier combinación de ganancia y desplazamiento de voltaje. Definamos Ra=R1|| R2, Rb=R3||R4||R5. Entonces las ganancias para las diferentes entradas serán: K(vin-)=-R2/R1 K(vin+)=(Rb/Ra)(R2/R4) K(voff)=(Rb/Ra)(R2/R5) La diferencia principal entre los dos amplificadores seria que el voltaje de entrada Vin- es cero en el amplificador sumador. Pueden usarse las resistencias R1, R2, R4 y R5 para establecer la ganancia y el voltaje de desplazamiento. Después puede usarse R3 para hacer que Ra = Rb y que las ganancias positivas coincidan con las deseadas al ser Ra/Rb=1. Cuando sea necesario alimentar al amplificador operacional con una sola fuente, como ocurre normalmente cuando se alimenta con baterías, se debe tener mucho cuidado de que el voltaje de salida nunca salga del rango que puede entregar el amplificador. Por ejemplo, si se alimenta al amplificador con una fuente de 5V, Se debe cuidar que el voltaje de salida siempre sea positivo y que no exceda los 5 V. Además se deben usar amplificadores de diseñados para trabajar con este tipo de alimentación, que entre otras características pueden entregar voltajes de salida muy cercanos al de alimentación y una razón de rechazo de modo común muy alta. Un ejemplo de este tipo de amplificador es el TLV2474 de TI. Al momento de diseñar el amplificador, también debe considerarse la impedancia de salida del sensor, ya que la impedancia de entrada del amplificador debe ser mayor que la del sensor para evitar que el efecto de carga degrade la medición. En caso de que se tenga un sensor con muy alta impedancia de salida, lo mas conveniente es colocar un seguidor de voltaje (o dos si la salida es diferencial) antes del amplificador sumador. Si la magnitud del la ganancia que se requiere es mayor que diez, puede ser conveniente incluir un amplificador de instrumentación como etapa de entrada para proporcionar una buena ganancia a la señal de entrada antes de sumar el voltaje de desplazamiento que se requiera. 2.2.1.2- Filtrado El criterio más importante para determinar que tipo de filtrado debe realizarse a una señal es conocer sus características, en particular el ancho de banda de la señal que desea muestrearse. Por el teorema del muestreo, sabemos que debemos muestrear una señal a por lo menos una frecuencia del doble del componente de frecuencia más alta de la señal o se perderá información en la conversión. Esta frecuencia es conocida como la frecuencia de Nyquist. También es necesario asegurarse de que no lleguen al convertidor analógico a digital componentes de frecuencia más alta que la máxima deseada y para esto es común colocar un filtro pasa bajos entre la fuente de señal y el convertidor AD. Este filtro puede ser desde un simple filtro RC pasivo de primer orden hasta filtros activos de orden superior. Para frecuencias bajas y ambientes sin mucho ruido un filtro RC es suficiente. Sin embargo, en la mayoría de los casos la mejor opción es un filtro activo de segundo orden o superior. La configuración Sallen-Key es particularmente útil. Esta configuración y otras son explicadas detalladamente en (Mallik1996), (Rashid 2000) y (Wait 1992). 6 Una alternativa a un filtro activo de orden alto, expuesta en (Oppenheim 2000), es muestrear a una frecuencia más alta que la de Nyquist, aplicar un filtro de orden alto digital y después diezmar las muestras para reducir la frecuencia de muestreo al valor deseado. 2.2.2- Convertidores Analógico Digital Los convertidores de analógico a digital (ADC) son dispositivos fundamentales para el funcionamiento de cualquier sistema de medición, ya que se encargan de convertir la magnitud de una variable analógica a una representación numérica que puede ser usada por el controlador del sistema de medición. De su buen funcionamiento depende la exactitud y precisión de la medición. Los parámetros más importantes a tomar en cuenta al seleccionar un ADC son: el rango a plena escala (FSR), es el conjunto de valores de la variable de entrada que puede aceptar; la resolución, es decir, la más pequeña diferencia entre dos valores de entrada que puede distinguir y que normalmente se relaciona con el número de bits del convertidor (n) por FSR/(2^n-1); el formato de la salida; la velocidad de conversión y finalmente el precio. Es muy común que los microcontroladores modernos incluyan un convertidor analógico digital como parte de sus periféricos internos, que debe ser suficiente para muchas aplicaciones. Sin embargo, estos convertidores suelen estar limitados particularmente en resolución (8 o 10 bits) y velocidad de conversión (máximo en aproximadamente 200,000 muestras por segundo) para las aplicaciones más demandantes, por lo que debe considerarse conectar un convertidor externo de más alto precio y desempeño al microcontrolador, o buscar otro microcontrolador que tenga un convertidor de mejores características. Conocer los tipos más comunes de convertidores y que se puede esperar de ellos será de mucha ayuda al momento de hacer la selección. 2.2.2.1- Convertidor tipo aproximaciones sucesivas Este tipo de topología es muy usada debido a que presenta varias ventajas: un tiempo de conversión fijo a un precio razonable. Es el tipo más comúnmente usado para los convertidores internos de los microcontroladores. El diagrama a bloques de este tipo de convertidores de muestra a continuación. Figura 2.3 Convertidor AD de aproximaciones sucesivas El bloque marcado como DAC es un convertidor de digital a analógico que transforma la salida digital en un valor analógico que se compara con la variable de entrada. La unidad de control y el registro de aproximaciones sucesivas (SAR) usan el resultado de esta comparación para determinar el valor de un BIT de la salida por ciclo de reloj. 2.2.2.2- Convertidor tipo Ráfaga y media Ráfaga 7 El objetivo del convertidor tipo ráfaga o flash es obtener el resultado de la conversión lo más rápidamente posible. Por esta razón, emplea un gran número de comparadores que comparan el voltaje de entrada con un voltaje de referencia generado por un divisor de tensión. Cada una de estos voltajes corresponde con el valor de entrada que produciría una salida diferente. La salida de los comparadores se codifica por medio de un circuito combinacional, por lo que ni siquiera es necesaria una señal de reloj para la operación de este convertidor. El tiempo de conversión es determinado únicamente por el tiempo de respuesta de los comparadores y el tiempo de retardo del codificador. Figura 2.4 Convertidor AD tipo ráfaga o flash de tres bits El principal problema de este tipo de convertidor es que la cantidad de comparadores que se necesitan crece exponencialmente con el número de bits del convertidor, lo que hace que el precio se dispare. Por esta razón su uso se limita a aplicaciones como la digitalización de video e instrumentos de medición de alta frecuencia donde el costo de estos convertidores se justifica. 2.2.2.3- Convertidor por doble integración Los convertidores de doble integración son muy económicos debido a que no requieren de más componentes complicados que un integrador, un comparador y un voltaje de referencia. Es el tipo de convertidor más comúnmente usado en los multimetros digitales debido a su bajo precio y buena resolución, precisión y exactitud. En algunos microcontroladores de bajo costo se incluyen la referencia de voltaje y el comparador para poder crear un convertidor de este tipo usando un integrador externo y simulando la unidad de control y el contador por software. 8 Figura 2.5 Convertidor AD de doble integración Al iniciar el proceso de conversión, el contador se pone a cero y se comienza a cargar al condensador del integrador con el voltaje de entrada, hasta que el contador alcanza su cuenta máxima. Posteriormente se descarga al condensador aplicando un voltaje de referencia negativo mayor que el voltaje de entrada. El tiempo que tarde en descargarse será proporcional a la relación entre el voltaje de entrada y el de referencia, por lo que el valor del contador en el momento determinarse la descarga será proporcional al voltaje de entrada. La principal limitante de estos convertidores es que son muy lentos, teniendo tiempos de conversión de cientos de milisegundos a varios segundos. La ventaja es que es relativamente simple incrementar la resolución del convertidor aumentando el tamaño del contador, en especial en implementaciones por software. 2.3 Técnicas para la programación de microcontroladores. 2.3.1- Técnica del ciclo de por pasos (Paced Loop) En sistemas basados microcontroladores pequeños cuentan con muy pocos recursos para la implementación de las aplicaciones, sin embargo, la mayoría de las aplicaciones requiere la realización de múltiples tareas de forma simultánea. Utilizar un sistema operativo multitarea completo es una opción que no siempre es factible, debido a que el CPU no cuenta con los recursos necesarios para su ejecución. La alternativa para aplicaciones simples es utilizar una técnica que permite simular el funcionamiento de multitareas. Existen varias técnicas para lograr esto, una de las más comúnmente usadas es el ciclo por pasos. La estructura principal del programa (Figura 2.6) consiste en una etapa de inicialización y un ciclo principal infinito. El ciclo principal es infinito debido a que el programa de aplicación no puede terminar por que no existe un sistema operativo que tome el control del procesador, además de que la naturaleza misma de las aplicaciones requieren que el programa continué ejecutándose mientras el sistema este energizado. 9 Inicialización Ciclo Principal Figura 2.6 Estructura principal del programa El ciclo principal usualmente comienza esperando a que se presente un evento del temporizador que asegure que cada pasada por el ciclo se ejecute después de un intervalo de tiempo predefinido. Lo anterior simplifica la implementación de retardos con solamente contar el número de pasadas por el ciclo principal. También es común que al terminar una pasada por el ciclo el procesador entre en un estado de ahorro de energía del que saldrá al presentarse el evento del temporizador. En medio del ciclo, se llama a una serie de funciones o subrutinas, cada una de las cuales implementa una función tarea en particular. Las funciones de tarea deben estar diseñadas para hacer una pequeña parte de la tarea y regresar en una fracción del intervalo de tiempo entre una pasada y la siguiente. Por esta razón, cada función debe encargarse de conservar en variables globales o estáticas toda la información relacionada con el estado de la tarea. Una manera muy conveniente de realizar esto es dividiendo la tarea en varas etapas y almacenar el número de etapa en una variable. Al entrar en la función se revisa el número de etapa por medio de una estructura switch-case y se realizan las acciones correspondientes a dicha etapa. Para pasar a la siguiente etapa y que las acciones correspondientes se ejecuten en la siguiente llamada a la función de tarea, lo único que debe hacerse es incrementar el contenido de la variable donde se almacena el número de etapa. En muchos casos se debe esperar a que se cumpla alguna condición o se espera a que se presente algún evento antes de pasar a la siguiente etapa. En estos casos solo se revisa la condición y si se cumple se incrementa la variable. De esta manera, el formato general de una función de tarea queda como se muestra en el siguiente listado: void tarea(void) { Static int etapa=0; switch etapa { case 0: acciones etapa 0; if (condición etapa 0) etapa++; ... case N: acciones etapa N; if (condición etapa 0) etapa=0; } } Esta técnica es utilizada para realizar las tareas de medición, transmisión e interfaz de usuario de forma simultánea en la estación. 10 3- Método 3.1- Introducción En esta sección se describe el desarrollo de una estación meteorológica para uso agrícola con el objeto de que sirva como ejemplo del proceso de diseño de un sistema de adquisición de datos remoto. 3.2- Diseño del sistema. 3.2.1- Especificaciones de la estación meteorológica El primer paso en el proceso de diseño de cualquier equipo es el establecer un conjunto de especificaciones que deben cumplirse. Estas deben establecerse con la ayuda de un especialista en el área en que se va utilizar el instrumento con el fin de asegurarse de que realmente sea útil. En este caso se consulto al Ing. Francisco Javier Maldonado Arceo de la Fundación Produce de Michoacán. Se determinó que el conjunto de variables mostrado en la tabla siguiente seria suficiente para la toma de decisiones en agricultura. Variable a medir Frecuencia Rango Temperatura interna Una muestra cada 10 min. o cada hora -50°C a 100°C Temperatura externa Una muestra cada 10 min. o cada hora -50°C a 100°C Humedad relativa Una muestra cada 10 min. o cada hora 0 a 100% Velocidad del viento Una muestra cada 10 min. o cada hora 0 a 300 Km/Hr Dirección del viento Una muestra cada 10 min. o cada hora 0 a 360° Tabla 3.1 Variables a medir por la estación meteorológica La frecuencia de muestreo de una muestra por hora es suficiente en las aplicaciones relacionadas con la producción, pero en algunas aplicaciones de investigación se requeriría una frecuencia de muestreo más alta, aunque no de más de una medición cada 10 minutos. La frecuencia de muestreo más baja tiene la ventaja de que permite que la misma cantidad de memoria almacene los datos correspondientes a un periodo de tiempo más grande. Se decidió ofrecer al usuario final la opción de escoger entre estas dos frecuencias de muestreo en un menú de configuración, para hacer a la estación más versátil. Dado el rango de las variables a medir, se determino que un tamaño de palabra de 16 bits basta para almacenar una muestra de cada una de las cinco variables, así como la hora en que se tomo compactada, lo que da un total de 12 bytes por muestra. Se desea que la estación sea capaz de almacenar los datos capturados durante 30 días. Una vez que se conoce la frecuencia de muestreo, el tamaño de cada muestra y por cuanto tiempo deben almacenarse, se puede especificar cuanta memoria será requerida en el sistema. Memoria requerida = 12 bytes/muestra*6 muestras/hora*24*30Horas=51, 840 Bytes Esta cantidad de memoria esta disponible internamente en la muchos microcontroladores modernos. 11 Además, como la frecuencia de muestreo es muy baja, el tiempo que toma escribir a la memoria Flash (que es relativamente lenta comparada con otros tipos de memorias), no representa un problema. 3.2.2- Selección de los componentes Ya que se tienen las especificaciones básicas que debe cumplir la estación meteorológica, se pueden escoger los componentes que la conformarán, buscando que tengan un bajo costo y consumo de energía, integren la mayor cantidad de funciones y que sea posible obtener herramientas de desarrollo para utilizarlos. Se utiliza un microcontrolador TI MSP430F149 como pieza central de la estación. La principal razón para escoger este microcontrolador fue que es el que presenta un menor consumo de energía. El ahorro de energía permite que dos de los elementos más costosos del sistema, los paneles solares y las baterías sean más pequeños y menos costosos, teniendo un impacto significativo en la reducción del precio final del sistema completo. Otras características del MSP430 que fueron determinantes en su elección son el convertidor analógico digital que tiene una resolución de 12 bits, superior a la de 10 bits que se encuentra en otros microcontroladores. Además contiene un sensor de temperatura integrado que permite realizar la temperatura interna sin añadir un sensor extra. También cuenta con 60K bytes de memoria Flash, suficientes para almacenar los datos capturados y el código del programa. Para escoger el microcontrolador se consideraron otras opciones como el 68HS12DP26 de Freescale (antes Motorola), pero aunque este dispositivo posee más recursos y es más rápido que el MSP430, su consumo de energía es mucho mayor, por lo que fue descartado. Los siguientes compones que se seleccionaron fueron los sensores. Para medir la temperatura interna, se escogió el LM35, por cubrir el rango completo en que se desea medir y estar ampliamente disponible en el mercado a precio muy accesible. Se consideraron otros sensores como el AD22103, el ADT7816 y el TMP06 , pero, o bien no cubrían el rango deseado completo, requieren voltajes de alimentación más altos o el encapsulado es de montaje superficial, lo que complica mucho el montaje en el exterior del gabinete de la estación. La salida de este sensor tuvo que ser acondicionada para que pudiera conectarse al convertidor analógico a digital del microcontrolador, para lo que se uso un amplificador operacional TLV2444. Se selecciono este amplificador por que puede funcionar con una sola fuente de voltaje, tiene cuatro amplificadores operacionales en su interior y un consumo de energía muy bajo, en el orden de los microamperes. Para la medición de humedad relativa se utilizo al IH-3610-1 de Honeywell. Este sensor se alimenta con una sola fuente de 5 V y entrega la salida directamente en voltaje. Otros sensores de humedad capacitivos requieren ser excitados por un oscilador sinusoidal y formar parte de un circuito tipo puente, o forma parte de un oscilador RC y que se mida la frecuencia de salida del mismo, lo que aumenta el número de partes, el costo y la complejidad del el sistema. Además de las ventajas ya mencionadas, el IH-3610-1 tiene un precio similar a los demás sensores de humedad y puede conseguirse en el país, por lo que fue la opción natural. 12 3.2.3- Diagrama a bloques Acondicionador de señal ADC1 Veleta MSP430F149 Baterias y paneles solares ADC0 Alimentación sensores P4.0 ADC2 Humedad Alimentación LCD P4.0 TMR0 Anemometro Alimentación microcontrolador LCD y teclado P4,P5 P3.2-5 y P1 Sensor de Temperatura LM35 Modem Figura 3.1 – Diagrama a bloques de la estación meteorológica La estación meteorológica consta de un microcontrolador, una serie de sensores, una pantalla LCD, un teclado y un sistema de alimentación. El microcontrolador se encarga de aceptar los comandos del usuario, llevar la cuenta del tiempo, determinar cuando se debe hacer una medición, activar a los sensores, realizar la medición, almacenar el resultado y comunicarse con una PC para transmitirle los datos obtenidos. Cada uno de los sensores se conecta de alguna forma al microcontrolador, dependiendo del tipo de salida que entregue. La mayoría tiene una salida en voltaje y se conecta a un canal del convertidor analógico a digital. Solo el anemómetro entrega su salida en forma de una señal digital que se conecta al temporizador para poder medir su frecuencia. En el subsistema de alimentación se encuentran tres reguladores de voltaje, dos de ellos cuentan con una entrada de habilitación que permite que el microcontrolador los active únicamente cuando es necesario, disminuyendo el consumo de energía. Uno de estos alimenta a la pantalla LCD y la activa solo cuando se reciben ordenes del usuario y el resto del tiempo le corta la alimentación, disminuyendo el consumo de corriente en 1.2 mA; el otro alimenta a los sensores y a la etapa de acondicionamiento de señal. Como la toma de una medición de todas las variables solo requiere de unos 3 segundos como máximo y debe realizarse a lo mucho cada 10 minutos, el tenerlos desconectados la mayor parte del tiempo también ahorra energía. El regulador que esta permanentemente activado es el que alimenta al microcontrolador. 13 3.2.4- Diagrama de flujo de la operación del sistema Este diagrama de flujo describe a grandes rasgos la operación general del sistema y sirve como base para posteriormente escribir el software del sistema. En este se describe la actividad principal del sistema que es la medición y almacenamiento de las variables. Sin embargo, en él se dejan fuera muchos detalles como el hecho de que el usuario debe ser capaz de acceder a la interfaz de configuración mientras que se están tomando las mediciones, para realizar consultas o dar la orden de iniciar la transmisión de los datos ya capturados. Además, la transmisión de las datos capturados debe hacerse al mismo tiempo que la captura, por lo que debe usarse algún esquema para que se puedan realizar todas la tareas en forma simultánea, así como varias rutinas de atención de interrupciones para responder rápidamente a los eventos de hardware que así lo requieren. 14 Configuración de la fecha, hora y la velocidad de muestreo por el usuario Programar la toma de la siguiente muestra ¿Ya es hora de tomar la siguiente muestra? Entrar a modo de ahorro de energía Encender la fuente de los sensores y dejar que se estabilice Realizar la medición y almacenarla en la memoria Flash Figura 3.2 Diagrama de flujo del proceso de medición y almacenamiento de la estación meteorológica. 15 3.3- Descripción del circuito 3.3.1- Subsistema de alimentación Figura 3.3 - Diagrama eléctrico del subsistema de alimentación. En la figura se puede observar la conexión de los los tres reguladores de baja caída de voltaje que se utilizaron en la estación meteorológica. El regulador TPS76933 con salida a 3.3V alimenta directamente al microcontrolador y se encuentra permanentemente activado. Los TPS76950 con salida de 5V alimentan a los sensores y a la pantalla LCD, los cuales solo se necesitan durante pequeños periodos de tiempo y pueden desconectarse el resto del tiempo para disminuir la corriente consumida. El microcontrolador puede encender los reguladores poniendo el bit cero o uno del puerto cuatro en alto en el momento en que se requiera. Este tipo de reguladores de baja caída de voltaje puede mantener el voltaje de salida regulado aunque el voltaje de entrada, proveniente de las baterías, este solamente unos cuantos milivoltios por encima del de salida, extendiendo el tiempo por el que se puede operar sin recargar las baterías. 3.3.2- Subsistema de acondicionamiento de señal En este subsistema se acondicionan las señales para poder aplicarlas al conversor analógico digital. El primer sensor que requiere acondicionamiento es el sensor de temperatura externa LM35. Este circuito integrado entrega un voltaje de salida proporcional a la temperatura (10mv/°C) el cual puede ser positivo o negativo (de -0.5 a 1.0V). Para poderlo alimentar con una sola fuente de alimentación, el fabricante recomienda conectarlo en serie con dos diodos 1N4148 para que la terminal de referencia quede a un voltaje intermedio y el voltaje de salida pueda ser negativo con respecto a la referencia, aunque sea positivo con respecto a tierra. Este voltaje de salida se aplica a un amplificador diferencial que lo amplifica y le suma un voltaje constante para que quede en el rango de 0 a 2.5v que requiere el conversor A/D. A continuación se presenta el diseño del amplificador. La configuración de amplificador que se va utilizar es la siguiente. 16 Figura 3.4 Amplificador diferencial con desplazamiento. Las ecuaciones que rigen el circuito son: Vo K Vin Vin K Vin Vin K Voff Voff K Vin R 2 R1 , K Vin Rb R a R 2 R4 , K Voff R a R1 R2 , R a R3 R 4 R 5 Rb R a R2 R5 El sensor entrega a su salida una señal diferencial entre –0.5V y +1.5V, correspondientes al rango de temperatura de –50°C a 150° C en que trabaja el sensor. Se desea llevar este voltaje de salida al rango de 0.33V a 2.33V para que la señal correspondiente a cualquier temperatura en el rango del sensor pueda ser convertida por el ADC del MSP430 usando una referencia interna de 2.5V. La conversión se puede lograr con un amplificador con una ganancia de uno y un voltaje de desplazamiento de 0.833V. Se desea generar el voltaje de desplazamiento a partir de la referencia de 2.5V. Para lograr esto, se debe tener K(vin-)=-1, K(vin+)=1, K(voff)=0.833V/2.5V=1/3. Se escoge R2=100K para mantener una impedancia alta y un consumo de corriente bajo. Como K(vin-) =-1, K(vin+)=1, K(voff)=0.4; R1= R2/K(vin-)=100K/1=100K. Se supone que Ra/Rb=1 y entonces R4=R2/K(vin+)=100K/1=100K, R5=R2/K(Voff)=100K/(1/3)=300K. Escogiendo una combinación de valores comerciales para R5, se pueden usar dos resistencias de 150K conectadas en serie. Con estos valores se puede calcular Ra=R1||R2=50K. Así, R3 debe escogerse de forma que Rb=R3||R4|| R5=Ra=50K. Despejando R3=1/(1/Ra-(1/R4+1/R5))=150k, la cual es un valor comercial. Figura 3.5 Diagrama del circuito de acondicionamiento para el sensor de temperatura 17 Figura 3.6 Diagrama eléctrico de circuito de acondicionamiento del sensor de humedad relativa Para el sensor de humedad, el acondicionamiento fue más simple, debido al rango de salida del sensor entre 0.92 y 4.09V, y por el hecho de que el voltaje de salida esta referido a tierra. El circuito consiste de un amplificador seguidor, que evita que se produzca un efecto de carga significativo en el sensor, y un divisor de voltaje para llevar el voltaje de salida del sensor a un rango que puede aplicarse al conversor A/D de microcontrolador. El divisor tiene un efecto de atenuación de 0.65 y rango de voltaje aplicado al convertidor es de 0.6 a 2.65V. Para realizar la conversión de este voltaje se utiliza el voltaje de referencia de 3.3V. Los errores debidos a la tolerancia de las resistencias utilizadas se compensan ajustando los coeficientes de la formula de conversión del resultado de la conversión a porcentaje de humedad relativa. Figura 3.7 Diagrama eléctrico de circuito de acondicionamiento del anemómetro y la veleta. La veleta esta acoplada mecánicamente a un potenciómetro de 22KΩsin tope, de manera que el voltaje en el cursor del potenciómetro es proporcional al ángulo de giro de la veleta. El potenciómetro esta conectado a JP3. La resistencia R11, reduce el voltaje rango de salida de 0 a 5V a un rango de 0 a 3.24V que puede aplicarse al ADC directamente. El eje del anemómetro tiene un imán que hace que se cierre un interruptor de lengüetas magnético sellado al vacío una vez por revolución. Este interruptor se conecta a JP4. El divisor de voltaje formado por R7 y R8 hacen que se aplique 3.2V a la entrada de captura del temporizador en lugar de los 5 V de la fuente, así como limita la corriente que circula por el interruptor cuando este se cierra. Los condensadores C1 y C2 reducen el ruido inducido en los cables de conexión, que tiene tres metros de largo. 3.3.3- Medición de la temperatura interna Para la medición de la temperatura interna, se uso el sensor de temperatura integrado del microcontrolador. Este sensor forma parte del modulo del convertidor analógico digital. Para utilizar este sensor solo debe seleccionarse el canal número 10 del convertidor (el cual esta conectado internamente al sensor) y usar un tiempo de muestreo de 30 microsegundos o más. Esto automáticamente enciende la referencia interna de 2.5V que alimenta al sensor. La siguiente gráfica muestra la relación entre la temperatura y voltaje de salida del sensor. Como puede observarse, la relación es lineal y corresponde a la ecuación Vtemp =0.00355T+0.986, donde Vtemp es el voltaje de salida en volts y T es la temperatura en grados centígrados. 18 Figura 3.8 Curva Temperatura contra voltaje de salida de sensor interno del MSP430 3.3.4- Comunicación RS232 Figura 3.9 Circuito de conversión de niveles lógicos a RS232 Para que el microcontrolador pueda conectarse con un modem o directamente con una PC los niveles de salida del puerto serie ( 0 -> 0V, 1 -> 3.3V) del microcontrolador deben convertirse a niveles RS232 (0 -> +12V, 1 -> -12V). El circuito integrado escogido para realizar esta función es el MAX3223E, él cual tiene la ventaja de que puede ser alimentado con voltajes entre 3.0V 5.5V. A partir de esta única fuente de alimentación se generan los voltajes positivos y negativos requeridos por el estándar RS232. Otra ventaja que tiene es que cuenta con un apagado automático del generador de los voltajes RS232 en cuanto se detecta que la línea RS232 esta desconectada, reduciendo el consumo de energía de aproximadamente un mili Amper a alrededor de un micro Ampere. El apagado de del convertidor de niveles también puede hacerse manualmente por medio de la línea FORCEOFF, permitiendo ahorrar 19 energía en periodos de tiempo largos en los que no se va a realizar ninguna comunicación. 3.3.5- Conexiones del microcontrolador Figura 3.10 Conexiones del microcontrolador Además de las conexiones con otros subsistemas de la estación meteorológica, el microcontrolador requiere de algunos elementos auxiliares para funcionar adecuadamente. El voltaje de alimentación del microcontrolador es la salida del regulador TPS76933 (IC3) comentado en la sección sobre el subsistema de alimentación. Los condensadores de desacoplo C14 a C17 sirven para eliminar el rizo en el voltaje de alimentación producido por la conmutación interna del microcontrolador. El cristal Q1 proporciona una referencia de tiempo estable para la operación del microcontrolador. La señal de salida del oscilador del que forma parte este cristal es usada para llevar un reloj de tiempo real, para medir la velocidad a la que gira el anemómetro y para controlar la frecuencia del oscilador RC interno de alta frecuencia que utiliza el CPU y el puerto serie. 20 El conector JP1 sirve para conectar la interfase JTAG utilizada para programar al microcontrolador y durante la depuración de los programas. La presencia de este conector es muy importante, ya que permite programar al microcontrolador cuando ya esta conectado en el circuito de aplicación y si es necesario se puede cambiar el programa sin tener que retirar el microcontrolador de la aplicación. También posibilita observar el contenido de la memoria y de los registros durante la ejecución normal del programa, facilitando él encontrar errores en la programación. La resistencia R8 y el condensador C3 se encargan de reiniciar el microcontrolador al conectarse la alimentación a la estación. El conector JP6 se permite tener acceso al puerto 1 desde el exterior del modulo principal de la estación meteorológica. A él se conectan cuatro interruptores tipo push-button con resistencias jalando hacia arriba, las cuales permiten al usuario manejar a la estación a través del sistema de menús de la interfase de usuario. Las entradas analógicas entran al convertidor analógico digital por medio de las terminales P6.0 a P6.2. El puerto P5 y las líneas P4.5 a P4.7 se conectan a la pantalla LCD. Finalmente las terminales P3.0 a P3.5 van a la interfase RS232. 3.4- Descripción del programa del sistema. Como este sistema se basa en un microcontrolador y este realiza muchas de las tareas, la programación del mismo constituye un gran porcentaje del trabajo de diseño. Durante el desarrollo, en realidad fue necesario escribir dos programas diferentes. El primero se utilizo para probar el circuito, y lo único que hacia era tomar las mediciones, mostrarlas en la pantalla LCD y transmitirlas a través del puerto serie para poder observar los resultados en un programa emulador de terminal. El segundo es la aplicación completa en si, que incluye una interfaz de usuario y puede tomar las mediciones, comunicar los resultados y atender al usuario al mismo tiempo. También se escribió un programa para la PC en lenguaje Basic (Gambas) para recibir los datos transmitidos por la estación a la PC y guardarlos en un archivo. En los siguientes párrafos se explica el funcionamiento de las partes más importantes de estos programas. 3.4.1- Programa de prueba El objetivo de este programa es probar que el circuito funcione correctamente; asegurarse de que el código que accede a los periféricos del microcontrolador, así como algunas librerías utilitarias, estuvieran libres de errores; y finalmente, tener un acceso continuo a los resultados de la medición para poder compararlos con otros instrumentos Este programa se divide en tres módulos: prueba6.c, lcd2.c y serie2.c. El listado completo de estos módulos se encuentra en uno de los apéndices. A continuación se describen las rutinas del modulo prueba6.c. Los otros dos módulos; lcd2.c y serie2.c; también son utilizados por el programa de aplicación de la estación meteorológica completa y serán descritos en la sección correspondiente a dicho programa. 3.4.1.1- Subrutina principal Este programa se basa en la estructura más común para programas para microcontroladores, la cual consiste en una etapa de inicialización y un ciclo principal. Esta estructura es usada debido a que los programas para microcontroladores no terminan nunca, debido a que no hay un sistema operativo al cual represarle el control del CPU cuando el programa termina. En la etapa de iniciación, se configuran a todas las terminales que no van a ser utilizadas como salidas, con el objeto de evitar que el ruido externo las haga cambiar de nivel y aumenten el consumo de 21 corriente. En este programa de prueba, se activan permanentemente las fuentes de alimentación de los sensores y de la pantalla LCD, así como el convertidor de niveles RS232 del puerto serie. Además se configura el puerto serie, el convertidor analógico a digital, el temporizador, la pantalla LCD y el temporizador vigía que se utilizará en la implementación del reloj de tiempo real. Antes de entrar al ciclo principal, se habilita la atención de interrupciones y se ponen a cero las variables del reloj de tiempo real. Al inicio del ciclo principal, se pone al microcontrolador en modo de ahorro de energía. Se sale de este modo cuando el temporizador vigía genera una interrupción, en este caso, cada segundo. Con esto se asegura que se ejecute el ciclo principal una vez por segundo sin tener ninguna rutina de retardo y con el menor consumo de corriente por parte del microcontrolador. El resto del código se encarga de tomar las mediciones, mostrar la hora, la temperatura interna y externa en la pantalla LCD y enviar todos los resultados al puerto serie. Todo esto se termina de hacer en menos de un segundo y se regresa de nuevo al modo de ahorro de energía. La temperatura interna, la temperatura externa, la humedad relativa y la dirección del viento se miden por medio del convertidor analógico a digital. Para realizar las conversiones, se programan cuatro conversiones por medio de los registros de control del ADC (ADC12MCTL0 a ADC12MCTL3), donde se indica el canal en el que se va ha efectuar la conversión y el voltaje de referencia que se va a utilizar. La temperatura interna se convierte el canal 10 (sensor interno) y la temperatura externa en el canal 0. Para ambos canales se utiliza la referencia interna de 2.5V. El canal 1 se usa para medir el voltaje en el potenciómetro de la veleta y el canal 2 para la salida del sensor de humedad relativa. Como el rango en que varían estos dos voltajes excede los 2.5V de la referencia interna, se usa directamente la alimentación de 3.3V como referencia para estos canales. El puerto serie se programa para transmisión y recepción de datos de 8 bits a 2400BPS y usando interrupciones. El reloj del puerto serie se genera a partir del cristal de 32768Hz con lo que se evita tener que controlar la frecuencia del reloj RC del CPU. Una de las partes más importantes de este programa de prueba es la que se encarga de convertir los datos obtenidos del convertidor analógico a digital y del temporizador a los valores en las unidades correspondientes a la variable medida. En el programa esta sección se ve como una serie de formulas de un reglón que no aparentan ser importantes, pero que son criticas para obtener resultados realmente útiles y la obtención de una formula que funcione correctamente no es obvia. La formula para la conversión de la temperatura externa se obtiene a partir de las siguientes relaciones básicas: el voltaje de salida del sensor se relaciona con la temperatura por Vs=0.01Te, donde T es la temperatura en grados centígrados y Vs el voltaje de salida en volts. La salida del sensor se aplica a un amplificador de acondicionamiento cuya salida en volts es Vamp=Vs+0.8333. Finalmente, dicho voltaje se convierte a un numero binario por el convertidor analógico a digital, de manera que ResulAD=Vamp*4095/2.5. De estas tres ecuaciones se puede despejar la temperatura, obteniendo la siguiente formula: Te=(ResADC*2.5/4095-0.8333)/0.01 Esta formula es esencialmente correcta, pero no puede implementarse directamente en el microcontrolador debido a que este solo cuenta con operaciones enteras y la formula tiene varios coeficientes fraccionarios que de ser truncados alterarían drásticamente el resultado final. La solución a este problema consiste en reagrupar los coeficientes, de manera que se obtengan números enteros de gran magnitud que no se alteren demasiado al ser truncados. Otra modificación que se le hizo a la formula fue multiplicar a la temperatura por 10 para dejarla en décimas de grado centígrado, que es la resolución con que quiere mostrarse el resultado. El reagrupamiento usado fue el siguiente: 22 10Te=(ResADC- (0.833*4095/2.5) ) * (10*2.5/0.01) / 4095 = (ResADC-1365)*2500/4095 En la medición de la temperatura interna, el voltaje del sensor de temperatura en volts es Vtemp=0.00355*Ti+0.986, donde Ti es la temperatura interna en grados centígrados. Este voltaje entra al convertidor analógico a digital obteniendo ResADC= Vtemp*4095/2.5. Nuevamente se puede obtener una formula de conversión a partir de estas dos igualdades, pero contendría coeficientes fraccionarios que no se pueden implementar en el microcontrolador. Así es que se reagrupan los coeficientes para obtener números enteros y también se multiplica la temperatura por 10 para dejarla en décimas de grados centígrado, de manera que la formula queda: 10Ti=10*(ResADC*2.5/4095-0.986)/0.00355 10Ti=(ResACD- (0.986*4095/2.5) )* (10*2.5/0.00355) /4095 10Ti=(ResADC-1615)*7042/4095 El sensor de humedad Honeywell modelo IH-3610 se vende junto con información de calibración de fabrica (Figura ???) que permite obtener el porcentaje de humedad relativa a partir del voltaje de salida del sensor. La relación que nos interesa es RH=(Vo-0.921)/0.0316. Antes de aplicarse al convertidor, la salida del sensor pasa por un divisor de voltaje formado por una resistencia de 330K y una de 180K, que entrega un voltaje Vdiv=Vo*330/(180+330). Como en la conversión de este canal se usa como referencia el voltaje de alimentación del microcontrolador de 3.3V, la salida del convertidor es ResADC=Vdiv*3.3/4095. Usando las ecuaciones anteriores, despejando la humedad relativa y reagrupando, se obtiene: RH=(ResADC*(3.3/4095)*(330+180)/330-0.921)/0.0316 RH=(ResADC- (0.921*(4095/3.3)*(330/510)) ) * (3.3*(510/330)/0.0316) /4095 RH=(ResADC—739)*161/4095) Figura 3.11 Información de calibración del sensor de humedad. La más simple de las formulas de conversión es la de la velocidad del viento. El potenciómetro acoplado a la veleta entrega 3.3V cuando se encuentra en la posición correspondiente a 360°. Estos mismos 3.3V se usan como referencia al hacer la conversión de analógico a digital, por lo que a 360° corresponde el resultado máximo de la conversión de 4095. De esta forma, la formula para calcular la dirección del viento es una simple regla de tres: DV=ResADC*360/4095. La única variable que no se mide usando el convertidor analógico a digital es la velocidad del viento, que se mide usando la función de captura de eventos del temporizador B. Al girar el anemómetro genera un pulso por cada revolución. Cada vez que el temporizador detecta un flanco de subida almacena el valor del contador del temporizador, el cual tiene un reloj de 32768Hz. Si se resta el valor de dos capturas consecutivas, se obtiene el tiempo (periodo en múltiplos de 1/32768 S ) que tardo el anemómetro en dar una revolución y a partir de él se puede calcular la frecuencia de la señal y la velocidad del viento. En cada revolución una paleta del anemómetro habrá recorrido una distancia 23 lineal igual a 2πr, donde r es el radio del anemómetro, en este caso 0.05m. La frecuencia de la salida del anemómetro (f) nos indica el número de veces por segundo que se recorre dicha distancia, por lo que la relación entre la velocidad del viento y la frecuencia en metros/S es v= 2πrf. Sustituyendo el radio del anemómetro y cambiando las unidades a Km/Hr, se tiene vel= 2π*(0.05m)*(1Km/1000m)*(3600S/1Hr)*f=1.1309*f Dado que el periodo de la señal se mide en múltiplos del periodo del reloj de 32768Hz, la frecuencia del anemómetro (f en Hz) es f=32768/periodo. Como se desea mostrar la velocidad del viento con un dígito decimal, se multiplica por diez la velocidad y la formula para convertir el periodo a velocidad del viento queda 10Vel=10*1.1309*32768/ periodo =3705973/periodo 3.4.2- Programa completo de aplicación El programa de aplicación consta de los módulos principal5.c, interfaz.c, transmite.c lcdand2.c y serie2.c. El módulo principal.c contiene la rutina principal del programa, varias de las rutinas de atención a interrupciones, una rutina para escribir a la memoria FLASH, la rutina que realiza el proceso de medición, una que controla la frecuencia del reloj RC del CPU y la que lleva el reloj de tiempo real. El módulo interfaz.c contiene las rutinas que implementan la interfaz con el usuario por medio de la pantalla LCD y un teclado de cuatro teclas; transmite.c incluye las rutinas necesarias para transmitir los datos capturados a la PC a través del puerto serie; lcdand2.c contiene rutinas para la escritura de datos y comandos a la pantalla LCD y finalmente, serie2.c permite leer y escribir al puerto serie por medio de interrupciones y con una cola circular como buffer. A continuación se describen las rutinas más importantes o las que tienen un funcionamiento que nos es totalmente obvio, con el objetivo de ayudar al lector a comprender el código fuente del anexo C 3.4.2.1- Subrutina principal Al igual que el programa de prueba, este programa se basa en la estructura consistente en una etapa de inicialización y un ciclo principal infinito. En la etapa de iniciación son pocas las diferencias. Una de las más notables es que el temporizador vigía esta programado para generar una interrupción cada doscientos cincuenta milisegundos en lugar de cada segundo, con lo que el tiempo que tarda la ejecución del ciclo principal se reduce. El puerto serie se programa para trabajar a una frecuencia de 9600 BPS, la que no puede ser obtenida a partir del reloj de baja frecuencia de 32768Hz, así que se genera a partir del reloj del CPU. Como este oscilador de tipo RC no es ni muy estable ni muy exacto en su frecuencia, debe ser ajustado cada cierto tiempo para mantener la frecuencia constante y evitar errores en la comunicación. Este ajuste se realiza llamando a la función Ajusta_DCO(). El ciclo principal en ese programa es más pequeño que en el de prueba, ya que algunas tareas se trasfirieron a otras rutinas. En el ciclo principal primero se revisa si se ha presionado alguna tecla y de ser así, se llama la rutina interfaz() para que la procese. Después se llama a la rutina de medición y a la de transmisión de datos por el puerto serie. Finalmente se pone al microcontrolador en un modo de ahorro de energía hasta que ocurre la siguiente interrupción del temporizador vigía que lo despierta y hace que se ejecute una vez más el ciclo principal. 3.4.2.2- Rutina de ajuste de la frecuencia del DCO El ajuste de la frecuencia del oscilador RC del CPU se realiza comparando la frecuencia del oscilador con alguna frecuencia estable y conocida, como es el caso de la del oscilador de cristal de baja 24 frecuencia. En otros diseños puede usarse la frecuencia de la corriente alterna de alimentación. Para realizar esta comparación se utiliza el temporizador A. El reloj de alta frecuencia se usa para excitar al contador del temporizador y se mide el periodo de la señal de referencia por medio de un canal de captura. Si el número de ciclos de reloj de alta frecuencia en un periodo de la señal de referencia es mayor que el deseado, la frecuencia del oscilador es muy alta y debe disminuirse. En caso contrario, la frecuencia debe aumentarse. En esta rutina no fue posible utilizar interrupciones para hacer la medición del periodo, ya que en un periodo de la señal de referencia de 32768Hz solo se tienen 32 ciclos del reloj de 1MHz del CPU, lo cual no es suficiente para completar la llamada y la ejecución de la rutina de atención de interrupciones. En su lugar, se usa la técnica de escrutinio (polling) para detectar el momento en que se presenta un flanco de subida y se realiza la captura. En realidad se cuentan ocho flancos para hacer que el tiempo con el que se compara la frecuencia del DCO sea mayor y se pueda obtener una mejor resolución en la medición. La frecuencia de oscilación del DCO puede controlarse por medio de tres mecanismos diferentes. El primero es cambiando la resistencia conectada al generador de corriente del DCO, lo que hace que se seleccione un rango de frecuencias diferente. Esto se logra modificando los bits RSELx del registro BSCCTL1. Dentro de cada rango se puede escoger una de ocho posibles frecuencias por medio de los bits DCOx del registro DCOCTL. Además, se pueden lograr 32 frecuencias efectivas intermedias entre cada una de esta ocho usando la modulación. La modulación consiste en alternar entre una frecuencia y la inmediata superior cada treinta y dos ciclos de reloj. Los bits MODx del registro DCOCTL indican cuantos de estos treinta y dos ciclos se tomaran de la frecuencia inmediata superior y el resto se tomara de la frecuencia seleccionada por los bits DCO. De esta forma se logra una frecuencia efectiva intermedia y el error en frecuencia se integra a cero cada treinta y dos ciclos de reloj. Los tres mecanismos son utilizados por la rutina de ajuste de la frecuencia del DCO. 3.4.2.3- Rutina de Medición. El proceso de medición puede llegar a tomar hasta 3 segundos, lo cual es un tiempo mayor al que toma realizar una pasada por el ciclo principal del programa. Por esta razón, la rutina de medición se diseño de manera que en cada ocasión en que es llamada, ejecuta una etapa del proceso de medición y regresa al programa principal para dar tiempo a que se ejecuten las rutinas de interfaz con el usuario y de transmisión de datos, de manera que entre la ejecución de una etapa y la siguiente existe por lo menos un cuarto de segundo. La rutina lleva el control de en que etapa del proceso de medición se encuentra por medio de la variable etapa_med, de forma que para pasar a otra etapa sólo se debe modificar esta variable. Por medio de una estructura switch se ejecuta el código correspondiente a cada etapa. Existen cinco etapas en el proceso de medición, las cuales se describen en la siguiente tabla. 25 Etapa Descripción 0 Se compara la hora actual con la hora en que se programo la siguiente medición. Cuando es el momento de hacer la medición, se encienden la fuente de alimentación de los sensores para dar tiempo a que se estabilice. Finalmente se borran las banderas para la medición de la velocidad del viento. 1 Se habilitan las interrupciones para la medición de la velocidad del viento. Se enciende la fuente interna del convertidor analógico a digital y se programa los canales donde se va a realizar una conversión. 2 Arranca la conversión de analógico a digital y una vez terminada, se aplican las formulas para obtener los valores de las variables en las unidades correctas. Se apaga la fuente del convertidor analógico a digital. 3 Se espera la medición de la velocidad del viento. 4 Se escriben los datos medidos en la memoria FLASH y se regresa a la etapa 0 Tabla 3.2 – Etapas del proceso de medición La medición de la velocidad del viento se hace en conjunto con la rutina de atención de interrupciones del temporizador B, por lo que es necesario en cada llamada a la rutina de medición revisar si ya se presentaron los dos flancos necesarios para tener una medición de velocidad completa. El código que realiza esta función se encuentra después de la estructura switch y es el que permite pasar de la etapa tres a la cuatro. 3.4.2.4- Rutina de escritura a la memoria FLASH El propósito de esta rutina es escribir un número de 16 bits en la memoria FLASH. Como los datos medidos son escritos en la memoria en secuencia, se usa la variable puntero para indicar en que dirección de memoria se debe almacenar el siguiente dato. El MSP430F149 cuenta con 60K de memoria FLASH que se localizan en el rango de direcciones que va de 1100h a FFFFh. El rango de 1100h a 11FFh esta ocupado por la llamada memoria de información, la cual se divide en dos bancos de 128 bytes y esta diseñada para guardar información de calibración. El resto de la memoria esta dividida en segmentos de 512 bytes, por lo que usar la memoria de información para almacenar datos complicaría el código de la rutina de escritura a memoria. En esta aplicación se usa el rango de DE00h a FFFFh para guardar el código del programa, de forma que el rango de direcciones que queda disponible para almacenar los datos capturados es de 1200h a DDFFh. La variable puntero recibe un valor inicial de 1200h en el programa principal, y cada vez que se realiza una escritura es incrementada en dos para que apunte a la siguiente palabra de 16 bits en la memoria. Antes de hacer cualquier escritura, la rutina revisa si la dirección a la que se va a escribir se sale del rango permitido y si se encuentra en el inicio de un segmento, en cuyo caso se borra el segmento para asegurarse de que se va a poder escribir en él sin problemas. El MSP430 cuenta con un circuito controlador especial para la memoria FLASH, por lo que el proceso de escritura resulta consiste únicamente en enviar un par de comandos al controlador y después escribir el dato a la localidad deseada como si se tratara de una localidad de memoria RAM. En ese momento la ejecución del programa por el CPU se detiene hasta que el controlador termina de realizar la escritura. 26 3.4.2.5- Rutinas de la interfaz con el usuario Al igual que la rutina de medición, la rutina de interfaz con el usuario esta diseñada para ser llamada, hacer alguna acción rápidamente y regresar al programa principal para permitir que se ejecuten otras tareas. La rutina de interfaz recibe del programa principal un parámetro que le indica cual fue la ultima tecla presionada y con base a este parámetro modifica su estado interno, la pantalla y de ser necesario, alguna de las variables de configuración que controlan el funcionamiento del resto del sistema. La interfaz con el usuario se basa en un sistema de menús y submenús a los cuales tiene acceso el usuario por medio de cuatro teclas: entrar, escape, anterior y siguiente. Al energizarse el sistema la pantalla LCD esta apagada para ahorrar energía, por lo que el usuario debe encenderla presionado la tecla entrar. En ese momento aparece un elemento del menú principal en el renglón superior de la pantalla. Presionado la tecla entrar se puede seleccionar ese elemento del menú principal y escoger entonces alguno de los submenús que aparecerán en el renglón inferior de la pantalla. La tecla escape permite salir del submenú actual y regresar al nivel superior. Las teclas siguiente y anterior permiten al usuario pasar al siguiente menú o submenú. La siguiente tabla lista los menús y submenús de la aplicación. Menú Configurar fecha Submenús Día Mes Año Configurar hora Hora Minuto Velocidad de captura Cada 10 minutos Cada hora Mostrar últimos resultados Temperatura y humedad relativa Velocidad y dirección del viento. Transmite datos A que teléfono Transmitir ahora Tipo de MODEM Capturar datos Tabla 3.3 - Listado de los menús de la estación meteorológica La interfaz con el usuario en realidad esta dividida en varias subrutinas: interfaz, realiza el manejo de los menús y submenús; pintamenus, escribe en la pantalla las leyendas correspondientes a cada menú y submenú; acción se llama una vez que se ha escogido un submenú y es donde realmente se realiza la acción correspondiente. Además se utilizan varias rutinas auxiliares para funciones tales como mostrar el valor de las variables, modificar una variable de configuración entera y modificar el número 27 telefónico a donde se va a trasmitir. 3.4.2.6- Rutinas de transmisión de datos El diseño de la rutina de transmisión esta pensado de manera que la rutina pueda llamarse desde el ciclo principal, efectuar una etapa del proceso de transmisión y regresar. Al igual que las rutinas de medición e interfaz, debe almacenar su estado interno en variables para que en cada llamada sepa que parte del código debe ejecutarse. La variable etapa_trans indica en que etapa se encuentra el proceso de transmisión, y para pasar de una etapa a otra, solo hay que modificar su valor. El código correspondiente a la etapa se selecciona por medio de una estructura switch. Las etapas que forman parte del proceso de medición se muestran en la siguiente tabla. Etapa Descripción 0 Envía un comando para reiniciar al módem 1 Espera la respuesta (“OK”) del módem y envía el comando de marcado 2 Espera que el módem confirme la conexión (CONNECT) 3 Transmite un bloque de máximo 120 palabras y su checksum 4 Espera la confirmación de recepción sin errores por la PC y revisa si hay más datos por transmitir 5 Indica que hubo un error en la transmisión 6 a 11 Envían la secuencia de escapa y el comando de colgar al módem Figura 3.4 - Etapas de la rutina de transmisión de datos 3.4.2.7- Rutinas para el manejo del puerto serie Este grupo de rutinas permite la escritura y lectura de datos del y al puerto serie por medio de interrupciones y una cola circular que sirve como almacenamiento intermedio. Realizar el acceso al puerto serie de esta manera tiene la ventaja de que la rutina de transmisión de datos puede escribir (o leer) los datos que deben transmitirse en la cola circular y regresar al programa principal en un tiempo menor al que realmente toma hacer la transmisión. Cuando el puerto serie esta listo para recibir un nuevo dato, genera una interrupción y la rutina de atención toma el dato de la cola circular y lo pasa al puerto serie. Las rutinas para el manejo del puerto serie se encuentran en el módulo serie2.c y entre ellas se encuentran las rutinas de atención a interrupciones de recepción y transmisión, rutinas para meter y sacar datos de las colas de recepción y transmisión, una rutina para saber si hay datos en el buffer de recepción, y rutinas para tomar una cadena de caracteres y mandarla al puerto serie. 3.4.2.8- Rutinas para escribir en la pantalla LCD. Para pode mostrar información al usuario a través de la pantalla LCD, es necesario enviarle algunos comando y los datos que se desea mostrar. De esto se encargan las rutinas de escritura a la pantalla LCD. Se cuenta con una rutina de escritura de datos y una de comandos, las cuales solo difieren el 28 valor lógico que ponen en la terminal RS de la pantalla, 0 para un comando y 1 para un dato. El proceso de escritura en si consiste en poner el dato en las terminales de datos de la pantalla, después poner la terminal E en uno y la terminal R/W en cero, y finalmente regresar la terminal E a cero para terminar la escritura. En esta aplicación no fue posible leer a la pantalla por que esta se alimenta con 5V, mientas que el microcontrolador se alimenta solo con 3.3V. El voltaje de salida de la pantalla podría dañar al microcontrolador, mientras que el voltaje de salida en nivel alto del microcontrolador es ligeramente más alto que el voltaje mínimo que la pantalla interpreta como nivel alto. De esta forma la escritura es posible, pero la lectura no es segura. Una consecuencia importante de no poder hacer lecturas de la pantalla es que no puede saberse cuando la pantalla esta lista para recibir un nuevo comando o dato, por lo cual hay que usar algunos retardos para asegurarse que la pantalla va a tener suficiente tiempo como para terminar de ejecutar el comando enviado. Además de las rutinas de escritura lectura de comandos y datos, el módulo lcdand2.c contiene una rutina para enviar una cadena de caracteres a la pantalla y la definición de constantes simbólicas para los comandos de la pantalla LCD. Antes de utilizar la rutina de escritura de cadenas, es conveniente asegurarse de que el cursor se encuentre en la posición deseada enviando el comando LCD_SET_DD_RAM_ADDRESS más la dirección de la localidad donde debe escribirse la cadena en la pantalla. 3.5- Descripción del programa de recepción de datos La funcionalidad de la estación meteorológica automatizada seria muy limitada si no se cuenta con la herramienta adecuada que permita recibir la información capturada por la estación y hacerla disponible a los especialistas en meteorología en u formato que facilite su consulta y análisis. Esta herramienta es en este caso una computadora personal corriendo el programa desarrollado en Gambas para esta aplicación en particular. Gambas es un intérprete avanzado de Basic, similar a Visual Basic, pero esta pensado para utilizarse en el sistema operativo GNU/LINUX y es de código fuente abierto. Utiliza los paradigmas de programación por eventos y orientada a objetos comunes en los lenguajes que permiten el desarrollo de programas con interfaz de usuario grafica. Los controles que formaran la interfaz de usuario se dibujan usando la barra de herramientas de Gambas y los nombres, clase y propiedades de estos se almacenan en un formato textual en un archivo con extensión .form. El texto de que representa la forma dibujada para esta aplicación se incluye en el apéndice C. 29 Figura 3.12 – Entorno de desarrollo Gambas El código en Basic del programa se guarda en un archivo con extensión .class y consiste en una serie de funciones de respuesta a eventos. La mayoría de los controles y sus respectivas rutinas de eventos sirven para configurar el proceso de recepción de datos, con opciones como indicar el puerto serie que se va a utilizar, la velocidad de las comunicaciones, el tipo de intercambio de saludos, si se va a realizar la comunicación a través de dos módems celulares GSM o si se va a simular el comportamiento de un módem para poder descargar los datos de la estación a través de una conexión directa por cable. Form_Open() es llamada cuando se carga la forma y se utiliza para dar un valor inicial a algunas variables. El proceso de recepción en realidad comienza cuando se presiona el botón que abre el puerto serial al que esta conectado el módem o la estación meteorológica. Además de abrir el puerto, esta rutina (Button1_Click()) arranca un temporizador para que después de un par de segundos se ejecute la rutina del temporizador donde se envían los comandos para preparar al módem para recibir datos. El temporizador se utiliza en otras ocasiones donde se requiere un retardo, tal como antes y después de enviar la secuencia de escape para colgar el módem. La mayor parte del proceso de comunicación se lleva a cabo en la rutina de lectura del puerto serie SPort_Read(). Esta es la rutina que es llamada cuando se tiene un número suficiente de caracteres recibidos en el puerto para que estos sean leídos y procesados por el programa de aplicación. El problema es que el momento en que es llamado puede ser algo aleatorio. La función no es llamada siempre cuando se tiene una cantidad fija de caracteres, ni tampoco cuando se recibe un carácter de final de línea, o cuando ha pasado un tiempo determinado. Todo lo anterior hace que la rutina no pueda estructurarse en una forma simple, sino que tenga que almacenar los caracteres recibidos que no han sido procesados y el estado del proceso de recepción en variables globales para que no se pierdan entre una llamada y la siguiente. De hecho, se usa una estructura similar a la usada en las rutinas de medición, transmisión e interfase de la estación meteorológica. El proceso se divide en una serie de etapas de las que se ejecuta una parte, una o varias etapas cada vez que la rutina es llamada. Las etapas 30 del proceso de recepción se describen en la tabla 3.5 Etapa 0 1 2 3 4 5 Descripción conexión por módem Descripción emulando módem Se espera la respuesta del módem al Se espera el comando inicial enviado por la comando inicial estación y se responde emulando al módem Espera la indicación de marcado por Espera el comando de marcado y responde parte el módem y responde indicando una conexión. Pasa a la etapa 3 Espera la indicación de conexión por Se omite parte del módem Recibe el tamaño del bloque o el indicador de final de la transmisión, en este caso se transfieren los datos contenidos en memoria a un archivo Recibe los datos y calcula la suma de comprobación Compara la suma de comprobación y envía una indicación de comprobación o de error, después regresa a la etapa 3 Tabla 3.5 – Etapas del proceso de recepción en la PC Figura 3.13 – Captura de pantalla del programa de recepción 31 4- Resultados, conclusiones y trabajo futuro 4.1 Introducción Los resultados obtenidos en el desarrollo del caso practico se pueden dividir en dos partes: la primera son los obtenidos con el programa de prueba y que se usaron para comparar las mediciones obtenidas con la estación meteorológica con las de otros instrumentos y la segunda son los obtenidos durante un periodo de prueba de tres días en los que la estación estuvo expuesta a la intemperie para probar su funcionamiento en condiciones más cercanas a las reales. Ambos resultados se presentan a continuación. 4.2- Resultados del programa de prueba Para verificar el correcto funcionamiento de las mediciones de temperatura interna y externa, primeramente se intento comparar los resultados obtenidos por la estación con los obtenidos por medio de un termómetro de mercurio marca Brannam graduado de -20 a 100°C. Este enfoque desafortunadamente no fue muy práctico. Para hacer las mediciones en ambientes controlados, se realizaban en el interior de un refrigerador y de un horno resistivo. En el caso del refrigerador era necesario abrir la puerta para poder ver la lectura del termómetro y aunque en el caso del horno se contaba con una perforación especial para poner un termómetro, el hecho de que la ubicación de esta perforación hacia imposible colocar el bulbo del termómetro en la misma posición que el sensor interno del microcontrolador y de que las paredes metálicas del horno conducían el calor hacia el termómetro más rápidamente que hacia los sensores de la estación; genero un gradiente de temperatura que hizo imposible aplicar la misma temperatura al termómetro y a los sensores electrónicos. Con esta prueba, lo que realmente se deseaba era, por un lado, calibrar al sensor de temperatura interna que no viene calibrado de fabrica, y por otro, compensar los errores en la función de transferencia del amplificador debidos a la tolerancia en las resistencias del mismo. Los datos necesarios para esta compensación se deben obtener al medir la misma temperatura con nuestros instrumentos con un instrumento de referencia, para lo que originalmente se pensó usar el termómetro. Al no ser practico usarlo, se cambio la referencia al mismo sensor de temperatura externa (LM35), midiendo su voltaje de salida directamente con un voltímetro. Como este sensor se encuentra calibrado de fabrica y tiene una exactitud de +/- 0.5°C y una linealidad de +/-0.25°C, puede usarse como una buena referencia. Lo primero que se hizo fue corregir los errores en el amplificador del sensor de temperatura interna. Para esto se midió la salida del sensor con un voltímetro, se convirtió a temperatura y se comparo con las lecturas obtenidas por la estación a tres temperaturas diferentes. Los resultados obtenidos se muestran en la siguiente tabla. Referencia (0.1°C) Estación (0.1°C) 56 36 200 182 316 300 Tabla 4.1 Resultados de las mediciones para la calibración de la medición interna. 32 Se aplico un análisis de regresión lineal con la medición de la estación como variable independiente y la referencia como variable dependiente y se obtuvo una pendiente de 0.9849 y una ordenada en el origen de 20.6. Usando estos datos la formula para convertir el resultado del convertidor analógico a digital a temperatura se modifica de TI = (ResADC-1365)*2500/4095 a TE = [ (ResADC-1365)*2500/4095] * 0.9849 +20.6 TE = (ResADC-1365+20.6*4095/(2500*0.9849) )*(2500*0.9849)/4095 TE = (ResADC-1330)*2462/4095 Una vez compensado el error del amplificador se utilizó la lectura del sensor externo como referencia para calibrar al sensor interno, que no viene calibrado de fábrica. Se colocaron los sensores uno junto al otro y se clocaron en un refrigerador y en el horno resistivo, leyendo los resultados de la medición de la estación por medio del puerto serie del microcontrolador, para no abrir la puerta y crear un gradiente de temperatura que arruinara la medición. Los datos obtenidos en estas pruebas se muestran a continuación. Temperatura Externa (0.1°C) Temperatura Interna (0.1°C) 31 20 194 178 406 397 Tabla 4.2 Resultados de las mediciones para la calibración de la medición interna. El análisis de regresión lineal da una pendiente de 1.0145 y una ordenada en el origen de 10.37. Corrigiendo la formula para obtener la temperatura interna a partir del resultado del ADC, se obtiene TI = [(ResADC-1615)*7042/4095]*1.0145+11 TI = (ResADC-1615+ (11*4095/(7042*1.0145)) ) * (7042*1.0145)/4095 TI = (ResADC-1608)*7144/4095 En cuanto al sensor de humedad, no fue posible conseguir otro instrumento con el cual comparar las mediciones de la estación. Como el sensor viene calibrado de fábrica, lo que se hizo fue medir el voltaje de salida del sensor, usar la información de calibración para calcular la humedad relativa y comprarla con la mostrada en ese momento por la estación. Los únicos errores que encontraron por este procedimiento son muy pequeños y pueden ser atribuidos al redondeo en el calculo con operaciones enteras en el microcontrolador. La medición de la dirección del viento se verifico en el laboratorio comparando la medición del ángulo de la veleta por medio de un transportador con el resultado entregado por la estación. Las mediciones se hicieron a ángulos de 0°, 90°, 180° y 270°. El error máximo encontrado fue de 3°, lo que indica un buen grado de linealidad en el potenciómetro acoplado a la veleta. El funcionamiento del anemómetro se probó de manera indirecta, aplicando una señal de una frecuencia conocida a la entrada y aprovechando el hecho de que la velocidad del viento es proporcional a la frecuencia. Las señales de referencia aplicadas, la velocidad medida y la velocidad esperada, se muestran en la tabla siguiente. Frecuencia de la señal de referencia (Hz) 201 101 50 Velocidad medida (Km/Hr) 227.13 114.13 56.5 Valor esperado (Km/Hr) 227.36 113.68 56.84 33 Tabla 4.3 – Mediciones de la calibración de la velocidad del viento Los errores presentados estuvieron dentro del 1% del valor esperado y pueden atribuirse en parte al redondeo por operaciones enteras. 4.3- Resultados de la prueba a la intemperie. La prueba de funcionamiento de la estación a la intemperie se realizó entre los días 4 y 8 de septiembre de 2004. La estación se coloco en la azotea de un edificio en la zona urbana de Morelia, Michoacán. El gabinete de la estación se coloco en el interior de una caja plástica para evitar que e mojara, quedando en el exterior del mismo únicamente el sensor de temperatura externa LM35, la veleta y el anemómetro. Los resultados de las mediciones de estos cuatro días se muestran a continuación. Fecha Hora 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 4/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 19:10:00 19:20:00 19:30:00 19:40:00 19:50:00 20:00:00 20:10:00 20:20:00 20:30:00 20:40:00 20:50:00 21:00:00 21:10:00 21:20:00 21:30:00 21:40:00 21:50:00 22:00:00 22:10:00 22:20:00 22:30:00 22:40:00 22:50:00 23:00:00 23:10:00 23:20:00 23:30:00 23:40:00 23:50:00 00:00:00 00:10:00 00:20:00 00:30:00 00:40:00 00:50:00 TI (°C) TE (°C) 23.2 23.2 22.8 22.3 21.8 21.3 21.1 20.8 20.8 20.8 20.6 20.6 20.2 20.1 20.1 20.1 19.5 19.4 19.2 19 18.5 18.2 18 17.7 17.5 17.7 17.5 17.3 17.5 17.3 17.5 17.3 17.1 17 16.8 22.7 22.2 21.6 21.3 21 20.8 20.8 20.9 20.8 20.6 20.9 20.2 20.5 20.3 20.3 18.9 18.3 18.4 17.9 17.3 17.3 17.2 17 18.3 16.9 17 16.3 17 17 17.4 17.3 16.7 16.6 16.7 16.6 HR Dir (°) DIR Vel. (Km/hr) 56.00% 55.00% 56.00% 58.00% 61.00% 62.00% 66.00% 66.00% 66.00% 67.00% 67.00% 69.00% 70.00% 71.00% 71.00% 74.00% 76.00% 77.00% 79.00% 80.00% 83.00% 84.00% 85.00% 87.00% 88.00% 88.00% 88.00% 89.00% 89.00% 89.00% 90.00% 90.00% 91.00% 91.00% 91.00% 313 340 340 301 296 224 352 352 174 187 187 265 174 174 174 133 176 176 176 234 234 234 234 234 234 234 234 234 234 234 160 147 31 32 109 NO NNO NNO ONO ONO SO N N S S S O S S S SE S S S SO SO SO SO SO SO SO SO SO SO SO SSE SSE NNE NNE ESE 0 0 0 0.59 0 0 0 1.33 1.18 0.72 0 0 0 1.78 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 34 Fecha Hora 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 01:00:00 01:10:00 01:20:00 01:30:00 01:40:00 01:50:00 02:00:00 02:10:00 02:20:00 02:30:00 02:40:00 02:50:00 03:00:00 03:10:00 03:20:00 03:30:00 03:40:00 03:50:00 04:00:00 04:10:00 04:20:00 04:30:00 04:40:00 04:50:00 05:00:00 05:10:00 05:20:00 05:30:00 05:40:00 05:50:00 06:00:00 06:10:00 06:20:00 06:30:00 06:40:00 06:50:00 07:00:00 07:10:00 07:20:00 07:30:00 07:40:00 07:50:00 08:00:00 08:10:00 08:20:00 08:30:00 08:40:00 08:50:00 09:00:00 09:10:00 09:20:00 TI (°C) TE (°C) 16.6 16.6 16.5 16.6 16.5 16.5 16.5 16.3 16.1 16.1 16.1 15.8 15.8 15.6 15.6 15.4 15.4 15.6 15.6 15.6 15.4 15.4 15.3 15.3 15.3 15.3 15.3 15.3 15.3 15.3 15.4 15.3 15.4 15.3 15.4 15.3 15.4 15.4 15.3 15.3 15.3 15.4 15.6 15.8 15.9 15.9 16.1 16.5 17 17.3 17.8 16.6 16.9 16.5 16.5 16.8 16.7 16.6 16.4 16.6 16.3 16.4 16 16 16.1 16.3 16.4 16.4 16.6 16.6 15.5 16.4 16.4 17.4 17.3 17.9 18.3 18.4 18.5 19.3 19.4 20 19.7 19.8 20 20.2 21.3 21.4 21.4 21.6 21.6 22 22.6 22.4 22.8 22.7 23.6 24.9 24.4 25.3 25.6 26 HR Dir (°) DIR Vel. (Km/hr) 92.00% 92.00% 93.00% 93.00% 92.00% 93.00% 93.00% 94.00% 93.00% 96.00% 95.00% 95.00% 95.00% 95.00% 96.00% 96.00% 96.00% 96.00% 96.00% 96.00% 97.00% 97.00% 96.00% 96.00% 97.00% 97.00% 96.00% 96.00% 97.00% 97.00% 97.00% 97.00% 97.00% 97.00% 97.00% 98.00% 97.00% 97.00% 97.00% 98.00% 98.00% 98.00% 97.00% 97.00% 97.00% 97.00% 97.00% 96.00% 96.00% 95.00% 94.00% 96 70 70 70 70 63 63 46 40 96 107 108 109 106 115 115 115 115 115 115 115 115 115 115 115 115 115 115 116 116 116 116 116 116 116 114 114 113 127 127 127 127 127 127 127 73 73 73 73 73 73 E ENE ENE ENE ENE ENE ENE NE NE E ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE ESE SE SE SE SE SE SE SE ENE ENE ENE ENE ENE ENE 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 35 Fecha Hora 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 09:30:00 09:40:00 09:50:00 10:00:00 10:10:00 10:20:00 10:30:00 10:40:00 10:50:00 11:00:00 11:10:00 11:20:00 11:30:00 11:40:00 11:50:00 12:00:00 12:10:00 12:20:00 12:30:00 12:40:00 12:50:00 13:00:00 13:10:00 13:20:00 13:30:00 13:40:00 13:50:00 14:00:00 14:10:00 14:20:00 14:30:00 14:40:00 14:50:00 15:00:00 15:10:00 15:20:00 15:30:00 15:40:00 15:50:00 16:00:00 16:10:00 16:20:00 16:30:00 16:40:00 16:50:00 17:00:00 17:10:00 17:20:00 17:30:00 17:40:00 17:50:00 TI (°C) TE (°C) 18.3 18.5 18.5 18.7 19.4 19.9 20.6 20.8 21.1 21.4 22 22.6 23.7 24.7 25.4 27.6 27.5 28.1 28.5 28.7 29.9 30.9 33.3 34 35.7 36.1 37.3 38.1 39 39.7 40.4 41.4 37.1 35 39.3 42.2 41.4 37.6 34.5 36.4 39.5 39.5 39.8 41.4 37.9 37.4 41 40.5 40 36.9 34.2 25.3 23.5 24.1 24.5 23.1 24.5 24.7 25.3 25.4 25.4 25.7 26.9 28.3 26.4 27 28.5 29 28.3 27 31.1 27.2 33.6 34.3 32.7 34.4 32 34.4 34.8 36 37.3 37.1 35.7 30.7 31 39.2 43.8 33 30.5 35.5 35.3 33.4 41.9 37.1 35.2 34.6 40.5 40.4 43.7 32.8 28.2 26.9 HR Dir (°) DIR Vel. (Km/hr) 92.00% 90.00% 86.00% 84.00% 81.00% 79.00% 77.00% 75.00% 72.00% 70.00% 67.00% 65.00% 60.00% 57.00% 55.00% 50.00% 48.00% 46.00% 45.00% 44.00% 41.00% 40.00% 36.00% 33.00% 30.00% 29.00% 27.00% 26.00% 24.00% 23.00% 22.00% 21.00% 28.00% 31.00% 25.00% 22.00% 21.00% 24.00% 29.00% 27.00% 23.00% 23.00% 22.00% 19.00% 23.00% 24.00% 19.00% 19.00% 21.00% 23.00% 28.00% 73 62 61 45 45 45 45 45 45 45 45 45 45 45 45 98 98 110 97 90 98 98 123 45 45 304 76 136 128 80 146 146 210 87 87 214 192 192 216 220 222 181 174 229 217 231 233 241 234 326 279 ENE ENE ENE NE NE NE NE NE NE NE NE NE NE NE NE E E ESE E E E E ESE NE NE NO ENE SE SE E SE SE SSO E E SO SSO SSO SO SO SO S S SO SO SO SO OSO SO NO O 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.8 0 0 0 0 0 0 0 0 0 0 0 1.22 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.74 0 0 0 0 0 1.18 2.2 1.39 36 Fecha Hora 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 5/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 18:00:00 18:10:00 18:20:00 18:30:00 18:40:00 18:50:00 19:00:00 19:10:00 19:20:00 19:30:00 19:40:00 19:50:00 20:00:00 20:10:00 20:20:00 20:30:00 20:40:00 20:50:00 21:00:00 21:10:00 21:20:00 21:30:00 21:40:00 21:50:00 22:00:00 22:10:00 22:20:00 22:30:00 22:40:00 22:50:00 23:00:00 23:10:00 23:20:00 23:30:00 23:40:00 23:50:00 00:00:00 00:10:00 00:20:00 00:30:00 00:40:00 00:50:00 01:00:00 01:10:00 01:20:00 01:30:00 01:40:00 01:50:00 02:00:00 02:10:00 02:20:00 TI (°C) TE (°C) 33.6 34.8 31.1 28.5 26.6 25 24.7 24.4 23.7 22.8 22.5 22 21.4 20.9 20.2 19.7 19.2 19.2 19.4 19 18.5 18 17.8 18 18.2 18.2 18.2 18 17.8 17.7 17.7 17.5 17.3 17.3 17.1 17.1 17.3 17.5 17.5 17.1 16.8 16.5 16.5 16.5 16.5 16.5 16.3 16.1 15.9 15.9 15.9 33.2 28.8 25 24.6 21.6 23.6 23.1 22.7 22 21.7 22.4 21.1 21.2 20 19.6 19.5 19.5 19.9 19.1 18.8 18.1 18 18.7 19 19 18.7 18.7 18.3 18.1 17.7 17.8 17.7 17.4 17.8 12 18.1 18.4 18.6 17.2 16.4 16.1 16 16.1 16.2 16.5 16.2 16.3 16.2 16.2 16.1 16.1 HR Dir (°) DIR Vel. (Km/hr) 30.00% 26.00% 33.00% 39.00% 49.00% 54.00% 55.00% 57.00% 59.00% 61.00% 77.00% 68.00% 69.00% 72.00% 75.00% 78.00% 79.00% 80.00% 79.00% 73.00% 70.00% 72.00% 74.00% 75.00% 75.00% 78.00% 82.00% 84.00% 86.00% 87.00% 89.00% 86.00% 85.00% 86.00% 86.00% 86.00% 85.00% 84.00% 85.00% 87.00% 88.00% 89.00% 89.00% 90.00% 89.00% 89.00% 90.00% 91.00% 91.00% 92.00% 93.00% 283 276 293 360 263 282 282 282 281 281 281 285 281 305 319 273 348 244 349 315 21 359 359 360 358 57 0 49 32 6 296 254 246 246 239 194 176 182 213 235 246 276 276 277 9 9 51 39 47 47 360 ONO O ONO N O ONO ONO ONO O O O ONO O NO NO O NNO OSO N NO NNE N N N N ENE N NE NNE N ONO OSO OSO OSO OSO SSO S S SSO SO OSO O O O N N NE NE NE NE N 1.44 1.98 0.69 1.01 1.65 0 0 0 1.2 0 0 0.72 0 1.19 0 0.69 0 0 0 0 1.2 0 0 0 0 0 0 0.68 0 0 0 0.71 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.81 0 0.8 0 37 Fecha Hora 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 02:30:00 02:40:00 02:50:00 03:00:00 03:10:00 03:20:00 03:30:00 03:40:00 03:50:00 04:00:00 04:10:00 04:20:00 04:30:00 04:40:00 04:50:00 05:00:00 05:10:00 05:20:00 05:30:00 05:40:00 05:50:00 06:00:00 06:10:00 06:20:00 06:30:00 06:40:00 06:50:00 07:00:00 07:10:00 07:20:00 07:30:00 07:40:00 07:50:00 08:00:00 08:10:00 08:20:00 08:30:00 08:40:00 08:50:00 09:00:00 09:10:00 09:20:00 09:30:00 09:40:00 09:50:00 10:00:00 10:10:00 10:20:00 10:30:00 10:40:00 10:50:00 TI (°C) TE (°C) 15.8 15.4 15.4 15.3 15.3 15.1 15.1 15.1 14.9 14.9 15.1 15.1 14.9 14.9 14.9 14.6 14.4 14.4 14.4 14.2 14 14 13.9 13.9 13.9 13.9 13.9 13.9 13.7 14.2 14.4 14.2 14.4 14.7 14.7 14.7 14.9 15.1 15.4 15.8 16.5 17.1 17.5 17.7 17.8 18.3 19 19.9 20.6 20.8 21.6 15.7 15.8 15.7 16.3 15.5 15.6 15.6 15.5 15.5 15.9 15.3 15.9 15.5 15.2 15.4 15.2 15 15.7 14.6 14.7 14.7 14.5 15.7 14.9 14.4 15 14.7 14.5 15.8 15.5 16 16.3 16.2 16.3 16.7 16.4 16.4 16.7 17.3 18.2 18.9 18.9 19.4 18.7 19.2 19.7 20.6 21 20.6 21.6 22.6 HR Dir (°) DIR Vel. (Km/hr) 92.00% 92.00% 92.00% 92.00% 92.00% 92.00% 93.00% 93.00% 92.00% 93.00% 92.00% 91.00% 91.00% 91.00% 91.00% 91.00% 92.00% 92.00% 92.00% 92.00% 92.00% 92.00% 92.00% 92.00% 93.00% 92.00% 93.00% 93.00% 94.00% 94.00% 95.00% 96.00% 96.00% 96.00% 96.00% 96.00% 96.00% 96.00% 94.00% 94.00% 92.00% 88.00% 85.00% 82.00% 81.00% 78.00% 76.00% 74.00% 71.00% 69.00% 67.00% 45 339 15 25 10 28 36 35 35 36 35 36 36 35 35 35 36 35 35 35 35 35 35 36 36 35 36 35 35 35 35 36 35 35 35 35 35 35 36 36 36 36 36 36 36 36 36 36 36 36 36 NE NNO NNE NNE N NNE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE 0 0 0 0 0 0.9 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 38 Fecha Hora 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 11:00:00 11:10:00 11:20:00 11:30:00 11:40:00 11:50:00 12:00:00 12:10:00 12:20:00 12:30:00 12:40:00 12:50:00 13:00:00 13:10:00 13:20:00 13:30:00 13:40:00 13:50:00 14:00:00 14:10:00 14:20:00 14:30:00 14:40:00 14:50:00 15:00:00 15:10:00 15:20:00 15:30:00 15:40:00 15:50:00 16:00:00 16:10:00 16:20:00 16:30:00 16:40:00 16:50:00 17:00:00 17:10:00 17:20:00 17:30:00 17:40:00 17:50:00 18:00:00 18:10:00 18:20:00 18:30:00 18:40:00 18:50:00 19:00:00 19:10:00 19:20:00 TI (°C) TE (°C) 22.8 23.7 24.2 23.8 25.7 28.1 29.7 30.9 32.1 33 35.4 35 38.6 38.5 39.5 39.7 39.5 39.1 37.9 33.8 33.3 36.9 33.3 30.6 29.3 28.7 28.3 27.1 26.1 25.7 25.6 25.4 23 20.6 19.2 18.7 18.9 19.5 23.7 23.7 22.6 21.4 20.8 20.4 19.9 19.4 19 18.9 18.7 18.5 18.3 24.9 24.6 23.9 24.3 27.9 28.9 27.7 30.7 29.4 35.3 33 36.4 32.9 34.7 38.3 37.3 36.8 36.8 31.6 29.4 31.7 31.6 27.7 27.1 27.5 27.7 26.1 24.9 24.9 25.2 25.3 20.6 17.6 16.6 17 16.4 17 18.3 22.4 18.6 17.9 17.9 18.1 18.3 17.5 18.2 17.8 17.5 17.4 17.4 17 HR Dir (°) DIR Vel. (Km/hr) 65.00% 61.00% 58.00% 59.00% 54.00% 47.00% 42.00% 40.00% 36.00% 35.00% 31.00% 30.00% 25.00% 25.00% 24.00% 24.00% 23.00% 24.00% 24.00% 28.00% 30.00% 25.00% 29.00% 34.00% 37.00% 40.00% 40.00% 43.00% 45.00% 46.00% 47.00% 52.00% 63.00% 69.00% 73.00% 76.00% 77.00% 78.00% 63.00% 57.00% 61.00% 63.00% 67.00% 70.00% 74.00% 77.00% 77.00% 78.00% 80.00% 81.00% 81.00% 36 36 43 53 53 53 53 53 53 53 53 59 59 284 284 212 213 213 197 134 134 147 132 132 132 132 132 132 124 114 114 206 211 130 130 130 130 130 130 121 121 121 121 121 122 122 122 122 163 180 180 NE NE NE NE NE NE NE NE NE NE NE ENE ENE ONO ONO SSO SSO SSO SSO SE SE SSE SE SE SE SE SE SE SE ESE ESE SSO SSO SE SE SE SE SE SE ESE ESE ESE ESE ESE ESE ESE ESE ESE SSE S S 0 0 0 0 0 0 0 0 7.21 0 0 0 0 0 0 0 0 0 5.32 0 0 0 0 0 0 0 0 0 0 1.84 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 39 Fecha Hora 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 6/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 19:30:00 19:40:00 19:50:00 20:00:00 20:10:00 20:20:00 20:30:00 20:40:00 20:50:00 21:00:00 21:10:00 21:20:00 21:30:00 21:40:00 21:50:00 22:00:00 22:10:00 22:20:00 22:30:00 22:40:00 22:50:00 23:00:00 23:10:00 23:20:00 23:30:00 23:40:00 23:50:00 00:00:00 00:10:00 00:20:00 00:30:00 00:40:00 00:50:00 01:00:00 01:10:00 01:20:00 01:30:00 01:40:00 01:50:00 02:00:00 02:10:00 02:20:00 02:30:00 02:40:00 02:50:00 03:00:00 03:10:00 03:20:00 03:30:00 03:40:00 03:50:00 TI (°C) TE (°C) 18.2 17.8 17.8 17.5 17.5 17.3 17.3 17.1 17.1 17 16.8 16.8 16.6 16.6 16.5 16.5 16.3 16.5 16.5 16.5 16.3 16.5 16.5 16.5 16.5 16.3 16.3 16.5 16.3 16.3 16.1 15.9 16.1 16.1 16.1 16.1 16.1 15.9 16.1 16.3 16.3 16.1 16.1 16.1 15.9 15.9 15.9 15.9 15.9 15.8 15.8 16.8 17 16.9 16.8 16.9 15.9 16.9 17.1 17.2 17.5 17.5 17.2 17.5 17.5 16.9 16.9 17.9 16.9 19.7 16.7 16.5 16.8 17 17.5 16.9 16.9 17.2 17.2 16.9 17 17 16.7 16.9 17.2 17.9 18.8 17.2 17.2 17.4 17.5 17.4 17.3 17.3 17.3 17.4 17.3 17.5 17.6 17.5 17.6 17.5 HR Dir (°) DIR Vel. (Km/hr) 82.00% 82.00% 83.00% 83.00% 84.00% 85.00% 86.00% 85.00% 85.00% 86.00% 88.00% 88.00% 88.00% 87.00% 87.00% 88.00% 87.00% 88.00% 88.00% 88.00% 88.00% 89.00% 89.00% 89.00% 90.00% 90.00% 90.00% 91.00% 91.00% 91.00% 92.00% 92.00% 92.00% 92.00% 92.00% 93.00% 93.00% 93.00% 93.00% 93.00% 94.00% 94.00% 94.00% 94.00% 95.00% 95.00% 94.00% 94.00% 94.00% 94.00% 94.00% 237 237 237 237 236 236 245 0 0 19 55 44 26 1 65 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 OSO OSO OSO OSO SO SO OSO N N NNE NE NE NNE N ENE N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N 0 0 0 0 0 0 0.8 0 0 1.22 2.77 0 0.58 0.81 0 0.68 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 40 Fecha Hora 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 04:00:00 04:10:00 04:20:00 04:30:00 04:40:00 04:50:00 05:00:00 05:10:00 05:20:00 05:30:00 05:40:00 05:50:00 06:00:00 06:10:00 06:20:00 06:30:00 06:40:00 06:50:00 07:00:00 07:10:00 07:20:00 07:30:00 07:40:00 07:50:00 08:00:00 08:10:00 08:20:00 08:30:00 08:40:00 08:50:00 09:00:00 09:10:00 09:20:00 09:30:00 09:40:00 09:50:00 10:00:00 10:10:00 10:20:00 10:30:00 10:40:00 10:50:00 11:00:00 11:10:00 11:20:00 11:30:00 11:40:00 11:50:00 12:00:00 12:10:00 12:20:00 TI (°C) TE (°C) 15.8 15.8 15.8 15.8 15.8 15.6 15.8 15.6 15.8 15.8 15.6 15.6 15.8 15.4 15.3 15.4 15.4 15.4 15.3 15.3 15.1 15.1 14.9 14.9 14.9 14.9 15.3 15.4 15.8 16.1 16.6 17.1 17.8 18.2 18 18.5 19.2 20.8 21.8 22.1 22.1 22 23 23.5 24.2 25.4 26.3 27.5 27.5 28.1 28.7 17.4 18 17.8 17.5 17.5 17.8 18.2 18.1 15.9 18.2 16.4 18.1 16.4 17.3 17.9 18 17.5 17.8 17 17.2 17 16.9 16.9 17.1 16.9 17 18.1 18.2 18.4 18.6 19.3 20.4 20.7 20.4 20.1 21.7 22.8 24.2 24.2 23.9 23.5 22.6 25.1 25.6 27 25.7 26.8 28.8 28 28.2 28.9 HR Dir (°) DIR Vel. (Km/hr) 94.00% 94.00% 94.00% 94.00% 94.00% 94.00% 95.00% 94.00% 94.00% 94.00% 94.00% 94.00% 94.00% 94.00% 95.00% 94.00% 94.00% 94.00% 94.00% 95.00% 95.00% 94.00% 95.00% 95.00% 94.00% 93.00% 92.00% 92.00% 91.00% 90.00% 89.00% 88.00% 86.00% 86.00% 86.00% 91.00% 90.00% 88.00% 79.00% 72.00% 67.00% 67.00% 66.00% 60.00% 60.00% 57.00% 53.00% 48.00% 48.00% 45.00% 44.00% 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 2 5 5 5 5 5 5 5 33 10 10 N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N N NNE N N 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 41 Fecha Hora 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 12:30:00 12:40:00 12:50:00 13:00:00 13:10:00 13:20:00 13:30:00 13:40:00 13:50:00 14:00:00 14:10:00 14:20:00 14:30:00 14:40:00 14:50:00 15:00:00 15:10:00 15:20:00 15:30:00 15:40:00 15:50:00 16:00:00 16:10:00 16:20:00 16:30:00 16:40:00 16:50:00 17:00:00 17:10:00 17:20:00 17:30:00 17:40:00 17:50:00 18:00:00 18:10:00 18:20:00 18:30:00 18:40:00 18:50:00 19:00:00 19:10:00 19:20:00 19:30:00 19:40:00 19:50:00 20:00:00 20:10:00 20:20:00 20:30:00 20:40:00 20:50:00 TI (°C) TE (°C) 30.9 33.8 34.5 35.5 36.2 33.6 31.2 31.1 30.9 32.6 38.8 42.8 38.3 35.9 34.8 33.5 32.1 35.2 37.1 35.5 32.1 29.3 26.9 25.4 25 24.5 24.5 24.7 24.7 24.9 24.5 23.7 22.6 22 21.6 21.3 20.9 20.9 20.8 20.8 20.6 20.2 19.9 19.7 19.4 19.4 19.2 19 18.9 18.9 18.7 32.1 33 33.5 32.7 30.1 28.6 28.9 30.7 27.9 36.8 40.5 40.2 31 30.8 31.1 30.6 32.9 37.1 31.6 28 27.7 25.2 24.3 24.3 23.3 23.4 23.8 23.8 24.3 23.4 23.5 22.7 21.4 21.1 21.1 21 21.3 20.9 21 20.8 21 20.3 20 19.9 19.6 19.8 19.6 19.3 19.2 19.4 19.4 HR Dir (°) DIR Vel. (Km/hr) 40.00% 34.00% 30.00% 28.00% 27.00% 29.00% 34.00% 35.00% 34.00% 33.00% 25.00% 21.00% 23.00% 25.00% 27.00% 29.00% 31.00% 26.00% 23.00% 25.00% 30.00% 35.00% 40.00% 43.00% 45.00% 48.00% 45.00% 45.00% 46.00% 47.00% 49.00% 51.00% 56.00% 58.00% 60.00% 61.00% 62.00% 63.00% 64.00% 65.00% 66.00% 67.00% 68.00% 69.00% 68.00% 69.00% 69.00% 70.00% 71.00% 72.00% 74.00% 12 11 11 11 47 39 40 38 39 49 49 53 102 241 218 218 265 292 104 100 108 120 84 83 182 158 234 230 228 228 226 231 190 158 141 131 132 115 160 154 143 51 85 86 84 112 81 96 80 96 120 NNE N N N NE NE NE NE NE NE NE NE ESE OSO SO SO O ONO ESE E ESE ESE E E S SSE SO SO SO SO SO SO S SSE SE SE SE ESE SSE SSE SE NE E E E ESE E E E E ESE 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 5.46 1.03 1.51 0 0.99 0 1.64 1.25 1.65 1.48 1.78 2.05 0 0 2.27 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 42 Fecha Hora 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 7/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 21:00:00 21:10:00 21:20:00 21:30:00 21:40:00 21:50:00 22:00:00 22:10:00 22:20:00 22:30:00 22:40:00 22:50:00 23:00:00 23:10:00 23:20:00 23:30:00 23:40:00 23:50:00 00:00:00 00:10:00 00:20:00 00:30:00 00:40:00 00:50:00 01:00:00 01:10:00 01:20:00 01:30:00 01:40:00 01:50:00 02:00:00 02:10:00 02:20:00 02:30:00 02:40:00 02:50:00 03:00:00 03:10:00 03:20:00 03:30:00 03:40:00 03:50:00 04:00:00 04:10:00 04:20:00 04:30:00 04:40:00 04:50:00 05:00:00 05:10:00 05:20:00 TI (°C) TE (°C) 18.7 18.7 18.5 18.3 18.5 18.5 18.5 18.5 18.3 18.3 18.3 18.2 17.5 17 16.6 16.5 16.3 16.1 16.3 16.1 15.9 15.9 15.9 15.9 15.8 15.9 16.1 16.3 16.1 16.1 16.1 16.3 16.1 16.1 15.9 16.1 15.9 15.9 15.8 15.8 15.9 15.9 15.8 15.8 15.8 15.9 15.9 15.9 15.9 15.8 15.9 19.2 19.2 19.1 19.2 19.3 19.4 19.4 19.3 19.3 19.5 19.2 17.2 16.2 15.9 16.1 16.5 16.4 16.2 15.8 15.8 15.5 15.6 15.5 15.5 15.7 15.9 15.9 16.4 17.8 16.9 16.5 16.4 16.3 16.2 16.6 16.6 16.3 16.1 16.4 16.5 16.6 16.4 16.4 16.4 16.6 16.5 16.4 16.1 16.5 16.4 16.7 HR Dir (°) DIR Vel. (Km/hr) 74.00% 74.00% 76.00% 77.00% 76.00% 77.00% 77.00% 76.00% 76.00% 76.00% 75.00% 74.00% 77.00% 79.00% 80.00% 81.00% 81.00% 81.00% 82.00% 82.00% 83.00% 83.00% 84.00% 85.00% 85.00% 85.00% 85.00% 86.00% 86.00% 86.00% 87.00% 87.00% 88.00% 88.00% 88.00% 89.00% 89.00% 89.00% 89.00% 89.00% 89.00% 89.00% 90.00% 90.00% 90.00% 91.00% 90.00% 89.00% 89.00% 89.00% 89.00% 21 21 20 32 20 21 24 194 214 176 193 200 190 47 44 80 60 46 61 61 44 56 56 56 60 50 49 53 49 50 49 48 47 52 45 52 55 52 50 44 50 45 44 42 48 46 41 47 51 44 48 NNE NNE NNE NNE NNE NNE NNE SSO SO S SSO SSO S NE NE E ENE NE ENE ENE NE NE NE NE ENE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE NE 0 0 0 0 0 0 0 2.78 0.97 2.52 2.29 2.64 0.89 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 43 Fecha Hora 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 05:30:00 05:40:00 05:50:00 06:00:00 06:10:00 06:20:00 06:30:00 06:40:00 06:50:00 07:00:00 07:10:00 07:20:00 07:30:00 07:40:00 07:50:00 08:00:00 08:10:00 08:20:00 08:30:00 08:40:00 08:50:00 09:00:00 09:10:00 09:20:00 09:30:00 09:40:00 09:50:00 10:00:00 10:10:00 10:20:00 10:30:00 10:40:00 10:50:00 11:00:00 11:10:00 11:20:00 11:30:00 11:40:00 11:50:00 12:00:00 12:10:00 12:20:00 12:30:00 12:40:00 12:50:00 13:00:00 13:10:00 13:20:00 13:30:00 13:40:00 13:50:00 TI (°C) TE (°C) 15.9 15.9 15.8 15.8 15.6 15.6 15.8 15.6 15.6 15.6 15.4 15.3 15.1 15.1 14.9 14.9 15.1 15.4 15.8 15.9 16.3 16.8 17.1 17.3 17.8 18.7 19.9 20.8 20.9 21.3 21.8 22.3 23.2 23.7 24.9 26.1 26.9 28.3 29.9 30.6 32.1 32.3 33.1 35.7 38.5 37.1 33 36.6 34.8 32.3 33.8 17 17 16.8 16.9 17 16.9 16.9 16.8 17 16.7 16.6 16.6 16.6 16.3 16.4 14.1 16.9 17 17 17.7 17.7 18.3 18.6 18.8 17 21.2 22.1 21.6 21.4 22.1 22.4 23.1 23.5 24.1 26.7 27.9 26.6 29.1 30.2 32 31.3 32 33.7 33.8 36 29.6 30 32.8 30.5 29.3 30 HR Dir (°) DIR Vel. (Km/hr) 88.00% 88.00% 89.00% 89.00% 89.00% 90.00% 91.00% 91.00% 91.00% 90.00% 91.00% 92.00% 90.00% 90.00% 89.00% 89.00% 89.00% 88.00% 87.00% 86.00% 85.00% 84.00% 84.00% 83.00% 87.00% 84.00% 80.00% 74.00% 70.00% 68.00% 66.00% 64.00% 60.00% 57.00% 53.00% 50.00% 47.00% 43.00% 39.00% 37.00% 34.00% 34.00% 31.00% 27.00% 24.00% 23.00% 30.00% 25.00% 26.00% 31.00% 27.00% 47 46 43 42 46 49 47 42 48 48 49 64 43 42 41 41 41 43 44 42 40 45 35 40 146 87 96 117 110 111 93 83 48 61 62 41 40 44 53 51 49 52 65 44 52 67 62 48 50 60 46 NE NE NE NE NE NE NE NE NE NE NE ENE NE NE NE NE NE NE NE NE NE NE NE NE SE E E ESE ESE ESE E E NE ENE ENE NE NE NE NE NE NE NE ENE NE NE ENE ENE NE NE ENE NE 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.93 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 44 Fecha Hora 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 8/09/04 14:00:00 14:10:00 14:20:00 14:30:00 14:40:00 14:50:00 15:00:00 15:10:00 15:20:00 15:30:00 15:40:00 15:50:00 16:00:00 16:10:00 16:20:00 16:30:00 16:40:00 16:50:00 17:00:00 17:10:00 17:20:00 17:30:00 17:40:00 17:50:00 18:00:00 18:10:00 18:20:00 18:30:00 18:40:00 18:50:00 19:00:00 19:10:00 19:20:00 19:30:00 19:40:00 19:50:00 20:00:00 20:10:00 20:20:00 20:30:00 20:40:00 20:50:00 21:00:00 21:10:00 21:20:00 21:30:00 21:40:00 21:50:00 22:00:00 22:10:00 22:20:00 TI (°C) TE (°C) 33 31.4 29.2 28.1 27.8 28.5 29.2 31.4 30.9 30.4 31.2 34.2 33.5 30 26.8 24.2 22 21.1 20.6 20.9 20.6 20.4 20.2 20.2 20.1 19.7 19.5 19.4 19.4 19.4 19.2 19 18.9 18.5 18.3 18.3 18.2 18 17.8 17.7 17.5 17.5 17.5 17.5 17.5 17.3 17.3 17.1 17.1 17 17 30 28.3 26.1 25.9 27.1 28.2 28.8 31.1 28.5 28.9 34 32.7 27.7 25.6 22.2 19.1 18.1 18.3 17.7 18.8 18 18.9 18.3 18.4 18.4 18.7 18.6 19.6 19.7 19.1 19.5 18.7 18.8 18.9 18.9 19 18.8 18.6 18.3 18 18.2 17.7 18.2 18 18 18 17.1 17.3 17 17 17.4 HR Dir (°) DIR Vel. (Km/hr) 29.00% 31.00% 35.00% 38.00% 40.00% 38.00% 37.00% 32.00% 32.00% 33.00% 32.00% 27.00% 27.00% 31.00% 41.00% 52.00% 62.00% 65.00% 68.00% 67.00% 67.00% 68.00% 67.00% 68.00% 68.00% 70.00% 69.00% 69.00% 70.00% 69.00% 69.00% 70.00% 71.00% 73.00% 74.00% 75.00% 76.00% 76.00% 75.00% 77.00% 76.00% 77.00% 77.00% 77.00% 77.00% 76.00% 75.00% 74.00% 72.00% 70.00% 67.00% 47 59 42 41 41 41 41 41 39 39 41 51 20 5 100 21 97 94 78 76 4 4 5 4 8 96 94 93 93 5 18 17 35 27 15 15 20 14 14 14 13 13 14 14 14 14 14 13 13 13 12 NE ENE NE NE NE NE NE NE NE NE NE NE NNE N E NNE E E ENE ENE N N N N N E E E E N NNE NNE NE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE NNE 0 0 0 0 0 0 0 0 0 0 0 0 1.03 0 2.28 1.32 0 1.39 0.79 0 0.73 0 0.67 1.03 0.74 1.07 0 0 0 0 0 0 0.58 0 1.26 89.3 0.82 0 0 0 0 0 0 0 0 0 0 0 0 0 0 45 Tabla 4.4 Resultados de la prueba a la intemperie. Te m pe ratura m e dida por la e s tación m e te orológica 50 45 40 Temperatura (°C) 35 30 TI (°C) 25 TE (°C) 20 15 10 5 0 04/09/20 05/09/20 05/09/20 06/09/20 06/09/20 07/09/20 07/09/20 08/09/20 08/09/20 09/09/20 09/09/20 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 Fe cha/Hora Figura 4.1 Gráfica de la temperatura interna y externa M e dicione s de la hum e dad re lativa 120.00% Humedad Relativa (%) 100.00% 80.00% 60.00% HR 40.00% 20.00% 0.00% 04/09/20 05/09/20 05/09/20 06/09/20 06/09/20 07/09/20 07/09/20 08/09/20 08/09/20 09/09/20 09/09/20 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 04 00:00 04 12:00 Fe cha / Hora Figura 4.2 Gráfica de la humedad relativa 46 El hecho de que las mediciones se hayan realizado en medio de una zona urbana y el de que la estación se colocara al lado de una pared de mampostería en una caja cerrada afectaron las mediciones. Las temperaturas máximas registradas (43°C) fueron en general más altas que las reportadas por el servicio meteorológico para la ciudad (min. 15°C, máx. 26°C). Lo anterior fue debido al efecto de invernadero que se presento en la caja plástica y al calor almacenado en la pared. Se observan descensos importantes en la temperatura que coinciden con las visitas para comprobar el funcionamiento de la estación, durante las cuales se abría la caja plástica y se dejaba escapar más rápidamente el aire caliente. En cuanto a las temperaturas mínimas, no se vieron tan afectadas ya que durante la noche el calor almacenado se disipaba y a las siete de la mañana (la hora en que se presentaba la temperatura mínima) ya no tenía ningún efecto en la medición de la temperatura. En cuanto a la velocidad del viento, todas las lecturas obtenidas fueron de magnitud pequeña, debido a que las construcciones circundantes al lugar donde se realizo la prueba impiden el paso de vientos fuertes. La presencia de ráfagas esporádicas de viento hacia que la posición de la veleta se mantuviera fija por periodos de tiempo considerables. Finalmente la humedad relativa fue muy alta debido a que durante los días de la prueba llovió por la tarde y noche. La humedad relativa reportada por el servicio meteorológico fluctuó entre el 50 y el 100%, mientras que la medida por la estación vario entre el 20 y el 98%. La discrepancia en el valor mínimo se debe a que el sensor de humedad se encuentra en el interior del gabinete de la estación, donde se presentaron temperaturas superiores a 40°C que contribuyeron a la reducción de la humedad relativa. 47 4.4- Conclusiones En el desarrollo del presente trabajo, se diseño y construyó un prototipo de una estación meteorológica capaz de medir, registrar y comunicar cinco variables diferentes. Este prototipo cumple con los requisitos planteados en los objetivos del presente trabajo. Puede medir cinco variables atmosféricas y almacenar los resultados de las mediciones por un periodo de treinta días. También es capaz de transmitir los datos capturados a una computadora personal a través de un módem analógico o GSM. Los costos de manufactura de la estación son los suficientemente bajos como para que se pueda considerar para emplearse en los proyectos de investigación y desarrollo de la fundación PRODUCE de Michoacán. El prototipo fue evaluado por los investigadores en agricultura de la fundación Produce de Michoacán y en su opinión esta en condiciones para ser utilizado en sus programas de investigación. Aunque este primer prototipo aún no se encuentra listo para una producción comercial, si puede usarse en programas de investigación en agricultura y en el desarrollo de una versión mejorada que si pueda fabricarse en masa y distribuirse a los productores agrarios del estado de Michoacán. En caso de que el prototipo llegue a producirse en masa como parte la puesta en practica de las técnicas mejoradas de producción que consideran al microclima local, el impacto de la estación en la productividad de los cultivos seria bastante importante, ya que preemitiría utilizar técnicas de riego, abono y fumigación que ahorren insumos y sean más eficientes. El proceso de diseño del equipo se documento de manera que puede servir para que las personas interesadas en diseñar un equipo similar conozcan los retos a los que pudieran enfrentarse, algunas posibles soluciones y recomendaciones para la toma de decisiones en el proceso de diseño. 48 4.5- Trabajo Futuro Al presentar el equipo a los investigadores de la Fundación Produce de Michoacán, estos quedaron contentos con el funcionamiento de la estación en cuanto a la medición de las variables meteorológicas y su almacenamiento, pero les pareció que el usar un módem y una línea telefónica, así sea una línea privada, iba a resultar poco práctico para los productores. La solución que se propone es hacer el enlace por medio de radiofrecuencia. Este cambio seria conveniente desde el punto de ahorro de engría ya que permitiría eliminar la interfase RS232 y al comunicarse por medio de un equipo transciver de RF conectado a una PC, podría eliminarse también la pantalla LCD y el teclado. Estos tres elementos, junto con el módem externo, son los que consumen la mayor cantidad de energía. Ya que existen módulos de RF que tienen un consumo de potencia muy bajo, es posible que se logre una unidad con menor consumo de energía, más compacta y más fácil de instalar. Como ya no se contara con una pantalla LCD la interfase del usuario se reducirá a un LED que parpadee al presionar una tecla, indicando que la estación funciona correctamente. El código de la interfase de usuario seria sustituido por código para responder a los comandos enviados a la estación por un programa ejecutándose en una PC, vía RF. El equipamiento de los productores con una PC para fines administrativos es un proyecto que ya se encuentra en marcha por parte de la fundación produce de Michoacán y esta misma puede ser usada para la recolección de datos de las estaciones meteorológicas. Él utilizar un entorno gráfico con menús y ventanas para trabajar con la estación meteorológica debe resultar más familiar y sencillo para los usuarios finales que la interfase LCD. El otro aspecto que debe mejorarse es el gabinete de la estación, que debe ser apto para proteger a la estación de la intemperie, pero debe tener una buena ventilación para evitar que el calor se acumule en su interior y afecte a las mediciones. También debe poder colocarse en lo alto de una torre, cerrarse con llave y resistir ataque vandálicos menores. 49 Bibliografía Acosta Jimeno, C. A. y otros. (1998) “Central hospitalaria de monitoreo” Memorias del XX Congreso internacional académico de ingeniería electrónica, ELECTRO’99. Chihuahua: Instituto Tecnológico de Chihuahua. Benitez Villalobos, Juan y otros. (1997) “Digitalización de un sistema de adquisición de datos para aplicaciones agrícolas” Memorias del VII Congreso interuniversitario de computación, eléctrica y electrónica, CIECE’97. Ensenada: Universidad Autónoma de Baja California. Bursky, Dave (1999) “Feature-rich flash memories deliver high density”. Electronic Design.; 9 de agosto de 1999; Vol. 47, No. 16; p. 67. Cleveland: Penton Media. Carlson Wireless Telephone, Inc. (1999) All Digital Remote Phone Link <http://www.i-wll.com/> (pagina web) Redway, CA: autor Carter, Bruce y Brown, Thomas R (2001). Handbook of operational amplifier aplications Dallas: Texas Instruments Inc. Disponible en < http://www.ti.com/msp430 > (pagina web, Núm. de doc. SBOA092A) Gracey, Ken (1999). “Connect a modem to a basic stamp”. EDN. 16 de septiembre 1999; Vol. 44, No. 19; pg. 194. Boston: Cahners Magazine. Malik, Norbert R. (1996) Circuitos electrónicos , análisis, simulación y diseño. Madrid Prentice Hall. Manzini, Ron (2001). Single-Supply Op Amp Design Techniques Application report. Dallas: Texas Instruments Inc. Disponible en < http://www.ti.com/msp430 > (pagina web, Núm. de doc. SLOA030A) Oppenheim, Allan V. et all Tratamiento de señales en tiempo discreto. Madrid Prentice Pass, David A. y Mamane, Charles. (1999) “Interactive telemetry controls remedial operations at hazardous waste site”. Pollution Engineering.; Abril de1999; Vol. 31, No. 4; p. 42. Newton: Cahners Magazine Rashid, Muhammad H. (2000) Circuitos micro electrónicos, análisis y diseño México D.F.: International Thomson Editores Texas Instruments Inc. (2003) MSP430x1xx Family Users Guide Dallas: Texas Instruments Inc. Disponible en < http://www.ti.com/msp430 > (pagina web, Núm. de doc. SLAU49C) Texas Instruments Inc. (2000) MSP430x13x, MSP430x14x, MSP430x14x1MIXED SIGNAL MICROCONTROLLER Data sheet Dallas: autor. Disponible en < http://www.ti.com/msp430 > (pagina web, Núm. de doc. SLAS272E) Texas Instruments Inc. (2000) MAX3223 Data sheet Dallas: autor. Disponible en < http://www.ti.com/msp430 > (pagina web, Núm. de doc. SLLS409K) 50 Texas Instruments Inc. (1996) TLV2442, TLV2442A, TLV2444, TLV2444A Advanced LinCMOS. RAIL-TO-RAIL OUTPUT WIDE-INPUT-VOLTAGE OPERATIONAL AMPLIFIERS Data sheet Dallas : autor. Disponible en < http://www.ti.com/msp430 > (pagina web, Núm. de doc. SLOS169H) Wait, John V. y otros (1992). Introduction to operational amplifier, theory and applications. New York (2ª Edición): McGraw Hill International Editions. 51 Índice de figuras Figura 2.1 Amplificador sumador no inversor...........................................................................................5 Figura 2.2 Amplificador sumador con entrada diferencial........................................................................ 5 Figura 2.3 Convertidor AD de aproximaciones sucesivas......................................................................... 7 Figura 2.4 Convertidor AD tipo ráfaga o flash de tres bits........................................................................8 Figura 2.5 Convertidor AD de doble integración.......................................................................................9 Figura 2.6 Estructura principal del programa.......................................................................................... 10 Figura 3.1 – Diagrama a bloques de la estación meteorológica ..............................................................13 Figura 3.2 Diagrama de flujo del proceso de medición y almacenamiento de la estación meteorológica. ..................................................................................................................................................................15 Figura 3.3 - Diagrama eléctrico del subsistema de alimentación.............................................................16 Figura 3.4 Amplificador diferencial con desplazamiento. ...................................................................... 17 Figura 3.5 Diagrama del circuito de acondicionamiento para el sensor de temperatura........................ 17 Figura 3.6 Diagrama eléctrico de circuito de acondicionamiento del sensor de humedad relativa......... 18 Figura 3.7 Diagrama eléctrico de circuito de acondicionamiento del anemómetro y la veleta............... 18 Figura 3.8 Curva Temperatura contra voltaje de salida de sensor interno del MSP430 .........................19 Figura 3.9 Circuito de conversión de niveles lógicos a RS232................................................................19 Figura 3.10 Conexiones del microcontrolador.........................................................................................20 Figura 3.11 Información de calibración del sensor de humedad............................................................. 23 Figura 3.12 – Entorno de desarrollo Gambas.......................................................................................... 30 Figura 3.13 – Captura de pantalla del programa de recepción.................................................................31 Figura 4.1 Gráfica de la temperatura interna y externa............................................................................46 Figura 4.2 Gráfica de la humedad relativa............................................................................................... 46 52 Índice de tablas Tabla 3.1 Variables a medir por la estación meteorológica..................................................................... 11 Tabla 3.2 – Etapas del proceso de medición............................................................................................ 26 Tabla 3.3 - Listado de los menús de la estación meteorológica...............................................................27 Figura 3.4 - Etapas de la rutina de transmisión de datos..........................................................................28 Tabla 3.5 – Etapas del proceso de recepción en la PC.............................................................................31 Tabla 4.1 Resultados de las mediciones para la calibración de la medición interna............................... 32 Tabla 4.2 Resultados de las mediciones para la calibración de la medición interna............................... 33 Tabla 4.3 – Mediciones de la calibración de la velocidad del viento...................................................... 34 Tabla 4.4 Resultados de la prueba a la intemperie...................................................................................46 53 Apéndice A - Diagrama Eléctrico de la estación meteorológica 54 Apéndice B – Circuito impreso de la estación meteorológica Fondo Frente 55 56 Apéndice C – Listado del programa de la estación meteorológica Modulo principal5.c // ****************************************************************************************** // Programa principal de la estacion meteorologica // // Hecho por Miguelangel Fraga Aguilar // // ******************** // Version 0.1 20/JUL/04 // Proporciona el marco de referencia para el intercambio de tareas cooperativo, el control // de la frecuencia de reloj Rc (DCO) e implementa un reloj de tiempo real por software // // Presupone que ACLK=32,768Hz, MCLK=SMCLK=DCO=1,048,576Hz // // En el ciclo principal se ejecuta cada 1000mS y llama a cada una de las tereas en orden y // al final entra en modo de ahorro de energia. // El reloj de tiempo real son 3 variables enteras que son actualizadas por la interrupci� // del temporizador vigia que trabaja como temporizador de intervalo // Para regular la frecueccia del DCO, esta se mide usando el temporizador A en modo continuo // y tomando com referencia la se�l del cristal de 32,768Hz. Si el valor medido es diferente // de el deseado, entonces se modifica la frecuencia del DCO // // *************************** // Version 0.2 04/agosto/2004 // Se conecta un teclado de cuatro teclas al puerto 1 bits 0 a 3 // Se detecta una pulsacion por medio de la interrupcion del puerto 1, de eliminan // los rebotes por medio de un retardo usando el timer B. // // *************************** // Version 0.3 10/agosto/04 // Cambia el periodo de la interrupcion de tiempo real de 1S a 250mS // inclulle una version basica de la interfaz de usuario // // *************************** // Version 0.3 20/agosto/04 // Portado a la version 3.2 del compilador IAR // Inclulle una version basica de las rutinas de comunicaciones // El reloj de tiempo real modifica el dia, mes y anio� // // *************************** // Version 0.4 20/septiembre/04 // Modificada para poder compilase con GCC para poder sobrepasar el limite de 4KB de codigo // del compilador IAR // // *************************** // version 0.5 17/enero/06 // Se incluye la opción de llamar a un telefono celular dados las bajas tarifas en llamadas de cel a cel // El cambio principal se da en el archivo interfaz.c // **************************** // Version0.5.1 10/04/06 // Se corrigen varios problemas de comunicacion, la transmision se pasa de binaria a // texto en hexadecimal. Se incluye control de flujo por hardware en la transmisión. // Los cambios principales se dan en los archivos transmite.c y serie2.c //****************************************************************************************** * #ifndef GCC #include <msp430x14x.h> #else 57 #include <io.h> #include <signal.h> #endif #include <stdio.h> #include "lcdand.h" #include "serie.h" //Cabeceras de funciones void Ajusta_DCO (void); void interfaz(char tecla); void programa_medicion(void); void mide(void); void transmite(void); // Variables globales // Reloj de tiempo real char cuartos=0, segundos=0,minutos=0,horas=0; char dia=0,mes=0, ano=0; // Resultados de las ultimas mediociones int int int int int temp_i=0; temp_e=0; velocidad=0; direccion=0; humedad=0; //Temperatura Interna C //Temperatura Externa C //Velocidad del Viento Km/Hr //Direccion del viento //Humedad relativa % //varibles para el ADC static unsigned int ADCresult,ADCresult2,ADCresult3,ADCresult4; // Medicion de la velocidad del viento unsigned T1,T2; unsigned periodo; char contseg; //contador para saber cuando se excede el periodo maximo. char banderas; // Varias banderas. // Bit 0 - Indica que ya se detecto el primer flanco de subida // Bit 1 - Indica que ya se detecto el segundo flanco de subida // Banderas de teclado unsigned char tecla; // /* Velocidad de capura 0 - cada 10 minutos 1 - cada hora */ char vel_cap=0; /*badera paraindicar si se esta realizando una medicion*/ char midiendo =0; /*variables que indican cuando se realizara la siguiente medicion*/ char hora_pro=0, minuto_pro=10; int *puntero= (int *)0x1200; //Inicio de la memoria Flash dedicada a almacenar datos int transmitiendo=0; //indica cuando se esta realizando una transmision int gsm=0; //indica si el modem receptor es un modem analogico (0) o un celular GSM (1) // Telefono a marcar para transmitir los datos char tel[17]=" "; //****************************************************************************** 58 //Programa principal int main(void) { WDTCTL = WDT_ADLY_250; // WDT funciona como interval timer con periodo de 250mS IE1 |= WDTIE; // Habilita la interupci� del WDT P1DIR = 0xF0; // Programa P1.x como salidas //Excepto los bits 0 a 3 que son las entradas del teclado P1OUT = 0; // borra P1.x P2DIR = 0xFF; // Programa P2.x como salidas P2OUT = 0; // borra P2.x P3DIR = 0xDA; // Programa P3.x como salidas //Exepto los bits 0,2 y 5 que reciben informaci� del puerto serie P3OUT = BIT3; // borra P3.x, exepto P3.1 // El bit p3.1 =0 activa al MAX3222E para las comunicaciones serie P3SEL |= 0x30; // P3.4,5 = USART0 TXD/RXD P5DIR = 0xFF; // Programa P5.x como salidas P5OUT = 0; P5SEL=0; P4DIR = 0xF7; // Programa P4.x como salidas //Exepto bit 3 P4OUT = 3; // borra P4.x //exepto bits 0 y 1 para mantener apagado la fuentes de 5V // borra P5.x P6DIR = 0xF8; // Programa P6.x como salidas //Exepto bits 0,1 y 2 P6OUT = 0; // borra P6.x //Preparacion del timer B para medir el periodo del anemometro y el retardo del teclado TBCTL=TBSSEL_1+MC_2; // Selecciona ACLK como reloj, modo continuo TBCCTL3=CM_1+CAP;//+CCIE; // Habilita captura, Captura en flanco de subida // y habilita interrupcion de TBCCR3 banderas=0; //Indica que no se ha presentado ningun flanco contseg=0; //Borra el contador de tiempo maximo P4SEL=BIT3; //Asigna la terminal P4.3 Anemometro al timer BCSCTL1=0X5; DCOCTL=0X20; Ajusta_DCO(); //inicializa el puerto serie 0. Puede quedar permanentemente activado ya que al pasar a LPM3 se //desactiva automaticamente. Solo el MAX3222E debe ser desactivado para ahorrar energia //P3OUT &= ~ BIT1; //Activa el MAX3222E UCTL0 |= CHAR + SWRST; // caracter de 8-bits , pone SWRST = 1 UTCTL0 |= SSEL1 + SSEL0; // + URXSE; // UCLK = SMCLK, no activa deteccion de flanco de inicio UBR00 = 0x6D; // 9600 a partir 1Mhz UBR10 = 0x00; UMCTL0 = 0x00; // sin modulacion ME1 |= UTXE0 + URXE0; // activa los modulos TXD/RXD del USART0 UCTL0 &= ~SWRST; // Inicializa el USART IE1 |= URXIE0; // habilita la interucion de RX del USART0 // Prepara las interrupciones del puerto 1 para esperar que se presione una tecla P1IES&=0xF0; // Interrupcion en el flanco de bajada P1IFG=0; // Borra las interrupciones pendientes P1IE|=0x0f; // habilita interrupcion en los bits bajos de P1 _EINT(); // Enable interrupts 59 /********************************************************************************* Ciclo Principal *********************************************************************************/ while(1) { /*Si hay una tecla presionada, la envia a la rutina de interface de usuario para que sea procesada*/ if(tecla!=0){ //putserial(tecla+'0'); //para depuracion interfaz(tecla); } tecla=0; mide(); transmite(); if((midiendo==0)&&(transmitiendo==0)) { _BIS_SR(LPM3_bits); // Entra al modo LPM3 } else { _BIS_SR(LPM0_bits); // o al modo LPM0 } } return(0); } interrupt (WDT_VECTOR) watchdog_timer(void) { cuartos++; if (cuartos>=4){ cuartos=0; segundos++; if(segundos >= 60){ segundos=0; minutos++; if(minutos>=60){ minutos=0; horas++; if(horas>=24) horas=0; dia++; if ( (mes==1 && dia>31)|| (mes==2 && dia>28 && ano%4!=0)|| (mes==2 && dia>29 && ano%4==0)|| (mes==3 && dia>31)|| (mes==4 && dia>30)|| (mes==5 && dia>31)|| (mes==6 && dia>30)|| (mes==7 && dia>31)|| (mes==8 && dia>31)|| (mes==9 && dia>30)|| (mes==10 && dia>31)|| (mes==11 && dia>30)|| (mes==12 && dia>31) ){ dia=1; mes++; if(mes>12){ mes=1; ano++; } } } 60 } } _BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR) } // Rutina de interrupcion del puerto 1 // Se activa al presionarsee un intrruptor del teclado interrupt ( PORT1_VECTOR ) port1_ISR( void ) { P1IFG=0; //Borra la bandera de interrupcion P1IE=0; //Deshabilita las interrupciones de P1 //Programa una captura en 25mS para eliminar rebotes TBCCR1=TBR+819; // 819=.025S*32768HZ= pulsos en 25mS TBCCTL1|= CCIE; } //************************************************************************** // ajusta el DCO a la frecuencia selecionada // Usa el timer A para medir la frecuencia del DCO // Trabaja por medio de escrutio y no de interrupciones por que a las frecuencias // de MCLK y ACLK hacen que en el tiempo de captura sea menor que el de respuesta // a una interrupcion. // Por lo anterior esta rutina debe llamarse con las interrupciones desactivadas void Ajusta_DCO (void) { #define DELTA 1024 // Frecuencia deseada en DCO = DELTA*(1024 HZ) = 1048576 //variables usadas para el control de la frecuencia del DCO unsigned int Captura=0, Captura_Ant; unsigned int cuenta_cap; _DINT(); //Deshabilita las interrupciones //configura el timer A CCTL2 = CM_1 + CCIS_1 + CAP ; // Captura en flanco de subida, entrada=ACLK TACTL = TASSEL_2 + MC_2 + TACLR; // reloj de TA=SMCLK, modo continuo, borrar TA while(1){ //Ciclo infinito, se sale de el cuando se alcanza la frecuncia deseada while (!(CCIFG & CCTL2)); // Espera a que ocurra una captura CCTL2 &= ~CCIFG; // ocurrio una captura, borra la bandera Captura_Ant = CCR2; // Almacena la captura actual cuenta_cap = 0; while (cuenta_cap < 32){ //Espera a que ocurran 32 capturas (32768/32=1024) while (!(CCIFG & CCTL2)); // Espera a que ocurra una captura CCTL2 &= ~CCIFG; // ocurrio una captura, borra la bandera cuenta_cap++; } Captura = CCR2; // Lee el valor de la captura Captura = Captura - Captura_Ant; // Resta la captura anterior if (( Captura>= DELTA-1) && (Captura<= DELTA+1)) break; // Si es el valor deseado, salir del ciclo else if (DELTA < Captura) { DCOCTL--; if (DCOCTL == 0xFF) // el DCO esta muy rapido, bajar velocidad { if (!(BCSCTL1 == (XT2OFF + DIVA_3))) BCSCTL1--; // Se alcanzo la frec. menor?, } // Seleccionar RSEL m� bajo 61 } else { DCOCTL++; // el DCO esta muy lento, aumentar velocidad if (DCOCTL == 0x00) { if (!(BCSCTL1 == (XT2OFF + DIVA_3 + 0x07))) BCSCTL1++; // Se alcanzo la frecuencia mayor? } // Escoger RSEL mas alta } } // fin del ciclo infinito _EINT(); //habilita las interrupciones CCTL2 = 0; // detener CCR2 TACTL = 0; // detner Timer_A } //ISR tic1 interrupt ( TIMERB1_VECTOR ) TIMERBISR( void ) { unsigned char mascara,valor,i; switch (TBIV) { case 2: //CCR1 TBCCTL1&= ~CCIE; //Deshabilita la interrupci� del timer mascara=1; i=4; valor=0; if((P1IN&0x0f)==0) { // Ninguna tecla esta presionada, volver a esperar que se presione // Prepara las interrupciones del puerto 1 para esperar que se presione una tecla P1IES&=0xF0; P1IFG=0; P1IE|=0x0f; // Interrupcion en el flanco de subida // Borra las interrupciones pendientes // habilita interrupcion en los bits bajos de P1 }else { if ((P1IES&0x0f)==0){ //Si se comprobo que la tecla fue presionada, revisar de que teclas se trata do{ valor++; if( (P1IN & mascara)!=0) break; i--; mascara<<=1; //Corre la mascara para probar el siguiente bit }while(i>0); tecla=valor; } // Espera a que se libere la tecla // Prepara las interrupciones del puerto 1 para esperar que se presione una tecla P1IES|=0x0F; P1IFG=0; P1IE|=0x0f; // Interrupcion en el flanco de bajada // Borra las interrupciones pendientes // habilita interrupcion en los bits bajos de P1 } break; case 4: break; //CCR2 case 6: T2=TBCCR3; if ((banderas & BIT0)==0){ //Si es el primer flanco T1=T2; banderas |= BIT0; //indica que ya paso el primer flanco 62 case case case case } }else{ // Si es el segundo flanco de un periodo periodo=T2-T1; T1=T2; banderas |= BIT1; //indica que ya hay una medici� lista para usarse contseg=0; //Pone el contador de tiempo m�imo a cero } 8: break; //CCR4 10: break; //CCR5 12: break; //CCR6 14: break; //TBOV } interrupt ( ADC_VECTOR ) ADC12ISR( void ) { ADCresult = ADC12MEM0; // Temperatura interna ADCresult2 = ADC12MEM1; // Temperatura externa ADCresult3 = ADC12MEM2; // Veleta ADCresult4 = ADC12MEM3; // Humedad _BIC_SR_IRQ(LPM3_bits); // Sale del modo LPM3 } void programa_medicion(void) { if(vel_cap){ if(horas<23)hora_pro=horas+1; else hora_pro=0; minuto_pro=minutos; }else{ minuto_pro=minutos+10; if (minuto_pro>=60){ minuto_pro-=60; if(horas<23)hora_pro=horas+1; else hora_pro=0; }else hora_pro=horas; } } //****************************************************************************** //Escribe una palabra en la Flash revisando si es una direcci� valida y si es //necesario borrar el segmento void flash_write(int dato) { if(((unsigned int)puntero)< (0xDE00-1)){ //Si no se ha llegado al final de la memoria if(((unsigned int)puntero & 0x1FF)==0){ //Si es el inicio de un segmento de 512Bytes FCTL1 = FWKEY + ERASE; // Activa el bit de borrado FCTL3 = FWKEY; // Borra el bit de bloqueo *puntero = 0; // falsa escritura para iniciar el borrado } FCTL3 = FWKEY; // Borra el bit de bloqueo FCTL1 = FWKEY + WRT; // Activa el bit de escritura *puntero++ = dato; // Escribe el valor a la flash FCTL1 = FWKEY; FCTL3 = FWKEY + LOCK; // Borra el bit de escritura // Activa el bit de bloqueo de la FLASH } } void mide(void) { static int etapa_med=0; int X; 63 switch(etapa_med){ case 0: if(hora_pro==horas) if(minuto_pro==minutos){ P4OUT&=~BIT0; //enciende la fuente de los sensores etapa_med++; midiendo=1; //Prepara la medicion de la vel. del viento, banderas=0; //Indica que no se ha presentado ningun flanco contseg=0; //Borra el contador de tiempo maximo } break; case 1: TBCCTL3|=CCIE; // Habilita la interrupcion por captura, Captura en flanco de subida // Preparacion del convertidor analogico a digital ADC12CTL0 = ADC12ON+MSC+REFON+REF2_5V+SHT0_6; // programa ADC12, ref., muestreo, // Multiples conversiones ADC12CTL1 = SHP+CONSEQ_1; // Usa el temporizador de muestreo, // una secuencia de conversiones ADC12MCTL0 = INCH_10+SREF_1; // Selecciona el canal A10, Vref+ ADC12MCTL1 = INCH_0+SREF_1; // Selecciona el canal A0, Vref+ ADC12MCTL2 = INCH_1; // Selecciona el canal A1 con AVCC como referencia ADC12MCTL3 = INCH_2+EOS; // Selecciona el canal A2, con AVCC ADC12IE = 0x04; // habilita las interrupciones con ADC12IFG.0 P6SEL=BIT0+BIT1+BIT2; etapa_med++; //espera otros 250mS para que se estabilicen las fuentes break; case 2: ADC12CTL0 |= ENC; // habilita las conversiones conversions ADC12CTL0 |= ADC12SC; // inicia la conversion _BIS_SR(LPM0_bits); // Enter LPM0 // temp_i = (Vsensor - 986mV)/3.55mV // Vsensor = (Vref)(ADCresult)/4095) // temp_i -> ((ADCresult - 1615)*704)/4095 temp_i = ((((long)ADCresult-1608)*7145)/4095); // temp_e = (Vsensor - 816mV)/10mV // Vsensor = (2.5)(ADCresult2)/4095) // temp_e -> ((ADCresult - 1365)*250)/4095 temp_e = ((((long)ADCresult2-1330)*2462)/4095); // Convierte el voltaje de la veleta a grados. direccion = ((((long)ADCresult3)*360)/4095); // Convierte el voltaje del sensor de humedad a porcentaje. humedad = (((unsigned long)ADCresult4-739)*161/4095); //apagado del conversor A/D ADC12CTL0 = 0; ADC12CTL1 = 0; ADC12IE = 0x0; etapa_med++; break; case 3: break; // se espera la medicion de la velocidad del viento case 4: // Escritura de los resultados en la Flash _DINT(); //Deshabilita las interrupciones 64 FCTL2 = FWKEY + FSSEL0 + FN0; // Escoge MCLK/2 como reloj del controlador de FLASH //Compacta la Hora para escribirla X=horas<<6|minutos; flash_write(X); //Escribe la hora flash_write(temp_i); //Escribe la temperatutra interna flash_write(temp_e); //Escribe la temperatura externa _EINT(); //habilita las interrupciones _NOP(); //para procesar las int. pendientes _DINT(); //Deshabilita las interrupciones flash_write(humedad); //humedad relativa flash_write(direccion); //Escribe la direcci� del viento flash_write(velocidad);//Escribe la velocidad del viento FCTL2 = FWKEY; // Escoge ACLK como reloj para ahorrar energia _EINT(); //habilita las interrupciones P4OUT|=BIT0;//Apaga los sensores etapa_med=0; //Termina la medicion midiendo=0; programa_medicion(); default: break; } // Actualiza la velocidad del viento. Detecta cuando han pasado 3 seg. // sin que se presenten interrupciones por el anemometo, lo que indica // una velocidad del viento nula contseg++; _DINT(); //Deshabilita las interrupciones if ((banderas & BIT1)!=0){ velocidad=(unsigned long)3705973/periodo; if(etapa_med==3){ //se obtubo una medicion correcta de la velocidad TBCCTL3&=~CCIE; // deshabilita la interrupcion� por captura etapa_med++; } } _EINT(); //habilita las interrupciones if (midiendo && (contseg >=12)){ velocidad=0; banderas=0; if(etapa_med==3){ //se obtubo una medicion correcta de la velocidad TBCCTL3&=~CCIE; // deshabilita la interrupcion por captura etapa_med++; } } } Modulo interfaz2.c //****************************************************************** // Archivo que contiene la parte de interfaz del usuario de // la estación meteorologica // // ************************** // Version 0.2 17/enero/2006 // Modificado para incluir la opcion de llamar de celular a celular // 65 #ifndef GCC #include <msp430x14x.h> #else #include <io.h> #include <signal.h> #endif #include <stdio.h> #include "lcdand.h" #define #define #define #define anterior 1 siguiente 2 entrar 3 escape 4 // Reloj de tiempo real extern char cuartos, segundos,minutos,horas; extern char dia,mes, ano; // Resultados de las ultimas mediciones extern extern extern extern extern int int int int int temp_i; temp_e; velocidad; direccion; humedad; //Temperatura Interna C //Temperatura Externa C //Velocidad del Viento Km/Hr //Direccion del viento //Humedad relativa % extern char vel_cap; extern int transmitiendo; //indica cuando se esta realizando una transmision extern int gsm; //indica si el modem receptor es analogico o un celular GSM // Telefono a marcar para transmitir los datos extern char tel[]; void programa_medicion(void); //del programa principal void char void char interfaz(char); accion(char n1,char n2,char tecla); pinta_menu(char n1,char n2); modifica(char *variable,char tecla, char max); void borraln(void){ wrcad(" } "); void interfaz(char tecla) { static char n1=0,n2=0,activo=0; /* n1 indica la seleccion menu principal, n2 es el submenu 0 indica que no hay nada selecionado */ const char max_submenu[7]={0,3,2,2,2,3,0}; if(!activo) { /* Si no esta activo un submenu, entonces determina la accion correpondiente a la tecla dentro del sistema de menus*/ switch (tecla){ case anterior: if(n1!=0){ if(n2==0) { /*si no hay submenus*/ 66 if(n1>1)n1--; /*va al menu anterior*/ else n1=6; }else if(n2>1) n2--; /*va al submenu anterior*/ else n2=max_submenu[n1]; } break; case siguiente: if(n1!=0){ if(n2==0) { /*si no hay submenus*/ if(n1<6)n1++; /*va al menu siguiente*/ else n1=1; }else if(n2<max_submenu[n1]) n2++; /*va al submenu siguente*/ else n2=1; } break; case entrar: if(n1==0){ P4OUT&= ~BIT1; //enciende la fuente de la pantalla n1=1; activo=0; //_BIS_SR(LPM0_bits); lcd_init(); /*enciende la pantalla LCD*/ }else if((n2!=0)||(max_submenu[n1]==0)){ /*si es un submenu valido, ejecuta la accion correpondiente*/ if(n1!=6){ /*el parametro tecla=0 indica que se acaba de selecionar el submenu*/ activo=accion(n1,n2,0); if(activo) return; }else{ n1=0; n2=0; P4OUT |= BIT1; //programa_medicion(); } }else n2=1; break; case escape: n2=0; activo=0; break; } pinta_menu(n1,n2); }else { activo=accion(n1,n2,tecla); if(!activo) pinta_menu(n1,n2); } } void pinta_menu(char n1,char n2) { /*muestra los mensajes adecuados para el menu y submenu*/ switch(n1){ case 1: wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta ala primera linea del LCD wrcad("Configurar fecha"); 67 wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD switch (n2){ case 0: borraln(); break; case 1: wrcad("dia "); break; case 2: wrcad("mes "); break; case 3: wrcad("a\xeeo "); break; } break; case 2: wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta ala primera linea del LCD wrcad("Configurar hora "); wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD switch (n2){ case 0: borraln(); break; case 1: wrcad("Hora "); break; case 2: wrcad("Minutos "); break; } break; case 3: wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta ala primera linea del LCD wrcad("Vel. de captura "); wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD switch (n2){ case 0: borraln(); break; case 1: wrcad("Cada 10 minutos "); break; case 2: wrcad("Cada hora "); break; } break; case 4: wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta ala primera linea del LCD wrcad("Ultimos result. "); wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD switch (n2){ case 0: borraln(); break; case 1: wrcad("Temperatura y HR"); break; case 2: wrcad("Vel. dir. viento"); break; } break; case 5: wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta ala primera linea del LCD wrcad("Transmite datos "); wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD switch (n2){ case 0: borraln(); break; 68 case 1: wrcad("A que telefono "); break; case 2: wrcad("transmitir ahora"); break; case 3: wrcad("tipo modem "); break; } break; case 6: wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta ala primera linea del LCD wrcad("Caputrar dtos "); wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD borraln(); break; } } char cadena[20]; //****************************************************************************** void i2cad6(unsigned int n,char *cad) { unsigned int res,coc; int i; coc=n; for(i=5;i>=0;i--){ res=coc%10; coc=coc/10; cad[i]=res|'0'; } cad[6]=0; } /* imprime en la pantalla LCD la temperatuta interna, externa y la humaedad realtiva*/ void wrTemp(void) { int X; wrcom(LCD_SET_DD_RAM_ADDRESS); if(temp_i>=0) X=temp_i; else X=-temp_i; i2cad6(X ,cadena+2); cadena[0]='T'; cadena[1]='I'; cadena[2]='='; if(temp_i<0)cadena[3]='-'; cadena[8]=cadena[7]; cadena[7]='.'; cadena[9]=0xdf; cadena[10]=' '; cadena[11]='H'; cadena[12]='='; cadena[13]=humedad/10+'0'; cadena[14]=humedad%10+'0'; cadena[15]='%'; cadena[16]=0; wrcad(cadena); //apunta ala primera linea del LCD 69 wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); if(temp_e>=0) X=temp_e; else X=-temp_e; i2cad6(X ,cadena+2); cadena[0]='T'; cadena[1]='E'; cadena[2]='='; if(temp_e<0)cadena[3]='-'; cadena[8]=cadena[7]; cadena[7]='.'; cadena[9]=0xdf; cadena[10]=' '; cadena[11]=' '; cadena[12]=' '; cadena[13]=' '; cadena[14]=' '; cadena[15]=' '; cadena[16]=0; wrcad(cadena); //apunta a la segunda linea del LCD } /* imprime en la pantalla LCD la velocidad y direccion del viento*/ void wrViento(void) { wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta ala primera linea del LCD cadena[0]='D'; cadena[1]='V'; cadena[2]='='; i2cad6((unsigned int)direccion ,cadena+3); cadena[9]=0xdf; cadena[10]=' '; cadena[11]=' '; cadena[12]=' '; cadena[13]=' '; cadena[14]=' '; cadena[15]=' '; cadena[16]=0; wrcad(cadena); wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD cadena[0]='V'; cadena[1]='='; i2cad6((unsigned int)velocidad ,cadena+2); cadena[8]=cadena[7]; cadena[7]=cadena[6]; cadena[6]='.'; cadena[10]='K'; cadena[11]='m'; cadena[12]='/'; cadena[13]='H'; cadena[14]=' '; cadena[15]=' '; cadena[16]=0; wrcad(cadena); } /****************************************************************** rutina que permite la modificacion del telefono *****************************************************************/ int modifica_tel(char tecla) { static char pos; 70 switch(tecla){ case 0: wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD wrcad(tel); pos=0; return(1); case anterior: if(tel[pos]==' ')tel[pos]='0'; else if(tel[pos]<'9') tel[pos]++; else tel[pos]=' '; //imprime el telefono wrcom(LCD_DISPLAY_ON);// hace que la pantalla oculte el cursor wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD wrcad(tel); return(1); case siguiente: if(pos<15) pos++; else pos=0; wrcom(LCD_DISPLAY_ON+2);// hace que la pantalla muestre el cursor wrcom(LCD_SET_DD_RAM_ADDRESS+0x40+pos); //apunta a la segunda linea del LCD //columna pos return(1); case entrar: //Tanto entrar com escape hacen que se salga modificando el telefono case escape: return(0); } return(0); } /****************************************************************** rutina que permite la modificacion del tipo de modem que va a recibir los datos. *****************************************************************/ int modifica_modem(char tecla) { static int valor; switch(tecla){ case 0: valor = gsm; wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD if(valor==0) wrcad("Analogico "); else wrcad("GSM "); return(1); case anterior: case siguiente: //Tanto anterior como siguiente modifican el tipo de modem wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD if(valor==1){ wrcad("Analogico "); valor=0; }else{ wrcad("GSM "); valor=1; } return(1); case entrar: gsm=valor; case escape: return(0); } 71 return(0); } /****************************************************************** rutina que ejecuta la accion correspondiente a una tecla en un submenu */ char accion(char n1,char n2,char tecla) { switch(n1){ case 1: //menu de configuración de fecha switch(n2){ case 1: /* dia */ wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta wrcad("dia "); return( modifica(&dia,tecla,31) ); case 2: /* mes */ wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta wrcad("mes "); return( modifica(&mes,tecla,12) ); case 3: /* a�*/ wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta wrcad("a\xeeo "); return( modifica(&ano,tecla,99) ); default: break; } break; case 2: //menu de configurcion de la hora switch(n2){ case 1: /* hora */ wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta wrcad("hora "); if(tecla==entrar) programa_medicion(); return( modifica(&horas,tecla,23) ); case 2: /* mes */ wrcom(LCD_SET_DD_RAM_ADDRESS); //apunta wrcad("minuto "); if(tecla==entrar) programa_medicion(); return( modifica(&minutos,tecla,59) ); default: break; } break; ala primera linea del LCD ala primera linea del LCD ala primera linea del LCD ala primera linea del LCD ala primera linea del LCD case 3: //menu de velocidad de captura if(n2==1){ /*cambiar velocidad de muestreo a cada 10 min*/ vel_cap=0; }else{ /*cambiar velocidad de muestreo a cada hora*/ vel_cap=1; } return (0); case 4: //menu para mostrar ultimos resultados if (n2==1){ /* mostrar tempreaturas y humedad rel.*/ wrTemp(); }else{ wrViento(); } if( (tecla==entrar)||(tecla==escape) ) return (0); else return(1); case 5: //menu configuración de comunicacion 72 switch(n2){ case 1: /* hora */ wrcom(LCD_SET_DD_RAM_ADDRESS); wrcad("telefono "); return( modifica_tel(tecla) ); case 2: /* mes */ transmitiendo=1; return (0); case 3: /* hora */ wrcom(LCD_SET_DD_RAM_ADDRESS); wrcad("tipo modem "); return( modifica_modem(tecla) ); //apunta ala primera linea del LCD //apunta ala primera linea del LCD default: break; } default: break; } return(1); } /* ************************************************************* rutina que permite modificar una variable de 2 digitos decimales */ char modifica(char *variable,char tecla, char max) { static char digitos[17]; static char pos; int i; switch(tecla){ case 0: digitos[0]=(*variable)/10+'0'; digitos[1]=(*variable)%10+'0'; for(i=2;i<16;i++) digitos[i]=' '; digitos[16]='\0'; wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD wrcad(digitos); pos=0; return(1); case anterior: if(digitos[pos]<'9') digitos[pos]++; else digitos[pos]='0'; if( ((digitos[0]&0x0F)*10+(digitos[1]&0x0F)) >max) digitos[pos]='0'; wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD wrcad(digitos); return(1); case siguiente: if(pos==0){ pos=1; wrcom(LCD_SET_DD_RAM_ADDRESS+0x40+1); //apunta a la segunda linea del LCD //segunda columna }else{ pos=0; wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD } return(1); case entrar: *variable= ((digitos[0]&0x0F)*10+(digitos[1]&0x0F)); case escape: return(0); 73 } return(0); } Modulo transmite.c /******************************************************************************************* ***** Rutina de transmision de datos para la estacion meteorologica version 0.02 18/enero/2006 Se añade la opcion de llamadas de telefono GSM a Tel GSM ******************************************************************************************** ****/ #ifndef GCC #include <msp430x14x.h> #else #include <io.h> #include <signal.h> #endif #include <string.h> #include "serie.h" #define #define #define #define etapa_tx1 3 etapa_tx2 4 etapa_error 5 etapa_final 6 char hexa[]="0123456789ABCDEF"; void Ajusta_DCO(void); extern int *puntero; //Inicio de la memoria Flash dedicada a almacenar datos extern int transmitiendo; //indica cuando se esta realizando una transmision extern int gsm; //vatiables para controlar la comunicación int etapa_trans=0; char recibido[30]; int indice=0,tiempo=0; extern char tel[]; int espera_respuesta(void) { tiempo ++; while(!serial_vacio()){ recibido[indice]=getserial(); tiempo=0; if((recibido[indice]=='\r')||(recibido[indice]=='\n')){ recibido[indice]='\0'; return(0); //ya se tiene una respuesta } if( indice<29 ) indice++; } if(tiempo>120){ //se excedio el tiempo de espera, error etapa_trans=etapa_error; //return(1); } return(1); //Todavia se debe esperar una respuesta } void transmite(void) { 74 static int *puntero_tx; int dato,t; static int i,suma,tamano; switch(etapa_trans){ case 0: //inicia la transmicion� reseteando el modem if(transmitiendo){ P3OUT&=~BIT3; //Enciende /DTR Ajusta_DCO(); //ajusta la frecuencia del oscilador //RC para asegurar la vel. del puerto serie etapa_trans++; //limpia el buffer de recepcion while(!serial_vacio())getserial(); if(gsm==0) wrcadserial("ATZ\r\r\n"); else wrcadserial("AT+CBST=71,0,1\r\r\n"); tiempo=0; indice=0; } break; case 1: //espera por "OK" if( espera_respuesta() )return; //termina si se supero //el tiempo de espera //revisa que la respuesta se a correcta. if((indice>=2) && (tiempo==0)) if(strcmp(recibido,"OK")==0){ etapa_trans++; wrcadserial("ATD"); wrcadserial(tel); wrcadserial("\r\r\n"); //limpia el buffer de recepcion while(!serial_vacio()) getserial(); tiempo=0; } indice=0; i=0; return; case 2: //espera por "CONNECT" if( espera_respuesta() )return; //termina si se supero //el tiempo de espera //revisa que la respuesta sea la correcta. i++; if(i>=3) i=0; if((indice>=7) && (tiempo==0)) recibido[7]='\0'; if(strcmp(recibido,"CONNECT")==0){ etapa_trans++; puntero_tx=(int *)0x1200; //inicia la transmision al comienzo // de la memoria de datos //limpia el buffer de recepcion while(!serial_vacio()) getserial(); tiempo=0; } indice=0; return; case etapa_tx1://transmite un bloque de maximo 120 palabras tamano=puntero-puntero_tx; 75 if(tamano>120)tamano=120; t=tamano&0xf; putserial(hexa[t]); //Transmite el tamano�del bloque t=(tamano>>4)&0xf; putserial(hexa[t]); t=(tamano>>8)&0xf; putserial(hexa[t]); t=(tamano>>12)&0xf; putserial(hexa[t]); suma=0; for(i=0;i<tamano;i++){ //transmite un dato dato=(*puntero_tx); t= dato &0xf; putserial(hexa[t]); t=(dato>>4)&0xf; putserial(hexa[t]); t=(dato>>8)&0xf; putserial(hexa[t]); t=(dato>>12)&0xf; putserial(hexa[t]); suma+=dato; puntero_tx++; } t=suma&0xf; putserial(hexa[t]); //Transmite la suma de comprobacion t=(suma>>4)&0xf; putserial(hexa[t]); t=(suma>>8)&0xf; putserial(hexa[t]); t=(suma>>12)&0xf; putserial(hexa[t]); etapa_trans=etapa_tx2; tiempo=0; return; case etapa_tx2: //espera la confirmación de recepción sin errores por la PC tiempo ++; if(!serial_vacio()){ tiempo=0; if(getserial()=='X'){//hubo un error, retransmitir el bloque puntero_tx-=tamano; } etapa_trans=etapa_tx1; if(puntero_tx>=puntero){ //si no faltan datos por transmitir //envia el indicador de terminacion de transmision //tamano=500 wrcadserial("4F10"); puntero_tx=puntero=(int *)0x1200; etapa_trans=etapa_final; } } if(tiempo>15){ //se excedio el tiempo de espera, error etapa_trans=etapa_error; return; } 76 //while(!serial_vacio()) getserial(); return; case etapa_error: //Indica //putserial('X'); wrcadserial("X\r\n"); //putserial(0X7F); etapa_trans++; break; que ocurrio un error en la transmision case etapa_final: //La transmision termino etapa_trans++; i=0; //putserial('+'); break; case (etapa_final+1): if(i<15) i++; else{ etapa_trans++; i=0; } //wrcadserial("+++"); break; case (etapa_final+2): etapa_trans++; //putserial('+'); wrcadserial("+++"); i=0; break; case (etapa_final+3): //retardo para que se reconosca la secuencia de escape if(i<15) i++; else{ etapa_trans++; i=0; } break; case (etapa_final+4): //La transmision termino etapa_trans++; wrcadserial("ATH\r\n"); break; case (etapa_final+5): //La transmision termino etapa_trans=0; transmitiendo=0; P3OUT|=BIT3; //apaga /DTR break; } } Modulo lcdadn2.c /*************************************************************** lcdand.c Libreria de funciones para escribir a una pantalla LCD 77 Alfanumerica inteligente (ej. AND491)conectada al puerto P4 y P5 del MSP430 de la siguiente forma: MPS430 AND491 P5.4 -D4 P5.5 -D5 P5.6 -D6 P5.7 -D7 P4.5 -RS P4.6 -R/W P4.7 -E Esta version solo utiliza cuatro bits de datos *****************************************************************/ #ifndef GCC #include <msp430x14x.h> #else #include <io.h> #include <signal.h> #endif #include "lcdand.h" /*Escribe un comando con RS=0*/ void wrcom(unsigned char comando) { P4OUT&= ~(BIT5+BIT6+BIT7); //RS=0,R/W=0, E=0 P5OUT=(comando&0xF0)|(P5OUT&0x0F); //Escribe la parte alta P4OUT|=BIT7; //Da un pulso en alto en E, E=1 P4OUT&= ~BIT7;// E=0 P5OUT=(comando<<4)|(P5OUT&0x0F); //Escribe la parte baja P4OUT|=BIT7; //Da un pulso en alto en E, E=1 P4OUT&= ~BIT7;// E=0 } /*Escribe un dato con RS=1*/ void wrdat(unsigned char comando) { P4OUT&= ~(BIT6+BIT7); //RS=1,R/W=0, E=0 P4OUT|= BIT5; P5OUT=(comando&0xF0)|(P5OUT&0x0F); //Escribe la parte alta P4OUT|=BIT7; //Da un pulso en alto en E, E=1 P4OUT&= ~BIT7;// E=0 P5OUT=(comando<<4)|(P5OUT&0x0F); //Escribe la parte baja P4OUT|=BIT7; //Da un pulso en alto en E, E=1 P4OUT&= ~BIT7;// E=0 } void lcd_init(void) { volatile int i; P5OUT=0; P5DIR=0xFF; //Programa el puerto P5 como salidas P4OUT&= ~(BIT5+BIT6+BIT7); P4DIR|=(BIT5+BIT6+BIT7); //Programa P4.5 a P4.7 como salidas. for (i = 2000; i>0; i--); wrcom(LCD_FUNCTION_SET4); for (i = 2000; i>0; i--); // retardo wrcom(LCD_FUNCTION_SET4+8); //Indica el numero de lineas en la pant. 78 for (i = 8000; i>0; i--); wrcom(LCD_FUNCTION_SET4+8); for (i = 1000; i>0; i--); wrcom(LCD_DISPLAY_ON); wrcom(LCD_DISPLAY_CLEAR); wrcom(LCD_ENTRY_MODE_SET); for (i = 1000; i>0; i--); // retardo //Indica el numero de lineas en la pant. // retardo } void wrcad(char *p) { while(*p){ wrdat(*p); p++; } } Modulo serie2.c #ifndef GCC #include <msp430x14x.h> #else #include <io.h> #include <signal.h> #endif #include "serie.h" /* Buffer de salida -- buffer circular FIFO de 64 bytes #define BUFSIZE (512) #define BUFSIZE_RX 128 */ unsigned char buffer[BUFSIZE]; volatile unsigned char * bufin = buffer; volatile unsigned char * bufout = buffer; unsigned inicio,fin; unsigned char bufferI[BUFSIZE_RX]; int serial_vacio(void) { return(inicio==fin); } inline void mete(unsigned char c) { if (fin >=inicio) { if (fin<BUFSIZE_RX) { bufferI[fin]=c; fin++; }else if (inicio>0){ bufferI[fin]=c; fin=0; } } else if ((fin+1)<inicio){ bufferI[fin]=c; fin++; } } inline unsigned char saca() { unsigned char t; if (inicio==fin) 79 t=0; else { t=bufferI[inicio]; if (inicio<BUFSIZE_RX) inicio++; else inicio=0; } return t; } unsigned char getserial(void) { unsigned char result; result = saca(); return result; } void putserial(unsigned char val) { int used; do { used = bufin - bufout; if ( used < 0 ) used += BUFSIZE; if ( used < BUFSIZE-1 ) { break; } _BIS_SR(LPM0_bits); } while ( 1 ); /* loop until break */ *bufin++ = val; if ( bufin == buffer+BUFSIZE ) { bufin = buffer; } /* Make sure transmitter interrupt enabled */ IE1 |= UTXIE0; // Enable USART0 TX interrupt } void wrcadserial(char *p) { while(*p){ putserial(*p); p++; } } #ifdef GCC interrupt ( UART0RX_VECTOR ) usart0_rx( void ) #else #if __VER__ < 200 interrupt [ UART0RX_VECTOR ] void usart0_rx( void ) #else #pragma vector=UART0RX_VECTOR __interrupt void usart0_rx( void ) #endif #endif { mete(RXBUF0); } #ifdef GCC interrupt (UART0TX_VECTOR) usart0_tx( void ) #else #if __VER__ < 200 interrupt [ UART0TX_VECTOR ] void usart0_tx( void ) #else #pragma vector=UART0TX_VECTOR __interrupt void usart0_tx( void ) #endif #endif 80 { if ( bufin == bufout ) { /* terminado -- desactiva la interrupcion del transmisor */ IE1 &= ~ UTXIE0; IFG1 |= UTXIFG0; } else { _EINT(); //habilita las interrupciones while((P3IN&4)!=0); //espera a que CTS=1 _DINT(); //habilita las interrupciones TXBUF0 = *bufout++; if ( bufout == buffer+BUFSIZE ) { bufout = buffer; } } } Modulo prueba6.c //****************************************************************************** // Program para llevar un reloj de tiempo real, medir la velocidad y // dirección del viento, Temperatura interna con el sensor integrado // y la externa con un sensor LM35. // Supone que esta conectado en la terminal P4.3(TB3) // un inerrruptor activado cada vez que un anemometro de 5cm de radio da una // revolución. En la terminal P6.1 se conecta un potenciometro sin tope // acoplado a una veleta para indicar la dirección del viento. // En P6.2 se conecta un sensor de humedad Honeywell IH-3610-1 // Humedad relativa= (Vout-0.921)/0.0316 // Tambien supone un cristal de 32765Hz en las terminales XIN y XOUT. // Las mediciones se muestran cada segundo y se enciende un led en P1.0 // mientras se estan realizando. // // MSP430F149 // --------------// /|\| XIN|// | | | 32kHz // --|RST XOUT|// | | // VELETA-|P6.1 P1.0|-->LED // | P4.3|--< Anemometro // LM35>--|P6.0 P6.3|--< Humedad // +833mV | | // // // La conversión de frecuencia (Hz o Rev/S) a vel (Km/hr) es // vel = (2*pi*r*f(m/s)*60(s/min)*60(min/hr) /1000(m/Km) // Para r=.05m // vel = 1.13097*f // // El rango de velocidad deseado es de 1 a 400 Km/Hr, 0.884 a 353Hz // prueba5.c ya muestra la velocidad del viento, Además almacena los resultados en la Flash // en el rango de 0x1200 a 0xEFFF (56,832 bytes - 55.5KB, 111 segmentos de 512 bytes) //****************************************************************************** #include #include #include #include <msp430x14x.h> <stdio.h> <lcdand.h> <serie.h> int segundos,minutos,horas; static unsigned int ADCresult,ADCresult2,ADCresult3,ADCresult4; static long int grados,DegC, DegC2; 81 unsigned T1,T2; unsigned periodo; char contseg; //contador para saber cuando se excede el periodo maximo. char banderas; // Varias banderas. // Bit 0 - Indica que ya se detecto el primer flanco de subida // Bit 1 - Indica que ya se detecto el segundo flanco de subida unsigned long velocidad; unsigned humedad; static int *puntero; //****************************************************************************** void imphora(char *cad) { int res,coc; res=horas%10; coc=horas/10; cad[0]=coc|'0'; cad[1]=res|'0'; cad[2]=':'; res=minutos%10; coc=minutos/10; cad[3]=coc|'0'; cad[4]=res|'0'; cad[5]=':'; res=segundos%10; coc=segundos/10; cad[6]=coc|'0'; cad[7]=res|'0'; cad[8]=0; } //****************************************************************************** void i2cad6(unsigned int n,char *cad) { unsigned int res,coc; int i; coc=n; for(i=5;i>=0;i--){ res=coc%10; coc=coc/10; cad[i]=res|'0'; } cad[6]=0; } //****************************************************************************** //Escribe una palabra en la Flash revisando si es una dirección valida y si es //necesario borrar el segmento void flash_write(int dato) { if(((unsigned int)puntero)< (0xF000-1)){ //Si no se ha llegado al final de la memoria if(((unsigned int)puntero & 0x1FF)==0){ //Si es el inicio de un segmento de 512Bytes FCTL1 = FWKEY + ERASE; // Activa el bit de borrado FCTL3 = FWKEY; // Borra el bit de bloqueo *puntero = 0; // falsa escritura para iniciar el borrado } FCTL3 = FWKEY; // Borra el bit de bloqueo 82 FCTL1 = FWKEY + WRT; *puntero++ = dato; FCTL1 = FWKEY; FCTL3 = FWKEY + LOCK; // Activa el bit de escritura // Escribe el valor a la flash // Borra el bit de escritura // Activa el bit de bloqueo de la FLASH } } //****************************************************************************** //Programa principal void main(void) { char cadena[20]; unsigned X,i; WDTCTL = WDT_ADLY_1000; // WDT funciona como interval timer con periodo de 1S IE1 |= WDTIE; // Habilita la interupción del WDT P1DIR = 0xFF; // Programa P1.x como salidas P1OUT = 0; // borra P1.x P2DIR = 0xFF; // Programa P2.x como salidas P2OUT = 0; // borra P2.x P3DIR = 0xDA; // Programa P3.x como salidas //Exepto los bits 0,2 y 5 P3OUT = 2; // borra P3.x // El bit p3.1 =0 activa al MAX3222E para las comunicaciones serie P5DIR = 0xFF; // Programa P5.x como salidas P5OUT = 0; P5SEL=0; P4DIR = 0xF7; // Programa P4.x como salidas //Exepto bit 3 P4OUT = 0; // borra P4.x //exepto bits 0 y 1 para mantener apagado la fuentes de 5V // borra P5.x P6DIR = 0xF8; // Programa P6.x como salidas //Exepto bits 0,1 y 2 P6OUT = 0; // borra P6.x puntero=(int *)0x1200; // P1SEL |= BIT4; //Inicio de la memoria Flash dedicada a almacenar datos //programa la terminal P1.4 para sacar la señal SMCLK /* Preparación del convertidor analogico a digital */ ADC12CTL0 = ADC12ON+MSC+REFON+REF2_5V+SHT0_6; // programa ADC12, ref., muestreo, // Multiples conversiones ADC12CTL1 = SHP+CONSEQ_1; // Usa el temporizador de muestreo, // una secuencia de conversiones ADC12MCTL0 = INCH_10+SREF_1; // Selecciona el canal A10, Vref+ ADC12MCTL1 = INCH_0+SREF_1; // Selecciona el canal A0, Vref+ ADC12MCTL2 = INCH_1; // Selecciona el canal A1 con AVCC como referencia ADC12MCTL3 = INCH_2+EOS; // Selecciona el canal A2, con AVCC // y marca el final de la secuencia. P6SEL=BIT0+BIT1+BIT2; /*Preparación del puerto serie 0 como UART*/ UCTL0 = CHAR; // caracter de 8-bit UTCTL0 = SSEL0; // UCLK = ACLK UBR00 = 0x0D; // 32k/2400 = 13.65 (Velocidad de TX y RX) UBR10 = 0x00; // UMCTL0 = 0x6B; // modulacion ME1 |= UTXE0 + URXE0; // habilita USART0 TXD/RXD IE1 |= URXIE0; // habilita la interrupcion de RX USART0 P3SEL |= 0x30; // P3.4,5 = USART0 TXD/RXD 83 //Preparación del timer B para medir el periodo del anemometro TBCTL=TBSSEL_1+MC_2+TBIE; // Selecciona ACLK como reloj, modo continuo // y habilita interrupciones TBCCTL3=CM_1+CAP+CCIE; // Habilita captura, Captura en flanco de subida // y habilita interrupción de TBCCR3 banderas=0; //Indica que no se ha presentado ningun flanco contseg=0; //Borra el contador de tiempo maximo P4SEL=BIT3; //Asigna la terminal P4.3 al timer for(i=25000;i>0;i--); lcd_init(); _EINT(); // Enable interrupts ADC12IE = 0x04; ADC12CTL0 |= ENC; // Enable ADC12IFG.0 // Enable conversions segundos=0; minutos=0; horas=0; while(1) { _BIS_SR(LPM3_bits); P1OUT |= 0x01; imphora(cadena); wrcom(LCD_SET_DD_RAM_ADDRESS); // Entra al modo LPM3 // Enciende el LED en P1.0 //apunta ala primera linea del LCD //wrcad(cadena); wrcadserial(cadena); putserial(' '); //wrdat(' '); ADC12CTL0 |= ADC12SC; _BIS_SR(LPM3_bits); // Start conversion // Enter LPM3 // // // DegC = (Vsensor - 986mV)/3.55mV Vsensor = (Vref)(ADCresult)/4095) DegC -> ((ADCresult - 1615)*704)/4095 DegC = ((((long)ADCresult-1615)*7040)/4095); // // // DegC = (Vsensor - 816mV)/10mV Vsensor = (2.5)(ADCresult2)/4095) DegC -> ((ADCresult - 1337)*250)/4095 DegC2 = ((((long)ADCresult2-1337)*2500)/4095); // Convierte el voltaje de la veleta a grados. grados = ((((long)ADCresult3-0)*360)/4095); // Convierte el voltaje del sensor de humedad a porcentaje. humedad = (((10*(unsigned long)ADCresult4-7392))/253); if(DegC>=0) X=DegC; 84 else X=-DegC; i2cad6(X ,cadena+2); cadena[0]='T'; cadena[1]='I'; cadena[2]='='; if(DegC<0)cadena[3]='-'; cadena[8]=cadena[7]; cadena[7]='.'; cadena[9]='°'; cadena[10]=' '; cadena[11]=0; wrcadserial(cadena); cadena[9]=0xDF; wrcad(cadena); wrcom(LCD_SET_DD_RAM_ADDRESS+0x40); //apunta a la segunda linea del LCD cadena[1]='E'; if(DegC2>=0) X=DegC2; else X=-DegC2; i2cad6(X ,cadena+2); cadena[2]='='; if(DegC2<0)cadena[3]='-'; cadena[8]=cadena[7]; cadena[7]='.'; cadena[9]='°'; cadena[10]=' '; cadena[11]=0; wrcadserial(cadena); cadena[9]=0xDF; wrcad(cadena); cadena[0]='D'; cadena[1]='V'; cadena[2]='='; i2cad6((int)grados ,cadena+3); cadena[9]='°'; cadena[10]=0; wrcadserial(cadena); putserial(' '); contseg++; if ((banderas & BIT1)!=0){ velocidad=(unsigned long)3705973/periodo; } if (contseg >=3){ velocidad=0; banderas=0; } cadena[0]='V'; cadena[1]='='; i2cad6((unsigned int)velocidad ,cadena+2); cadena[8]=cadena[7]; cadena[7]=cadena[6]; cadena[6]='.'; cadena[10]='K'; cadena[11]='m'; cadena[12]='/'; cadena[13]='H'; cadena[14]=0; wrcadserial(cadena); putserial(' '); 85 cadena[0]='H'; cadena[1]='R'; cadena[2]='='; i2cad6((int)humedad ,cadena+3); cadena[9]='%'; cadena[10]=0; wrcadserial(cadena); putserial('\r'); // Escritura de los resultados en la Flash _DINT(); //Deshabilita las interrupciones FCTL2 = FWKEY + FSSEL0 + FN0; // Escoge MCLK/2 como reloj del controlador de FLASH //Compacta la Hora para escribirla X=horas<<6+minutos; flash_write(X); //Escribe la hora flash_write(DegC); //Escribe la temperatutra interna flash_write(DegC2); //Escribe la temperatura externa flash_write(grados); //Escribe la dirección del viento flash_write(velocidad);//Escribe la velocidad del viento FCTL2 = FWKEY; // Escoge ACLK como reloj para ahorrar energia _EINT(); //habilita las interrupciones P1OUT &= ~0x01; // Clear P1.0 LED off } } interrupt[WDT_VECTOR] void watchdog_timer (void) { segundos++; if(segundos >= 60){ segundos=0; minutos++; if(minutos>=60){ minutos=0; horas++; if(horas>=24) horas=0; } } _BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR) } interrupt[ADC_VECTOR] void ADC12ISR (void) { ADCresult = ADC12MEM0; // Temperatura interna ADCresult2 = ADC12MEM1; // Temperatura externa ADCresult3 = ADC12MEM2; // Veleta ADCresult4 = ADC12MEM3; // Humedad _BIC_SR_IRQ(LPM3_bits); // Sale del modo LPM3 } //ISR tic1 interrupt[TIMERB1_VECTOR] void TIMERBISR (void) { switch (TBIV) { case 2: break; //CCR1 86 case 4: break; //CCR2 case 6: T2=TBCCR3; if ((banderas & BIT0)==0){ //Si es el primer flanco T1=T2; banderas |= BIT0; //indica que ya paso el primer flanco }else{ // Si es el segundo flanco de un periodo periodo=T2-T1; T1=T2; banderas |= BIT1; //indica que ya hay una medición lista para usarse contseg=0; //Pone el contador se tiempo máximo a cero } case 8: break; //CCR4 case 10: break; //CCR5 case 12: break; //CCR6 case 14: break; //TBOV } } Modulo serie.h #ifndef _serie_ #define _serie_ int serial_vacio(void); unsigned char getserial(void); void putserial(unsigned char val); void wrcadserial(char *p); #endif Modulo lcdand.h /*************************************************************** lcdand.h Libreria de funciones para escribir a una pantalla LCD Alfanumerica inteligente (ej. AND491)conectada al puerto P2 y P5 del MSP430 de la siguiente forma: MPS430 AND491 P5.0 -D0 P5.1 -D1 P5.2 -D2 P5.3 -D3 P5.4 -D4 P5.5 -D5 P5.6 -D6 P5.7 -D7 P2.0 -RS P2.1 -R/W P2.2 -E *****************************************************************/ #ifndef LCDAND #define LCDAND //Declaracion de constantes #define LCD_FUNCTION_SET8 0x30 //Establece la comunicación con 8 bits de datos #define LCD_FUNCTION_SET4 0x20 //Establece la comunicación con 4 bits de datos #define LCD_DISPLAY_ON 0x0C // Activa el display #define LCD_DISPLAY_CLEAR 0x01 // Limpia el display #define LCD_ENTRY_MODE_SET 0x06 // Establece el modo de entrada de datos #define LCD_SET_DD_RAM_ADDRESS 0x80 // Estable la direccion donde se escribiran los datos 87 //hay que sumarle la direccion de 7 bits /*Escribe un comando con RS=0*/ void wrcom(unsigned char comando); /*Escribe un dato con RS=1*/ void wrdat(unsigned char comando); void lcd_init(void); void wrcad(char *p); #endif Modulo interfaz.h void char void char interfaz(char); accion(char n1,char n2,char tecla); pinta_menu(char n1,char n2); modifica(char *variable,char tecla, char max); Modulo serialport.form # Gambas Form File 1.0 { FSerialPort Form MoveScaled(39.25,7.125,51.625,73.625) 'Move(314,57,413,589) Text = ("Serial Port") { TextLabel1 TextLabel MoveScaled(1,2,21,3) 'Move(8,16,168,24) Text = ("Port Name :") } { TxtPort TextBox MoveScaled(23,2,15,3) 'Move(184,16,120,24) Text = ("/dev/ttyS0") } { TextLabel2 TextLabel MoveScaled(1,6,21,3) 'Move(8,48,168,24) Text = ("Speed :") } { CmbSpeed ComboBox MoveScaled(23,6,15,1) 'Move(184,48,120,8) Text = ("") ReadOnly = True List = ("1200\n2400\n9600\n19200\n38400") } { TextLabel3 TextLabel MoveScaled(1,10,21,3) 'Move(8,80,168,24) Text = ("Parity :") } { TextLabel4 TextLabel MoveScaled(1,14,21,3) 'Move(8,112,168,24) 88 Text = ("Data Bits :") } { TextLabel5 TextLabel MoveScaled(1,18,21,3) 'Move(8,144,168,24) Text = ("Stop Bits :") } { CmbParity ComboBox MoveScaled(23,10,15,1) 'Move(184,80,120,8) Text = ("") ReadOnly = True List = ("None\nEven\nOdd") } { CmbData ComboBox MoveScaled(23,14,15,1) 'Move(184,112,120,8) Text = ("") ReadOnly = True List = ("8\n7\n6\n5") } { CmbStop ComboBox MoveScaled(23,18,15,1) 'Move(184,144,120,8) Text = ("") ReadOnly = True List = ("1\n2") } { Button1 Button MoveScaled(22,22,16,3) 'Move(176,176,128,24) Text = ("Open") } { TxtSend TextBox MoveScaled(1,38,43,3) 'Move(8,304,344,24) Text = ("") } { Button2 Button MoveScaled(45,38,6,3) 'Move(360,304,48,24) Text = ("CR") } { TextArea1 TextArea MoveScaled(1,42,50,8) 'Move(8,336,400,64) Text = ("") Wrap = True } { ChkDSR CheckBox MoveScaled(39,14,11,3) 'Move(312,112,88,24) Text = ("DSR") } { ChkDTR CheckBox MoveScaled(39,2,11,3) 'Move(312,16,88,24) Text = ("DTR") } { ChkRTS CheckBox MoveScaled(39,5,11,3) 'Move(312,40,88,24) Text = ("RTS") } { ChkCTS CheckBox MoveScaled(39,8,11,3) 89 'Move(312,64,88,24) Text = ("CTS") } { ChkDCD CheckBox MoveScaled(39,11,11,3) 'Move(312,88,88,24) Text = ("DCD") } { ChkRNG CheckBox MoveScaled(39,17,11,3) 'Move(312,136,88,24) Text = ("RNG") } { Label1 Label MoveScaled(1,27,15,3) 'Move(8,216,120,24) Text = ("Flow control :") } { ComboBox1 ComboBox MoveScaled(18,27,20,2) 'Move(144,216,160,16) Text = (" ") ReadOnly = True List = ("NONE\nCRTSCTS\nXON/XOFF\nCRTSCTS + XON/XOFF") } { SPort #SerialPort #X = 320 #Y = 176 } { CheckBox1 CheckBox MoveScaled(29,32,19,2) 'Move(232,256,152,16) Text = ("conexión via celular") Value = True } { CheckBox2 CheckBox MoveScaled(4,32,22,3) 'Move(32,256,176,24) Text = ("Emular modem") } { Timer1 #Timer #X = 128 #Y = 536 Delay = 2500 } { TextEtapa TextBox MoveScaled(37,67,9,3) 'Move(296,536,72,24) Text = ("0") } { TextLabel6 TextLabel MoveScaled(28,67,9,3) 'Move(224,536,72,24) Text = ("etapa") } { TextRecibe TextArea MoveScaled(1,52,50,14) 'Move(8,416,400,112) Text = ("") } } Modulo serialport.class 90 ' Gambas class file 'PRIVATE Sport AS SerialPort 'PUBLIC SUB Form_Open() ' Sport=NEW SerialPort AS "Sport" 'END PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE PRIVATE etapa AS Integer dato AS Integer buffer[27000] AS Integer indice AS Integer tam AS Integer i AS Integer suma AS Long cadena AS String escape AS Boolean PUBLIC SUB Form_Close() IF Sport.Status = Net.Active THEN CLOSE Sport END PUBLIC SUB Check_Status() ChkDSR.Value ChkDTR.Value ChkCTS.Value ChkRTS.Value ChkDCD.Value ChkRNG.Value = = = = = = Sport.DSR Sport.DTR Sport.CTS Sport.RTS Sport.DCD Sport.RNG END PUBLIC SUB Button1_Click() DIM j AS Integer IF Sport.Status = Net.Active THEN CLOSE Sport Button1.Text = "Open" ELSE ' Line parameters Sport.PortName = TxtPort.Text Sport.Speed = CmbSpeed.Text Sport.Parity = CmbParity.Index Sport.DataBits = CmbData.Text Sport.StopBits = CmbStop.Text ' keep DTR on Sport.FlowControl = ComboBox1.Index Sport.Open() Check_Status() TextArea1.Text = "Port Opened : " & Sport.PortName & " Settings : " & Sport.Speed & "," & Sport.Parity & "," & Sport.DataBits & "," & Sport.StopBits & Chr(13) & Chr(10) Button1.Text = "Close" etapa = 0 TextEtapa.Text = Str(etapa) 'retardo Timer1.Delay = 2500 Timer1.Enabled = TRUE TextRecibe.Text = "" ENDIF END 91 PUBLIC SUB SPort_Read() DIM s AS String DIM cade2 AS String DIM n AS Long DIM chksum AS Integer DIM linea AS String DIM hfile AS File DIM j AS Integer DIM k AS Integer DIM salir AS Boolean cade2 = "" READ #Sport, s, Lof(Sport) cadena = cadena & s TextRecibe.Text = TextRecibe.Text & s IF checkbox2.Value AND (etapa < 3) THEN 'si se esta emulando un modem, hacer eco de los caracteres recibidos PRINT #Sport, s; END IF salir = FALSE IF Left(S, 1) = "X" THEN TextArea1.Text = "Error de en la recepcion" etapa = 0 TextEtapa.Text = Str(etapa) cadena = "" ENDIF WHILE ((Len(cadena) > 0) AND ( NOT salir)) WHILE (Asc(cadena, 1) = 13) OR (Asc(cadena, 1) = 10) cadena = Right(cadena, -1) WEND SELECT etapa CASE 0 salir = TRUE FOR k = 1 TO Len(cadena) IF (Asc(cadena, k) = 13) OR (Asc(cadena, k) = 10) THEN cade2 = Left(cadena, k - 1) cadena = Right(cadena, - k) salir = FALSE BREAK END IF NEXT IF checkbox2.Value THEN 'espera el comando de atencion y responde simulando un modem IF Upper$(Left$(cade2, 3)) = "ATZ" THEN PRINT #Sport, "OK"; Chr(13); Chr$(13); Chr$(10); etapa = 1 TextEtapa.Text = Str(etapa) borra_buffer() ENDIF ELSE 'espera OK del modem IF Upper$(Left$(cade2, 2)) = "OK" THEN etapa = 1 TextEtapa.Text = Str(etapa) ELSE IF cade2 <> "" THEN salir = FALSE 'revisa si hay mas caracteres leidos ENDIF 92 ENDIF ENDIF TextArea1.Text = cade2 CASE 1 cade2 = "" salir = TRUE FOR k = 1 TO Len(cadena) IF (Asc(cadena, k) = 13) OR (Asc(cadena, k) = 10) THEN cade2 = Left(cadena, k - 1) cadena = Right(cadena, - k) salir = FALSE BREAK END IF NEXT IF checkbox2.Value THEN 'espera el comando de atencion y responde simulando un modem IF Upper$(Left$(cade2, 3)) = "ATD" THEN PRINT #Sport, "CONNECT 19400"; Chr(13); Chr$(13); Chr$(10); etapa = 3 TextEtapa.Text = Str(etapa) cadena = "" TextArea1.Text = cade2 ELSE IF cade2 <> "" THEN salir = FALSE 'revisa si hay mas caracteres leidos ENDIF ENDIF ELSE 'espera el indicador de llamada del modem y ordena contestar IF Upper$(Left$(cade2, 4)) = "RING" THEN cadena = "" TextArea1.Text = cade2 'PRINT #Sport, "A"; Timer1.Delay = 500 Timer1.Enabled = TRUE ELSE IF cade2 <> "" THEN salir = FALSE 'revisa si hay mas caracteres leidos ENDIF ENDIF ENDIF CASE 2 salir = TRUE FOR k = 1 TO Len(cadena) IF (Asc(cadena, k) = 13) OR (Asc(cadena, k) = 10) THEN cade2 = Left(cadena, k - 1) cadena = Right(cadena, - k) salir = FALSE BREAK END IF NEXT 'espera "CONNECT" del Modem IF Upper$(Left$(cade2, 7)) = "CONNECT" THEN etapa = 3 TextEtapa.Text = Str(etapa) TextArea1.Text = TextArea1.Text & cade2 borra_buffer() 93 ELSE 'IF (Upper$(Left$(cade2, 10)) = "NO CARRIER") OR (Upper$(Left$(cade2, 2)) = "OK") THEN IF (Upper$(Left$(cade2, 10)) = "NO CARRIER") THEN 'fallo la coneccion reiniciar el proceso etapa = 0 TextEtapa.Text = Str(etapa) TextArea1.Text = TextArea1.Text & cade2 Timer1_Timer() ELSE IF cade2 <> "" THEN salir = FALSE 'revisa si hay mas caracteres leidos ENDIF END IF ENDIF 'TextArea1.Text = TextArea1.Text & cade2 CASE 3 'En esta etapa se recibe el tamaño del bloque o el indicador de fin de transmision IF Len(cadena) >= 4 THEN n = ascii2hex(Asc(cadena, 1)) + ascii2hex(Asc(cadena, 2)) * 16 n = n + ascii2hex(Asc(cadena, 3)) * 256 + ascii2hex(Asc(cadena, 4)) * 4096 etapa = 4 TextEtapa.Text = Str(etapa) tam = n AND 65535 suma = 0 i = 0 'TextArea1.Text = TextArea1.Text & "recibiendo " & Str$(n) & " datos" & Chr(10) & Chr(13) cadena = Right$(cadena, -4) IF tam = 500 THEN 'se termino la recepcion 'Envia el comado de colgar despues de un retardo Timer1.Delay = 2000 Timer1.Enabled = TRUE etapa = 10 TextEtapa.Text = Str(etapa) 'Guarda los datos recibidos en un archivo csv para poderlos pasar a excel OPEN "/home/mfraga/datos.csv" FOR WRITE CREATE AS #hfile FOR j = 0 TO indice - 1 SELECT (j + 1) MOD 6 CASE 1 linea = Str(Int(buffer[j] / 64)) & ":" & Str(buffer[j] AND 63) & "," CASE 2 linea = linea & Str(buffer[j] / 10.0) & "," CASE 3 linea = linea & Str(buffer[j] / 10.0) & "," CASE 4 linea = linea & Str(buffer[j] / 100.0) & "," CASE 5 linea = linea & Str(buffer[j]) & "," CASE 0 linea = linea & Str(buffer[j] / 100.0) PRINT #hfile, linea END SELECT NEXT CLOSE #hfile 94 borra_buffer() cadena = "" s = "" TextArea1.Text = TextArea1.Text & Chr(13) & Chr(10) TextArea1.Text = TextArea1.Text & "Se termino la recepcion" ELSE TextArea1.Text = "recibiendo " & Str$(n) & " datos" TextArea1.Text = TextArea1.Text & Chr(13) & Chr(10) IF tam = 0 THEN etapa = 5 TextEtapa.Text = Str(etapa) ENDIF ENDIF ELSE salir = TRUE ENDIF CASE 4 'se reciben los datos del bloque WHILE (Len(cadena) >= 4) IF i < tam THEN n = ascii2hex(Asc(cadena, 1)) + ascii2hex(Asc(cadena, 2)) * 16 n = n + ascii2hex(Asc(cadena, 3)) * 256 + ascii2hex(Asc(cadena, 4)) * 4096 buffer[indice] = n 'almacena el valor aceptado indice = indice + 1 suma = suma + n TextArea1.Text = TextArea1.Text & Str$(n) & " " cadena = Right$(cadena, -4) i = i + 1 ELSE etapa = 5 TextEtapa.Text = Str(etapa) BREAK ENDIF WEND IF etapa = 4 THEN salir = TRUE END IF CASE 5 'Recibe el CheckSum y lo verifica, confirma la recepcion de los datos IF Len(cadena) >= 4 THEN n = ascii2hex(Asc(cadena, 1)) + ascii2hex(Asc(cadena, 2)) * 16 n = n + ascii2hex(Asc(cadena, 3)) * 256 + ascii2hex(Asc(cadena, 4)) * 4096 chksum = n AND 65535 TextArea1.Text = TextArea1.Text & Chr(13) & Chr(10) TextArea1.Text = TextArea1.Text & "checsum= " & Str$(n) cadena = Right$(cadena, -4) IF (suma AND 65535) = chksum THEN PRINT #Sport, "U"; etapa = 3 TextEtapa.Text = Str(etapa) ELSE PRINT #Sport, "X"; etapa = 3 TextEtapa.Text = Str(etapa) cadena = "" indice = indice - tam ENDIF ELSE salir = TRUE ENDIF 95 CASE 10, 11, 12 'etapa de colgado cadena = "" cade2 = "" END SELECT WEND END PUBLIC SUB SPort_RNGChange(iVal AS Boolean) ChkRng.Value = iVal END PUBLIC SUB SPort_DTRChange(iVal AS Boolean) ChkDTR.Value = iVal END PUBLIC SUB SPort_DSRChange(iVal AS Boolean) ChkDSR.Value = iVal END PUBLIC SUB SPort_CTSChange(iVal AS Boolean) ChkCTS.Value = iVal END PUBLIC SUB SPort_DCDChange(iVal AS Boolean) ChkDCD.Value = iVal END PUBLIC SUB SPort_RTSChange(iVal AS Boolean) ChkRTS.Value = iVal END PUBLIC SUB Button2_Click() IF Sport.Status = Net.Inactive THEN Message("Open port first!") ELSE 'WRITE #Sport,TxtSend.Text & Chr(13) & Chr(10), txtSend.Length + 2 PRINT #Sport, txtSend.Text; Chr$(13); Chr$(10); END IF END PUBLIC SUB ChkDTR_Click() Sport.DTR = ChkDTR.Value Check_Status END PUBLIC SUB ChkRTS_Click() Sport.RTS = ChkRTS.Value Check_Status END PUBLIC SUB ComboBox1_Click() IF Sport.Status = Net.Inactive THEN Sport.FlowControl = ComboBox1.Index END IF END 96 PUBLIC SUB Form_Open() cmbSpeed.Index = cmbSpeed.Find("9600") ComboBox1.Index = ComboBox1.Find("CRTSCTS") etapa = 0 END PUBLIC SUB borra_buffer() DIM j AS Integer FOR j = 0 TO 26999 buffer[j] = 0 NEXT indice = 0 END PUBLIC FUNCTION ascii2hex(t AS Integer) AS Integer IF (t >= Asc("0")) AND (t <= Asc("9")) THEN RETURN t AND 15 ELSE IF (t >= Asc("A")) AND (t <= Asc("F")) THEN RETURN t - Asc("A") + 10 ELSE IF (t >= Asc("a")) AND (t <= Asc("f")) THEN RETURN t - Asc("a") + 10 ELSE RETURN 0 END IF END IF END IF END PUBLIC SUB Timer1_Timer() SELECT etapa CASE 0, 2 Timer1.Enabled = FALSE IF checkbox2.Value = FALSE THEN 'si no se esta emulando un modem IF checkbox1.Value THEN 'Inicializa el modem celular PRINT #Sport, "AT+CBST=71,0,1"; Chr$(13); Chr$(10); ELSE 'Inicializa el modem analogico PRINT #Sport, "ATZ"; Chr$(13); Chr$(10); ENDIF ENDIF CASE 1 PRINT #Sport, "ATA"; Chr$(13); Chr$(10); etapa = 2 TextEtapa.Text = Str(etapa) Timer1.Enabled = FALSE CASE 10 'Envia la secuencia de escape para colgar PRINT #Sport, "+++"; etapa = 11 97 TextEtapa.Text = Str(etapa) CASE 11 PRINT #Sport, "ATH"; Chr$(13); Chr$(10); etapa = 12 'descarta la respuesta del modem TextEtapa.Text = Str(etapa) CASE 12 'PRINT #Sport, "ATH"; Chr$(13); Chr$(10); etapa = 0 'regresa a reinicializar el modem TextEtapa.Text = Str(etapa) END SELECT END 98