Autor Tema: DTMF y Checksum  (Leído 1795 veces)

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

Desconectado cvargcal

  • PIC16
  • ***
  • Mensajes: 166
DTMF y Checksum
« en: 16 de Abril de 2017, 15:05:22 »
Saludos, quiero enviar código dtmf, pero en forma de una trama por ejemplo *A123456#
El receptor debe validar el * y comenzar a guardar el resto del numero hasta que llegue el #.
¿Cómo implemento un checksum para validar que el código que envió es el correcto?


Código: C
  1. int DTMF_CMD;
  2. int8 j=0;
  3. int8 Temp;
  4. int dtmf=0;
  5. char RX_DTMF[15];
  6. char const ASCII[16] = {'D','1','2','3','4','5','6','7','8','9','0','*','#','A','B','C'};
  7.  
  8. // Interrupción para detectar el DTMF
  9.  
  10. #int_EXT
  11. void EXT_isr(void){
  12.    DTMF_CMD = 0x0;
  13.    Temp = input_b();                           // Leer todo PORTB
  14.    if (bit_test(Temp,1)) bit_set(DTMF_CMD,3);  // Leer bit 1 (B1) de Temp y guardar en el bit 3 DTMF_CMD   3---
  15.    if (bit_test(Temp,2)) bit_set(DTMF_CMD,2);  // Leer bit 2 (B2) de Temp y guardar en el bit 2 DTMF_CMD   -2--
  16.    if (bit_test(Temp,3)) bit_set(DTMF_CMD,1);  // Leer bit 3 (B3) de Temp y guardar en el bit 1 DTMF_CMD   --1-
  17.    if (bit_test(Temp,4)) bit_set(DTMF_CMD,0);  // Leer bit 4 (B4) de Temp y guardar en el bit 0 DTMF_CMD   ---0
  18.    
  19.    DTMF_CMD=ASCII[DTMF_CMD];  // Busca el ASCCI correspondiente
  20.    RX_DTMF[j++]=DTMF_CMD;             // Va guardando los 9 caracteres, *A123456#
  21.  
  22.    if (j==9){                                    //*A123456#
  23.       RX_DTMF[9]='\0';                    // Reinicio contador y agrega un null
  24.       disable_interrupts(int_ext);      // Deshabilitar interrupción
  25.       dtmf=1;                                   // Esta listo el  DTMF *A123456*
  26.       j=0x00;//
  27.    }
  28. }
  29.  
  30.  
  31. // Loop principal
  32. /******************* <<< Ciclo Principal >>> **********************************/
  33.    while(true){
  34.                     if (dtmf){    
  35.                         fprintf(debug,"%s\r\n",RX_DTMF);  
  36.                        memset(RX_DTMF,NULL,sizeof(RX_DTMF));             // Set all elements to NULL
  37.                        dtmf=0; enable_interrupts(int_ext);                       // Interrupcion EXT
  38.                     }
  39.    }
  40.    
  41. }

en este código no estoy validando nada, guardo y muestro, pero tengo un problema, solo funciona a la primera vez, no se si es porque el dtmf es muy rápido y la interrupción muy lenta. cuando envío otros código por lo general no funciona ( imprime números rezagador). y si pongo a leer y escribir cada tono, veo que que  si llegan bien ( de 10, un tono llega mal, pero eso lo mejoro con  la duración del tono).

¿Alguna sugerencia para mejor esto?
Gracias
« Última modificación: 16 de Abril de 2017, 15:12:44 por cvargcal »

Desconectado KILLERJC

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 8242
Re:DTMF y Checksum
« Respuesta #1 en: 16 de Abril de 2017, 15:36:50 »
En realidad no me convence lo que te voy a pasar como para dejarlo definitivo, pero es para que tengas una idea de masomenos como podes hacerlo:


