Autor Tema: Como capturar una trama de datos "diferente"  (Leído 4710 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Como capturar una trama de datos "diferente"
« en: 08 de Julio de 2011, 20:46:43 »
Hola a todos!
Tengo un mando a distancia de cuatro canales, el cual tiene una direccion interna unica de 220 combinaciones, y cuatro bits mas para el estado de los canales.
Los 24 bits forman una trama que se envia cuando se pulsa un boton.
Lo curioso para mi es que el mando envia UNOS y CEROS de la siguente forma:
Un CERO: 160uS pulso alto, 480uS pulso bajo
Un UNO: 480uS pulso alto, 160uS pulso bajo
Una vez enviados los 24 bits de esta manera, luego se envia una señal de sincronismo con la siguiente forma:
160uS pulso alto, 4960uS (4.96mS) pulso bajo.
Y luego se repite el proceso mientras este pulsado algun boton del mando.
Aqui esta la hoja de datos del encoder: http://www.princeton.com.tw/downloadprocess/downloadfile.asp?mydownload=PT2240B_1.pdf

Estuve buscando pero no encontre un decoder para esto, asi que lo reproducire con un PIC. Incluso me gustaria poder hacer una libreria para esto.
Mi idea es usar un receptor de radiofrecuencia para capturar los 24 bits que envia el mando y luego poder procesarlos, pero de que manera podre hacerlo de manera sencilla? La verdad se me ocurren ideas sueltas pero no se como juntarlas para conseguir hacer algo!  :(
Tal vez con la interrupcion externa y los flancos ascendentes y descendentes, en conjunto con el modulo CCP para medir la duracion de los pulsos.
Alguien que me de un empujoncito en la direccion adecuada?  :g)

Gracias y salu2!
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado Suky

  • Moderador Local
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: Como capturar una trama de datos "diferente"
« Respuesta #1 en: 08 de Julio de 2011, 21:29:40 »
Citar
Lo curioso para mi es que el mando envia UNOS y CEROS de la siguente forma:

Es un tipo de codificación digital, como por ejemplo Manchester: http://es.wikipedia.org/wiki/Codificaci%C3%B3n_digital

Leer la trama parece bastante sencilla, se puede con una interrupción externa con flanco ascendente para determinar el primer bit, esperar unos 50a y tester el pin, si es 5V es un 1 lógico, sino queda esperar si dentro de los 78a ocurre otro flanco es un 0 lógico, sino es un sincronismo.


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Como capturar una trama de datos "diferente"
« Respuesta #2 en: 09 de Julio de 2011, 00:13:38 »
El método que propone Suky creo que es el más simple.

La otra manera que se me ocurre es que la interrupción externa sólo salte con flancos descendentes y un timer que desborde en un rango entre 640us y 4096us. Cada vez que entre en la interrupción externa miras el timer y lo reinicias.
Si el timer te da un valor de 160us (inferior a 320us) es un cero, si es superior a 320 se tratará de un 1.
Si el timer desborda, el último cero que capturaste es en realidad un sincronismo.

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re: Como capturar una trama de datos "diferente"
« Respuesta #3 en: 18 de Julio de 2011, 17:20:04 »
Estoy a la espera de un modulo RF, porque tenia un emisor en 315Mhz y un receptor en 433Mhz...
Por eso no funcionaba!!! jjajja
Luego hare las pruebas
Gracias!
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado Francirius

  • PIC10
  • *
  • Mensajes: 32
Re: Como capturar una trama de datos "diferente"
« Respuesta #4 en: 05 de Agosto de 2011, 17:28:25 »
Yo estuve haciendo esto para decodificar señales de controles remotos IR de tv y radio, y la idea es la misma, con una interrupcion con flanco ascendente o descendente, entra a la interrupcion que inicia el timer, y cambia el flanco, luego sale de la interrupcion y cuando detecta el otro flanco, guarda el estado del timer, y compara.

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Como capturar una trama de datos "diferente"
« Respuesta #5 en: 05 de Agosto de 2011, 22:00:57 »
otra opcion seria usar la interrupion externa empezando en flanco de subida, y en cada interrupcion ir alternado el flanco que te genera la interrupcion
cada que tengas la interrupcion lees el valor del timer( despues lo pones a cero para medir el siguiente puslo) y lo vas guardando en algun vetor a partir de tu bit de inicio y despues en otra funcion discriminas si son ceros o unos asi sabrias el ancho de pulso de todos los datos de la trama.
"Nada es imposible, no si puedes imaginarlo"

Desconectado Francirius

  • PIC10
  • *
  • Mensajes: 32
Re: Como capturar una trama de datos "diferente"
« Respuesta #6 en: 10 de Agosto de 2011, 01:04:49 »
otra opcion seria usar la interrupion externa empezando en flanco de subida, y en cada interrupcion ir alternado el flanco que te genera la interrupcion
cada que tengas la interrupcion lees el valor del timer( despues lo pones a cero para medir el siguiente puslo) y lo vas guardando en algun vetor a partir de tu bit de inicio y despues en otra funcion discriminas si son ceros o unos asi sabrias el ancho de pulso de todos los datos de la trama.

Ja, lo mismo que dije yo, pero con otras palabras

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re: Como capturar una trama de datos "diferente"
« Respuesta #7 en: 10 de Agosto de 2011, 08:21:02 »
Ya tengo el modulo emisor y receptor, pero aun no he podido ponerme con ello...
El viernes empiezo mis dos semanas de vacaciones en Alicante :) e intentare pillar el portatil y programar un poquito cuando mi novia no me vea, porque como se entere me MATAAAAAAAA  :mrgreen:
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18286
    • MicroPIC
