UNIVERSIDAD TECNOLOGICA NACIONAL FACULTAD REGIONAL SAN NICOLAS INGENIERIA EN ELECTRONICA PROBLEMA DE INGENIERÍA TECNICAS DIGITALES III MANDO A DISTANCIA PARA PC Integrantes: - Buxman Jorge A. - De Nicoló Lisandro. - Gallina Luciano . Docentes: - Profesor: Poblete Felipe - Auxiliar: González Mariano AÑO 2007 Técnicas Digitales III – Problema de ingeniería INDICE OBJETIVOS DEL TRABAJO 3 MATERIAS INTEGRADAS......................................................................................................... 3 POSIBLES APLICACIONES........................................................................................................ 3 PROFESORES ENTREVISTADOS.............................................................................................. 3 BIBLIOGRAFÍA ........................................................................................................................... 3 DESARROLLO 4 INTRODUCCIÓN......................................................................................................................... 4 TEORIA DE FUNCIONAMIENTO .............................................................................................. 4 EL ENLACE INFRARROJO............................................................................................................4 RECEPCION DE INFRARROJO ....................................................................................................6 PROTOCOLO DE PHILIPS RC-05..................................................................................................9 EL URC SBC-RU-240/38 DE PHILIPS..........................................................................................12 ESTANDAR RS- 232 ....................................................................................................................13 DIAGRAMAS Y CIRCUITOS..................................................................................................... 15 PRIMER INTENTO .......................................................................................................................15 RECEPTOR ...................................................................................................................................16 EL CODIGO FUENTE DEL PIC16F84A.....................................................................................19 ESTRUCTURA DE UN PROGRAMA WINDOWS GUI............................................................. 20 Parámetros de entrada de "WinMain"..............................................................................................22 Función WinMain típica .................................................................................................................23 Declaración.....................................................................................................................................24 Inicialización ..................................................................................................................................24 Bucle de mensajes...........................................................................................................................24 El procedimiento de ventana ......................................................................................................... 25 Sintaxis...........................................................................................................................................25 Prototipo de procedimiento de ventana............................................................................................26 Implementación del procedimiento de ventana simple.....................................................................26 RESULTADOS DE LAS PRUEBAS ........................................................................................... 27 CONCLUSIONES 29 ANEXOS 33 Anexo A: LISTADO DE PROGRAMAS...................................................................................... 33 Código fuente para el PIC16F84A: .................................................................................................33 Código fuente para la PC: ...............................................................................................................41 Anexo B: Sitios en la WEB........................................................................................................... 57 Anexo C: GL3276A-datasheets (no incluído en este documento) .................................................. 57 Anexo D: MAX232-datasheets (no incluído en este documento)................................................... 57 2 Técnicas Digitales III – Problema de ingeniería OBJETIVOS DEL TRABAJO Lograr el manejo o accionamiento de los comandos básicos de programas multimedia en plena reproducción mediante un mando a distancia enlazado con la PC a través de un enlace de señal infrarroja. La implementación requiere de la utilización de un control remoto comercial del tipo universal o cualquier otro control remoto de cualquier equipo en desuso (Equipo de audio o Tv, etc.). MATERIAS INTEGRADAS Informática I y II. Técnicas digitales I, II, y III. Física II y III. POSIBLES APLICACIONES Implementación de control sobre archivos multimedia en plena reproducción logrando una mayor comodidad, ya sean de audio o video. PROFESORES ENTREVISTADOS Ramiro Vota (Interfaz RS-232 en Windows XP). Mariano Gonzales (Ídem). BIBLIOGRAFÍA Turbo C/C++ Manual de referencia-Herbert Schildt (serie McGary-Hill de Informática). Programación Elemental en C++ Manual de Referencia Abreviado revisión 1.2 (Universidad de Málaga Dpto. de Ing. Informática) Programación en C Metodología, algoritmos y estructura de datos.-Luis Joyanes Aguilar / Ignacio Zahonero Martínez. Protocolo Philips RC-5 para control remoto descripción por Eduardo J. Carletti (Comunicacion_protocolorc5.htm). RS-232 Ingeniería en microcontroladores Ing. Eric López Pérez. Hojas de datos de los sistemas involucrados (apéndices). Organización de las computadoras-un enfoque estructurado-Andrew S. Tanembaum. Diversos sitios web (ver al final de este informe). 3 Técnicas Digitales III – Problema de ingeniería DESARROLLO INTRODUCCIÓN Probablemente los botones más frecuentemente pulsados en cualquier casa son los del mando a distancia de la televisión, y es que actualmente el control remoto de aparatos electrónicos es algo habitual. Resulta evidente que los mandos por infrarrojos han sido una revolución. Por otra parte, es indudable que la presencia de ordenadores personales en hogares y oficinas, que duplican su capacidad a velocidades vertiginosas, facilita la extensa tarea en las diversas actividades que realiza el ser humano. La tendencia actual es optimizar el ordenador al máximo. Por todo ello, ¿por qué no aplicar las comodidades del control remoto al ordenador? . Se pretende recibir la información enviada desde un emisor de infrarrojos, que será un mando a distancia convencional, procesar esa información y enviarla vía RS-232 a un ordenador personal. La información extraída del mando es una serie de pulsos que, en principio, no sirve de nada si no se procesa adecuadamente. Para llevar a cabo este proceso se utiliza un PIC modelo 16F84A de Microchip, que es un pequeño microcontrolador de 18 pines. Dicho PIC dispone de un entorno de desarrollo para la confección del programa que ejecutará y se encargará de procesar convenientemente la trama recibida del IR, obteniéndose así otra trama de ceros y unos que ahora sí es comprensible por cualquier sistema (palabra digital de 6 bits). Finalmente, como esta información se desea transmitir vía serie siguiendo el estándar RS-232, se utilizará un integrado comercial (MAX232) que adecua los niveles de la trama extraída por el PIC (trama TTL) a los requeridos por la norma. Importante señalar que el PIC ya se ha encargado de añadir los bits de STOP y START a cada una de las palabras digitales, no utilizándose control de flujo hardware. Se emplea como emisor un mando a distancia universal al que se le ha programado el código 033 correspondiente a los mandos PHILIPS (RC-05). TEORIA DE FUNCIONAMIENTO EL ENLACE INFRARROJO Un enlace infrarrojo consiste en una comunicación vía señalización lumínica. La luz infrarroja no es más que una onda electromagnética como las de radio (claro es, que se trata de una frecuencia muy diferente) y como las del resto de las ondas que constituyen el espectro de luz visible (desde el infrarrojo hasta el ultravioleta). El nombre de luz infrarroja, que significa por debajo del rojo, proviene de la primera vez que fue observada al dividir la luz solar en diferentes colores por medio de un prisma que separaba la luz en su espectro de manera que a ambos extremos aparecen visibles, las componentes del rojo al violeta (en ambos extremos). 4 Técnicas Digitales III – Problema de ingeniería Aunque estas experiencias habían sido realizadas anteriormente por Isaac Newton, William Herschel observó en el año 1800 que se recibía radiación debajo del rojo al situar medidores de calor en las diferentes zonas no visiblemente irradiadas por el espectro. Imagen de un perro tomada con radiación infrarroja media («térmica») y coloreada: Su longitud de onda es del orden de los 700 nano-metros: 5 Técnicas Digitales III – Problema de ingeniería Y su frecuencia: Todos estos parámetros son característicos de cualquier tipo de onda: RECEPCION DE INFRARROJO Todos los dispositivos semiconductores son sensibles a la luz (a todo tipo de luz), de hecho este es el principal factor que determina el encapsulado de los chips: un plástico completamente opaco, normalmente negro. Un sensor de infrarrojos está construido básicamente por una unión semiconductora recubierta por un cristal que sólo deja pasar la luz infrarroja (photodiodo). Un sensor de infrarrojos construido de esa forma será capaz de detectar la presencia de cualquier luz infrarroja, independientemente de la fuente que la genere. Los diseñadores de mandos a distancia tuvieron que añadir una característica diferenciadora a la luz emitida desde un mando a distancia para hacerla distinguible del resto de fuentes luminosas. La señal emitida por un mando está modulada a una frecuencia entre 32 y 40 KHz, dependiendo del fabricante y modelo del mando a distancia. No tenemos que perder de vista que todo lo que se haga para emitir la señal, luego durante la recepción se tendrá que deshacer. Si se emite luz infrarroja, luego se tendrá que recibir; si esta señal se modula con una portadora luego se tendrá que eliminar (filtrar) esa portadora. La demodulación se realiza analógicamente con un sencillo filtro paso banda (eliminar todas las frecuencias que no sean próximas a la frecuencia de emisión) junto con un rectificador/integrador. 6 Técnicas Digitales III – Problema de ingeniería Una onda modulada es una forma de onda obtenida mediante una operación matemática implementada a través de circuitos electrónicos y en la que intervienen la señal que se quiere transmitir (moduladora) y al onda portadora. Esta onda portadora es de una frecuencia mucho más alta que la de la señal moduladora (la señal que contiene la información a transmitir). Al modular una señal desplazamos su contenido espectral en frecuencia, ocupando un cierto ancho de banda alrededor de la frecuencia de la onda portadora (f0). Esto nos permite multiplexar en frecuencia varias señales simplemente utilizando diferentes ondas portadoras y conseguir así un uso más eficiente del espectro de frecuencias. Luz infrarroja modulada a una frecuencia de 36 KHz (para nuestro caso de RC-05), es el medio de comunicación entre el emisor (mando a distancia) y el receptor (PIC16F84A). Ahora queda por determinar cómo se transmite la información, esto es, los bits que identifican la tecla del mando a distancia que se ha pulsado, pero esto se detallara en el apartado del protocolo RC-05. Para la realización de la tarea de recibir el dato empleamos un circuito integrado comercial estándar cuyas especificaciones se pueden consultar en el Anexo A (hoja de datos). Es el GL3276A el circuito mencionado y brevemente podemos decir que consta de los siguientes bloques funcionales: Características del integrado: Menor numero de errores asociados a la alta frecuencia emanada por luces fluorescentes (impulsos luminiscentes) mediante circuito trampa interna. Frecuencia de portadora (demodulación) preselecionable mediante resistencia instalada en el pin f0 en un rango de 30 a 80 KHz. Margen de variación de f0 reducido. Pocos elementos externos necesarios. Resistencias de pull-ups y filtros internas. Capacitores externos de capacidades bajas. Salida a colector abierto con resistencia de pull-up. 7 Técnicas Digitales III – Problema de ingeniería Este es un circuito integrado analógico diseñado especialmente para este tipo de aplicaciones, tanto es así que el fabricante nos aporta el circuito de aplicación típico que obviamente se consigue en cualquier tienda de electrónica completo dentro de una caja de chapa que hace a las veces de jaula de Faraday para disminuir el efecto de interferencias por ondas electromagnéticas. Como veremos a este se acopla directamente el photodiodo receptor y un conjunto mínimo de componentes de seteo y demás. Como se muestra en su diagrama de bloques consta en una primera instancia de un amplificador de entada, seguido de u limitador, un filtro pasa banda, un circuito detector y un acondicionador de forma de onda que va directo a la etapa de salida a colector abierto. El valor de R(f0) lo encontramos mediante las curvas aportadas por el fabricante del circuito integrado. Para 36 KHz seria al rededor de 156 KΩ. 8 Técnicas Digitales III – Problema de ingeniería PROTOCOLO DE PHILIPS RC-05 Es evidente, dada la forma de modular la señal, que la información se transmite en serie, esto es, un bit detrás de otro, y por tanto sólo es necesario una línea (de datos) para recibirla. Descubramos un poco que es y como esta hecho el protocolo de Philips. El código RC-05 de Philips es, posiblemente, el protocolo más utilizado por los experimentadores, debido a la amplia disponibilidad de controles remotos baratos que se basan en él. Además, dentro de este protocolo hay comandos predefinidos para distintos artefactos, una característica que aporta una mayor compatibilidad al utilizarlo con muchos equipos hogareños. Philips ha comenzado a utilizar un nuevo protocolo, el RC-06, que tiene más capacidades. Características Dirección de 5 bit y comando de 6 bit (7 bits de comando para RC-05X) Codificación de doble fase o bi-fase (Bi-phase, también llamada código Manchester) Frecuencia de portadora de 36 KHz. Tiempo de bit constante de 1,778 ms (64 ciclos de 36 KHz.) Modulación El protocolo está basado en una modulación Manchester de doble fase sobre una portadora de 36 KHz. En esta codificación, todos los bits tienen la misma longitud, de 1,778 ms. La mitad del bit es un tren de pulsos de la portadora de 36 KHz., y en la otra mitad la señal está plana. El cero lógico es representado por un tren de pulsos en la primera mitad (primer nible) del tiempo que corresponde al bit. El uno lógico es representado por un tren de pulsos en la segunda mitad de este tiempo. La relación entre pulso y pausa en la portadora de 36 KHz. es de 1/3 o 1/4, lo que reduce el consumo de energía. Protocolo La imagen muestra un típico tren de pulsos en un mensaje RC-05. En este ejemplo se transmite la dirección $05 y el comando $35. Los dos primeros bits son los de inicio (start), que deben ser dos "1" lógicos. Nótese que transcurre medio tiempo de bit hasta que el receptor se entera de que ha comenzado el mensaje. 9 Técnicas Digitales III – Problema de ingeniería El protocolo RC-05 extendido (RC-05x) tiene un solo bit de inicio y este es en realidad el que utilizaremos pues es el que mas abunda aunque lo sigamos llamando RC-05. El tercer bit del protocolo RC-05, marcado como “T” en el dibujo, es el bit de conmutación (toggle). Este bit es invertido cada vez que se libera una tecla en el control remoto y se la presiona de nuevo o se presiona otra diferente. De esta manera el receptor puede distinguir entre una tecla que permanece presionada (mientras lo esté, el comando que le corresponde se repite indefinidamente en la señal) y una misma tecla a la que se la presiona varias veces. Para nuestra aplicación lo que haremos es que el PIC16f84A decodifique el mensaje enviado por el control remoto y envíe los datos a la PC mediante el puerto serie. Ya que hacemos esto, no es necesario pasarle a la PC toda la cadena, basta con que le pasemos el dato de comando para que la PC ejecute una tarea respectiva. Entonces el dato correspondiente al dispositivo que “nos habla” se lo queda el PIC para lograr el reconocimiento del mismo y así impedir leer mensajes de otros controles remotos circundantes. En la cadena que le pasamos a la PC haremos que, ya que nos sobran dos bis para completar el byte (6 bits de comando), el bit 6 (cadena 0~7 bits) de dicha cadena sea “1” lógico para informar no repetición de la tecla y “0” lógico para representar repetición de la tecla y así la PC pueda hacer alguna discriminación de ser necesario. El bit que sigue al bit “T” es el primero de la dirección del dispositivo receptor de infrarrojos (identificación de quien nos habla y por esto, obviamente, para quien es el mensaje), poniendo en primer lugar el bit más significativo de la dirección. A esta dirección le sigue el comando de 6 bits, también con su bit más significativo en primer lugar. Un mensaje, entonces, consiste de un total de 14 bits, que sumados dan una duración total del mensaje de 25 ms. A veces puede parecer que un mensaje es más corto debido a que la primera parte del bit de inicio S1 es inactiva. Mientras se mantenga presionada la tecla, el mensaje se repite cada 114 ms. El bit de conmutación mantendrá el mismo nivel lógico durante la repetición de un mensaje. Comandos predefinidos Philips ha creado una lista de comandos estandarizados. Esto asegura compatibilidad entre artefactos de un mismo tipo y evita que la tecla que cambia de canal en un televisor produzca al mismo tiempo algún efecto en una videocasetera que también esté allí, enfrente del control remoto. Una característica interesante es que la mayoría de los artefactos están representados dos veces, lo que permitiría tener dos videocaseteras juntas sin tener problemas para comandarlas por separado. 10 Técnicas Digitales III – Problema de ingeniería La lista que sigue no es exhaustiva. Dirección RC-5 Dispositivo Comando RC-5 Comando TV Comando VCR $00 - 0 TV1 $00 - 0 0 0 $01 - 1 TV2 $01 - 1 1 1 $02 - 2 Teletexto $02 - 2 2 2 $03 - 3 Video $03 - 3 3 3 $04 - 4 LV1 $04 - 4 4 4 $05 - 5 VCR1 $05 - 5 5 5 $06 - 6 VCR2 $06 - 6 6 6 $07 - 7 Experimental $07 - 7 7 7 $08 - 8 Sat1 $08 - 8 8 8 $09 - 9 Cámara $09 - 9 9 9 $0A - 10 Sat2 $0A - 10 -/-- -/-- $0C - 12 Espera Espera $0B - 11 $0C - 12 CDV $0D - 13 Silenciar $0D - 13 Camcorder $10 - 16 Volumen + $0E - 14 $11 - 17 Volumen - $0F - 15 $12 - 18 Brillo + $10 - 16 Preamplificador $13 - 19 Brillo - $11 - 17 Sintonizador $20 - 32 Programa + Programa + $12 - 18 Grabador1 $21 - 33 Programa - Programa - $13 - 19 Preamplificador $32 - 50 Retroceso rápido $14 - 20 Reproductor CD $34 - 52 Retroceso rápido $15 - 21 Teléfono $35 - 53 Reproducir $16 - 22 SatA $36 - 54 Detener $17 - 23 Grabador2 $37 - 55 Grabar $18 - 24 $19 - 25 $1A - 26 CDR $1B - 27 $1C - 28 $1D - 29 Iluminación $1E - 30 Iluminación $1F - 31 Teléfono 11 Técnicas Digitales III – Problema de ingeniería EL URC SBC-RU-240/38 DE PHILIPS Utilizamos este control remoto universal de Philips y lo configuramos para trabaja con una VRC pues nos habilita la mayor cantidad de botones posible permitiéndonos, en definitiva, el mayor rango de interacción con la PC. Conseguimos entonces las siguientes salidas del control hacia nuestro sistema receptor: Estos códigos de salida además de aparecer en la tabla antes mostrada, los podemos comprobar y lo hicimos mediante el ordenador. En el código fuente del programa de la PC haremos la siguiente tabla de asignaciones por defecto (el usuario puede modificar dicha tabla cuando abre el programa). Esta es una asignación por defecto para controlar el programa WINAMP (configuración de teclado por defecto, del programa) de reproducción de archivos multimedia y además nos permitirá interactuar en lo que a las principales funciones respecta, con el sistema operativo Windows. 12 Técnicas Digitales III – Problema de ingeniería Para la configuración del control remoto: Elegir dispositivo (uno de cuatro los botones superiores), en nuestro caso VCR. Mantener presionado los botones “numero 1” y “numero 3”, destello de led indicador de envío dos veces. Ingresar el código correspondiente al protocolo que el control remoto debe emitir, para nuestro caso es “033”, destello de led indicador de envío una vez. Ahora tenemos el mando a distancia configurado para emitir en protocolo RC-05X en modo VCR. ESTANDAR RS- 232 La transmisión de datos en serie es una de las más comunes para aquellas aplicaciones en las que la velocidad no es demasiado importante, o no es posible conseguirla (por ejemplo, vía red telefónica). Para simplificar el proceso de enviar los bits uno por uno han surgido circuitos integrados que realizan la función, teniendo en cuenta todos los tiempos necesarios para lograr una correcta comunicación y aliviando a la CPU de esta pesada tarea. El circuito que estudiado es el 8250 de National, fabricado también por Intel, aunque existen diferencias respecto al 16550. Esta última UART es más reciente y mucho más potente (aunque solo sea por unos pequeños detalles) y cada vez está más extendida, en particular en las actuales placas base. 13 Técnicas Digitales III – Problema de ingeniería La línea que transmite los datos en serie está inicialmente en estado alto. Al comenzar la transferencia, se envía un bit a 0 ó bit de inicio. Tras él irán los 8 bits de datos a transmitir (en ocasiones son 7, 6 ó 5): estos bits están espaciados con un intervalo temporal fijo y preciso, ligado a la velocidad de transmisión que se esté empleando, en nuestro caso es de 9600 baudios. Tras ellos podría venir o no un bit de paridad generado automáticamente por la UART. Al final, aparecerá un bit (a veces un bit y medio ó dos bits) a 1, que son los bits de parada o bits de stop. Lo de medio bit significa que la señal correspondiente en el tiempo a un bit dura la mitad. La presencia de bits de arranque y paro permite sincronizar la estación emisora con la receptora, haciendo que los relojes de ambas vayan a la par. A la hora de transmitir los bits de datos unos tras otros, no se necesitan señales de reloj como se requieren para otras comunicaciones como es por ejemplo el I2C y por esto se considera al protocolo RS-232 asíncrono. El ACE 8250 (Asynchronous Communication Element) integra en un solo chip una UART (Universal Asynchronous Receiver/Transmitter) y un BRG (Baud Rate Generator). Soporta velocidades de hasta 625000 baudios con relojes de hasta 10 MHz. El BRG incorporado divide la frecuencia base para conseguir las velocidades estándar de la RS-232. Para llevar a cabo ala comunicación el integrado consta de varios registros en los que se aloja bandera de estado, configuración de línea y modem. También están los registros buffer en los que se encuentran los datos recibidos, los datos a enviar, el registro de salida secuencial bit a bit e ídem para la entrada. Desde un punto de vista eléctrico la norma RS-232 establece: Un “1” lógico es un voltaje comprendido entre –5v y –15ven el transmisor y entre -3v y 25v en el receptor. Un “0” lógico es un voltaje comprendido entre +5v y +15v en el trasmisor y entre +3v y +25 v en el receptor. Para adaptar las salidas del micro controlador al protocola se usa el MAX232 este chip se utiliza en aquellas aplicaciones donde no se dispone de fuentes dobles de +12 y –12 Volts. El MAX 232 necesita solamente una fuente de +5V para su operación, internamente tiene un elevador de voltaje que convierte el voltaje de +5V al de doble polaridad de +12V y -12V. Cabe mencionar que existen una gran variedad de CI que cumplen con la norma RS-232 como lo son: MAX220, DS14C232, MAX233, LT1180A. 14 Técnicas Digitales III – Problema de ingeniería Implementación cableada En la siguiente tabla se muestra las señales y configuración RS-232 más común según se implemente ficha DV9 o DV25: DIAGRAMAS Y CIRCUITOS PRIMER INTENTO Parea enriquecimiento de nuestra experiencia en un primer intento por querer logra la comunicación vía puerto serie de la PC e ignorantes totalmente de la existencia del MAX232 intentamos hacer la adaptación de niveles de voltaje a través de un circuito a base de amplificadores operacionales (LM324) puestos como comparadores. Si bien conseguimos la comunicación, el dato transmitido era muy distante del que realmente queríamos enviar. Al observar el comportamiento del amplificador operacional configurado de esa manera con un osciloscopio, al atravesarlo un dato a transmitir, pudimos ver que la salida no podía acompañar a la entrada en tiempo y forma. Así que intentamos resolver el problema bajando la velocidad de transmisión, ya teníamos el hardware armado. Conseguimos una leve mejora a 330 baudios, así que debíamos intentar configurar el operacional como amplificador inverso de alguna manera. Como fuese, había que modificar el hardware y a su vez ya nos habíamos enterado de MAX232, así que para evitar mayores perdidas de tiempo nos inclinamos a la implementación de integrado, y problema resuelto. Además el otro método, por supuesto nos demandaba una fuente bipolar. 15 Técnicas Digitales III – Problema de ingeniería RECEPTOR E sistema de recepción esta compuesto por un hardware de detección-decodificación, integrado por un microcontrolador PIC16F84A, y la PC para la ejecución de una tarea determinada. En el circuito de detección-decodificación, el PIC16F84A, toma el dato serie (onda cuadrada) que el GL3276A proporciona como salida al recibir la señal del mando a distancia. Separa el código de mando del de dispositivo, hace el reconocimiento del dispositivo y envía el dato de comando mas el de repetición a la PC mediante el protocolo RS-232 a través del puerto serie de la misma. Para logra el cometido anterior, entre el PIC16F84A se instala un driver adaptador de nivel de señal MAX232. Este circuito integrado adapta la señal de 0V~5V que emite el PIC16F84A en su salida de dato a la PC a los respectivos niveles 10V~ (-10V) necesarios para representar el estado lógico en el protocolo RS-232. La transmisión a través del puerto serie se hace a 9600 baudios (baudio=bit/segundos) preseleccionados en la programación del PIC16F84A (ver código en PIC16F84A), y en el código fuente del programa que correrá en el ordenador (ver código en PC). Este es un esquemático del hardware de detección-decodificación: 16 Técnicas Digitales III – Problema de ingeniería Es un circuito muy sencillo: Led “PWR”: se enciende al alimentar el circuito. Led “Led V”: emite un destello por cada dato enviado a la PC, permanece encendido durante un segundo, aproximadamente (simultáneamente con “Led R”) de no poder concretar la comunicación. De presionar el pulsador “Borrar disp.” durante cierto tiempo el led enciende por un segundo dos veces para indicar salida de dato paralelo y una ves para indicar salida de datos serie. Led “Led R”: al encender el receptor, este no esta vinculado a ningún dispositivo (TV, etc.…) entonces esta situación se ve indicada por la permanencia de este led encendido. La situación se revierte al enviarle algún mensaje desde el control remoto (presionando cualquier tecla del control). A partir de entonces el receptor solo reconocerá mensajes provenientes de ese mando a distancia y con ese código de dispositivo. Si se quiere cambiar el código de dispositivo de reconocimiento por cualquier razón, el receptor consta de un pulsador “Borrar disp.” Que al presionarlo durante un tiempo reducido deshace la vinculación encendiendo nuevamente “Led R” y poniendo al receptor a la espera del nuevo código de reconocimiento. Pulsador “Borrar disp.”: pensionándolo durante un breve lapso de tiempo se deshace la vinculación del receptor y el código de dispositivo (código de reconocimiento), se encenderá entonces el “Led R”. Si el pulsador se presiona durante un tiempo prolongado el receptor, además de desvincular el mendo a distancia, cambia su modo de transmisión de datos a la PC, si estaba transmitiendo en serie lo hará en paralelo entonces (enciende por un segundo dos veces “Led V”), y viceversa (enciende por un segundo una vez “Led V”). Nota: para que el hardware pueda comunicarse con el ordenador mediante el puerto paralelo, se debe quita el buffer MAX232 lo cual se puede llevar a cabo interponiendo un conector entre este y la electrónica principal. En este conector también se debe conectar el adaptador de conexiones para efectuar la comunicación vía puerto paralelo. Esta comunicación envía el dato en dos partes como puede verse en el código fuente del PIC16F84A. En una primera instancia se envían los cuatro bits más significativos, se espera un determinado tiempo 17 Técnicas Digitales III – Problema de ingeniería una confirmación por parte de la PC y se procede al envío del pedazo restante para completar el byte. Esto es así para aprovechar mejor y de manera más simple las características del puerto según nuestras necesidades. Puerto paralelo: El puerto paralelo se implementa en hardware a través de una ficha DV25 (25 pines) macho (hembra en la PC) de los cuales desde el pin 18, inclusive, hasta el pin 25, también inclusive, sirven de masa. EL controlador de la comunicación consta de tres registros de 8 bit cada uno (un byte). El registro PORT 888, puerto de datos, (dirección en memoria 888), Pines del 2 al 9, es de solo escritura, por este registro se envían los datos al exterior de la PC. El registro PORT 889, puerto de estado, es de solo lectura, por aquí se enviaremos señales eléctricas al ordenador, de este registro solo se utilizan los cinco bits de más peso, que son el bit 7, 6, 5, 4 y 3 teniendo en cuenta que el bit 7 funciona en modo invertido, pines 15, 13, 12, 10 y 11. El registro PORT 890, puerto de control, es de lectura/escritura, es decir, podremos enviar o recibir señales eléctricas, según nuestras necesidades. De los 8 bits de este registro solo se utilizan los cuatro de menor peso o sea el 0, 1, 2 y 3, con un pequeño detalle, los bits 0, 1, y 3 están invertidos. Adaptación: Para enviar el dato a la PC utilizamos del puerto de estado los pines 10, 12, 13, y 15 (E6, E5, E4 y E3 respectivamente). Para la confirmación la esperamos por el puerto de datos, pin 2 (D0). La conexión cableada deberá hacerse como se indica a continuación: 18 Técnicas Digitales III – Problema de ingeniería EL CODIGO FUENTE DEL PIC16F84A Este código fuente debe encargarse de las tareas descriptas antes. Es importante remarcar que la comunicación con la PC mediante el protocolo RS-232 se debe programar porque no viene incorporada a diferencia del siguiente modelo de microcontrolador de Microchip PIC16F873. Para entender más fácilmente el código se muestra el siguiente diagrama de bloque del algoritmo. 19 Técnicas Digitales III – Problema de ingeniería Código fuente: Para la elaboración de este código fuente se utilizo un entorno de desarrollo integrado distribuido en forma gratuita por Microchip, el MPLAB 9.0 IDE. Para la programación o grabado del código en la memoria del PIC16F84A se uso otro programa de distribución libre y gratuita, el IC-Prog. Para esta ultima tarea también se hizo uso de una tarjeta de programación llamada ProPic 2 Programer. (Ver código fuente para PIC16F84A en Anexo C). ESTRUCTURA DE UN PROGRAMA WINDOWS GUI Para el desarrollo de este código fuente se utilizo un entorno de desarrollo integrado también. Se utilizo Dev-C 4.9, un producto de Bloodshed y se programo WIN API (Appication Programming Interface) con clases. Los programas Windows son independientes de la máquina en la que se ejecutan (o al menos deberían serlo), el acceso a los dispositivos físicos se hace a través de interfaces, y nunca se accede 20 Técnicas Digitales III – Problema de ingeniería directamente a ellos. Esta es una de las principales ventajas para el programador, ya que no hay que preocuparse por el modelo de tarjeta gráfica o de impresora, la aplicación funcionará con todas, y será el sistema operativo el que se encargue de que así sea. Un concepto importante es el de recurso. Desde el punto de vista de Windows, un recurso es todo aquello que puede ser usado por una o varias aplicaciones. Existen recursos físicos, que son los dispositivos que componen el ordenador, como la memoria, la impresora, el teclado o el ratón y recursos virtuales o lógicos, como los gráficos, los iconos o las cadenas de caracteres, etc. Por ejemplo, si nuestra aplicación requiere el uso de un puerto serie, primero debe averiguar si está disponible, es decir, si existe y si no lo está usando otra aplicación; y después lo reservará para su uso. Esto es necesario porque este tipo de recurso no puede ser compartido. Los programas en Windows están orientados a eventos, esto significa que normalmente los programas están esperando a que se produzca un acontecimiento que les incumba, y mientras tanto permanecen aletargados o dormidos. Un evento puede ser por ejemplo, el movimiento del ratón, la activación de un menú, la llegada de información desde el puerto serie, una pulsación de una tecla... Esto es así porque Windows es un sistema operativo multitarea, y el tiempo del microprocesador ha de repartirse entre todos los programas que se estén ejecutando. Si los programas fueran secuenciales puros, esto no sería posible, ya que hasta que una aplicación finalizara, el sistema no podría atender al resto. Ejemplo de programa secuencial: Ejemplo de programa por eventos: 21 Técnicas Digitales III – Problema de ingeniería Hay algunas diferencias entre la estructura de un programa C/C++ normal, y la correspondiente a un programa Windows GUI. Algunas de estas diferencias se deben a que los programas GUI estás basados en mensajes, otros son sencillamente debidos a que siempre hay un determinado número de tareas que hay que realizar. // Ficheros include: #include <windows.h> // Prototipos: LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM); // Función de entrada: int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { // Declaración: // Inicialización: // Bucle de mensajes: return Message.wParam; } // Definición de La función de entrada de un programa Windows es "WinMain", en lugar de la conocida "main". Normalmente, la definición de esta función cambia muy poco de una aplicación a otra. Se divide en tres partes claramente diferenciadas: declaración, inicialización y bucle de mensajes. Parámetros de entrada de "WinMain" int WINAPI WinMain(HINSTANCE lpszCmdParam, int nCmdShow) hInstance, HINSTANCE hPrevInstance, LPSTR La función WinMain tiene cuatro parámetros de entrada: hInstance es un manipulador para la instancia del programa que estamos ejecutando. Cada vez que se ejecuta una aplicación, Windows crea una Instancia para ella, y le pasa un manipulador de dicha instancia a la aplicación. hPrevInstance es un manipulador a instancias previas de la misma aplicación. Como Windows es multitarea, pueden existir varias versiones de la misma aplicación ejecutándose, varias instancias. En Windows 3.1, este parámetro nos servía para saber si nuestra aplicación ya se estaba ejecutando, y de ese modo se podían compartir los datos comunes a todas las instancias. Pero eso era antes, ya que en Win32 usa un segmento distinto para cada instancia y este parámetro es siempre NULL, sólo se conserva por motivos de compatibilidad. lpszCmdParam, esta cadena contiene los argumentos de entrada del comando de línea. 22 Técnicas Digitales III – Problema de ingeniería nCmdShow, este parámetro especifica cómo se mostrará la ventana. Para ver sus posibles valores consultar valores de ncmdshow. Se recomienda no usar este parámetro en la función ShowWindow la primera vez que se ésta es llamada. En su lugar debe usarse el valor SW_SHOWDEFAULT. Función WinMain típica int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpszCmdParam, int nCmdShow) { /* Declaración: */ HWND hwnd; MSG mensaje; WNDCLASSEX wincl; /* Inicialización: */ /* Estructura de la ventana */ wincl.hInstance = hInstance; wincl.lpszClassName = "NUESTRA_CLASE"; wincl.lpfnWndProc = WindowProcedure; wincl.style = CS_DBLCLKS; wincl.cbSize = sizeof(WNDCLASSEX); /* Usar icono y puntero por defecto */ wincl.hIcon = LoadIcon(NULL, IDI_APPLICATION); wincl.hIconSm = LoadIcon(NULL, IDI_APPLICATION); wincl.hCursor = LoadCursor(NULL, IDC_ARROW); wincl.lpszMenuName = NULL; wincl.cbClsExtra = 0; wincl.cbWndExtra = 0; wincl.hbrBackground = (HBRUSH)COLOR_BACKGROUND; /* Registrar la clase de ventana, si falla, salir del programa */ if(!RegisterClassEx(&wincl)) return 0; hwnd = CreateWindowEx( 0, "NUESTRA_CLASE", "Ejemplo 001", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 544, 375, HWND_DESKTOP, NULL, hThisInstance, NULL ); 23 Técnicas Digitales III – Problema de ingeniería ShowWindow(hwnd, SW_SHOWDEFAULT); /* Bucle de mensajes: */ while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } return mensaje.wParam; } Declaración En la primera zona declararemos las variables que necesitamos para nuestra función WinMain, que como mínimo serán tres: HWND hWnd, un manipulador para la ventana principal de la aplicación. Ya sabemos que nuestra aplicación necesitará al menos una ventana. MSG Message, una variable para manipular los mensajes que lleguen a nuestra aplicación. WNDCLASSEX wincl, una estructura que se usará para registrar la clase particular de ventana que usaremos en nuestra aplicación. Existe otra estructura para registrar clases que se usaba antiguamente, pero que ha sido desplazada por esta nueva versión, se trata de WNDCLASS. Inicialización Esta zona se encarga de registrar la clase o clases de ventana, crear la ventana y visualizarla en pantalla. Para registrar la clase primero hay que rellenar adecuadamente la estructura WNDCLASSEX, que define algunas características que serán comunes a todas las ventanas de una misma clase, como color de fondo, icono, menú por defecto, el procedimiento de ventana, etc. Después hay que llamar a la función RegisterClassEx. En el caso de usar una estructura WNDCLASS se debe registrar la clase usando la función RegisterClass. A continuación se crea la ventana usando la función CreateWindowEx, la función CreateWindow ha caído prácticamente en desuso. Cualquiera de estas dos funciones nos devuelve un manipulador de ventana que podemos necesitar en otras funciones, sin ir más lejos, la siguiente. Pero esto no muestra la ventana en la pantalla. Para que la ventana sea visible hay que llamar a la función ShowWindow. La primera vez que se llama a ésta función, después de crear la ventana, se puede usar el parámetro nCmdShow de WinMain como parámetro o mejor aún, como se recomienda por Windows, el valor SW_SHOWDEFAULT. 24 Técnicas Digitales III – Problema de ingeniería Bucle de mensajes Este es el núcleo de la aplicación, como se ve en el ejemplo el programa permanece en este bucle mientras la función GetMessage retorne con un valor TRUE. while(TRUE == GetMessage(&mensaje, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } Este es el bucle de mensajes recomendable, aunque no sea el que se usa habitualmente. La razón es que la función GetMessage puede retornar tres valores: TRUE, FALSE ó -1. El valor -1 indica un error, así que en este caso se debería abandonar el bucle. El bucle de mensajes que encontraremos habitualmente es este: while(GetMessage(&mensajee, 0, 0, 0)) { TranslateMessage(&mensaje); DispatchMessage(&mensaje); } NOTA: El problema con este bucle es que si GetMessage regresa con un valor -1, que indica un error, la condición del "while" se considera verdadera, y el bucle continúa. Si el error es permanente, el programa jamás terminará. La función TranslateMessage se usa para traducir los mensajes de teclas virtuales a mensajes de carácter. Los mensajes traducidos se reenvían a la lista de mensajes del proceso, y se recuperarán con las siguientes llamadas a GetMessage. La función DispatchMessage envía el mensaje al procedimiento de ventana, donde será tratado adecuadamente. El procedimiento de ventana Cada ventana tiene una función asociada, esta función se conoce como procedimiento de ventana, y es la encargada de procesar adecuadamente todos los mensajes enviados a una determinada clase de ventana. Es la responsable de todo lo relativo al aspecto y al comportamiento de una ventana. Normalmente, estas funciones están basadas en una estructura "switch" donde cada "case" corresponde aun determinado tipo de mensaje. Sintaxis LRESULT CALLBACK WindowProcedure( 25 Técnicas Digitales III – Problema de ingeniería HWND hwnd, // Manipulador de ventana UINT msg, // Mensaje WPARAM wParam, // Parámetro palabra, varía LPARAM lParam // Parámetro doble palabra, varía ); hwnd es el manipulador de la ventana a la que está destinado el mensaje. msg es el código del mensaje. wParam es el parámetro de tipo palabra asociado al mensaje. lParam es el parámetro de tipo doble palabra asociado al mensaje. Podemos considerar este prototipo como una plantilla para crear nuestros propios procedimientos de ventana. El nombre de la función puede cambiar, pero el valor de retorno y los parámetros deben ser los mismos. El miembro lpfnWndProc de la estructura WNDCLASS es un puntero a una función de este tipo, esa función es la que se encargará de procesar todos los mensajes para esa clase de ventana. Cuando registremos nuestra clase de ventana, tendremos que asignar a ese miembro el puntero a nuestro procedimiento de ventana. Prototipo de procedimiento de ventana LRESULT CALLBACK WindowProcedure(HWND, UINT, WPARAM, LPARAM); Implementación del procedimiento de ventana simple /* Esta función es llamada por la función del API DispatchMessage() */ LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { switch (msg) /* manipulador del mensaje */ { case WM_DESTROY: PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */ break; default: /* para los mensajes de los que no nos ocupamos */ return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } En general, habrá tantos procedimientos de ventana como programas diferentes y todos serán distintos, pero también tendrán algo en común: todos ellos procesarán los mensajes que lleguen a una clase de ventana. En este ejemplo sólo procesamos un tipo de mensaje, se trata de WM_DESTROY que es el mensaje que se envía a una ventana cuando se recibe un comando de cerrar, ya sea por menú o mediante el icono de aspa en la esquina superior derecha de la ventana. 26 Técnicas Digitales III – Problema de ingeniería Este mensaje sólo sirve para informar a la aplicación de que el usuario tiene la intención de abandonar la aplicación, y le da una oportunidad de dejar las cosas en su sitio: cerrar ficheros, liberar memoria, guardar variables, etc. Incluso, la aplicación puede decidir que aún no es el momento adecuado para abandonar la aplicación. En el caso del ejemplo, efectivamente cierra la aplicación, y lo hace enviándole un mensaje WM_QUIT, mediante la función PostQuitMessage. El resto de los mensajes se procesan en el caso "default", y simplemente se cede su tratamiento a la función del API que hace el proceso por defecto para cada mensaje, DefWindowProc. Este es el camino que sigue el mensaje WM_QUIT cuando llega, ya que el proceso por defecto para este mensaje es cerrar la aplicación. A grandes rasgos, básicamente, ya sabemos hacer el esqueleto de una aplicación de Windows. Para entender el resto del código que se presenta a continuación se pide al lector remitirse a la bibliografía. (ver código fuente para la PC en Anexo C). RESULTADOS DE LAS PRUEBAS Las pruebas fueron satisfactorias. Hubo que realizar algunas modificaciones antes de alcanzar el material o información expuesta en este informe. Finalmente conseguimos “fabricar” tanto la aplicación de la PC como el Hardware externo para el resolver el problema de ingeniería que se nos propuso. El archivo ejecutable de la aplicación resultante consta de la siguiente representación grafica básica: Haciendo click sobre el botón “Principal” El ítem “Reorganizar Botones” modifica la organización de la tabla cargada por defecto mostrada en el apartado “EL URC SBC-RU-240/38 DE PHILIPS”. Al presionar este item se abre un nuevo cuadro de dialogo que nos permite elegir la combinación de teclas a reordenar y a continuación el programa se dispone a esperar el correspondiente código emitido por el control remoto. Cuando la PC recibe este dato, el programa nos devuelve un mensaje de código guardado. En este ejemplo se selecciona la opción 2 (Alt). 27 Técnicas Digitales III – Problema de ingeniería Después de aceptar la elección, presionamos un botón del mando a distancia y el programa nos informa de su recepción: El ítem “Recordatorios” nos permite colocar una etiqueta recordatorio para cada combinación de tecla disponible. 28 Técnicas Digitales III – Problema de ingeniería El ítem “Default”, carga la tabla indicada en el apartado “EL URC SBC-RU-240/38 DE PHILIPS” en el caso de que el usuario no encuentre una mejor disposición del control remoto. Por ultimo, el ítem “Comenzar” provoca que el programa se disponga a “vigilar” el puerto serie en espera por la entrada de cada nuevo comando. CONCLUSIONES Durante la realización del proyecto el grupo tuvo que enfrentarse a muchísimos problemas, algunos comentados en este informe. Tuvimos muchísimos problemas, en un principio con la comunicación por el puerto serie. En primer lugar era tema de total desconocimiento para todos nosotros, así mismo con la comunicación por puerto paralelo, la cual la aprendimos por necesidad para poder solucionar el problema de no funcionamiento del puerto serie. Por suerte justo antes de hacer la implementación, de dicha comunicación, en el código fuente de la PC, probamos por última vez con el puerto serie y nos anduvo. Por ello es que en el código fuente de la aplicación para la PC no aparece la interacción con el puerto paralelo a pesar de que el PIC16F84A si es capaz de soportarla (en teoría pues no la alcanzamos a probar). En cuanto a la programación en entorno Windows tuvimos que leer muchísimo para así a duras penas poder hacer algo. En los comienzos logramos antes que nada establecer la comunicación serie en Windows 98 con un código programado en Borland C++ que andaba pero al no ser una aplicación de Windows, no podíamos de ninguna manera simular el teclado. Entonces ya con medio proyecto realizado tuvimos que echarnos atrás, desistir del Borland C++ y utilizar las API de Windows. 29 Técnicas Digitales III – Problema de ingeniería Código en Borland: #include #include #include #include <dos.h> <conio.h> <stdio.h> <stdlib.h> #define #define #define #define #define #define #define #define #define LCR IER DLL DLM MCR MSR LSR RBR THR #define #define #define #define #define #define DR OE PE FE BI DSR (base+3) (base+1) (base+0) (base+1) (base+4) (base+6) (base+5) (base+0) (base+0) 1 2 4 8 16 32 /* /* /* /* /* /* /* /* /* registro de control de linea */ registro de activacion de interrupciones */ parte baja del divisor */ parte alta del divisor */ registro de control del modem */ registro de estado del modem */ registro de estado de linea */ registro buffer de recepcion */ registro de retencion de transmision */ /* /* /* /* /* /* bit bit bit bit bit bit dato disponible del LSR */ de error de overrun del LSR */ de error de paridad del LSR */ de error en bits de stop del LSR */ de error de break en el LSR */ de data set ready */ unsigned com, base, dll, dlm, entrada, lsr, lcr, mcr, msr, divisor, con=0; char opc='z',c='z'; void impcart(void); void error(void); void correr(void); void ventana(void); void transdat(void); void main() { com=1; princ: clrscr(); impcart(); printf("\n\r1:Eleccion de puerto serie\n\r2:Correr programa\n\r3:Salir\n\rOpcion: "); opc=getch(); switch (opc) { case '1': { sound(1250); delay(250); nosound(); ventana(); scanf ("%d", &com); sound(1250); delay(225); nosound(); delay(100); sound(1250); delay(225); nosound(); } break; case '2': { sound(1250); delay(225); 30 Técnicas Digitales III – Problema de ingeniería nosound(); delay(100); sound(1250); delay(225); nosound(); correr(); } break; } if(opc=='3'); else goto princ; } void correr() { clrscr(); impcart(); base=peek(0x40, (com-1)*2); if (base==0) { error(); goto finc; } divisor=115200/8300; //para 9600 baudios outportb (LCR, 0x83); /* DLAB=1, 8 bits, 1 stop, sin paridad */ outportb (IER, 0); outportb (DLL, divisor%256); //resto de la division por 256 outportb (DLM, divisor/256); //parte entera de la division por 256 dll=inportb(DLL); dlm=inportb(DLM); outportb (LCR, 0x03); /* DLAB=0, 8 bits, 1 stop, sin paridad */ corr: outportb (MCR, 1); //limpio el control de modem do { lsr=inportb(LSR); msr=inportb(MSR); if(lsr & DR) outportb(MCR, 0); /* if (lsr & (PE|FE|BI)) { error(); goto corr; }*/ }while(!(lsr & DR) && !kbhit()); entrada=inportb(RBR); if(kbhit()) c=getche(); if(c=='e') goto finc; clrscr(); printf("dato: %d", entrada); transdat(); goto corr; finc: c='z'; return; } void error() { 31 Técnicas Digitales III – Problema de ingeniería gotoxy(23,11); textcolor(6); textbackground(4); cprintf(" error en la comunicacion textcolor(7); textbackground(0); getch(); return; } void impcart() { gotoxy(23,1); textcolor(4); textbackground(3); cprintf(" control remoto IR textcolor(7); textbackground(0); return; } void ventana() { gotoxy(23,11); textcolor(1); textbackground(3); cprintf(" ingrese el puerto preferido: textcolor(7); textbackground(0); return; } void transdat() { FILE *archi; archi=fopen("trans.txt", "w"); fprintf(archi, "%d", entrada); fclose(archi); return; } "); \n"); "); En este código se puede ver el intento de envío del dato recibido por el puerto a través de un archivo de texto para interactuar con el programa que simulaba el teclado y que si corría bajo Windows. Si bien esta técnica presenta muchos problemas de errores conceptuales, conseguíamos una mínima interacción entre el control remoto y la PC. El grupo entero considera un enriquecimiento muy importante de conocimientos, aprendimos mucho acerca de Windows como sistema operativo y de la PC como sistema eléctrico. También consideramos haber aprendido mucho de cómo es que se encara un trabajo particular a nivel profesional. Agradecemos la interacción constante por parte de los profesores entrevistados, agradecemos toda su paciencia y participación para con los alumnos y los problemas con los que nos enfrentamos… Gracias Ramiro… 32 Técnicas Digitales III – Problema de ingeniería ANEXOS Anexo A: LISTADO DE PROGRAMAS Código fuente para el PIC16F84A: List P=16F84 pua pub copua copub inte coti opci esta equ equ equ equ equ equ equ equ cblock 05h 06h 85h 86h 0Bh 01h 81h 03h 0X0C cnttrb cbyte byte cont1 cont2 cont3 disp1 disp contr contr1 contr2 aux endc #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define #define ir rts dtr txd rxd dsr cts bot ledv ledr prvz resul aplv tsp terr resu bit cop toif rbo tmro todas rbof car z org 00h pub,0 pub,1 pub,2 pub,3 pub,4 pub,5 pub,6 pub,7 pua,0 pua,2 aux,0 aux,1 aux,2 aux,3 aux,4 aux,5 aux,6 aux,7 inte,2 inte,4 inte,5 inte,7 inte,1 esta,0 esta,2 33 Técnicas Digitales III – Problema de ingeniería goto org goto inicio 04h intsub clrf bsf movlw movwf movlw movwf clrf bsf bcf clrf bsf clrf bsf bsf clrf clrf clrf movlw movwf clrf clrf clrf movlw movwf esta esta, 5 b'10001111' copub b'11111010' copua opci ;iterrupcion por flanco ;desendente opci,7 esta, 5 pua ledr pub dsr rxd inte aux disp h'ff' disp disp1 byte cbyte b'10010000' inte ;habilita IR rcecptor btfss goto bot esper movlw movwf d'33' cont1 movlw movwf d'255' cont2 decfsz goto decfsz goto btfss goto cont2,1 con2 cont1,1 con1 bot esper clrf bcf bsf call btfss goto movlw xorwf bsf call bcf btfss goto call bsf disp1 prvz ledr retalar bot esper b'00001000' aux, 1 ledv retalar ledv tsp esper retalar ledv inicio esper con1 con2 ;para retardo del pulsador ;la cantidad de pulsos de 1us ; para un reloj de 4 Mhz son: ;1 ;1 ; ;1*k ;1*k ; ;255*k+k=256*k ;2*255*k=510*k ;k+1 ;2*k ;************** ;771*k+3=>si 771*k+3=20 ms/1 ;us=25000=>k=32.42~33 34 Técnicas Digitales III – Problema de ingeniería call retalar bcf ledv goto esper ;****************************************************** ledat bsf esta,5 ;con un reloj de 4 Mhz: movlw b'10000001' ;tb'=889 us ;->tb=2*tb'=1.778 ms movwf opci ;TOIF= ;div*(257 us-tin)+2=889 bcf esta,5 ;con div=4=> ;tin=257-887/4=35.25~35 ;pero experimentalmente ;~36 entce ;voy a esperar ;que pase el primer ;bit de ;sincr btfss ir goto entce movlw d'147' ;pero la primer pregunta ;es a TOIF/2 movwf coti ;=>con div=4, ;tin=146.125=> ;tin~146, pero ;experimentalmente ~147 bcf toif clrf byte bcf bit clrf disp1 movlw d'26' movwf cnttrb etmr btfss toif goto etmr bcf toif movlw d'36' movwf coti decf cnttrb,1 movlw d'24' subwf cnttrb,0 btfss z goto etmr comie btfss toif goto comie movlw d'36' movwf coti bcf toif decf cnttrb,1 movlw d'12' subwf cnttrb,0 btfss z goto dsipo bcf bit incf cnttrb,1 ;para corregir tb el ultimo nibble goto cmnz dsipo movlw b'01000000' xorwf aux,1 btfss bit 35 Técnicas Digitales III – Problema de ingeniería goto btfsc goto bsf sgdo ir cerx disp1,0 goto comie bcf goto disp1,0 comie btfss goto btfss goto bcf rlf goto ir ceroz disp1,0 listim car disp1,1 comie btfsc goto bcf rlf goto disp1,0 listim car disp1,1 comie btfss goto movlw movwf bcf toif cmnz d'36' coti toif movlw xorwf btfss goto btfsc goto bsf goto b'01000000' aux,1 bit sgdz ir crxz byte,0 parch bcf byte,0 goto parch btfss goto btfss goto bcf rlf goto ir crz byte,0 listim car byte,1 parch btfsc goto bcf rlf byte,0 listim car byte,1 decfsz goto cnttrb,1 cmnz ;en disp1 esta guardando 1 ;bit de ;"T" y los 5 de ;dispositivo cerx sgdo ceroz cmnz comma crxz ;en byte guarda los 6 bit del comando sgdz crz parch acoreg ;pongo un cero en el bit 7 36 Técnicas Digitales III – Problema de ingeniería ;de byte si se da ;codigo de repeticion bcf rrf comf car byte,1 byte,1 movlw andwf andwf btfss goto btfss goto bcf goto b'00111111' disp1,1 byte,1 disp1,5 not disp,5 ciro byte,6 listi bsf bsf goto disp,5 byte,6 listi ;los datos estan ;exactamente al reves, ;comprobado con ;sciloscopio ciro not ;pongo un uno en el bit 7 ;de byte si no se da ;codigo de repeticion btfsc goto bcf goto disp,5 cir byte,6 listi bcf bsf goto disp,5 byte,6 listi bsf terr cir listim listi return ;****************************************************** cmprb movf disp1,0 subwf disp,0 btfsc z bsf cop finto return ;****************************************************** intsub bcf todas call ledat btfsc terr goto finle btfsc prvz goto disp1,0 movwf disp bsf prvz bcf ledr bsf ledv call retalar bcf ledv fingdi call cmprb btfss cop 37 Técnicas Digitales III – Problema de ingeniería goto bcf bsf btfss goto call goto finle cop ledv tsp serie datopcp finle call datopcs serie finle bcf ledv bcf terr bcf rbof bsf todas retfie ;****************************************************** datopcs movf byte,0 movwf cbyte movlw d'09' movwf contr bcf dsr ;espero un rato lo que dura un ;mensaje (25ms) y si la pc no me ;contesta, fue... bsf esta,5 ;para 25ms =>con div=128=> ;tin~61.7~62, pero ;experimentalmente ~61 movlw b'10000110' movwf opci movlw b'10001111' movwf copub bcf esta,5 movlw d'61' movwf coti bcf toif agnte btfss dtr goto acseg btfss toif goto agnte bsf ledr call retalar bcf ledr goto fintr acseg bsf esta,5 movlw b'10000000' movwf opci bcf esta,5 ;con un reloj de 4 Mhz, y ;para 9600 b/s: bcf toif ;tb=1/9600=104.16 us bcf rxd ;TOIF->104.16 ;us=>TOIF=(257us*div)+2 ;=>div=102.16 ;us/257us=0.398 movlw d'206' ;=>adopto div=2 y preseteo ;el TMRO: movwf coti ;=>(257-in)*2us+2us= ;104.16 us=> ;tin=257-102.16/2= ;205.92~206 ;experimentalmente ~206 38 Técnicas Digitales III – Problema de ingeniería bcf goto toif sgteb btfss cbyte,0 goto bsf rrf goto escer rxd cbyte,1 sgteb bcf rrf rxd cbyte,1 btfss goto movlw movwf bcf decfsz goto toif sgteb d'206' coti toif contr,1 estmr btfss goto bsf toif dtlst rxd estmr ;0 para empezar; ;transmitiendo el LSB. 7 ;de lo contrario. Se ;modifica el sentido de ;rotacion tb escer sgteb dtlst fintr bsf dsr bsf rxd return ;************************************************* retalar movlw d'20' movwf cont1 bsf esta,5 movlw b'10000111' movwf opci bcf esta,5 aquie clrf coti bcf toif pruev btfss toif goto pruev decfsz cont1,1 goto aquie return ;******************************************************* datopcp bsf esta, 5 movlw b'10000101' movwf copub bcf esta, 5 clrf cbyte btfsc byte, 0 bsf cbyte, 5 btfsc byte, 1 bsf cbyte, 6 btfsc byte, 2 bsf cbyte, 3 39 Técnicas Digitales III – Problema de ingeniería btfsc bsf movf movwf byte, 3 cbyte, 1 cbyte, 0 pub bsf esta,5 movlw movwf bcf movlw movwf bcf b'10000110' opci esta,5 d'61' coti toif btfsc goto btfss goto bsf call bcf goto dtr acsegp toif agntep ledr retalar ledr fintra clrf btfsc bsf btfsc bsf btfsc bsf btfsc bsf movf movwf cbyte byte, 4 cbyte, 5 byte, 5 cbyte, 6 byte, 6 cbyte, 3 byte, 7 cbyte, 1 cbyte, 0 pub ;espero un rato lo que dura un ;mensaje ; ;(25ms) y si la pc no me ;contesta, fue... ;para 25ms =>con div=128=> ;tin~61.7~62, ;pero experimentalmente ~61 agntep acsegp fintra call retalar clrf pub return ;*************************************************** END 40 Técnicas Digitales III – Problema de ingeniería Código fuente para la PC: WinMain: #include #include #include #include #include #include #include #include <windows.h> <IDS3.h> <iostream> <string.h> <assert.h> <stdlib.h> <windows.h> <cstdlib> using namespace std; typedef struct { char Puerto[5]; int Baudios; int BitsDatos; int BitsStop; char Paridad[25]; } tipoOpciones; // Variables globales: tipoOpciones Ops; // Opciones HGLOBAL hCadena, hSalida; // Buffers int *sal, *cad; DCB dcb; // Puerto serie HANDLE idComDev; bool Comunicacion; int aux2; char dinum[20]="C:\\nume.txt"; char diide[20]="C:\\iden.txt"; FILE *numeros, *ide; int num[50], con1, tec[50]; char idtf[22][80]; // Prototipos: void IniciarBuffers(); void comenzar(void); void actualizar(); void actualizaride(); void LiberarBuffers(); bool InicioComunicacion(void); bool FinComunicacion(void); int lee_el_puerto(void); void LeeSerie(); void crear_la_tabla(); void crear_la_tablaide(); void cargar_archivo(); void cargar_archivoide(); /* Declaración del procedimiento de ventana */ LRESULT CALLBACK WindowProcedure (HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DlgProc(HWND, UINT, WPARAM, LPARAM); BOOL CALLBACK DlgProc2(HWND, UINT, WPARAM, LPARAM); 41 Técnicas Digitales III – Problema de ingeniería /* Declaraciones de tipos */ typedef struct stDatos { int Teclas; char identif1[80]; char identif2[80]; char identif3[80]; char identif4[80]; char identif5[80]; char identif6[80]; char identif7[80]; char identif8[80]; char identif9[80]; char identif10[80]; char identif11[80]; char identif12[80]; char identif13[80]; char identif14[80]; char identif15[80]; char identif16[80]; char identif17[80]; char identif18[80]; char identif19[80]; char identif20[80]; char identif21[80]; } DATOS; int WINAPI WinMain (HINSTANCE hThisInstance, HINSTANCE hPrevInstance, LPSTR lpszArgument, int nFunsterStil) { HWND hwnd; /* Manipulador de ventana */ MSG mensaje; /* Mensajes recibidos por la aplicación */ WNDCLASSEX wincl; /* Estructura de datos para la clase de ventana */ num[0]=EOF; idtf[21][0]=EOF; tec[0]=EOF; /* Estructura de la ventana */ wincl.hInstance = hThisInstance; wincl.lpszClassName = "NUESTRA_CLASE"; wincl.lpfnWndProc = WindowProcedure; /* Esta función es invocada por Windows */ wincl.style = CS_DBLCLKS; /* Captura los doble-clicks */ wincl.cbSize = sizeof (WNDCLASSEX); /* Usar icono y puntero por defecto */ wincl.hIcon = LoadIcon (hThisInstance, "icono"); wincl.hIconSm = LoadIcon (hThisInstance, "icono"); wincl.hCursor = LoadCursor (NULL, IDC_ARROW); wincl.lpszMenuName = "Menu"; wincl.cbClsExtra = 0; /* Sin información adicional para la */ wincl.cbWndExtra = 0; /* clase o la ventana */ /* Usar el color de fondo por defecto para la ventana */ wincl.hbrBackground = (HBRUSH) COLOR_BACKGROUND; /* Registrar la clase de ventana, si falla, salir del programa */ if(!RegisterClassEx(&wincl)) return 0; 42 Técnicas Digitales III – Problema de ingeniería /* La clase está registrada, crear la ventana */ hwnd = CreateWindowEx( 0, /* Posibilidades de variación */ "NUESTRA_CLASE", /* Nombre de la clase */ "Control Remoto", /* Texto del título */ WS_OVERLAPPEDWINDOW, /* Tipo por defecto */ CW_USEDEFAULT, /* Windows decide la posición */ CW_USEDEFAULT, /* donde se coloca la ventana */ 200, /* Ancho */ 100, /* Alto en pixels */ HWND_DESKTOP, /* La ventana es hija del escritorio */ NULL, /* Sin menú */ hThisInstance, /* Manipulador de instancia */ NULL /* No hay datos de creación de ventana */ ); /* Mostrar la ventana */ ShowWindow(hwnd, SW_SHOWDEFAULT); /* Bucle de mensajes, se ejecuta hasta que haya error o GetMessage devuelva FALSE */ while(TRUE == GetMessage(&mensaje, NULL, 0, 0)) { /* Traducir mensajes de teclas virtuales a mensajes de caracteres */ TranslateMessage(&mensaje); /* Enviar mensaje al procedimiento de ventana */ DispatchMessage(&mensaje); } /* Salir con valor de retorno */ return mensaje.wParam; } /* Esta función es invocada por la función DispatchMessage() */ LRESULT CALLBACK WindowProcedure(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) { static HINSTANCE hInstance; static DATOS Datos; switch (msg) /* manipulador del mensaje */ { case WM_CREATE: hInstance = ((LPCREATESTRUCT)lParam)->hInstance; /* Inicialización de los datos de la aplicación */ Datos.Teclas = 1; return 0; break; case WM_COMMAND: if(LOWORD(wParam) == CM_DIALOGO) DialogBoxParam(hInstance, "DialogoTeclas", hwnd, DlgProc, (LPARAM)&Datos); if(LOWORD(wParam) == CM_DIALOGO2) DialogBoxParam(hInstance, "DialogoTeclasmos", hwnd, DlgProc2, (LPARAM)&Datos); if(LOWORD(wParam) == CM_DIALOGO3) { comenzar(); } if(LOWORD(wParam) == CM_DIALOGO4) crear_la_tabla(); 43 Técnicas Digitales III – Problema de ingeniería break; case WM_DESTROY: PostQuitMessage(0); /* envía un mensaje WM_QUIT a la cola de mensajes */ break; default: /* para los mensajes de los que no nos ocupamos */ return DefWindowProc(hwnd, msg, wParam, lParam); } return 0; } BOOL CALLBACK DlgProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { BOOL NumeroOk; static DATOS *datos; int nume, auxi, auxi2; if((numeros=fopen(dinum, "rb"))==NULL) crear_la_tabla(); else fclose(numeros); cargar_archivo(); switch (msg) /* manipulador del mensaje */ { case WM_INITDIALOG: datos = (DATOS *)lParam; SetDlgItemInt(hDlg, ID_TECLAS, (UINT)datos->Teclas, FALSE); SetFocus(GetDlgItem(hDlg, ID_TECLAS)); return FALSE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: nume = GetDlgItemInt(hDlg, ID_TECLAS, &NumeroOk, FALSE); if(NumeroOk) { inv: datos->Teclas = nume; EndDialog(hDlg, FALSE); if(nume>21 || nume<1) { MessageBox(hDlg, "Entrada Invalida", "Relacionando", MB_OK); return FALSE; } auxi=lee_el_puerto(); MessageBox(hDlg, "Codigo Guardado", "Relacionando", MB_OK); auxi2=num[nume-1]; for(con1=0;con1<21;con1++) if(num[con1]==auxi) num[con1]=auxi2; con1++; num[nume-1]=auxi; actualizar(); } else MessageBox(hDlg, "Número no válido", "Error", MB_ICONEXCLAMATION | MB_OK); break; case IDCANCEL: 44 Técnicas Digitales III – Problema de ingeniería EndDialog(hDlg, FALSE); break; } return TRUE; } return FALSE; } BOOL CALLBACK DlgProc2(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) { static DATOS *datos; if((ide=fopen(diide, "a"))==NULL) crear_la_tablaide(); else fclose(ide); cargar_archivoide(); switch (msg) /* manipulador del mensaje */ { case WM_INITDIALOG: datos = (DATOS *)lParam; SetDlgItemText(hDlg, ID_IDENT1, idtf[0]); SetDlgItemText(hDlg, ID_IDENT2, idtf[1]); SetDlgItemText(hDlg, ID_IDENT3, idtf[2]); SetDlgItemText(hDlg, ID_IDENT4, idtf[3]); SetDlgItemText(hDlg, ID_IDENT5, idtf[4]); SetDlgItemText(hDlg, ID_IDENT6, idtf[5]); SetDlgItemText(hDlg, ID_IDENT7, idtf[6]); SetDlgItemText(hDlg, ID_IDENT8, idtf[7]); SetDlgItemText(hDlg, ID_IDENT9, idtf[8]); SetDlgItemText(hDlg, ID_IDENT10, idtf[9]); SetDlgItemText(hDlg, ID_IDENT11, idtf[10]); SetDlgItemText(hDlg, ID_IDENT12, idtf[11]); SetDlgItemText(hDlg, ID_IDENT13, idtf[12]); SetDlgItemText(hDlg, ID_IDENT14, idtf[13]); SetDlgItemText(hDlg, ID_IDENT15, idtf[14]); SetDlgItemText(hDlg, ID_IDENT16, idtf[15]); SetDlgItemText(hDlg, ID_IDENT17, idtf[16]); SetDlgItemText(hDlg, ID_IDENT18, idtf[17]); SetDlgItemText(hDlg, ID_IDENT19, idtf[18]); SetDlgItemText(hDlg, ID_IDENT20, idtf[19]); SetDlgItemText(hDlg, ID_IDENT21, idtf[20]); SetFocus(GetDlgItem(hDlg, ID_IDENT1)); return FALSE; case WM_COMMAND: switch(LOWORD(wParam)) { case IDOK: GetDlgItemText(hDlg, ID_IDENT1, datos->identif1, 80); strcpy(idtf[0], datos->identif1); GetDlgItemText(hDlg, ID_IDENT2, datos->identif2, 80); strcpy(idtf[1], datos->identif2); GetDlgItemText(hDlg, ID_IDENT3, datos->identif3, 80); strcpy(idtf[2], datos->identif3); GetDlgItemText(hDlg, ID_IDENT4, datos->identif4, 80); strcpy(idtf[3], datos->identif4); GetDlgItemText(hDlg, ID_IDENT5, datos->identif5, 80); strcpy(idtf[4], datos->identif5); GetDlgItemText(hDlg, ID_IDENT6, datos->identif6, 80); strcpy(idtf[5], datos->identif6); GetDlgItemText(hDlg, ID_IDENT7, datos->identif7, 80); strcpy(idtf[6], datos->identif7); 45 Técnicas Digitales III – Problema de ingeniería GetDlgItemText(hDlg, ID_IDENT8, datos->identif8, 80); strcpy(idtf[7], datos->identif8); GetDlgItemText(hDlg, ID_IDENT9, datos->identif9, 80); strcpy(idtf[8], datos->identif9); GetDlgItemText(hDlg, ID_IDENT10, datos->identif10, 80); strcpy(idtf[9], datos->identif10); GetDlgItemText(hDlg, ID_IDENT11, datos->identif11, 80); strcpy(idtf[10], datos->identif11); GetDlgItemText(hDlg, ID_IDENT12, datos->identif12, 80); strcpy(idtf[11], datos->identif12); GetDlgItemText(hDlg, ID_IDENT13, datos->identif13, 80); strcpy(idtf[12], datos->identif13); GetDlgItemText(hDlg, ID_IDENT14, datos->identif14, 80); strcpy(idtf[13], datos->identif14); GetDlgItemText(hDlg, ID_IDENT15, datos->identif15, 80); strcpy(idtf[14], datos->identif15); GetDlgItemText(hDlg, ID_IDENT16, datos->identif16, 80); strcpy(idtf[15], datos->identif16); GetDlgItemText(hDlg, ID_IDENT17, datos->identif17, 80); strcpy(idtf[16], datos->identif17); GetDlgItemText(hDlg, ID_IDENT18, datos->identif18, 80); strcpy(idtf[17], datos->identif18); GetDlgItemText(hDlg, ID_IDENT19, datos->identif19, 80); strcpy(idtf[18], datos->identif19); GetDlgItemText(hDlg, ID_IDENT20, datos->identif20, 80); strcpy(idtf[19], datos->identif20); GetDlgItemText(hDlg, ID_IDENT21, datos->identif21, 80); strcpy(idtf[20], datos->identif21); actualizaride(); EndDialog(hDlg, FALSE); break; case IDCANCEL: EndDialog(hDlg, FALSE); break; } return TRUE; } return FALSE; } int lee_el_puerto(void) { int c; DWORD dwEvtMask; DWORD n, param, id; // Inicializar opciones del puerto serie: strcpy(Ops.Puerto, "COM1"); Ops.Baudios = 9600; Ops.BitsDatos = 8; Ops.BitsStop = 1; strcpy(Ops.Paridad, "Sin paridad"); IniciarBuffers(); // No se ha establecido comunicación: Comunicacion = false; if(!InicioComunicacion()) { LiberarBuffers(); return 1; } 46 Técnicas Digitales III – Problema de ingeniería do { }while(!((WaitCommEvent(idComDev, &dwEvtMask, NULL))&&(dwEvtMask & EV_RXCHAR))); LeeSerie(); c=*cad; FinComunicacion(); LiberarBuffers(); aux2=c&127; c=c&63; aux2=aux2-c; return(c); } // Reservar memoria global para buffers del puerto serie: void IniciarBuffers() { hCadena = GlobalAlloc(GMEM_MOVEABLE, 4096); hSalida = GlobalAlloc(GMEM_MOVEABLE, 4096); cad = (int *)GlobalLock(hCadena); sal = (int *)GlobalLock(hSalida); } // Liberar memoria global de buffers del puerto serie: void LiberarBuffers() { GlobalUnlock(hCadena); GlobalUnlock(hSalida); GlobalFree(hCadena); GlobalFree(hSalida); } // Iniciar el puerto serie: bool InicioComunicacion(void) { bool fSuccess; // Abrir el fichero asociado al puerto: idComDev = CreateFile(Ops.Puerto, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); if(idComDev ==INVALID_HANDLE_VALUE) return false; // Leer estructura de control del puerto serie, cdb: fSuccess = GetCommState(idComDev, &dcb); if(!fSuccess) return false; // Modificar el dcb según las opciones definidas: dcb.BaudRate = Ops.Baudios; dcb.ByteSize = Ops.BitsDatos; if(!strcmp(Ops.Paridad, "Sin paridad")) dcb.Parity = NOPARITY; if(!strcmp(Ops.Paridad, "Paridad par")) dcb.Parity = EVENPARITY; if(!strcmp(Ops.Paridad, "Paridad impar")) dcb.Parity = ODDPARITY; switch(Ops.BitsStop) { case 1: dcb.StopBits = ONESTOPBIT; break; case 2: dcb.StopBits = TWOSTOPBITS; break; 47 Técnicas Digitales III – Problema de ingeniería } // Modificar la estructura de control del puerto serie: fSuccess = SetCommState(idComDev, &dcb); if(!fSuccess) return false; // Especifica que queremos monitorizar la recepción de datos: if(!SetCommMask(idComDev, EV_RXCHAR)) return false; // Comunicación establecida: Comunicacion = true; return true; } // Finalizar comunicación por puerto serie: bool FinComunicacion(void) { // Liberar máscara de eventos del puerto serie: SetCommMask(idComDev, 0); // Cerrar el puerto serie: CloseHandle(idComDev); // Comunicación interrumpida: Comunicacion = false; return true; } // Leer datos del puerto serie: void LeeSerie() { int i, j, k; DWORD x; COMSTAT cs; // Actualizar COMSTAT, sirve para // averiguar el número de bytes en el buffer de entrada: ClearCommError(idComDev, &x, &cs); // Leer cs.cbInQue caracteres: ReadFile(idComDev, cad, cs.cbInQue, &x, NULL); // Actualizar el fin de cadena: cad[x]=0; return; } void comenzar() { int delcontr, aux, i, k=0; //inicio if((numeros=fopen(dinum, "rb"))==NULL) crear_la_tabla(); else fclose(numeros); cargar_archivo(); if((ide=fopen(diide, "r"))==NULL) crear_la_tablaide(); else fclose(ide); cargar_archivoide(); for(i=0;i<21;i++) tec[i]=i+1; tec[21]=EOF; otra: 48 Técnicas Digitales III – Problema de ingeniería delcontr=lee_el_puerto(); con1=0; while(num[con1]!=delcontr && (con1<100)) con1++; if((num[con1]==EOF)||((aux!=9)&&(aux!=10)&&(aux2==0))) goto otra; aux=tec[con1]; switch(aux) { case 1: keybd_event(VK_RIGHT,0xcd,0 , 0); // Periona Flecha derecha keybd_event(VK_RIGHT,0xcd,KEYEVENTF_KEYUP,0); // Suelta Flecha derecha break; case 2: if((k%2)==0) keybd_event(VK_MENU,0xb8,0 , 0); //Presiona Alt else keybd_event(VK_MENU,0xb8,KEYEVENTF_KEYUP,0); // Suelta Alt k++; break; case 3: keybd_event(VkKeyScan('B'),0xb0,0 , 0); // Presiona 'B' keybd_event(VkKeyScan('B'),0xb0, KEYEVENTF_KEYUP,0); // Suelta 'B' break; case 4: keybd_event(VkKeyScan('Z'),0xac,0 , 0); // Presiona 'Z' keybd_event(VkKeyScan('Z'),0xac, KEYEVENTF_KEYUP,0); // Suelta 'Z' break; case 5: keybd_event(VkKeyScan('X'),0xad,0 , 0); // Presiona 'X' keybd_event(VkKeyScan('X'),0xad, KEYEVENTF_KEYUP,0); // Suelta 'X' break; case 6: keybd_event(VK_RETURN,0x9c,0 , 0); // Periona Enter keybd_event(VK_RETURN,0x9c,KEYEVENTF_KEYUP,0); // Suelta Enter break; case 7: keybd_event(VkKeyScan('L'),0xa6,0 , 0); // Presiona 'L' keybd_event(VkKeyScan('L'),0xa6, KEYEVENTF_KEYUP,0); // Suelta 'L' break; case 8: keybd_event(VK_RSHIFT,0xb6,0 , 0); // Periona Shift derecho keybd_event(VkKeyScan('L'),0xa6,0 , 0); // Presiona 'L' keybd_event(VkKeyScan('L'),0xa6, KEYEVENTF_KEYUP,0); // Suelta 'L' keybd_event(VK_RSHIFT,0xb6,KEYEVENTF_KEYUP,0); // Suelta Shift derecho break; case 9: keybd_event(VK_UP,0xc8,0 , 0); // Periona Flecha arriba keybd_event(VK_UP,0xc8,KEYEVENTF_KEYUP,0); // Suelta Flecha arriba break; case 10: keybd_event(VK_DOWN,0xd0,0 , 0); //Presiona Flecha abajo keybd_event(VK_DOWN,0xd0,KEYEVENTF_KEYUP,0); // Suelta Flecha abajo break; case 11: keybd_event(VK_ESCAPE,0x81,0 , 0); // Presiona Esape keybd_event(VK_ESCAPE,0x81, KEYEVENTF_KEYUP,0); // Suelta Esape break; case 12: keybd_event(VK_SPACE,0xb9,0 , 0); // Presiona Barra espaciadora keybd_event(VK_SPACE,0xb9, KEYEVENTF_KEYUP,0); // Suelta Barra espaciadora break; case 13: keybd_event(VK_BACK,0x8e,0 , 0); // Presiona Back Space 49 Técnicas Digitales III – Problema de ingeniería keybd_event(VK_BACK,0x8e, KEYEVENTF_KEYUP,0); // suelta Back Space break; case 14: keybd_event(VK_MENU,0xb8,0 , 0); //Presiona Alt keybd_event(VK_SPACE,0xb9,0 , 0); // Presiona Barra espaciadora keybd_event(VK_SPACE,0xb9, KEYEVENTF_KEYUP,0); // Suelta Barra espaciadora keybd_event(VK_MENU,0xb8,KEYEVENTF_KEYUP,0); // Suelta Alt break; case 15: keybd_event(VK_MENU,0xb8,0 , 0); //Presiona Alt keybd_event(VK_F4,0xbe,0 , 0); // Presiona Tecla F4 keybd_event(VK_F4,0xbe, KEYEVENTF_KEYUP,0); // Suelta Tecla F4 keybd_event(VK_MENU,0xb8,KEYEVENTF_KEYUP,0); // Suelta Alt break; case 16: keybd_event(VK_CONTROL,0x9d,0 , 0); // Periona Ctrl keybd_event(VK_TAB,0x8f,0 , 0); //Prtesiona tab keybd_event(VK_TAB,0x8f, KEYEVENTF_KEYUP,0); //suelta tab keybd_event(VK_CONTROL,0x9d,KEYEVENTF_KEYUP,0); // Suelta Ctrl break; case 17: keybd_event(VK_TAB,0x8f,0 , 0); //Prtesiona tab keybd_event(VK_TAB,0x8f, KEYEVENTF_KEYUP,0); //suelta tab break; case 18: keybd_event(VK_LEFT,0xcb,0 , 0); // Flecha izquierda keybd_event(VK_LEFT,0xcb, KEYEVENTF_KEYUP,0); // Flecha izquierda break; case 19: keybd_event(VK_LWIN,0x9b,0 , 0); // Periona Windows keybd_event(VK_LWIN,0x9b,KEYEVENTF_KEYUP,0); // Suelta Windows break; case 20: keybd_event(VK_LWIN,0x9c,0 , 0); // Periona Windows keybd_event(VkKeyScan('M'),0xa6,0 , 0); // Presiona 'M' keybd_event(VkKeyScan('M'),0xa6, KEYEVENTF_KEYUP,0); // Suelta 'M' keybd_event(VK_LWIN,0x9c,KEYEVENTF_KEYUP,0); // Suelta Windows break; case 21: keybd_event(VK_RSHIFT,0xb6,0 , 0); // Periona Shift derecho keybd_event(VK_TAB,0x8f,0 , 0); //Prtesiona tab keybd_event(VK_TAB,0x8f, KEYEVENTF_KEYUP,0); //suelta tab keybd_event(VK_RSHIFT,0xb6,KEYEVENTF_KEYUP,0); // Suelta Shift derecho break; } goto otra; } void crear_la_tabla() { num[0]=52; num[1]=9; num[2]=3; num[3]=1; num[4]=2; num[5]=12; num[6]=7; num[7]=8; num[8]=32; num[9]=33; num[10]=55; num[11]=0; num[12]=48; num[13]=15; 50 Técnicas Digitales III – Problema de ingeniería num[14]=56; num[15]=5; num[16]=4; num[17]=50; num[18]=54; num[19]=53; num[20]=6; num[21]=EOF; numeros=fopen(dinum, "wb"); for(con1=0;con1<21;con1++) fprintf(numeros, "%d\n", num[con1]); fclose(numeros); fclose(numeros); return; } void cargar_archivo() { numeros=fopen(dinum, "rb"); for(con1=0;con1<21;con1++) fscanf(numeros, "%d", &num[con1]); fclose(numeros); return; } void actualizar() { numeros=fopen(dinum, "wb"); con1=0; do { fprintf(numeros, "%d\n", num[con1]); con1++; }while(num[con1]!=EOF); fclose(numeros); return; } void actualizaride() { ide=fopen(diide, "w"); fprintf(ide, "p\n"); for(con1=0;con1<21;con1++) fprintf(ide, "%s\n", idtf[con1]); fprintf(ide, "%d\n", EOF); fclose(ide); return; } void cargar_archivoide() { char pru; ide=fopen(diide, "r"); fscanf(ide, "%c\n", &pru); for(con1=0;con1<21;con1++) fscanf(ide, "%s\n", &idtf[con1][0]); fclose(ide); return; } void crear_la_tablaide() { for(con1=0;con1<21; con1++) strcpy(idtf[con1], " "); actualizaride(); return; 51 Técnicas Digitales III – Problema de ingeniería } Archivo de Recursos: #include <windows.h> #include <IDS3.H> Menu MENU BEGIN POPUP "&Principal" BEGIN MENUITEM "&Reorganizar Botones", CM_DIALOGO MENUITEM SEPARATOR MENUITEM "&Recordatorios", CM_DIALOGO2 MENUITEM SEPARATOR MENUITEM "&Comenzar", CM_DIALOGO3 MENUITEM SEPARATOR MENUITEM "&Default Botones", CM_DIALOGO4 END END icono ICON "ICONGROUP_92.ico" DialogoTeclas DIALOG 0, 0, 145, 200 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Ingresar Tecla" FONT 8, "Helv" { CONTROL "1) Flchder", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 5, 52, 34 CONTROL "2) Alt", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 20, 52, 34 CONTROL "3) B", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 35, 52, 34 CONTROL "4) Z", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 50, 52, 34 CONTROL "5) X", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 65, 52, 34 CONTROL "6) Enter", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 85, 52, 34 CONTROL "7) L", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 100, 52, 34 CONTROL "8) Shift+L", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 115, 52, 34 CONTROL "9) Flcharr", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 130, 52, 34 CONTROL "10) Flchaba", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 145, 52, 34 CONTROL "11) Esc", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 5, 52, 34 52 Técnicas Digitales III – Problema de ingeniería CONTROL "12) BarEspc", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 20, 52, 34 CONTROL "13) BackSpc", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 35, 52, 34 CONTROL "14) Alt+Espc", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 50, 52, 34 CONTROL "15) Alt+F4", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 65, 52, 34 CONTROL "16) Ctrl+Tab", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 85, 52, 34 CONTROL "17) Tab", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 100, 52, 34 CONTROL "18) Flchizq", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 115, 52, 34 CONTROL "19) Inicio", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 130, 52, 34 CONTROL "20) Escritorio", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 145, 52, 34 CONTROL "21) Shift+Tab", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 88, 160, 52, 34 CONTROL "Eleccion:", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 160, 52, 34 CONTROL "", ID_TECLAS, "EDIT", ES_NUMBER | ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 46, 160, 36, 12 CONTROL "Aceptar", IDOK, "BUTTON", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 75, 175, 45, 14 CONTROL "Cancelar", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 15, 175, 45, 14 } DialogoTeclasmos DIALOG 0, 0, 310, 200 STYLE DS_MODALFRAME | WS_POPUP | WS_VISIBLE | WS_CAPTION CAPTION "Relaciones Disponibles" FONT 8, "Helv" { CONTROL "<-Recordartorios->", -1, "static", SS_LEFT | WS_CHILD | WS_VISIBLE, 121, 5, 60, 34 CONTROL "1) Flchder :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 5, 52, 34 CONTROL "", ID_IDENT1, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 55, 5, 66, 12 CONTROL "2) Alt :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 20, 52, 34 53 Técnicas Digitales III – Problema de ingeniería CONTROL "", ID_IDENT2, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 20, 66, 12 CONTROL "3) B :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 35, 52, 34 CONTROL "", ID_IDENT3, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 35, 66, 12 CONTROL "4) Z :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 50, 52, 34 CONTROL "", ID_IDENT4, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 50, 66, 12 CONTROL "5) X :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 65, 52, 34 CONTROL "", ID_IDENT5, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 65, 66, 12 CONTROL "6) Enter :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 85, 52, 34 CONTROL "", ID_IDENT6, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 85, 66, 12 CONTROL "7) L :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 100, 52, 34 CONTROL "", ID_IDENT7, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 100, 66, 12 CONTROL "8) Shift+L :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 115, 60, 34 CONTROL "", ID_IDENT8, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 115, 66, 12 CONTROL "9) Flcharr :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 130, 60, 34 CONTROL "", ID_IDENT9, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 130, 66, 12 CONTROL "10) Flchaba :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 145, 60, 34 CONTROL "", ID_IDENT10, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 55, 145, 66, 12 CONTROL ":12) Esc", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 5, 52, 34 CONTROL "", ID_IDENT11, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER 180, 5, 66, 12 CONTROL ":13) BarEsp", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 20, 52, 34 CONTROL "", ID_IDENT12, "EDIT", | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, | WS_TABSTOP, 54 Técnicas Digitales III – Problema de ingeniería ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 20, 66, 12 CONTROL ":14 BackSpa", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 35, 52, 34 CONTROL "", ID_IDENT13, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 35, 66, 12 CONTROL ":15) Alt+Spac", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 50, 52, 34 CONTROL "", ID_IDENT14, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 50, 66, 12 CONTROL ":16) Alt+F4", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 65, 52, 34 CONTROL "", ID_IDENT15, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 65, 66, 12 CONTROL ":17) Ctrl+Tab", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 85, 52, 34 CONTROL "", ID_IDENT16, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 85, 66, 12 CONTROL ":18) Tab", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 100, 52, 34 CONTROL "", ID_IDENT17, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 100, 66, 12 CONTROL ":19) Flchizq", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 115, 52, 34 CONTROL "", ID_IDENT18, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 115, 66, 12 CONTROL ":20) Inicio", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 130, 52, 34 CONTROL "", ID_IDENT19, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 130, 66, 12 CONTROL ":21) Escritorio", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 250, 145, 52, 34 CONTROL "", ID_IDENT20, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 180, 145, 66, 12 CONTROL "11) Shift+Tab :", -1, "STATIC", SS_LEFT | WS_CHILD | WS_VISIBLE, 8, 160, 70, 34 CONTROL "", ID_IDENT21, "EDIT", ES_LEFT | WS_CHILD | WS_VISIBLE | WS_BORDER | WS_TABSTOP, 55, 160, 66, 12 CONTROL "Aceptar", IDOK, "BUTTON", BS_DEFPUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 250, 175, 50, 14 CONTROL "Cancelar", IDCANCEL, "BUTTON", BS_PUSHBUTTON | BS_CENTER | WS_CHILD | WS_VISIBLE | WS_TABSTOP, 55 Técnicas Digitales III – Problema de ingeniería 160, 175, 50, 14 } Código de la librería IDS3.H Esta librería la creamos nosotros para suministrar las definiciones de las constantes que luego usamos tanto en el WinMain como en el archivo de recursos /* Identificadores */ /* Identificadores de comandos */ #define CM_DIALOGO 101 #define CM_DIALOGO2 102 #define CM_DIALOGO3 103 #define CM_DIALOGO4 104 /* Identificadores de diálogo */ #define ID_TECLAS 100 #define ID_TECLASMOS 101 #define ID_IDENT1 102 #define ID_IDENT2 103 #define ID_IDENT3 104 #define ID_IDENT4 105 #define ID_IDENT5 106 #define ID_IDENT6 122 #define ID_IDENT7 107 #define ID_IDENT8 108 #define ID_IDENT9 109 #define ID_IDENT10 110 #define ID_IDENT11 111 #define ID_IDENT12 112 #define ID_IDENT13 113 #define ID_IDENT14 114 #define ID_IDENT15 115 #define ID_IDENT16 116 #define ID_IDENT17 117 #define ID_IDENT18 118 #define ID_IDENT19 119 #define ID_IDENT20 120 #define ID_IDENT21 121 56 Técnicas Digitales III – Problema de ingeniería Anexo B: Sitios en la WEB http://localhost/conclase/c/ficheros/para-pdf/curso.php http://findquest.net /Davshomepage.htm http://www-wjp.cs.uni-sb.de/~columbus/lirc/ article137.html#lfindex0 http://www.geocities.com/SiliconValley/Hardware/8000/index.htm/raton.htm http://www.servisystem.com.ar/remoto.html www.beyondlogic.org http://todohard.awardspace.com/tutrs232 http://www.philips.com/global https://www.glue.umd.edu/~nsw/ench250/scancode.htm#Key1 http://www.barcodeman.com/altek/mule/scandoc.php#Top http://www.georgehernandez.com/h/ Scan Codes by George Hernandez.htm http://www.quadibloc.com/main.htm http://www.clubse.com.ar/DIEGO/NOTAS/3notas/nota02-1.htm http://www.p4c.philips.com/files/s/sru4050_37/sru4050_37_dfu_aen.pdf. http://informatica.uv.es/it3guia/FT/prac5-232.pdf http://www.tscm.com/rs-232.pdf www.pablin.com.ar/electron/circuito/mc/receprc5/index.htm http://www.thescripts.com/forum/threadedpost2251579.html#post2251579 www.codeproyect.com/system/serial.asp http://www.geocities.com/horacespider/Serial_IO/DEV-C/terminal.c http://www.geekhideout.com/parmon.shtml http://winapi.conclase.net/curso http://gd.tuwien.ac.at/languages/c/programming-bbrown/advcw2.htm#graphics http://www.modelo.edu.mx/univ/virtech/frontal/paralelo.htm http://r-luis.xbot.es/puerto/index.html Anexo C: GL3276A-datasheets (no incluído en este documento) Anexo D: MAX232-datasheets (no incluído en este documento) 57