Autor Tema: Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP  (Leído 14138 veces)

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

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Seguimos dándole vueltas al Tema de Capturar el ancho de un pulso ...

En Midiendo un pulso. 1ª Parte. Tiempo en Alto con INTEXT hemos utilizado la técnica de recoger el valor de TMR1 cuando ocurre la interrupción externa por RB0, sea en el flanco de caída, sea en el de subida. Con los valores de ambos flancos y simplemente restando el uno del otro tenemos el valor del ancho del pulso.

Hay otra manera de hacer exactamente lo mismo de una forma absolutamente similar: Utilizando el módulo CCP del PIC funcionando en modo Capture.

A.- Conceptos involucrados:

Los conceptos son exactamente los mismos que los descritos en la parte anterior por lo que os ruego que  consultéis si os es necesario: Midiendo un pulso. 1ª Parte

B.- Técnica a Aplicar:

El módulo hardware CCP del PIC en configuración Capture realiza de forma automática (por hardware) lo que implementamos en nuestro anterior Técnica en C mediante la interrupción externa por RB0.

Cuando activamos el módulo CCP, le configuramos el flanco que deseamos que lo dispere, subida o bajada, automáticamente cada vez que se nos presente dicho flanco en el pin correspondiente se copia el valor de TMR1, de 16 bits, en la pareja de registros CCPRL y CCPRH.

Cada vez que llega un flanco tenemos en CCPR el valor en ese momento de TMR1.

Si además habilitamos la Interrupción CCP del PIC se producirá además una Petición de Servicio para esta interrupción cada vez que nuestro esperado flanco se presente en el pin correspondiente.

En esta rutina de interrupción podremos así cambiar el modelo de flanco a utilizar para el siguiente disparo del CCP, cambiándolo ahora al flanco de bajada, y así en el siguiente  disparo tendremos en CCPR el nuevo valor de TIMER1 con lo restando éste del anterior tendremos el ancho de pulso en High que deseamos.

Como véis es absolutamente identico al método anterior pero sin tener que recoger "a mano" el valor de TMR1.

C.- Implementación en C:

Nota Importante: En mi ejemplo utilizo el 18F4550 de la RRBOARD2 usando del módulo CCP2, de los dos que tiene este PIC, configurándolo además para que CCP2 en lugar de estar en RC1 como originalmente está configurado y que estoy usando para otras cosas, se multiplexe por RB3 que lo tengo libre. Esto último se consigue en el 18F4550 usando el fuse CCP2B3.  :mrgreen:

Para configurar inicialmente el flanco de subida a detectar utilizaremos:

Código: C
  1. setup_ccp2(CCP_CAPTURE_RE);      // Configuro captura de 1er flanco de subida
  2.    flagToggleFlanco = 0;            // inicializo el Flag para cambiar de flanco
  3.    enable_interrupts(int_ccp2);
  4.    enable_interrupts(global);

Nuestra rutina ISR para CCP quedaría como sigue:

Código: C
  1. #int_ccp2
  2. void handle_ccp2_int(){
  3.    if(flagToggleFlanco==0){                 // He recibido Flanco de Subida
  4.       t1=CCP_2;                      // Guardo la captura del CCP2 al Flanco de Subida
  5.       setup_ccp2(CCP_CAPTURE_FE);           // Configuro para capturar siguiente flanco de Bajada
  6.       flagToggleFlanco=1;                   // Indico que el siguiente flanco será de Bajada
  7.  
  8.    } else {                                 // He recibido Flanco de Bajada
  9.  
  10.       t2=CCP_2;                      // Guardo en t2 la nueva captura de CCP2 al Flanco de Bajada
  11.       setup_ccp2(CCP_CAPTURE_RE);               // Configuro para capturar siguiente flanco de subida
  12.       flagToggleFlanco=0;                   // Indico que el siguiente flanco será de Subida
  13.       if(flagHayDatos==0){                  // Si los datos anteriores han sido procesados ...
  14.          flagHayDatos=1;                    // Indico que ya hay nuevos datos de flancos para calcular
  15.       }
  16.    }

El resto de la implementación en C de esta Técnica es identica a la mostrada en Midiendo un pulso. 1ª Parte. Tiempo en High con Int_Ext

D.- Ejemplo funcionando:



La señal inyectada podéis verla en :



Bueno, y esto es todo por hoy amigos.  :)
Mañana, más.