Re: Como capturar una trama de datos "diferente"
« Respuesta #8 en: 10 de Agosto de 2011, 11:24:38 »
Eso, y tú no quieres que se entere, y lo escribes en un foro  :D

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Como capturar una trama de datos "diferente"
« Respuesta #9 en: 10 de Agosto de 2011, 12:25:38 »
Eso, y tú no quieres que se entere, y lo escribes en un foro  :D

dado que casi no hay mujeres en el foro, no creo que eso sea problema. :D
"Nada es imposible, no si puedes imaginarlo"

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re: Como capturar una trama de datos "diferente"
« Respuesta #10 en: 26 de Octubre de 2011, 07:16:08 »
Ayer me tome el dia para terminar este proyecto y creo que el codigo ya esta listo!!! O al menos compila, jeje
Hoy voy a hacer pruebas a ver que tal funciona.
Cuando lo tenga funcionando pongo el codigo.
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado rivale

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1707
Re: Como capturar una trama de datos "diferente"
« Respuesta #11 en: 26 de Octubre de 2011, 09:27:28 »
muy bien!! :-/ :-/ :-/
a hacer pruebas se ha dicho!!
"Nada es imposible, no si puedes imaginarlo"

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re: Como capturar una trama de datos "diferente"
« Respuesta #12 en: 26 de Octubre de 2011, 17:15:17 »
Uff... que putada....
Estoy haciendo las pruebas, y no son NADA parecidas a lo que pensaba  :8}
Hice todo el programa basandome en la TEORIA de funcionamiento segun el datasheet, pero al parecer en la practica es completamente diferente!!!
En principio hay 3 tipos de pulsos: Cortos (32*ALFA), Largos (96 * ALFA) y Sync (992 * ALFA). ALFA es 1 / Fosc del emisor. Que en mi caso el emisor oscila a 200K.
Cada uno de estos tres pulsos puede ser HIGH o LOW.
Basicamente mi idea era medir el pulso que entra por el receptor RF y si corresponde con alguno de los esperados procesarlo segun corresponda.
Pero OH SORPRESA cuando, antes de probar mi codigo en el PIC, pruebo la entrada en el osciloscopio, y la longitud de los pulsos no es ni de cerca la esperada... y si solo fuera eso, y tuviese que calcular nuevamente la longitud de los pulsos, vaya y pase... pero es que los pulsos no se corresponden con los calculos matematicos. Tendria que ir midiendo con el osciloscopio, y no se si eso sera fiable luego en la practica.
Yo ya tuve en cuenta un margen de error de aproximadamente un 10% por arriba y por abajo del pulso teorico!
Voy a llorar y reflexionar un poco sobre esto y a ver que sale...  :oops:
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re: Como capturar una trama de datos "diferente"
« Respuesta #13 en: 26 de Octubre de 2011, 21:05:19 »
Bueno, vamos mejorando...
Ya lo hice funcionar... Aunque no se la fiabilidad, ni lo optimo del codigo, pero por las pruebas que hice funciona bastante bien.

