TODOPIC
Bienvenido(a), Visitante. Por favor, ingresa o regístrate.
¿Perdiste tu email de activación?
03 de Septiembre de 2010, 05:28:48

Ingresar con nombre de usuario, contraseña y duración de la sesión
Buscar:     Búsqueda Avanzada
257111 Mensajes en 28437 Temas por 27916 Usuarios
Último usuario: zororyuzaki
* Inicio Ayuda Buscar Calendario Ingresar Registrarse
Buscar en TodoPIC
+  TODOPIC
|-+  Microcontroladores PIC
| |-+  Lenguaje C para microcontroladores PIC (Moderadores: Modulay, pikman, pocher, vszener, Suky)
| | |-+  Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP
0 Usuarios y 1 Visitante están viendo este tema. « anterior próximo »
Páginas: [1] Marcar como favorito Imprimir
Autor Tema: Serie Técnicas en C : Midiendo un pulso. 2ª Parte. Tiempo en Alto con INTCCP  (Leído 1753 veces)
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« : 25 de Octubre de 2006, 04:28:16 »

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.  Mr. Green

Para configurar inicialmente el flanco de subida a detectar utilizaremos:

Código
GeSHi (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);
  5.  

Nuestra rutina ISR para CCP quedaría como sigue:

Código
GeSHi (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.   }
  17.  

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.  Smile
Mañana, más.




« Última modificación: 11 de Agosto de 2010, 04:28:02 por RedPic » En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
RedPic
Administrador
DsPIC33
*******
Desconectado Desconectado

Sexo: Masculino
Tibet Tibet

Mensajes: 4876



WWW
« Respuesta #1 : 27 de Octubre de 2006, 03:45:59 »

Aqui tienes filth el código completo de la medida del pulso en alto con CCP:

Código
GeSHi (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. }
  172.  
« Última modificación: 28 de Octubre de 2006, 07:17:27 por RedPic » En línea

Contra la estupidez los propios dioses luchan en vano. Schiller
Mi Güeb : Picmania
__ERoS__
PIC10
*
Desconectado Desconectado

Mensajes: 22


« Respuesta #2 : 22 de Agosto de 2007, 02: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
En línea
pablomanieri
Colaborador
PIC18
*****
Desconectado Desconectado

Sexo: Masculino
Argentina Argentina

Mensajes: 413



« Respuesta #3 : 05 de Marzo de 2008, 08: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
En línea
TODOPIC
   

 En línea
Páginas: [1] Imprimir 
« anterior próximo »
Ir a:  

Impulsado por MySQL Impulsado por PHP Powered by SMF 1.1.11 | SMF © 2006-2008, Simple Machines LLC XHTML 1.0 válido! CSS válido!
Página creada en 0.167 segundos con 22 consultas.