« Última modificación: 24 de Octubre de 2014, 09:56:07 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado RedPic

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 5544
    • Picmania by Redraven
Re: Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP
« Respuesta #1 en: 27 de Octubre de 2006, 15:45:59 »
Aqui tienes filth el código completo de la medida del pulso en alto con CCP:

Código: C
  1. ////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Midiendo_un_pulso_2_CCP.c
  4. //
  5. // SERIE: "Técnicas en C" para el Foro TODOPIC
  6. //
  7. // (c) 10.2006 by RedPic
  8. //
  9. // Propósito: Medir el tiempo que permanece un pulso en alto
  10. //
  11. // Condiciones de Test: Inyección por RB3 de una señal de 2 Khz (0.5 ms de periodo)
  12. //
  13. // Técnica Empleada: Detectar mediante la Interrupción CCP (Compare)
  14. //                   un flanco de subida de un pulso, guardar el estado
  15. //                   de TMR1,  detectar  a  continuación el  siguiente
  16. //                   flanco de bajada, guardar el nuevo estado de TMR1,
  17. //                   realizar las substracción de ambos para obtener el
  18. //                   tiempo que permanece en alto y transmitir mediante
  19. //                   el puerto RS232 a petición.
  20. //
  21. ////////////////////////////////////////////////////////////////////////////////////
  22.  
  23.  
  24. #include <18f4550.h>
  25. #fuses HS,MCLR,CCP2B3,NOWDT,NOPROTECT,NOPUT,NOBROWNOUT,NOPBADEN,NOLVP,NOCPD,NODEBUG,NOWRT,NOVREGEN
  26. #use delay(clock=20000000)
  27.  
  28. #use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
  29.  
  30.  
  31. ////////////////////////////////////////////////////////////////////////////////////
  32. //
  33. // Defines y Constantes
  34. //
  35. ////////////////////////////////////////////////////////////////////////////////////
  36.  
  37. #define LED PIN_E0                          // Defino el Pin del Led
  38. #define FLASH Output_Toggle(LED)            // Defino la funcion Flash de monitor
  39.  
  40. float const uSxTick = 0.2;                  // Microsegundos por Tick de TMR1 a 20 Mhz
  41.  
  42.  
  43. ////////////////////////////////////////////////////////////////////////////////////
  44. //
  45. // Variables en RAM
  46. //
  47. ////////////////////////////////////////////////////////////////////////////////////
  48.  
  49. char  cRec=0x00;                            // Último caracter recibido via serie
  50. char  Command=0x00;                         // Comando a procesar
  51. int1  flagToggleFlanco=0;                   // Flag para cambiar de flanco
  52. int16 t1=0x00,t2=0x00,tt=0x00;              // Variables para guardar estados de ...
  53. float st=0.0;                               // TMR1 en cada flanco y hacer la resta
  54. int1  flagHayDatos=0;                       // Flag para indicar que ya hay datos de ..
  55.                                             // dos flancos (de subida y bajada)
  56. int1  flagHayTransmitir=0;                  // Flag para indicar que hay datos para ...
  57.                                             // Transmitir al PC.
  58.  
  59. ////////////////////////////////////////////////////////////////////////////////////
  60. //
  61. // Interrupción por Recepción Serie RS232
  62. //
  63. ////////////////////////////////////////////////////////////////////////////////////
  64.  
  65.  
  66. #int_rda
  67. void handle_rda_int(){
  68.  
  69.    if(kbhit()){                             // Si hay algo pdte de recibir ...
  70.       cRec=getc();                          // lo recibo sobre cRec ...
  71.       if(cRec!=0x00){                       // Si es distinto de \0 ...
  72.          Command=ToUpper(cRec);             // cargo cRec sobre Command para procesarlo
  73.       }                                     // pasándolo a Mayúsculas para no confundir.
  74.    }
  75. }
  76.  
  77. ////////////////////////////////////////////////////////////////////////////////////
  78. //
  79. // Interrupción por Externa por Cambio de Flanco en RB0
  80. //
  81. ////////////////////////////////////////////////////////////////////////////////////
  82.  
  83.  
  84. #int_ccp2
  85. void handle_ccp2_int(){
  86.  
  87.    if(flagToggleFlanco==0){                 // He recibido Flanco de Subida
  88.  
  89.       t1=get_timer1();                      // Guardo en t1 el valor de TMR1 al Flanco de Subida
  90.       setup_ccp2(CCP_CAPTURE_FE);           // Configuro para capturar siguiente flanco de Bajada
  91.       flagToggleFlanco=1;                   // Indico que el siguiente flanco será de Bajada
  92.  
  93.    } else {                                 // He recibido Flanco de Bajada
  94.  
  95.       t2=get_timer1();                      // Guardo en t2 el valor de TMR1 al Flanco de Bajada
  96.       setup_ccp2(CCP_CAPTURE_RE);               // Configuro para capturar siguiente flanco de subida
  97.       flagToggleFlanco=0;                   // Indico que el siguiente flanco será de Subida
  98.       set_timer1(0);                        // Reinicio TMR1
  99.       if(flagHayDatos==0){                  // Si los datos anteriores han sido procesados ...
  100.          flagHayDatos=1;                    // Indico que ya hay nuevos datos de flancos para calcular
  101.       }
  102.    }
  103.  
  104.    FLASH;                                   // Reproduzco la entrada mediante un LEd en E0;
  105.  
  106. }
  107. void main() {
  108.  
  109.  
  110.     ////////////////////////////////////////// INICIALIZACIONES GENERALES
  111.  
  112.    delay_ms(333);                           // Espero a que todo se estabilice e ...
  113.    disable_interrupts(global);              // Inicializo el Micro y ...
  114.    disable_interrupts(int_timer1);          // deshabilitando todo lo no necesario ...
  115.    disable_interrupts(int_rda);
  116.    disable_interrupts(int_ext);
  117.    disable_interrupts(int_ext1);
  118.    disable_interrupts(int_ext2);
  119.    setup_adc_ports(NO_ANALOGS);
  120.    setup_adc(ADC_OFF);
  121.    setup_spi(FALSE);
  122.    setup_psp(PSP_DISABLED);
  123.    setup_counters(RTCC_INTERNAL,RTCC_DIV_2);
  124.    setup_timer_0(RTCC_OFF);
  125.    setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
  126.    setup_timer_2(T2_DISABLED,0,1);
  127.    setup_timer_3(T3_DISABLED);
  128.    setup_comparator(NC_NC_NC_NC);
  129.    setup_vref(FALSE);
  130.    port_b_pullups(FALSE);
  131.    delay_ms(333);
  132.  
  133.    /////////////////////////////////////////// INICIALIZACIONES PERTINENTES A LA APLICACION
  134.  
  135.    set_tris_c(0b10000000);                  // Habilito como entrada RC7 para canal RS232
  136.  
  137.    setup_ccp2(CCP_CAPTURE_RE);              // Configuro captura de 1er flanco de subida
  138.    flagToggleFlanco = 0;                    // inicializo el Flag para cambiar de flanco
  139.  
  140.    enable_interrupts(int_rda);              // Habilito las interrupciones necesarias
  141.    enable_interrupts(int_ccp2);
  142.    enable_interrupts(global);
  143.  
  144.    printf("\r\nMidiendo un pulso : CCP\r\n");
  145.    printf("By Redpic para Foro TODOPIC\r\n\n");
  146.  
  147.    do {
  148.  
  149.       if(flagHayDatos==1){                  // Detecto que ya hay datos de flancos ...
  150.          if(t2 > t1){                       // Compruebo que estoy en la misma vuelta de TMR1
  151.             tt = t2 - t1;                   // Calculo en Tick's de TMR1 el tiempo entre flancos
  152.             st = uSxTick * tt;              // Calculo en uS el tiempo.
  153.             flagHayTransmitir=1;            // Indico que tengo nuevo valor para transmitir
  154.          }
  155.          flagHayDatos=0;                    // Indico que ya han sido procesados los datos.
  156.       }
  157.       if(Command!=0x00){                    // Si he recibido un comando vía Serie ...
  158.          if(Command=='T'){                  // Si el comando es 'T' (Transmite) ...
  159.             if(flagHayTransmitir==1){       // Si hay algo pendiente de transmitir ...
  160.  
  161.                printf("Ticks %Lu - %Lu = %Lu = %3.1fuS \r\n",t2,t1,tt,st);
  162.  
  163.                flagHayTransmitir=0;         // Indico que ya he transmitido lo pendiente.
  164.             }
  165.          }
  166.          Command=0x00;                      // Indico que ya he procesado el comando.
  167.       }
  168.  
  169.  
  170.    } while (TRUE);
  171. }