Código: C
  1. #include <16F1823.h>
  2. #device adc=8
  3.  
  4. #FUSES NOFCMEN          //NO fail safe clock monitor
  5. #FUSES NOIESO           //NO internal external switchover
  6. #FUSES NOBROWNOUT       //NO brownout reset
  7. #FUSES CPD                      //NO eeprom protegido de lecturas
  8. #FUSES PROTECT          //NO codigo protegido de lecturas
  9. #FUSES NOMCLR           //NO mclr
  10. #FUSES PUT                      //power up timer
  11. #FUSES NOWDT            //NO watch dog timer
  12. #FUSES INTRC_IO         //oscilador interno, pines CLK como I/O
  13.  
  14. #use delay(clock=8000000)       //clock de 8Mhz
  15. #use fast_io(a)                         //se accede al puerto a como memoria
  16. #use fast_io(c)                         //se accede al puerto c como memoria
  17.  
  18. //Direcciones de registros
  19. #byte PORTA             = 0x0C
  20. #byte PORTC             = 0x0E
  21. #byte OPT_REG   = 0x95
  22.  
  23. #bit INTEDG             = OPT_REG.6     //direccion de int edge selection bit. 1=RISING, 0=FALLING
  24.  
  25. //--- Puertos ---
  26. //0b11111110
  27. //#define TX    PIN_A0
  28. //#define RX    PIN_A1
  29. #bit RF_IN      = PORTA.2
  30. #bit A3         = PORTA.3
  31. #bit A4         = PORTA.4
  32. #bit A5         = PORTA.5
  33. //0b11111011
  34. #bit C0         = PORTC.0
  35. #bit C1         = PORTC.1
  36. #bit LED        = PORTC.2
  37. #bit C3         = PORTC.3
  38. #bit C4         = PORTC.4
  39. #bit C5         = PORTC.5
  40. //---------------
  41.  
  42. //--- Constantes ---
  43. #define LOW                     0       //pulso low
  44. #define HIGH            1       //pulso high
  45.  
  46. #define FALLING         0       //falling edge
  47. #define RISING          1       //rising edge
  48. //------------------
  49.  
  50. //---Porcentajes del pulso HIGH sobre el pulso completo
  51. #define MIN_CERO        15
  52. #define CERO            25
  53. #define MAX_CERO        35
  54.  
  55. #define MIN_UNO         65
  56. #define UNO                     75
  57. #define MAX_UNO         85
  58.  
  59. #define MIN_SYNC        1
  60. #define SYNC            3.125
  61. #define MAX_SYNC        5
  62. //--------------------------
  63.  
  64. short flagPulso = FALSE;        //indica cuando se produjo un flanco
  65. short Direccion[24];            //variable que almacena la direccion recibida (24 bits)
  66. int Bits_Contados = 0;          //numero de bits contados
  67. int Duty = 0;                           //porcentaje de pulso alto sobre la duracion del pulso
  68. long TiempoHigh = 0;            //tiempo medido de la parte HIGH del pulso
  69. long TiempoTot = 0;                     //tiempo total del pulso (high y low)
  70. //-----------------
  71.  
  72. // --- INT EXT ---
  73. #int_EXT
  74. void EXT_isr(void) {
  75.         if(INTEDG == RISING){                   //flanco ascendente, empieza el pulso
  76.                 TiempoTot = get_timer1();       //obtiene la duracion total del pulso anterior
  77.                 set_timer1(0);                          //resetea el timer
  78.                 flagPulso = TRUE;                       //indica que leyo un pulso completo
  79.         }
  80.         else{                                                   //flanco descendente, termina la parte HIGH del pulso
  81.                 TiempoHigh = get_timer1();      //lee cuanto duro el pulso HIGH
  82.         }
  83.  
  84.         INTEDG = !INTEDG;                       //invierte el flanco
  85. }
  86. // ---------------
  87.  
  88. void main(void) {
  89.  
  90.         setup_wdt(WDT_OFF);                                             //configuracion wdt
  91.         setup_timer_0(T0_INTERNAL|RTCC_DIV_1);  //configuracion timer0
  92.         setup_timer_1(T1_INTERNAL|T1_DIV_BY_2); //configuracion timer1
  93.         setup_timer_2(T2_DISABLED,0,1);                 //configuracion timer2
  94.         setup_dac(DAC_OFF);                                             //configura DAC
  95.         setup_adc(ADC_OFF);                                             //configura ADC
  96.         setup_ccp1(CCP_OFF);                                    //configura CCP
  97.         setup_spi(FALSE);                                               //configura SPI
  98.         setup_comparator(NC_NC_NC_NC);                  //comparador apagado
  99.         setup_vref(FALSE);                                              //no se usa voltaje de referencia
  100.        
  101.         ext_int_edge(L_TO_H);                                   //configura int ext ASCENDENTE
  102.        
  103.         enable_interrupts(INT_EXT);                             //interrupcion externa
  104.                
  105.         enable_interrupts(GLOBAL);                              //habilita las interrupciones
  106.         setup_oscillator(OSC_8MHZ|OSC_INTRC);   //configura oscilador interno
  107.        
  108.         set_tris_a(0b11011111);                                 //
  109.         set_tris_c(0b11111011);                                 //
  110.  
  111.         do{
  112.                 if(flagPulso == TRUE){
  113.                         flagPulso = FALSE;
  114.                        
  115.                         Duty = ((int32)TiempoHigh * 100) / TiempoTot;
  116.                        
  117.                         if((MIN_CERO <= Duty) && (Duty <= MAX_CERO)){
  118.                                 shift_right(&Direccion,3,CERO); //coloca el bit recibido en la ultima posicion
  119.                                 if(Bits_Contados < 24)                  //no suma mas de 24
  120.                                         ++Bits_Contados;                        //suma uno
  121.                         }
  122.                         else if((MIN_UNO <= Duty) && (Duty <= MAX_UNO)){
  123.                                 shift_right(&Direccion,3,UNO);  //coloca el bit recibido en la ultima posicion
  124.                                 if(Bits_Contados < 24)                  //no suma mas de 24
  125.                                         ++Bits_Contados;                        //suma uno
  126.                         }
  127.                         else if((MIN_SYNC <= Duty) && (Duty <= MAX_SYNC)){
  128.                                 if(Bits_Contados == 24){                //direccion completa?
  129.                                         //direccion correcta
  130.                                         disable_interrupts(GLOBAL);
  131.                                        
  132.                                         LED = 1;
  133.                                         delay_ms(300);
  134.                                         LED = 0;
  135.                                         enable_interrupts(GLOBAL);
  136.                                 }
  137.                                 else{                                           //no se contaron 24 bits
  138.                                         Bits_Contados = 0;              //reinicia la recepcion de datos
  139.                                 }
  140.                         }
  141.                         else{                                                   //el pulso recibido no es nada esperado
  142.                                 Bits_Contados = 0;                      //reinicia la recepcion de datos
  143.                         }
  144.                 }
  145.         }while(true);
  146. }