Código: C
  1. int DTMF_CMD;
  2. int8 j=1;
  3. int8 Temp;
  4. int8 dtmf = 0;
  5. char RX_DTMF[15];
  6. char const ASCII[16] = {'D','1','2','3','4','5','6','7','8','9','0','*','#','A','B','C'};
  7.  
  8. // Interrupción para detectar el DTMF
  9.  
  10. #int_EXT
  11. void EXT_isr(void){
  12.    DTMF_CMD = 0x0;
  13.    Temp = input_b();                           // Leer todo PORTB
  14.    if (bit_test(Temp,1)) bit_set(DTMF_CMD,3);  // Leer bit 1 (B1) de Temp y guardar en el bit 3 DTMF_CMD   3---
  15.    if (bit_test(Temp,2)) bit_set(DTMF_CMD,2);  // Leer bit 2 (B2) de Temp y guardar en el bit 2 DTMF_CMD   -2--
  16.    if (bit_test(Temp,3)) bit_set(DTMF_CMD,1);  // Leer bit 3 (B3) de Temp y guardar en el bit 1 DTMF_CMD   --1-
  17.    if (bit_test(Temp,4)) bit_set(DTMF_CMD,0);  // Leer bit 4 (B4) de Temp y guardar en el bit 0 DTMF_CMD   ---0
  18.    
  19.    DTMF_CMD=ASCII[DTMF_CMD];  // Busca el ASCCI correspondiente
  20.    switch(dtmf)
  21.    {
  22.         case 0:
  23.                 if(DTMF_CMD == '*'){
  24.                         dtmf++;
  25.                         RX_DTMF[0] = DTMF_CMD;
  26.                 }
  27.                 break;
  28.         case 1:
  29.                 if(DTMF_CMD == '#' || j >= 9) {  // Proteccion, la primera es cuando recibe el # sabeidno que termino, y la segunda es para que no supere la cantidad maxima de digitos
  30.                         dtmf++;
  31.                         RX_DTMF[9] = '\0';
  32.                         j = 1;
  33.                 }
  34.                 else {
  35.                         RX_DTMF[j++] = DTMF_CMD;
  36.                 }
  37.         break;
  38.         case 2:
  39.                 // Aca estaria completo y no haria nada hasta que se ponga en 0 dtmf
  40.         break;
  41.    }
  42.    
  43. }
  44.  
  45.  
  46. // Loop principal
  47. /******************* <<< Ciclo Principal >>> **********************************/
  48. void main(void){
  49.    
  50.    while(true){
  51.  
  52.         if(dtmf >= 2) {
  53.                        fprintf(debug,"%s\r\n",RX_DTMF);  
  54.                        dtmf=0;
  55.         }
  56.    }
  57.    
  58. }

Respecto al codigo, es insensato guardar los '*' y '#', yo intente dejarlo como estaba, la otra es que podes prescindir del '#' ya que podes recibir hasta que se reciba otro '*'. Acomode el codigo para que funcione como lo tenias casi, pero no hace falta.

Y el checksum es muy simple, procedes a sumar todos los digitos, suponete que tenes:

"*A123456#"

En ves de enviar esto envias asi:

"*A123456C"

Donde la C es el checksum. Este valor lo calculas con un for y sumando todos los anteriores. Suponete esto:

Código: C
  1. int8 Checksum = 0;
  2. char TX_DTMF[15] = "*A123456";
  3. int8 i=0;
  4.  
  5. for(i=0; TX_DTMF!='\0';i++)
  6. {
  7.         Checksum += TX_DTMF[i];
  8. }
  9. // Revisar si es ++i o i en esta que sigue
  10. TX_DTMF[++i] = Checksum;
  11. TX_DTMF[++i] = '\0';

Entonces en tu receptor vas a sumar todo menos el ultimo y restarle el ultimo, o sino para simplficar la parte del receptor podes hacer:

Código: C
  1. int8 Checksum = 0;
  2. char TX_DTMF[15] = "*A123456";
  3. int8 i=0;
  4.  
  5. for(i=0; TX_DTMF!='\0';i++)
  6. {
  7.         Checksum += TX_DTMF[i];
  8. }
  9. // Revisar si es ++i o i en esta que sigue
  10. TX_DTMF[++i] = ~Checksum + 1;
  11. TX_DTMF[++i] = '\0';

Asi de esa forma en el receptor solo tenes que sumar TODO, y si es correcto deberia darte 0.

------------