« Última modificación: 28 de Octubre de 2006, 19:17:27 por RedPic »
Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania

Desconectado __ERoS__

  • PIC10
  • *
  • Mensajes: 22
Re: Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP
« Respuesta #2 en: 22 de Agosto de 2007, 14:36:50 »
Hola

Expongo aqui mi problema ya que me he basado en este hilo, espero que no moleste el reflote que hago.

Os pongo en situacion: quiero medir el tiempo desde que activo un pin, hasta que otro pin conectado al CPP2 se pone en alto. El tiempo maximo que puede transcurrir son aproximadamente unos 60ms desde que activo el pin hasta que recibo la respuesta por el otro. Por tanto, con mi pic18f4550 a 48mhz y haciendo los calculos tengo que si uso preescaler 8 (el maximo para el timer1) desborda el timer cada 43,69 ms. Como no me llega, y tal como dice Redpic debo contar las vueltas que de el timer1 (como maximo en mi caso sera una).

Esto es lo que hago:

setup_ccp2(CCP_CAPTURE_RE);      //Configuro captura del 1er flanco de subida
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);      //Desborda cada 43,690667 ms
 
#int_ccp2
void handle_ccp2_int()
{
   t1=CCP_2;         //Guardo la captura del CCP2 al Flanco de Subida
   flagHayDatos=1;
}