Despues de darle MUCHISIMAS vueltas al datasheet y de varias ideas diferentes, me quede con esto, que resulta en un codigo muy cortito.
Tan solo parpadea un LED si recibe una direccion valida. No comprueba ni compara la direccion, tan solo parpadea el LED si recibe los 24 bits consecutivos seguido de un pulso SYNC. Comprobar el codigo recibido con una tabla seria muy sencillo, pero de momento no es mi objetivo.

Un bit CERO es un pulso del 25% de duty, un UNO tiene un 75% de duty, y un SYNC tiene aprox un 3% de duty. A partir de ahi mido los pulsos recibidos y compruebo si por el duty es un CERO, un UNO, un SYNC o si es RUIDO.

Lo malo es que tuve que ponerle margenes son muy amplios (+-10% para CERO y UNO, +-2% para SYNC), y si bien seria MUY MUY MUY improbable que RUIDO provoque 24 bits CONSECUTIVOS Y EN EL FORMATO CORRECTO, no me gusta que no funcione segun los calculos del datasheet y tenga que hacerlo "por tanteo".

Bueno, si a alguien se le ocurre alguna mejora sera bien recibida :)

Tambien, si a alguien le interesa tengo el codigo para emular el encoder del emisor. Asi esta completa la pareja de encoder y decoder  :-/
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado AngelGris

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 2480
Re: Como capturar una trama de datos "diferente"
« Respuesta #14 en: 26 de Octubre de 2011, 22:03:48 »
............
En principio hay 3 tipos de pulsos: Cortos (32*ALFA), Largos (96 * ALFA) y Sync (992 * ALFA). ALFA es 1 / Fosc del emisor. Que en mi caso el emisor oscila a 200K.
Cada uno de estos tres pulsos puede ser HIGH o LOW.
............

.............
Un bit CERO es un pulso del 25% de duty, un UNO tiene un 75% de duty, y un SYNC tiene aprox un 3% de duty. A partir de ahi mido los pulsos recibidos y compruebo si por el duty es un CERO, un UNO, un SYNC o si es RUIDO.
.............

  Para los CEROS y UNOS veo la cosa igual. O sea... si (32*ALFA) = 25%  es correcto decir que (96*ALFA) = 75%. Ahora, con el pulso de SYNC se me fueron los cálculos  :5]
De vez en cuando la vida
nos besa en la boca
y a colores se despliega
como un atlas