PD: Ahora que se que queres hacer con el ordenado de los bits, lo podes hacer mas rapido.

Aca tenes el codigo, como vos usas los bits xxxa aaax, (donde 'a' son los bits que me interesan) lo primero que hago es rotar y luego una AND asi quedan 0000 aaaa. Al pasarlos por la tabla
en ves de invertirlos, directamente uso ese indice y que me de como resultado los valores invertidos, por eso cambio la tabla. Estimo ahora que con 2 instrucciones haces lo del puerto A y luego la tabla queda fuera de discusión ya que antes no hablamos de la misma.

Código: C
  1. int DTMF_CMD;
  2. int8 j=1;
  3. int8 Temp;
  4. int8 dtmf = 0;
  5. char RX_DTMF[15];
  6. char const ASCII[16] = {'D','8','4','#','2','0','6','B','1','9','5','A','3','*','7','C'};
  7.  
  8. // Interrupción para detectar el DTMF
  9.  
  10. #int_EXT
  11. void EXT_isr(void){
  12.  
  13.    DTMF_CMD = ASCII[(input_b() >> 1) & 0xF] ;                           // Leer todo PORTB
  14.  
  15.    switch(dtmf)
  16.    {
  17.         case 0:
  18.                 if(DTMF_CMD == '*'){
  19.                         dtmf++;
  20.                         RX_DTMF[0] = DTMF_CMD;
  21.                 }
  22.                 break;
  23.         case 1:
  24.                 if(DTMF_CMD == '#' || j >= 9) {  // Proteccion, la primera es cuando recibe el # sabeidno que termino, y la segunda es para que no supere la cantidad maxima de digitos
  25.                         dtmf++;
  26.                         RX_DTMF[9] = '\0';
  27.                         j = 1;
  28.                 }
  29.                 else {
  30.                         RX_DTMF[j++] = DTMF_CMD;
  31.                 }
  32.         break;
  33.         case 2:
  34.                 // Aca estaria completo y no haria nada hasta que se ponga en 0 dtmf
  35.         break;
  36.    }
  37.    
  38. }
« Última modificación: 16 de Abril de 2017, 18:14:54 por KILLERJC »

Desconectado cvargcal

  • PIC16
  • ***
  • Mensajes: 166
Re:DTMF y Checksum
« Respuesta #2 en: 16 de Abril de 2017, 19:18:17 »
Código: [Seleccionar]
[quote author=KILLERJC link=topic=47590.msg396266#msg396266 date=1492367810]
En realidad no me convence lo que te voy a pasar como para dejarlo definitivo, pero es para que tengas una idea de masomenos como podes hacerlo:
....

}

Genial, muchas gracias... iré a probarlo...
Claro, lo que cambia es la tabla...  :mrgreen: :-/
Muchas gracias.

Edit.

Ahora todo es super rápido, incluso para tonos de 20m, muchas gracias.  ((:-)) ((:-)) ((:-)) eres un maestro.
« Última modificación: 16 de Abril de 2017, 20:35:26 por cvargcal »

Desconectado Ruco

  • PIC12
  • **
  • Mensajes: 62
Re:DTMF y Checksum
« Respuesta #3 en: 10 de Abril de 2023, 17:16:55 »
Saludos. Espero no sea un tema olvidado. Ya que lo estoy tomando para hacer algo para mi necesidad, incluso estoy partiendo de este código ya iniciado.

Recién me intereso el tema de los DTMF con el MT8870. Espero de su ayuda, verán lo que requiero es hacer algo similar.

Lo que requiero recibir es algo asi... *1234#; si recibo correctamente esa trama, entonces enciende un lLED

De otra manera, si recibo *4321#, entonces apago el LED.

podrian ayudarme?.


Aquí anexo lo que e complementado del código Leyendo este tema el Sr. KILLERJC pone un código que dice estar de la mejor manera y es por eso que lo tomo a lo que yo e querido hacer...