#int_timer1
void handle_timer1_overflow()

   n_vueltas_timer1++;
}

Mi rutina hace:

 n_vueltas_timer1=0;
 enable_interrupts(int_timer1);
 ACTIVAR(PIN_D4); 
 set_timer1(0);
   
 while(!flagHayDatos) ;  //Espero el eco
   
 disable_interrupts(int_timer1);
 printf("%d vueltas\n\r",n_vueltas_timer1);
 printf("%lu ticks\n\r",t1);
 tiempo = (n_vueltas_timer1 * uSxTick * 65536 ) + uSxTick * t1;    // Calculo en uS el tiempo.
 DESACTIVAR(PIN_D4);
 flagHayDatos=0; 

Asi tendria el tiempo en us.

El problema: siempre me entra una vez en la interrupcion del timer1, aunque no llegue a 43,6ms. Sabeis porque?

Saludos y gracias

Desconectado pablomanieri

  • Colaborador
  • PIC24F
  • *****
  • Mensajes: 639
Re: Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP
« Respuesta #3 en: 05 de Marzo de 2008, 21:21:40 »
el problema está en que tenes que hacerlo entrar 2 veces a la interrupcion del timer1 ya que con el prescaler en 8 y a 48 M
tenes

83.3333 nanosegundos por instrucción, *8 =666.66666nanos, multiplicados por 256, que es cunado se desbora una vez el timer1 =170.6666666microsegundos. si entras otra vez a la interrupcion, *256=43.6906666mseg

Desconectado ajcev

  • PIC10
  • *
  • Mensajes: 3
