TODOPIC

Microcontroladores PIC => Lenguaje C para microcontroladores PIC => Mensaje iniciado por: RedPic en 27 de Julio de 2006, 14:47:03

Título: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 27 de Julio de 2006, 14:47:03
Ya estoy aqui con otro invento. En este caso es una copia descarada del de Manolo Nocturno en su Interpretando mando infrarrojos con dsPIC  (http://www.elrebujito.es/modules.php?name=News&file=article&sid=90&mode=&order=0&thold=0) pero a mi manera ...  :mrgreen:


Debemos empezar por describir el protocolo que deseamos decodificar. En mi caso, al enfrentarme a un nuevo protocolo, en principio desconocido, lo que hago es colgarle el TSOP1738 (http://picmania.garcia-cuervo.net/recursos/tsop17xx.pdf) al Analizador lógico (http://www.todopic.com.ar/foros/index.php?topic=8109.0). Con él obtengo una serie de cronogramas que voy comparando con la información sobre protocolos de la que dispongo y mas pronto que tarde logro encontrar al que corresponde.

(http://picmania.garcia-cuervo.net/images/ir_dump_02_cronograma_sony_sirc_command_16_11.gif)

El mejor sitio donde encontrar información sobre los distintos protocolos es SB-Projects: IR remote control  (http://www.xs4all.nl/~sbp/projects/ircontrol/ircontrol.htm)

Alternativamente un buen método de rastrear un protocolo consiste en hacer un programa para el PIC que registre sucesivamente los tiempos que separan dos flancos de bajada correlativos. Yo lo he realizado utilizando las interrupción externa de RB0 y guardando los valores de TIMER0 cada vez que llegaba un flanco de este tipo. Al registrar una serie suficientemente larga de ellos, entre 25 y 35 pulsos consecutivos, transmitía vía RS232 los valores de TIMER0 recogidos al PC y los veía sobre un Monitor Serie estilo HyperTerminal o Siow.

(http://picmania.garcia-cuervo.net/images/ir_dump_05_tiempos_nec-32.gif)

De un simple vistazo a los valores recibidos se puede deducir la estructura de los datos recogidos.
Una vez identificado el protocolo del que se trata podremos encarar la realización del software que lo interpreta. En el ejemplo que os brindo a continuación se trata del protocolo NEC-32 que lleva embebido el mando ANSONIC SDG-20H de mi decodificador de Televisión Digital Terrestre.


Fundamentos del Protocolo NEC-32:

1.- Longitud de 8 bits de dirección y 8 bits de comando.
2.- Tanto la dirección como el comando son enviados dos veces a modo de CRC.
3.- La primera vez los bits originales y la segunda los mismos pero negados.
4.- Los pulsos son por modulación de amplitud.
5.- La frecuencia portadora es de 38kHz (detectable por el TSOP1738).
6.- La longitud de un Bit "0" es de 1.12ms y la de un "1" es de 2.25ms.
7.- En total de transmiten un bit de Start de 9ms+4.5ms=13.5ms mas 32 bits de datos.

(http://picmania.garcia-cuervo.net/images/ir_nec_modulation.gif)

(http://picmania.garcia-cuervo.net/images/ir_nec_train.gif)

Desarrollo del software de decodificación:

Con el fin de mostrar claramente el funcionamiento de nuestro decodificador vamos a recoger los distintos bits uno a uno y guardarlos en una tabla de bits, posteriormente los trataremos para componer los bytes correspondientes.

La tabla de bits es char sbits[32] y la inicializamos (limpiamos) con '\0'. Cuando los hayamos recibidos todos los acumularemos sobre bytes[4] que son los valores a recoger.

Todo el software gira en torno a la Interrupción externa por RB0, que es donde recogemos los distintos Bits. En #int_ext podemos distinguir tres bloques distintos:

Código: C
  1. #int_ext
  2. void ext_isr() {
  3.  
  4.    // Obtengo datos de Timer0
  5.    tt = get_timer0();
  6.    t = tt-tti;
  7.    tti= tt;
  8.  
  9.    // Si he recibido el Start Bit puedo guardar
  10.    if(start_recived==1){
  11.       // Bit "0"
  12.       if(t>40 && t<50){ sbits[ntbits]='0'; }
  13.       // Bit "1"
  14.       if(t>85 && t<90){ sbits[ntbits]='1'; }
  15.       // Si he recibido 32 bits entonces hay dato
  16.       if(++ntbits==total_bits){
  17.          hay_dato=1;
  18.       }
  19.    }
  20.  
  21.    // Detecto Start Bit
  22.    if(t>525 && t<530){
  23.       start_recived=1;
  24.       limpia_bits();
  25.    }
  26. }
  27.  

Para recoger cada bit, o mejor dicho el ancho de cada bit que es lo que nos interesa, lo que hacemos es guardar la diferencia entre el estado del TIMER0 en cada interrupción y el valor que tenía en la interrupción anterior. Esto es lo que hacemos en la primera parte donde el valor de t alcanza el valor de dicha diferencia.

Para comenzar a recoger los 32 bits correspondientes a los cuatro bytes de dirección y comando debemos esperar a recibir el bit de Start, a partir del cual comenzaremos a acumular valores de bits en sbits[ x ].

Para un Cristal de 20 Mhz y un Preescaler  de TIMER0 de RTCC_DIV_128 el bit de Start son unos 525 Ticks de TIMER0, así que solo tras haber recibido un bit de una amplitud aproximada, entre 525 y 530 ticks de ancho, habilitaremos la recepción de los demás mediante la variable de tipo flag start_recived.

Para un Cristal de 20 Mhz y un Preescaler  de TIMER0 de RTCC_DIV_128 un bit "0" son unos 44 Ticks de TIMER0, así que guardamos un '0' si recibimos un bit de una amplitud aproximada de entre 40 y 50 ticks de ancho, y como un bit "1" son unos 88 Ticks de TIMER0 guardamos un '1' si recibimos un bit de una amplitud de entre 85 y 90 ticks de ancho.

Una vez recogidos los 32 bits podemos pasar a convertirlos en los correspondientes 4 bytes de dirección y comando (recordad que según este protocolo en particular el primer byte es la dirección, el segundo es la misma dirección pero con todos los bits "invertidos", el tercero es el comando y el cuarto y último es el comando "invertido")

Código: C
  1. int bits[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  2.  
  3. void convierte_bits_a_bytes(void){
  4.  
  5.   for(i=0;i<4;++i){
  6.     Bytes[i]=0x00;
  7.     for(j=0;j<8;++j){
  8.       if(sbits[(i*8)+j]=='1'){
  9.         bytes[i]=bytes[i]|Bits[j];
  10.       }
  11.     }
  12.   }
  13. }
  14.  

Todo lo demás de programa es "paja" ... o sea habilitar que todo esto sea posible. El programa completo es:

Código: C
  1. // ir_capture ANSONIC SDG-20H (TDT) with NEC-32 Protocol
  2. //
  3.  
  4. #include <18f4550.h>
  5. #fuses HS,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOPBADEN,NOLVP,NOCPD,NODEBUG,NOWRT,NOVREGEN
  6. #use delay(clock=20000000)
  7. #use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)
  8.  
  9.  
  10. const char Version[]="1.0.H\0";
  11.  
  12. const int total_bits=32;
  13. const int total_bytes=4;
  14.  
  15. char sbits[total_bits];
  16. int1 first_ext=0;
  17. int1 start_recived=0;
  18. int i,j,k;
  19. long tt,tti,t;
  20. int ntbits=0;
  21. int1 hay_dato=0;
  22. char sbit1;
  23. int bits[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  24. int bytes[total_bytes]={0x00,0x00,0x00,0x00};
  25.  
  26. void limpia_bits(void);
  27.  
  28. // INTERRUPCION por RECEPCION SERIE -------------------------------------------
  29.  
  30. #int_rda
  31. void serial_isr() {
  32.   if(kbhit()){
  33.     putchar(getc());
  34.   }
  35. }
  36.  
  37. // INTERRUPCION EXT por RB0 --------------------------------------------------
  38.  
  39. #int_ext
  40. void ext_isr() {
  41.  
  42.   // Obtengo datos de Timer0
  43.   tt = get_timer0();
  44.   t = tt-tti;
  45.   tti= tt;
  46.  
  47.   // Si he recibido el Start Bit puedo guardar
  48.   if(start_recived==1){
  49.     // Bit "0"
  50.     if(t>40 && t<50){ sbits[ntbits]='0'; }
  51.     // Bit "1"
  52.     if(t>85 && t<90){ sbits[ntbits]='1'; }
  53.     // Si he recibido 32 bits entonces hay dato
  54.     if(++ntbits==total_bits){
  55.       hay_dato=1;
  56.     }
  57.   }
  58.  
  59.   // Detecto Start Bit
  60.   if(t>525 && t<530){
  61.     start_recived=1;
  62.     limpia_bits();
  63.   }
  64. }
  65.  
  66. //-----------------------------------------------------------------------------
  67.  
  68. void flash_porte(void){
  69.  
  70.   for(i=0;i<3;i++){
  71.     output_e(0x07);
  72.     delay_ms(75);
  73.     output_e(0x00);
  74.     delay_ms(75);
  75.   }
  76. }
  77.  
  78. void limpia_bits(void){
  79.  
  80.   for(i=0;i<total_bits;++i){
  81.     sbits[i]='\0';
  82.   }
  83.   ntbits=0;
  84. }
  85.  
  86. void convierte_bits_a_bytes(void){
  87.  
  88.   for(i=0;i<4;++i){
  89.     Bytes[i]=0x00;
  90.     for(j=0;j<8;++j){
  91.       if(sbits[(i*8)+j]=='1'){
  92.         bytes[i]=bytes[i]|Bits[j];
  93.       }
  94.     }
  95.   }
  96. }
  97.  
  98. void muestra_bits(void){
  99.  
  100.   printf("\r\nPULSO RECIBIDO -----------------------\r\n");
  101.  
  102.   for(i=0;i<4;++i){
  103.     printf("Byte %u = ",i+1);
  104.     for(k=0;k<2;++k){
  105.       if(k==1){
  106.         printf(" ",i+1);
  107.       }
  108.       for(j=0;j<8;++j){
  109.         switch(k){
  110.           case 0: printf("%2u ",(i*8)+j+1);
  111.                   break;
  112.           case 1: printf("%2c ",sbits[(i*8)+j]);
  113.                   break;
  114.         }
  115.       }
  116.       if(k==0){ printf("\r\n"); }
  117.     }
  118.     printf(" Valor = %u\r\n",Bytes[i]);
  119.   }
  120.   printf("Address = %u Command = %u\r\n",Bytes[0],Bytes[2]);
  121.  
  122.   ntbits=0;
  123. }
  124.  
  125. void main() {
  126.  
  127.   disable_interrupts(global);
  128.   setup_adc_ports(NO_ANALOGS);
  129.   setup_adc(ADC_OFF);
  130.   setup_spi(FALSE);
  131.   setup_psp(PSP_DISABLED);
  132.   setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  133.   setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
  134.   setup_timer_2(T2_DISABLED,0,1);
  135.   setup_timer_3(T3_DISABLED);
  136.   setup_comparator(NC_NC_NC_NC);
  137.   setup_vref(FALSE);
  138.   port_b_pullups(FALSE);
  139.  
  140.   setup_timer_0(RTCC_INTERNAL | RTCC_DIV_128);
  141.  
  142.   set_tris_b(0b00000001);
  143.   set_tris_c(0b10000000);
  144.   set_tris_e(0b00010000);
  145.   output_e(0x00);
  146.  
  147.   delay_ms(500);
  148.   printf("\r\n");
  149.   printf("[RRBOARD2] IR TSOP1738 Reader-Decoder version %s\r\n",version);
  150.   printf("for ANSONIC SDG-20H (TDT) with NEC-32 Protocol\r\n\n");
  151.   flash_porte();
  152.  
  153.   ext_int_edge(H_TO_L);
  154.   first_ext=0;
  155.   start_recived=0;
  156.   hay_dato=0;
  157.  
  158.   limpia_bits();
  159.  
  160.   enable_interrupts(int_rda);
  161.   enable_interrupts(int_ext);
  162.   enable_interrupts(global);
  163.  
  164.   do {
  165.  
  166.     if(hay_dato==1){
  167.        hay_dato=0;
  168.        convierte_bits_a_bytes();
  169.        muestra_bits();
  170.        limpia_bits();
  171.     }
  172.  
  173.   } while (TRUE);
  174. }
  175.  

Y por supuesto el famoso ejemplo final. Que en este caso corresponde a lo trasmitido tras pulsar los cuatro cursores del mando:

(http://picmania.garcia-cuervo.net/images/ir_dump_04_decode_nec-32.jpg)

Espero que os haya gustado.  :mrgreen:

Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: ALE1973 en 27 de Julio de 2006, 15:21:17
Exelente... como anillo al dedo, justo estaba por comenzar a hacer un proyecto en que estoy necesitando interpretar comandos de un control remoto....

Saludos y felicitaciones por el trabajo.

Alejandro.
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: piclord en 27 de Julio de 2006, 18:31:41
Hola muchachos
Hace un par de mese construí un decoder similar al que señala RedPIC..detecté que en el caso de mi mando infrarrojo (sony), no todas las teclas tiene en mismo largo en bits, entre 12, 15 y 20 bits es el largo de los codigos...asi...no podia dar un largo fijo de bits a recivir...otra cosa que sucedía era que a veces la trama se enviaba sin el start bit, e incluso se repetia la trama hasta 5 veces, de modo que opte por detectar primero la presencia del start bit y luego la llegada de un segundo start bit, si es que aplica, y de ese modo determiné el envío de un comando, ya sea en 12, 15 o 20 bits....ahora, no me preocupé de asignarle a cada trama recivida la tecla que le corresponde en el mando, sino que asigne dicha trama a una funcion especifica, onda el metodo de aprender que nos entregó nocturno con su dimmer infrarrojo.

Eso era, para tenerlo en cuenta tambien..

Saludos..
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 28 de Julio de 2006, 01:21:32
ALE1973:  Todo tuyo. Muchas gracias.

Piclord: Si, el SONY además tiene una portadora de 40 Khz, por lo que el TSOP1738 lo recibe pero mal. Lo suyo es detectarlo con el TSOP1740 que para eso está. Hasta que me di cuenta de esto anduve perplejo con falsos bits que aparecían de vez en cuando.

Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: Nocturno en 28 de Julio de 2006, 01:28:50
Cuando empecé a leer y vi esas palabras "...a mi manera..." me eché a temblar.

Al terminar de leer he comprobado que mis temblores eran fundados. Menuda manera de documentar un proyecto, maestro Diego.
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 28 de Julio de 2006, 01:35:31
Frank Sinatra cantaba My Way, yo no puedo porque canto menos que un grillo enterrado en alquitrán.  :P

Manuelo, ya sabes que "a mi manera" es:

Escribiendo una novela, salpicada aquí y allá de algun comentario jocoso y festivo, con una cierta pátina de hablar para quien sabe poco o nada, o sea alguien como yo mismo, y con un estilo parafraseando a Groucho Marx que demuestre que me siento muy orgulloso de que empezando de la nada puedo alcanzar las mas altas cotas de la miseria ... ja ja ja  :D  :D  :D

Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: Algec en 28 de Julio de 2006, 08:55:02
Sencillamente, de nuevo me dejas sin palabras.
Un 10 simple y llanamente no se puede mejorar, Gracias
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: piclord en 28 de Julio de 2006, 11:56:13
ALE1973:  Todo tuyo. Muchas gracias.

Piclord: Si, el SONY además tiene una portadora de 40 Khz, por lo que el TSOP1738 lo recibe pero mal. Lo suyo es detectarlo con el TSOP1740 que para eso está. Hasta que me di cuenta de esto anduve perplejo con falsos bits que aparecían de vez en cuando.




Hola maestro RedPIC..
Si, efectivamente, el sony usa una portadora de 40 Khz, pero es es relativo, pues los IR receiver que he visto, la mayoria tiene la frecuencia central en 38Khz, y con ellos he podido capturar las trama sin problemas...Yo usé el IRM8601, que anduvo perfecto...
Notar otra cosa, este IR receiver, cuando no tiene señal de entrada, en su salida tiene un 1, osea, que invierte la señal entrante....De eso se desprende que si los flancos a detectar son de bajada, entonces se monitorea el tiempo bajo...Entonces, para los tiempos de 1200 us, corresponde un bit 1 enviado desde el mando, que tiene esa duracion, pero a la salida del receptor tenemos un 0....en definitiva, como dice redPIC, basta con medir los tiempos 1200us y 2250us...dando = si se trata de un 0 ó un 1, puesto que el largo de ese pulso determina de que bit se trata...
Tambien observar que la cantidad de ticks no simpre es fija...por tanto hay que dar un rango, el que puede ser determiando empíricamente.....

Muy buen proyecto...yo lo uso en la alarma de mi casa....chavela...

Modificado por Redpic para convertir "rago" en "rango".

Les dejo algo de lo que tengo aca en mi pc, informacion sobre las tramas capturadas

Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 28 de Julio de 2006, 14:49:03
Gracias ALE1973 .... Y ahora a continuar con los IR. Ahora mismo estoy haciendo un sistema "experto". Quiero definir unas funciones básicas y asociarla a comandos recibidos vía RS232 ... o con un mando IR, cualquier mando IR, asignar secuencialmente cada función a una pareja address/command, independiente de mando de que se trate y del protocolo que use .... ya ire posteando resultados.
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 29 de Julio de 2006, 12:38:26
Buenoooo ... ya tenemos otro programa un poco mas avanzado.

Basandome en todo lo escrito anteriormente he construido un programa que realiza una serie de funciones básicas como activar o desactivar unos pines del PIC o incrementar o decrementar cierto valor.

Lo bonito de este programa es que los comandos para realizar estas funciones pueden enviarse al PIC vía RS232 como en tantos de mis ejemplos anteriores (vénase por ejemplo los Ejemplitos Recibiendo del RS232 sobre un Buffer y procesandolo posteriormente (http://www.todopic.com.ar/foros/index.php?topic=4573.0), Desde el PC a una EEPROM I2C y viseversa a través de mi PIC (http://www.todopic.com.ar/foros/index.php?topic=4783.0), Controlando un SERVO con el PIC desde nuestro PC (http://www.todopic.com.ar/foros/index.php?topic=4629.0) y La EEPROM interna puesta a nuestro servicio. (http://www.todopic.com.ar/foros/index.php?topic=4639.0))

Pero ademas pueden enviarse vía IR utilizando el mando del televisor.

El rollo estaba en que para realizarlo había antes que leer los comandos que dicho mando IR envía con las teclas que nos interesaban y despues programar nuestro programa para que las recibiese y aceptase en cada caso. Pero esta forma de hacerla no es elegante.

Lo elegante y bonito es que el programa fuese capaz de leer comandos y asignarlos a cada función, guardandolos en la EEPROM durante lo que podríamos llamar como fase de aprendizaje o memorización.

A partir de ahí tendríamos guardados los comandos asignados a cada función y que podrían ser cambiados en cualquier momento con solo reprogramar los comandos de nuevo.

Además para hacerlo elegante del todo debería haber una manera de hacer todo esto sin hacer uso de hardware accesorio alguno, ningún botón, ni software externo, nada de enviar un comando RS232 para entrar en modo programación.

Para ello decidi que iba a tener disponibles 5 segundos tras el reset para que si en ese lapso recibía cualquier comando IR entonces entraba automáticamente en modo programación. Si transcurrido ese lapso de tiempo no recibía nada entonces recargaba desde la EEPROM los comandos configurados anteriormente y santas pascuas.

De cualquier forma le he dejado implementado el que cada ejecución que realiza lo monitoriza por la RS232 para que podamos seguir su funcionamiento.

Imagen de una programación completa tras un Reset:

(http://picmania.garcia-cuervo.com/images/IR_COMMAND_Dump_02_Modo_Programacion.GIF)

Imagen de un funcionamiento normal fuera de la fase de programación:

(http://picmania.garcia-cuervo.com/images/IR_COMMAND_Dump_01_Menu_Recibiendo_Comandos.GIF)

Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: Nocturno en 29 de Julio de 2006, 12:42:57
Diego, en modo programación tuve que hacer que el Minidimmer  (http://www.elrebujito.es/modules.php?name=News&file=article&sid=180&mode=&order=0&thold=0) solicitase cada tecla dos veces, porque a veces pillaba basura y de esta forma me aseguraba de que todo iba perfecto. ¿No te ha pasado a ti eso?

P.D.: has puesto las imágenes al revés, aunque se entiende tu artículo a la perfección
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 29 de Julio de 2006, 12:44:38
El programa de mi post anterior (no me ha dejado postearlo en el mismo porque me decía que exedía no se qué número de bytes por post)

Código: C
  1. // ir_command.c by Redpic
  2. // ANSONIC SDG-20H (TDT) supporting NEC-32 Protocol
  3. // With recording Command send function
  4. // and automode programing on reset
  5.  
  6. #include <18f4550.h>
  7. #fuses HS,MCLR,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOPBADEN,NOLVP,NOCPD,NODEBUG,NOWRT,NOVREGEN
  8. #use delay(clock=20000000)
  9. #use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7)
  10.  
  11. #define PIN_FUNC1 PIN_E0
  12. #define PIN_FUNC2 PIN_E1
  13. #define PIN_FUNC3 PIN_E2
  14.  
  15. #define PIN_LED PIN_E0
  16.  
  17. // CONSTANTES -
  18.  
  19. const char Version[]="1.0.H\0";
  20.  
  21. const int total_bits  = 32;
  22. const int total_bytes =  4;
  23.  
  24. const char COMANDO232_MENU  = '?'; const char COMANDO232_TXT_MENU[]  = "Muestra menu de opciones RS232.";
  25. const char COMANDO232_MODO_PROG = 'p'; const char COMANDO232_TXT_MODO_PROG[] = "Entrar en modo Programación.";
  26. const char COMANDO232_FUNC_ON = 'o'; const char COMANDO232_TXT_FUNC_ON[] = " * 1 Activa/Desactiva procesar Comandos IR.";
  27. const char COMANDO232_FUNC_1  = '1'; const char COMANDO232_TXT_FUNC_1[]  = " * 2 Ejecutar Función 1";
  28. const char COMANDO232_FUNC_2  = '2'; const char COMANDO232_TXT_FUNC_2[]  = " * 3 Ejecutar Función 2";
  29. const char COMANDO232_FUNC_3  = '3'; const char COMANDO232_TXT_FUNC_3[]  = " * 4 Ejecutar Función 3";
  30. const char COMANDO232_FUNC_VEX  = 'f'; const char COMANDO232_TXT_FUNC_VEX[]  = " * 5 Ver Estado actual de funciones.";
  31. const char COMANDO232_FUNC_VER  = 'm'; const char COMANDO232_TXT_FUNC_VER[]  = " * 6 Ver Comandos almacenados por función.";
  32. const char COMANDO232_FUNC_RESET= 'r'; const char COMANDO232_TXT_FUNC_RESET[]= " * 7 Reset Hardware.";
  33. const char COMANDO232_FUNC_PLUS = '+'; const char COMANDO232_TXT_FUNC_PLUS[] = " * 8 Incrementa valor Ref.";
  34. const char COMANDO232_FUNC_Minus= '-'; const char COMANDO232_TXT_FUNC_MINUS[]= " * 9 Decrementa valor Ref.";
  35.  
  36. const int  MODO_INACTIVO    =  0;  const char MODO_TXT_INACTIVO[]    = "INACTIVO";
  37. const int  MODO_ACTIVO    =  1;  const char MODO_TXT_ACTIVO[]    = "ACTIVO";
  38. const int  MODO_PROGRAMACION  =  2;  const char MODO_TXT_PROGRAMACION[]  = "PROGRAMACIÓN";
  39.  
  40. const int  RTCCS_AUTOPROG = 3;
  41.  
  42. // VARIABLES EN RAM -
  43.  
  44. // De recepción IR y generales --
  45.  
  46. int1 first_ext=0;
  47. int1 start_recived=0;
  48. int1 hay_dato=0;
  49. int1 autoprog_enabled=0;
  50. int1 flag_flash_led=0;
  51. char sbits[total_bits];
  52. int  i,j,k;
  53. long tt,tti,t;
  54. int  ntbits=0;
  55. char sbit1;
  56. int  bits[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
  57. int  bytes[total_bytes]={0x00,0x00,0x00,0x00};
  58. int  nrtcc=0;
  59.  
  60. // De Comandos y Funciones --
  61.  
  62. char rec232=0x00;
  63. char opcion=0x00;
  64. int  Modo=MODO_INACTIVO;
  65. int  nextPROG=0;
  66.  
  67. int1 FUNC1=0;
  68. int1 FUNC2=0;
  69. int1 FUNC3=0;
  70. int  VALREF;
  71.  
  72. int ADDRESSDEV;
  73. int COMANDODEV_FUNC_ON;
  74. int COMANDODEV_FUNC_1;
  75. int COMANDODEV_FUNC_2;
  76. int COMANDODEV_FUNC_3;
  77. int COMANDODEV_FUNC_VEX;
  78. int COMANDODEV_FUNC_VER;
  79. int COMANDODEV_FUNC_RESET;
  80. int COMANDODEV_FUNC_PLUS;
  81. int COMANDODEV_FUNC_MINUS;
  82.  
  83. // Prototipos de funciones --
  84.  
  85. void flash_led(int n);
  86. void limpia_bits(void);
  87. void convierte_bits_a_bytes(void);
  88. void muestra_bits(void);
  89. void lee_config_desde_EEPROM(void);
  90. void programar_comandos(int funcion, int device_address, int device_command);
  91. void presenta_menu(void);
  92. void on_reset(void);
  93.  
  94. // INTERRUPCION por RECEPCION SERIE -
  95.  
  96. #int_rda
  97. void serial_isr() {
  98.  
  99.  rec232=0x00;
  100.  if(kbhit()){
  101.    rec232=getc();
  102.    if( rec232==COMANDO232_MENU   ||
  103.    rec232==COMANDO232_MODO_PROG  ||
  104.    rec232==COMANDO232_FUNC_ON  ||
  105.    rec232==COMANDO232_FUNC_1   ||
  106.    rec232==COMANDO232_FUNC_2   ||
  107.    rec232==COMANDO232_FUNC_3   ||
  108.    rec232==COMANDO232_FUNC_PLUS  ||
  109.    rec232==COMANDO232_FUNC_MINUS ||
  110.    rec232==COMANDO232_FUNC_RESET ||
  111.    rec232==COMANDO232_FUNC_VEX ||
  112.    rec232==COMANDO232_FUNC_VER){
  113.    opcion=rec232;
  114.    }
  115.  }
  116. }
  117.  
  118. // INTERRUPCION EXT por RB0 --
  119.  
  120. #int_ext
  121. void ext_isr() {
  122.  // Obtengo datos de Timer0
  123.  tt = get_timer0();
  124.  t  = tt-tti;
  125.  tti= tt;
  126.  // Si he recibido el Start Bit puedo guardar
  127.  if(start_recived==1){
  128.   // Bit "0"
  129.   if(t>40 && t<50){ sbits[ntbits]='0'; }
  130.   // Bit "1"
  131.   if(t>85 && t<90){ sbits[ntbits]='1'; }
  132.   // Si he recibido 32 bits entonces hay dato
  133.   if(++ntbits==total_bits){
  134.    hay_dato=1;
  135.   }
  136.  }
  137.  // Detecto Start Bit
  138.  if(t>525 && t<530){
  139.   start_recived=1;
  140.   limpia_bits();
  141.  }
  142. }
  143.  
  144.  
  145. // INTERRUPCION RTCC por TIMER0 -
  146.  
  147. #int_rtcc
  148. void rtcc_isr() {
  149.  
  150.  if(autoprog_enabled){
  151.   ++nrtcc;
  152.   printf(".");
  153.   flag_flash_led=1;
  154.   if(nrtcc==RTCCS_AUTOPROG){
  155.    autoprog_enabled=0;
  156.    printf("\r\nAutoprog disabled.\r\n");
  157.   }
  158.  }
  159. }
  160.  
  161. //-
  162.  
  163. void flash_led(int n){
  164.  
  165.  for(i=0;i<n-1;i++){
  166.   output_high(PIN_LED);
  167.   delay_ms(75);
  168.   output_low(PIN_LED);
  169.   delay_ms(75);
  170.  }
  171. }
  172.  
  173. void limpia_bits(void){
  174.  
  175.  for(i=0;i<total_bits;++i){
  176.   sbits[i]='\0';
  177.  }
  178.  ntbits=0;
  179. }
  180.  
  181. void convierte_bits_a_bytes(void){
  182.  
  183.  for(i=0;i<4;++i){
  184.   Bytes[i]=0x00;
  185.   for(j=0;j<8;++j){
  186.    if(sbits[(i*8)+j]=='1'){
  187.     bytes[i]=bytes[i]|Bits[j];
  188.    }
  189.   }
  190.  }
  191. }
  192.  
  193. void muestra_bits(void){
  194.  
  195.  printf("[COMANDO] %u\\%u\r\n",Bytes[0],Bytes[2]);
  196. }
  197.  
  198. void lee_config_desde_EEPROM(void){
  199.  
  200.  ADDRESSDEV    = read_eeprom( 0); if(ADDRESSDEV     ==0xFF){ADDRESSDEV=64;}
  201.  VALREF      = read_eeprom( 1); if(VALREF     ==0xFF){VALREF=127;}
  202.  COMANDODEV_FUNC_ON  = read_eeprom( 2); if(COMANDODEV_FUNC_ON ==0xFF){COMANDODEV_FUNC_ON = 24;} // Btn ON/OFF
  203.  COMANDODEV_FUNC_1   = read_eeprom( 3); if(COMANDODEV_FUNC_1  ==0xFF){COMANDODEV_FUNC_1  = 26;} // Btn 1
  204.  COMANDODEV_FUNC_2   = read_eeprom( 4); if(COMANDODEV_FUNC_2  ==0xFF){COMANDODEV_FUNC_2  = 17;} // Btn 2
  205.  COMANDODEV_FUNC_3   = read_eeprom( 5); if(COMANDODEV_FUNC_3  ==0xFF){COMANDODEV_FUNC_3  =  9;} // Btn 3
  206.  COMANDODEV_FUNC_VEX = read_eeprom( 6); if(COMANDODEV_FUNC_VEX  ==0xFF){COMANDODEV_FUNC_VEX  =  7;} // Btn Ok
  207.  COMANDODEV_FUNC_VER = read_eeprom( 7); if(COMANDODEV_FUNC_VER  ==0xFF){COMANDODEV_FUNC_VER  = 25;} // Btn Menu
  208.  COMANDODEV_FUNC_RESET = read_eeprom( 8); if(COMANDODEV_FUNC_RESET==0xFF){COMANDODEV_FUNC_RESET=  3;} // Btn Exit
  209.  COMANDODEV_FUNC_PLUS  = read_eeprom( 9); if(COMANDODEV_FUNC_PLUS ==0xFF){COMANDODEV_FUNC_PLUS=  13;} // Btn CH+
  210.  COMANDODEV_FUNC_MINUS = read_eeprom(10); if(COMANDODEV_FUNC_MINUS==0xFF){COMANDODEV_FUNC_MINUS= 30;} // Btn CH-
  211.  
  212. }
  213.  
  214. void programar_comandos(int funcion, int device_address, int device_command){
  215.  
  216.  switch(funcion){
  217.   case  0:
  218.     printf("Modo PROGRAMACIÓN activado ...\r\n");
  219.     printf("Pulse cualquier botón para obtener el ADDRESS ");
  220.     flash_led(1);
  221.     break;
  222.   case  1:
  223.     printf("Address=%2u (0x%x)\r\n",device_address,device_address);
  224.     write_eeprom(0,device_address);
  225.     delay_ms(10);
  226.     printf("Pulse para [Activar/Desactivar] ");
  227.     flash_led(2);
  228.     break;
  229.   case  2:
  230.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  231.     write_eeprom(2,device_command);
  232.     delay_ms(10);
  233.     printf("Pulse para [Ejecutar Función 1] ");
  234.     flash_led(3);
  235.     break;
  236.   case  3:
  237.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  238.     write_eeprom(3,device_command);
  239.     delay_ms(10);
  240.     printf("Pulse para [Ejecutar Función 2] ");
  241.     flash_led(4);
  242.     break;
  243.   case  4:
  244.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  245.     write_eeprom(4,device_command);
  246.     delay_ms(10);
  247.     printf("Pulse para [Ejecutar Función 3] ");
  248.     flash_led(5);
  249.     break;
  250.   case  5:
  251.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  252.     write_eeprom(5,device_command);
  253.     delay_ms(10);
  254.     printf("Pulse para [Ver estado de funciones] ");
  255.     flash_led(6);
  256.     break;
  257.   case  6:
  258.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  259.     write_eeprom(6,device_command);
  260.     delay_ms(10);
  261.     printf("Pulse para [Ver comandos almacenados] ");
  262.     flash_led(7);
  263.     break;
  264.   case  7:
  265.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  266.     write_eeprom(7,device_command);
  267.     delay_ms(10);
  268.     printf("Pulse para [Reset Hardware] ");
  269.     flash_led(8);
  270.     break;
  271.   case  8:
  272.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  273.     write_eeprom(8,device_command);
  274.     delay_ms(10);
  275.     printf("Pulse para [Inc. Valor Ref.] ");
  276.     flash_led(9);
  277.     break;
  278.   case  9:
  279.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  280.     write_eeprom(9,device_command);
  281.     delay_ms(10);
  282.     printf("Pulse para [Dec. Valor Ref.] ");
  283.     flash_led(9);
  284.     break;
  285.   case  10:
  286.     printf("Command=%2u (0x%x)\r\n",device_command,device_command);
  287.     write_eeprom(10,device_command);
  288.     delay_ms(11);
  289.     // fin programación
  290.     printf("Fin Modo PROGRAMACION.\r\n");
  291.     on_reset();
  292.     break;
  293.  }
  294. }
  295.  
  296. //-
  297.  
  298. void presenta_menu(void){
  299.  
  300.  printf("Opciones Menu RS232:\r\n\n");
  301.  printf(" [%c]  %s\r\n", COMANDO232_MENU,  COMANDO232_TXT_MENU);
  302.  printf(" [%c]  %s\r\n", COMANDO232_MODO_PROG, COMANDO232_TXT_MODO_PROG);
  303.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_ON, COMANDO232_TXT_FUNC_ON);
  304.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_1,  COMANDO232_TXT_FUNC_1);
  305.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_2,  COMANDO232_TXT_FUNC_2);
  306.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_3,  COMANDO232_TXT_FUNC_3);
  307.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_VEX,  COMANDO232_TXT_FUNC_VEX);
  308.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_VER,  COMANDO232_TXT_FUNC_VER);
  309.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_RESET,COMANDO232_TXT_FUNC_RESET);
  310.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_PLUS, COMANDO232_TXT_FUNC_PLUS);
  311.  printf(" [%c]  %s\r\n", COMANDO232_FUNC_MINUS,COMANDO232_TXT_FUNC_MINUS);
  312.  printf("\r\n");
  313. }
  314.  
  315. void on_reset(void){
  316.  
  317.  disable_interrupts(global);
  318.  setup_adc_ports(NO_ANALOGS);
  319.  setup_adc(ADC_OFF);
  320.  setup_spi(FALSE);
  321.  setup_psp(PSP_DISABLED);
  322.  setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  323.  setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
  324.  setup_timer_2(T2_DISABLED,0,1);
  325.  setup_timer_3(T3_DISABLED);
  326.  setup_comparator(NC_NC_NC_NC);
  327.  setup_vref(FALSE);
  328.  port_b_pullups(FALSE);
  329.  
  330.  setup_timer_0(RTCC_INTERNAL | RTCC_DIV_128);
  331.  
  332.  set_tris_b(0b00000001);
  333.  set_tris_c(0b10000000);
  334.  set_tris_e(0b00010000);
  335.  output_e(0x00);
  336.  
  337.  delay_ms(500);
  338.  printf("\r\n");
  339.  printf("[RRBOARD2] IR Command Receiver version %s\r\n",version);
  340.  printf("TSOP1738 Reader-Decoder over 18F4550\r\n");
  341.  printf("for ANSONIC SDG-20H with NEC-32 Protocol\r\n\n");
  342.  flash_led(3);
  343.  presenta_menu();
  344.  
  345.  ext_int_edge(H_TO_L);
  346.  first_ext=0;
  347.  start_recived=0;
  348.  hay_dato=0;
  349.  
  350.  limpia_bits();
  351.  
  352.  
  353.  rec232=0x00;
  354.  opcion=0x00;
  355.  Modo=MODO_INACTIVO;
  356.  FUNC1=0;
  357.  FUNC2=0;
  358.  FUNC3=0;
  359.  nextPROG=0;
  360.  nrtcc=0;
  361.  flag_flash_led=0;
  362.  autoprog_enabled=1;
  363.  
  364.  lee_config_desde_EEPROM();
  365.  
  366.  delay_ms(500);
  367.  printf("Autoprog enabled ");
  368.  
  369.  enable_interrupts(int_rda);
  370.  enable_interrupts(int_ext);
  371.  enable_interrupts(int_rtcc);
  372.  enable_interrupts(global);
  373.  
  374. }
  375.  
  376. void main() {
  377.  
  378.  on_reset();
  379.  do {
  380.   // Recibe y procesa IR Command para generar 232 Command -
  381.   if(hay_dato==1){
  382.    hay_dato=0;
  383.    // Extrae byte recibido y limpia -
  384.    convierte_bits_a_bytes();
  385.    limpia_bits();
  386.    // Detecta cualquier pulsacion IR durante Autoprog_enabled -
  387.    if(Autoprog_enabled){
  388.     Autoprog_enabled=0;
  389.     Opcion=COMANDO232_MODO_PROG;
  390.    }else{
  391.     // Si no estamos en modo PROGRAMACION -
  392.     if(Modo!=MODO_PROGRAMACION){
  393.      muestra_bits();
  394.      // Si el Address es correcto ... -
  395.      if(Bytes[0]==ADDRESSDEV){
  396.       // Comando COMANDO232_FUNC_ON -
  397.       if(Bytes[2]==COMANDODEV_FUNC_ON){
  398.        opcion=COMANDO232_FUNC_ON;
  399.       }
  400.       // Comando FUNC1 --
  401.       if(Bytes[2]==COMANDODEV_FUNC_1){
  402.        opcion=COMANDO232_FUNC_1;
  403.       }
  404.       // Comando FUNC2 --
  405.       if(Bytes[2]==COMANDODEV_FUNC_2){
  406.        opcion=COMANDO232_FUNC_2;
  407.       }
  408.       // Comando FUNC3 --
  409.       if(Bytes[2]==COMANDODEV_FUNC_3){
  410.        opcion=COMANDO232_FUNC_3;
  411.       }
  412.       // Comando FUNC_VEX -
  413.       if(Bytes[2]==COMANDODEV_FUNC_VEX){
  414.        opcion=COMANDO232_FUNC_VEX;
  415.       }
  416.       // Comando FUNC_VER -
  417.       if(Bytes[2]==COMANDODEV_FUNC_VER){
  418.        opcion=COMANDO232_FUNC_VER;
  419.       }
  420.       // Comando FUNC_RESET -
  421.       if(Bytes[2]==COMANDODEV_FUNC_RESET){
  422.        opcion=COMANDO232_FUNC_RESET;
  423.       }
  424.       // Comando FUNC_PLUS --
  425.       if(Bytes[2]==COMANDODEV_FUNC_PLUS){
  426.        opcion=COMANDO232_FUNC_PLUS;
  427.       }
  428.       // Comando FUNC_MINUS --
  429.       if(Bytes[2]==COMANDODEV_FUNC_MINUS){
  430.        opcion=COMANDO232_FUNC_MINUS;
  431.       }
  432.      }
  433.      // Si estamos en Modo PROGRAMACION -
  434.     }else{
  435.      programar_comandos(++nextPROG,bytes[0],bytes[2]);
  436.     }
  437.    }
  438.   }
  439.   // Recibe y procesa RS232 Opcion
  440.   if(opcion!=0x00){
  441.    Switch(opcion){
  442.     // Muestra menu de opciones -
  443.     case  COMANDO232_MENU:
  444.       presenta_menu();
  445.       break;
  446.     // Entrar en Modo PROGRAMACION --
  447.     case  COMANDO232_MODO_PROG:
  448.       nextPROG=0;
  449.       Modo=MODO_PROGRAMACION;
  450.       programar_comandos(0,0,0);
  451.       break;
  452.     // Activa/Desactiva procesar Comandos FUNC --
  453.     case  COMANDO232_FUNC_ON:
  454.       if(Modo==MODO_INACTIVO){
  455.        Modo=MODO_ACTIVO;
  456.        printf("Modo : Activada recepción de Comandos\r\n");
  457.       }else{
  458.        Modo=MODO_INACTIVO;
  459.        printf("Modo : Desactivada recepción de Comandos\r\n");
  460.       };
  461.       break;
  462.     // Reset de Hardware --
  463.     case  COMANDO232_FUNC_RESET:
  464.       if(Modo==MODO_ACTIVO){
  465.        on_reset();
  466.       }else{
  467.        printf("**Error, Recibido RESET pero Modo=INACTIVO\r\n");
  468.       }
  469.       break;
  470.     // Ejecutar Función 1 -
  471.     case  COMANDO232_FUNC_1:
  472.       if(Modo==MODO_ACTIVO){
  473.        FUNC1=!FUNC1;
  474.         if(FUNC1){
  475.         output_high(PIN_FUNC1);
  476.         printf("FUNC1 : Activada\r\n");
  477.         }else{
  478.         output_low(PIN_FUNC1);
  479.         printf("FUNC1 : Desactivada\r\n");
  480.         }
  481.       }else{
  482.        printf("**Error, Recibido F1 pero Modo=INACTIVO\r\n");
  483.       }
  484.       break;
  485.     // Ejecutar Función 2 -
  486.     case  COMANDO232_FUNC_2:
  487.       if(Modo==MODO_ACTIVO){
  488.        FUNC2=!FUNC2;
  489.         if(FUNC2){
  490.         output_high(PIN_FUNC2);
  491.         printf("FUNC2 : Activada\r\n");
  492.         }else{
  493.         output_low(PIN_FUNC2);
  494.         printf("FUNC2 : Desactivada\r\n");
  495.         }
  496.       }else{
  497.        printf("**Error, Recibido F2 pero Modo=INACTIVO\r\n");
  498.       }
  499.       break;
  500.     // Ejecutar Función 3 -
  501.     case  COMANDO232_FUNC_3:
  502.       if(Modo==MODO_ACTIVO){
  503.        FUNC3=!FUNC3;
  504.         if(FUNC3){
  505.         output_high(PIN_FUNC3);
  506.         printf("FUNC3 : Activada\r\n");
  507.         }else{
  508.         output_low(PIN_FUNC3);
  509.         printf("FUNC3 : Desactivada\r\n");
  510.         }
  511.       }else{
  512.        printf("**Error, Recibido F3 pero Modo=INACTIVO\r\n");
  513.       }
  514.       break;
  515.     // Ejecutar Plus --
  516.     case  COMANDO232_FUNC_PLUS:
  517.       if(Modo==MODO_ACTIVO){
  518.        ++VALREF;
  519.        write_eeprom(1,VALREF);
  520.        printf("V.Ref.=%u\r\n",VALREF);
  521.       }else{
  522.        printf("**Error, Recibido Inc. pero Modo=INACTIVO\r\n");
  523.       }
  524.       break;
  525.     // Ejecutar Minus -
  526.     case  COMANDO232_FUNC_MINUS:
  527.       if(Modo==MODO_ACTIVO){
  528.        --VALREF;
  529.        write_eeprom(1,VALREF);
  530.        printf("V.Ref.=%u\r\n",VALREF);
  531.       }else{
  532.        printf("**Error, Recibido Dec. pero Modo=INACTIVO\r\n");
  533.       }
  534.       break;
  535.     // Ver Estado actual de funciones -
  536.     case  COMANDO232_FUNC_VEX:
  537.       switch(Modo){
  538.        case MODO_PROGRAMACION:
  539.           printf("Estado = %s, ",MODO_TXT_PROGRAMACION);
  540.           break;
  541.        case MODO_INACTIVO:
  542.           printf("Estado = %s, ",MODO_TXT_INACTIVO);
  543.           break;
  544.        case MODO_ACTIVO:
  545.           printf("Estado = %s, ",MODO_TXT_ACTIVO);
  546.           break;
  547.       }
  548.       printf("V.Ref.=%u, ",VALREF);
  549.       if(FUNC1) printf("F1 = ON, ");   else printf("F1 = OFF, ");
  550.       if(FUNC2) printf("F2 = ON, ");   else printf("F2 = OFF, ");
  551.       if(FUNC1) printf("F3 = ON\r\n ");  else printf("F3 = OFF\r\n");
  552.       break;
  553.  
  554.     // Ver Comandos almacenados por función -
  555.     case  COMANDO232_FUNC_VER:
  556.       printf("Address= %3u (0x%x)\r\n",ADDRESSDEV,ADDRESSDEV);
  557.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_ON,  COMANDODEV_FUNC_ON,  COMANDO232_TXT_FUNC_ON);
  558.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_1,   COMANDODEV_FUNC_1,   COMANDO232_TXT_FUNC_1);
  559.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_2,   COMANDODEV_FUNC_2,   COMANDO232_TXT_FUNC_2);
  560.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_3,   COMANDODEV_FUNC_3,   COMANDO232_TXT_FUNC_3);
  561.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_VEX, COMANDODEV_FUNC_VEX, COMANDO232_TXT_FUNC_VEX);
  562.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_VER, COMANDODEV_FUNC_VER, COMANDO232_TXT_FUNC_VER);
  563.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_RESET, COMANDODEV_FUNC_RESET, COMANDO232_TXT_FUNC_RESET);
  564.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_PLUS,  COMANDODEV_FUNC_PLUS,  COMANDO232_TXT_FUNC_PLUS);
  565.       printf("Command= %3u (0x%x) %s\r\n",COMANDODEV_FUNC_MINUS, COMANDODEV_FUNC_MINUS, COMANDO232_TXT_FUNC_MINUS);
  566.       break;
  567.     //-
  568.    }
  569.    opcion=0x00;
  570.   }
  571.   // Detecto FLASH LED --
  572.   if(flag_flash_led){
  573.    flag_flash_led=0;
  574.    flash_led(2);
  575.   }
  576.  } while (TRUE);
  577. }
  578.  
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 29 de Julio de 2006, 12:53:06
No Manolo, no me está recogiendo basura. En el anterior ejemplo, con el SONY SIRC si me cogía basura de vez en cuando, pero con este ANSONIC NEC-32 es absolutamente preciso y en todas las pruebas que he hecho no he notado que haya tomado erróneamente ni un solo comando.  :mrgreen:

Lo del SONY se lo achaco presumiblemente a que la portadora original es de 40 Khz y yo estoy decodificando con un TSOP1738 para portadoras de 38 Khz. Y en verdad que noté que cada veinte o treinta bits recogía uno que no era ni carne ni pescado, ni "0" ni "1" y me dejaba el recogedor hecho unos zorros ...  :D  :D  :D

P.D. Ya he puesto las imagenes al derecho
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 29 de Julio de 2006, 13:59:18
Y ahora vamos a abrir la siguiente fase, entrando en otros terrenos quizás mas interesantes:

Hasta ahora hemos estado jugando con protocolos conocidos y andando sobre caminos trillados por otros amigos .... y esto es una carga que debemos soportar. O sabemos qué es lo que esperamos recibir o ....

Leemos lo que llegue y tratamos de sacar conclusiones, independiente del protocolo que se use. Y a esto es a lo que me refiero. Deseo desarrollar un sistema que reciba "lo-que-sea" y sea capaz de establecer automáticamente cúal es el bit de start y cúales son los bits "1" y "0".

Y que sea capaz asimismo de discernir qué parte es la común a todos los comandos, normalmente el Address, y qué parte es única para cada uno de ellos, normalmente el Command ....

La recepción ha de ser muy similar a la implementada en el Analizador lógico (http://www.todopic.com.ar/foros/index.php?topic=8109.0) que no entiende de protocolos, sino de tiempos ... y con esa información ver si somos capaces de sacar las conclusiones oportunas ...

Ahí os dejo un par de cronogramas tomados con el Analizador desde el mando del aire acondicionado de mi oficina, cuyo protocolo a lo mejor lo conocen sus constructores pero que no se parece a nada que yo conozca ... voy a ver cómo lo puedo masticar y tragar sin que se me atasque ...  :mrgreen:

(http://picmania.garcia-cuervo.com/images/IR_RLA_Mando_Aire_Boton_Naranja.GIF)
(http://picmania.garcia-cuervo.com/images/IR_RLA_Mando_Aire_Boton_Reloj.GIF)

Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: flacomaida en 18 de Diciembre de 2007, 13:54:44
Y ahora vamos a abrir la siguiente fase, entrando en otros terrenos quizás mas interesantes:

Hasta ahora hemos estado jugando con protocolos conocidos y andando sobre caminos trillados por otros amigos .... y esto es una carga que debemos soportar. O sabemos qué es lo que esperamos recibir o ....

Leemos lo que llegue y tratamos de sacar conclusiones, independiente del protocolo que se use. Y a esto es a lo que me refiero. Deseo desarrollar un sistema que reciba "lo-que-sea" y sea capaz de establecer automáticamente cúal es el bit de start y cúales son los bits "1" y "0".

Y que sea capaz asimismo de discernir qué parte es la común a todos los comandos, normalmente el Address, y qué parte es única para cada uno de ellos, normalmente el Command ....

La recepción ha de ser muy similar a la implementada en el Analizador lógico (http://www.todopic.com.ar/foros/index.php?topic=8109.0) que no entiende de protocolos, sino de tiempos ... y con esa información ver si somos capaces de sacar las conclusiones oportunas ...

Ahí os dejo un par de cronogramas tomados con el Analizador desde el mando del aire acondicionado de mi oficina, cuyo protocolo a lo mejor lo conocen sus constructores pero que no se parece a nada que yo conozca ... voy a ver cómo lo puedo masticar y tragar sin que se me atasque ...  :mrgreen:

(http://picmania.garcia-cuervo.com/images/IR_RLA_Mando_Aire_Boton_Naranja.GIF)
(http://picmania.garcia-cuervo.com/images/IR_RLA_Mando_Aire_Boton_Reloj.GIF)



Hola REdPic. Un favor. Me puedes enviar el LOGIC y como funciona?? Tambien ando en lo mismo. Hasta ahora trate de capturar la trama de un mando IR atravez de la placa de sonido con un editor de audio, idea de un amigo. Pero no se ve muy claro y tampoco el tiempo es preciso. Un abrazo...
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: flacomaida en 19 de Diciembre de 2007, 07:56:45
Hola REdPic. Un favor. Me puedes enviar el LOGIC y como funciona?? Tambien ando en lo mismo. Hasta ahora trate de capturar la trama de un mando IR atravez de la placa de sonido con un editor de audio, idea de un amigo. Pero no se ve muy claro y tampoco el tiempo es preciso. Un abrazo...
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: delmo en 06 de Abril de 2008, 14:27:21
he analizado el codigo de RedPic para aplicarlo a un decodificador Sony SIRC y le encuentro dos fallos, creo que de ahi lo de recger basura.
1º.- El 32avo bit nuncalo recive, ya que su trasicion de H_TO_L se corresponderia con el siguiete bit de start con lo que el timer se va de madre.
2º.- La variable start_recived una vez puesta a uno nunca se pone a cero.
En mi codigo alternativo en cambiado start_recived a int juego con el cambio de la señal de disparo y he añadido una variable nueva cuando se repite la pulsacion de la tecla. Obviamente los tiempos corresponden al SIRC. Tambien detecto errores y reinicio la trama.

// INTERRUPCION EXT por RB0 --

#int_ext
void ext_isr()                      // Obtengo datos de Timer0
   {
   if(start_recived==0)             //aun no estamos en el inicio de una trama
      {
      ext_int_edge(L_TO_H);
      star_recived=1;               // marcamos inicio de trama
      tt=get_timer0();              // cogemos timer para ver si
      if (tt>1740 && tt<1780)       // es la tecla repetida inervalos de 45ms
         {
         printf("\r\nTecla mantenida.\r\n");
         if (repe<10)
            ++repe;
         }   
      set_timer0(0x00);             // Iniciamos timer para no coger tramas a medias
      }
   else
      {
      tt = get_timer0();
      t = tt-tti;
      tti= tt;
      if (star_recived==2)
         {
         if(t>45 && t<50)              // Bit "0"
            {
            sbits[ntbits]='0';
            if(++ntbits==total_bits)   // Si he recibido 32 bits entonces hay dato
               {
               hay_dato=1;
               start_recived=0;
               ext_int_edge(H_TO_L);
               }
            }
         else if(t>68 && t<72)         // Bit "1"
            {
            sbits[ntbits]='1';
            if(++ntbits==total_bits)   // Si he recibido 32 bits entonces hay dato
               {
               hay_dato=1;
               start_recived=0;
               ext_int_edge(H_TO_L);
               }
            }
         else                          //error
            {
            start_recived=0;
            ext_int_edge(H_TO_L);
            }
         }
      else                             //error
         }
         if(t>115 && t<120)            // Detecto Start Bit
            {
            start_recived=2;
            limpia_bits();                // iniciamos nueva captura de bits
            }
         else
            {
            start_recived=0;
            ext_int_edge(H_TO_L);
            }
         }
      }
   }
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: samshiel_pic en 11 de Octubre de 2008, 12:40:11
hola chicos que tal?? Yo estoy inmerso en un programita que me permita utilizar un mando infrarrojo, del que sea tv,radio,..., para segun que funcion. Y llevo 3 o 4 dias trabajando con el receptor infrarrojos y ya he conseguido saber cual es el protocolo que utiliza. El protocolo que utiliza es RC5 de PHILIPS y los distintos pulsos con el mando vistos por el osciloscopio os lo pongo adjunto. Gracias al programa de Diego de TECNICAS EN C: MIDIENDO UN PULSO. 4º PARTE (http://picmania.garcia-cuervo.net/Tecnicas_en_C_4.php) verifique que los tiempos y la frecuencia pertenecian a dicho protocolo.

Pero ahora tengo una duda como puedo hacer para que me muestre por pantalla mediante hiperterminal exactamente como en esta imagen:
(http://picmania.garcia-cuervo.net/images/IR_Dump_05_Tiempos_NEC-32.GIF)

es que me gustaria guardar en memoria las tramas y despues comparar con las que se han pulsado y llevar a cabo su funcion.

Yo lo he intentado con una interrupcion externa, cuando pulso una tecla el pic comienza mirar el RB0 cada 1,770 ms y mostrando por hiperterminal el estado del PIN pero no corresponde con la imagen del osciloscopio.
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: DarkVect en 17 de Octubre de 2008, 04:24:23
Redpic, igual es una tontería pero tengo una duda leyendo tú código de arriba de todo. Qué pasa cuando el timer pasa de 255 a 0? Si en tti tenías un valor 240 y el siguiente get_timer0() te devuelve 15, cómo lo interpretas?

 

Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: RedPic en 17 de Octubre de 2008, 10:12:47
Hummmm .... no tengo ni idea. Ja, ja, ja, ja  :D :D :D :D

Hace dos años y dos meses que hice ese programa y no he vuelto a verlo ni utilizarlo ... imagino que podría ocurrir cualquier tipo de error absolutamente inesperado, curioso o incluso gracioso. Habría que estudiarlo.

¿Alguien se ofrece? (es broma) Si puedo le doy un vistazo a ver qué ocurriría,  :mrgreen:
Título: Re: Decodificando un protocolo IR y obteniendo direcciones y comandos.
Publicado por: gera en 27 de Enero de 2009, 02:05:57
Mil gracias redpic por tu trabajo, me viene de diez para lo q estoy haciendo. Sin embargo tengo una pequeña duda. Es necesario decodificar la trama? Si yo quiero q el circuito responda cuando apreto cierto boton del control, no puedo simplemente grabar lo q viene despues del encabezado, y despues quedarme a la espera de q se repita tal cual?
Gracias de nuevo!
PD: pienso usar el control remoto de un estereo pioneer, no se como sera el protocolo de este