Código: C
  1. /*       L=LOGIC LOW, H=LOGIC HIGH, Z=HIGH IMPEDANCE, X = DON'T CARE
  2.          
  3.          |-----------------------------------------------|
  4.          |        Functional Decode Table MT8870         |
  5.          |-----------------------------------------------|
  6.          |  Dig   TOE   INH   ESt   Q4    Q3    Q2    Q1 |
  7.          |  ANY   L     X     H     Z     Z     Z     Z  |
  8.          |  1     H     X     H     0     0     0     1  |
  9.          |  2     H     X     H     0     0     1     0  |
  10.          |  3     H     X     H     0     0     1     1  |
  11.          |  4     H     X     H     0     1     0     0  |
  12.          |  5     H     X     H     0     1     0     1  |
  13.          |  6     H     X     H     0     1     1     0  |
  14.          |  7     H     X     H     0     1     1     1  |
  15.          |  8     H     X     H     1     0     0     0  |
  16.          |  9     H     X     H     1     0     0     1  |
  17.          |  0     H     X     H     1     0     1     0  |
  18.          |  *     H     X     H     1     0     1     1  |
  19.          |  #     H     X     H     1     1     0     0  |
  20.          |  A     H     L     H     1     1     0     1  |
  21.          |  B     H     L     H     1     1     1     0  |
  22.          |  C     H     L     H     1     1     1     1  |
  23.          |  D     H     L     H     0     0     0     0  |
  24.          |-----------------------------------------------|
  25.          |  A     H     H     L | undetected, the output |
  26.          |  B     H     H     L | code will remain the   |
  27.          |  C     H     H     L | same as the previous   |
  28.          |  D     H     H     L | detected code.         |
  29.          |----------------------------------------------*/
  30.          
  31.          // DTMF a recivir: *A123456#
  32.          
  33. #include <18f4550.h>                                                          // #include <18f4550.h>                              
  34. #fuses HS,PROTECT,PUT,WDT,NOBROWNOUT,NOLVP,NOCPD,WRT,MCLR
  35. #use delay(clock=20000000, crystal=20000000)  
  36. #byte PORTA=0xf80 #byte TRISA=0xf92 #byte PORTB=0xf81 #byte TRISB=0xF93 #byte PORTC=0xf82 #byte TRISC=0xF94 #byte PORTD=0xf83 #byte TRISD=0xF95 #byte PORTE=0xf84 #byte TRISE=0xF96
  37. #byte LATA=0xf89 #byte LATB=0xf8a #byte LATC=0xf8b #byte LATD=0xf8c #byte LATE=0xf8d
  38. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8, stop=1, stream=debug, ERRORS)                      
  39.          
  40. int DTMF_CMD;
  41. int8 j=1;
  42. int8 Temp;
  43. int8 dtmf = 0;
  44. char RX_DTMF[15];
  45. char const ASCII[16] = {'D','8','4','#','2','0','6','B','1','9','5','A','3','*','7','C'};
  46.  
  47. // Interrupción para detectar el DTMF
  48.  
  49. #int_EXT
  50. void EXT_isr(void){
  51.  
  52.    DTMF_CMD = ASCII[(input_b() >> 1) & 0xF] ;                           // Leer todo PORTB
  53.  
  54.    switch(dtmf)
  55.    {
  56.         case 0:
  57.                 if(DTMF_CMD == '*'){
  58.                         dtmf++;
  59.                         RX_DTMF[0] = DTMF_CMD;
  60.                 }
  61.                 break;
  62.         case 1:
  63.                 if(DTMF_CMD == '#' || j >= 9) {  // Proteccion, la primera es cuando recibe el # sabeidno que termino, y la segunda es para que no supere la cantidad maxima de digitos
  64.                         dtmf++;
  65.                         RX_DTMF[9] = '\0';
  66.                         j = 1;
  67.                 }
  68.                 else {
  69.                         RX_DTMF[j++] = DTMF_CMD;
  70.                 }
  71.         break;
  72.         case 2:
  73.                 // Acá estaría completo y no haría nada hasta que se ponga en 0 dtmf
  74.         break;
  75.    }
  76.    
  77. }
  78.  
  79.          void main(void){
  80.          porta=0x00; set_tris_a(0b00000000); portb=0x00; set_tris_b(0b11111111); portc=0x00; set_tris_c(0b10000000); portd=0x00; set_tris_d(0b00000000); porte=0x00; set_tris_e(0b00001000);                  
  81.          enable_interrupts(INT_EXT);
  82.          ext_int_edge(L_TO_H);
  83.          enable_interrupts(GLOBAL);
  84.          
  85.          while(true){
  86.  
  87.  
  88.  
  89.          }
  90.          }