Re: Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP
« Respuesta #4 en: 21 de Junio de 2011, 15:41:47 »
Hola, estoy tratando de medir el ancho de pulso de una señal PWM, para leer un sensor de CO2, que posee dicha salida,bueno el caso es que he estado probando un programa en el que se usan los modulos CCP1 y CCP2 en modo captura, en el programa basicament se activan las interrupciones para dichos modulos por flanco ascendente y descendente (CCP1 Y CCP2 respectivamente), se coloca un variable (t) que en este caso se incrementa hasta tener el flanco de bajada, ahora pienso que esa variable no es el valor final que se deberia mostrar, por lo que he leído en este foro, (y la verdad no estoy muy al tanto) pero se debe multiplicar ese valor por 0.2 (tick's) esto usando un oscilador de 20Mhz, inicialmente estaba usando el PIC18F4550, pero el programa actualmente esta con el PIC16F877A. El código realizado esta en MikroBasic.

'...
program probe2


dim t as word
dim temp as word
dim temp2 as float
dim temp3 as float
dim txt as string[6]
dim txt4 as string[6]

'...............................................................................
sub procedure Interrupt()
  if(TestBit(pir1, ccp1IF)= 1)   then 'PREGUNTO SI HA OCURRIDO UNA INTERRUPCION POR FLANCO ASCENDENTE EN CCP1

        ccp2con = 0X04   ' CONFIGURO EL MODULO CCP2 PARA QUE SE ACTIVE LA INTERRUPCION POR FLANCO DESCENDENTE
        PIE2.CCP2IE = 1  ' HABILITO EL ENABLE PARA INTERRUPCION POR CCP2
        if  (TestBit(pir2, ccp2IF)= 1) then  ' PREGUNTO SI HA OCURRIDO INTERRUPCION EN MODULO CCP2
             PIE1.ccp1IE = 0        ' DESABILITO EL ENABLE DE CCP1
             PIR1.ccp1IF = 0        ' DESABILITO LA BANDERA DE INTERRUPCION DE CCP1
             PIE2.ccp2IE = 0        ' DESABILITO EL ENABLE DE CCP2
             PIR2.ccp2IF = 0        ' DESABILITO LA BANDERA DE INTERRUPCION DE CCP2
             ccp1con=0              ' DESABILITO EL MODULO CCP1
             ccp2con=0              ' DESABILITO EL MODULO CCP2
             temp = t           ' CAPTURO EL VALOR DEL CONTADOR EN UN ARREGLO WORD
             'pos = pos +1           ' INCREMENTO LA POSICION DEL ARREGLO
             t=0                    ' ENCERO EL CONTADOR DE LA SEÑAL PWM
        end if
        inc(t)    ' INCREMENTO EL CONTADOR MIENTRAS NO EXISTA ENTERRUPCION EN EL MODULO CCP2
  end if

end sub
'...............................................................................
sub procedure inicializar()
  INTCON = 0x00           ' DESABILITO GIE, PEIE
  PIR1.ccp1IF = 0         ' DISABLE CCP1
  PIE1.CCP1IE = 0         ' ENABLE PARA INTERRUPCION POR CCP1
  PIR2.ccp2IF = 0         ' DISABLE CCP2
  PIE2.CCP2IE = 0         ' ENABLE PARA INTERRUPCION POR CCP2
  INTCON.INTE = 0         
  INTCON.INTF = 0         
  t=0                     ' ENCERO CONTADOR DE ANCHO DE PULSO

end sub
'...............................................................................
sub procedure habilitar()
  INTCON = 0xC0          ' Set GIE, PEIE
  CCP1CON = 0x05         ' CONFIGURO CAPTURA DE SEÑAL EN FLANCO ASCENDENTE
  PIE1.CCP1IE = 1        ' ENABLE PARA INTERRUPCION POR CCP1
  INTCON.INTE = 1
end sub

sub procedure conversion()
temp3=temp*0.1
temp2=temp div 100
temp2=temp2-177
temp2=temp2*2
temp2=temp2+350
end sub


sub procedure mostrar_ancho()
delay_ms(50)
FloatToStr(temp2, txt)         
Lcd_Out(2, 1, txt)
end sub


'...............................................................................

main:

ADCON1=7
TRISD = %00000000
TRISC = %00000110
Lcd_Config(PORTD,7,6,5,4,PORTD,3,1,2)     'Lcd_Config(PORTB,7,6,5,4,PORTB,3,2,1)
Lcd_Cmd(LCD_CURSOR_OFF)
Lcd_Cmd(LCD_FIRST_ROW)
Delay_ms(300)
Lcd_Out(1, 1, "PRUEBA")


inicio:
Delay_ms(100)
inicializar()
habilitar()
conversion()
mostrar_ancho()


goto inicio

end.
...
Por favor si alguien me puede ayudar con una revisadita, se los agradecería por que sinceramente ya lo he probado varias veces y no se como interpretar el valor que tengo, que obviamnete no es el que debería....., las mediciones de la señal que poroporciona el sensor de CO2 las he estado verificando mediante un osciloscopio que posee una tarjeta de adquisición de datos que dispongo (myDAQ)

Desconectado diegol_2006

  • PIC10
  • *
  • Mensajes: 4
Re: Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP
« Respuesta #5 en: 25 de Octubre de 2011, 18:45:49 »
Gracias por este aporte RedPIC, de mucha ayuda me ha sido! saludos!!