Desconectado Ruco

  • PIC12
  • **
  • Mensajes: 62
Re:DTMF y Checksum
« Respuesta #4 en: 11 de Abril de 2023, 02:15:48 »
Bueno realice un programita con un PIC16F873A que simule el MT8870 enviando los tonos DTMF *1234#, estos son introducidos al PIC18F4550 quien los recibe y los visualizo por el terminal virtual.

Corte unas partes del programa que ya estaba y recibe al menos simulando.

Así quedo el código que recibe:

Código: C
  1. #include <18f4550.h>                                                          // #include <18f4550.h>                              
  2.    #fuses HS,PROTECT,PUT,WDT,NOBROWNOUT,NOLVP,NOCPD,WRT,MCLR
  3.    #use delay(clock=20000000, crystal=20000000)  
  4.    #byte PORTA=0xf80 #byte TRISA=0xf92 #byte PORTB=0xf81 #byte TRISB=0xF93 #byte PORTC=0xf82 #byte TRISC=0xF94 #byte PORTD=0xf83 #byte TRISD=0xF95 #byte PORTE=0xf84 #byte TRISE=0xF96
  5.    #byte LATA=0xf89 #byte LATB=0xf8a #byte LATC=0xf8b #byte LATD=0xf8c #byte LATE=0xf8d
  6.    #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8, stop=1, stream=debug, ERRORS)                      
  7.            
  8.    int DTMF_CMD;
  9.    int8 Temp;
  10.    int8 dtmf = 0;
  11.    char RX_DTMF[15];
  12.    char const ASCII[16] = {'D','1','2','3','4','5','6','7','8','9','0','*','#','A','B','C'};
  13.    
  14.    // Interrupción para detectar el DTMF
  15.  
  16.    #int_EXT
  17.    void EXT_isr(void){
  18.    DTMF_CMD = 0x0;
  19.    Temp = input_b();                           // Leer todo PORTB
  20.    if (bit_test(Temp,1)) bit_set(DTMF_CMD,3);  // Leer bit 1 (B1) de Temp y guardar en el bit 3 DTMF_CMD   3---
  21.    if (bit_test(Temp,2)) bit_set(DTMF_CMD,2);  // Leer bit 2 (B2) de Temp y guardar en el bit 2 DTMF_CMD   -2--
  22.    if (bit_test(Temp,3)) bit_set(DTMF_CMD,1);  // Leer bit 3 (B3) de Temp y guardar en el bit 1 DTMF_CMD   --1-
  23.    if (bit_test(Temp,4)) bit_set(DTMF_CMD,0);  // Leer bit 4 (B4) de Temp y guardar en el bit 0 DTMF_CMD   ---0
  24.    
  25.    DTMF_CMD=ASCII[DTMF_CMD];  // Busca el ASCCI correspondiente
  26.  
  27.    dtmf++;
  28.    RX_DTMF[0] = DTMF_CMD;              
  29.    }
  30.  
  31.    void main(void){
  32.    porta=0x00; set_tris_a(0b00000000); portb=0x00; set_tris_b(0b11111111); portc=0x00; set_tris_c(0b10000000); portd=0x00; set_tris_d(0b00000000); porte=0x00; set_tris_e(0b00001000);                  
  33.    enable_interrupts(INT_EXT);
  34.    ext_int_edge(L_TO_H);
  35.    enable_interrupts(GLOBAL);
  36.          
  37.    while(true){
  38.    fprintf(debug," %s ",RX_DTMF);  
  39.    dtmf=0;    
  40.    }  
  41.    }

Mas no se si es de la mejor manera, ya que solo corte algunas cosas que no creí conveniente. Podrían opinar por favor??..

Ahora faltaría la parte de comparar el *1234# que llego correctamente para encender el led.


 

anything