Contar pulsos con CCP en modo captura

Hasta acá voy muy bien, puedo contar los pulsos, lo que no sé cómo hacer, es medir el duty de la señal y mostrarlo en porcentaje. ¿Cómo lo hago?
No me doy idea de cómo hacer para mostrarlo en el lcd y que cálculo hacer.

PHP:
#include <16f883.h>            
#device ADC=10
#use delay (internal = 8MHz)
#FUSES NOWDT                   
#FUSES XT                       
#FUSES PUT                      
#FUSES NOPROTECT               
#FUSES NODEBUG                  
#FUSES NOLVP                    
#FUSES NOCPD                    


      

#include <lcd.C>                

int16 pulso_total;
int16 pulsos;
int8 aux;



#int_TIMER1              
void temp1s(void)       
{  
   aux++;
   if (aux == 2)
   {   
      pulso_total = pulsos;
      pulsos = 0;
      aux = 0;
   }      
   set_timer1 (3036);  
   
}

#int_ccp1
void trata_pulsos(void)
{
   pulsos++;
}


void main()
{
   lcd_init();                   
   
   setup_ccp1(CCP_CAPTURE_RE);   
   setup_timer_1 (T1_INTERNAL | T1_DIV_BY_8);  
      
   enable_interrupts(INT_CCP1);
   enable_interrupts(INT_TIMER1);              
   enable_interrupts(global);                   
   set_timer1 (3036);                            
   
   while(TRUE)                                  
   {
   lcd_gotoxy(7,2);
      printf(lcd_putc,"speed=%03lu",pulso_total);
      delay_ms (500);
      
   }
}
 
Última edición por un moderador:
Vuelvo con el caballo agotado, no cansado.
Éste código mide perfecto, sólo no logro medir el duty. ¿Me pueden dar una mano?
PHP:
#include <16f883.h>
#device ADC=10
#use delay (internal = 8MHz)
#define use_portb_lcd true
 #fuses NOFCMEN, NOIESO,INTRC_IO,NOWDT,NOLVP,MCLR,NOPROTECT,
#include <lcd.c>
 int16 tic,tic2,tic3,f;
int1 tiempo,tiempo2;
float T,Periodo;
int8 duty;
#int_CCP1
void  CCP1_isr(void) 
{
   if(!tiempo)                         
   {
      tic2 = CCP_1;   //alto               
      tiempo = 1;                       
   }
   
   else
   {
      tic3 = CCP_1;        //bajo           
      tiempo = 0;                       
      
      if(!tiempo2) tiempo2 = 1;               
   }
 }
 void main()
{
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
   setup_ccp1(CCP_CAPTURE_rE);
 enable_interrupts(INT_CCP1);
 enable_interrupts(GLOBAL);
  lcd_init(); 
 while (true){
 
 if(tiempo2)                       
      {
        
         tic = (tic3 - tic2); 
         
            T=4.0*8.0/8000000.0;
 
   Periodo=T*tic;
   
   F=1/Periodo;
             
         tiempo2 = 0;                   
        
      }
 
 duty=tic*100 /(tic+tic2);
      lcd_gotoxy(1,2);
   printf(lcd_putc,"d=%u",duty);
   
   
     lcd_gotoxy(9,2);
   printf(lcd_putc,"F=%03lu",F);
 }
}
 }
 
Última edición por un moderador:
Para calcular el ciclo activo, debes obtener el tiempo en alto del pulso y el periodo de la frecuencia.
Luego lo obtienes con ésta fórmula: [latex]{Duty} = \frac{t}{T}[/latex]
Donde "t" es la duración del pulso en estado alto y "T" es el periodo.
 
Si está bien esa fórmula, pero mejor trata de hacerlo por medio de la interrupción externa por RB0 y mide los periodos con el Timer 1.

Hace algún tiempo hice eso para obtener el ciclo activo de una señal PWM y obtuve buenos resultados.
 
Si usas la librería "lcd.c", puedes direccionar los pines de datos y control al puerto que quieras.
Ve la información en la misma librería.
 
Gracias D@RKBYTE!!!

después de tantas idas y venidas funciono
solo tengo 2 problemas que ya no se como resolverlo
1) cuando enciendo el lcd no me aparece el valor en pantalla, aparece cuando empieza a contar.
2) cuando cuenta y corto el pulso no vuelve a cero y es el if(pulsonuevo) pero no se como solucionarlo, gracias
Código:
 #include <16f883.h>
#device ADC=10
#use delay (internal = 8MHz)
#define use_portb_lcd true
 #fuses NOFCMEN, NOIESO,INTRC_IO,NOWDT,NOLVP,MCLR,NOPROTECT,
#include <lcd.c>
int1 nuevopulso=0;
int16 t_bajada_1=0,t_subida_1=0,t_on=0,t_total=0,t_subida_2=0;
float32  t=0,f,duty,periodo;
int flag;
#int_ccp1
void ccp1_int(void)
{
if(flag == 3)
{
flag = 0;
}
if (flag == 0 )
{
t_subida_1=ccp_1;
setup_ccp1(CCP_CAPTURE_FE);
}
if (flag ==1 )
{
t_bajada_1=ccp_1;
setup_ccp1(CCP_CAPTURE_RE);
}
if ( flag==2)
{
t_subida_2=ccp_1;
setup_ccp1(CCP_CAPTURE_RE);
 if (nuevopulso==0)
{
nuevopulso=1;
}
}
flag++;
}
 void main()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_ccp1(CCP_CAPTURE_RE);
flag=0;
 enable_interrupts(int_ccp1);
enable_interrupts(global);
nuevopulso=0;
lcd_init();
while(true)
{
 if(nuevopulso)
{
t_on=(t_bajada_1-t_subida_1);
 t_total=(t_subida_2-t_subida_1);
 t=4.0*8.0/8000000.0;
   Periodo=T*t_total;
f=1/periodo;
 duty=(float)t_on*100/t_total;
 delay_ms(50);
  lcd_gotoxy(1,2);
printf(lcd_putc,"F=%3.0f",f);
    lcd_gotoxy(9,2);
printf(lcd_putc,"duty=%2.0f%%",duty);    
delay_ms(100);
nuevopulso=0;
 }
 }
  
 
}
 
1) cuando enciendo el lcd no me aparece el valor en pantalla, aparece cuando empieza a contar.
R = porque toda la operación la tienes dentro de la sentencia if(nuevopulso) { }
 
No creo (si sigues una lógica no puedes equivocarte). Prueba lo siguiente,
Código:
if(nuevopulso)
{
t_on=(t_bajada_1-t_subida_1);
t_total=(t_subida_2-t_subida_1);
t=4.0*8.0/8000000.0;
Periodo=T*t_total;
f=1/periodo;
duty=(float)t_on*100/t_total;
delay_ms(50);
nuevopulso=0;
}
lcd_gotoxy(1,2);
printf(lcd_putc,"F=%3.0f",f);
lcd_gotoxy(9,2);
printf(lcd_putc,"duty=%2.0f%%",duty);    
delay_ms(100);
Siempre mostrara el valor, porque las variables f y duty las declaraste como globales y el valor queda guardado hasta calcular uno nuevo.
 
Probé así y no me muestra bien los datos en el lcd. igual me falta ver como hago para que cuando cuente y cuando pare de recibir los pulso muestre cero.
 
Última edición:
Si quieres mostrar correctamente el porcentaje del ciclo activo, olvídate del CCP y hazlo por interrupción externa usando el Timer 1 para medir los periodos.
 
Hola darkbyte la verdad cambie a basic pro y ya estoy un poco mejor tengo que revisar que funcione todo bien y depurar un poco el código si queres mirarlo y darme una mano bienvenido sea.

Código:
DEFINE LCD_DREG PORTB
DEFINE LCD_DBIT 4
DEFINE LCD_RSREG PORTB
DEFINE LCD_RSBIT 1
DEFINE LCD_EREG PORTB
DEFINE LCD_EBIT 0
define lcd_lines 2
define intosc 8
DEFINE ADC_BITS 8
DEFINE ADC_CLOCK 3 
DEFINE ADC_SAMPLEUS 50
ANSEL = %11111111 
ANSELH = %00000000 
lectura var word
lectura2 var word
resultado VAR word
resultado2 var word
f var word
bajo VAR WORD 
alto VAR WORD 
total VAR WORD 
duty VAR WORD 


lcdout $fe,1," iniciando "
pause 200 
LCDOUT $FE, 1 
inicio:

ADCIN 0, LECTURA 
RESULTADO = (LECTURA */ 500)
adcin 2,lectura2
resultado2 = (lectura2 */500)

PULSIN PORTc.2 , 0 , bajo : PULSIN PORTc.2 , 1 , alto
COUNT PORTc.2, 1000, f
cutdown2:
total = bajo + alto
if total > 655 then 
bajo = bajo / 2 : alto = alto / 2 : goto cutdown2
endif
duty = ( alto* 100 ) / total
LCDOut $fe , 1
lcdout $fe ,$80 ," DUTY:" , DEC2 duty +1 ,"%"
LCDOUT $fe , $C0 ,"CPS:" , DEC3 f 
LCDOUT $fe, $8a, "V=", DEC (RESULTADO/10),".",dec1 resultado
lcdout $fe,$c9, " A=", dec (resultado2/10),".",dec1 resultado2
pause 200

GOTO inicio 
end
 
El problema con la instrucción "Count", es que detiene la ejecución del programa por el tiempo establecido, en tu caso, 1000 ms.
Todavía aparte de ese retardo, estás poniendo otro de 200 ms.
De esa forma nunca vas a medir los pulsos correctamente.

Pues que mal que hayas cambiado de lenguaje, porque en C lo pudiste haber hecho más fácil.
Duty Percent.jpg

En PICBasic también lo puedes lograr, pero debes hacer uso de interrupciones y timers.
 
Si, tenéis razón. Lo que pasa es que se me hizo una ensalada y como no me quedaba como quería en c, probé en basic.
En basic me funcionó pero el código no es estable, lo colocas en un lcd y corre por momentos o no corre y en c funcionaba mejor.

Entonces vos que sabes, me recomendáis hacerlo en c con el timer1.
Bien, como arranco con el timer1 ya quedó, sé como seguir. Gracias por tu tiempo.

--- Actualizado ---

Esto es lo que hice hasta ahora y no me funciona. ¡Ayuda!
Código:
#include <16f883.h>
#device ADC=10
#use delay (internal = 8MHz)
#define use_portb_lcd true
 #fuses NOFCMEN, NOIESO,INTRC_IO,NOWDT,NOLVP,MCLR,NOPROTECT,
#include <lcd.c>
 int16 bajo,alto, tiempo;
int1 pulso;
float t,periodo,f;
int bandera;
#int_timer1
void timer1_int(void)
{
 if(bandera==0){
 bajo=get_timer1();
 EXT_INT_EDGE(0,L_TO_H);
 
}
if ( bandera==1)
{
alto=get_timer1();
EXT_INT_EDGE(0,H_TO_L);
 if (pulso ==0)
{
pulso=1;
}
}
bandera++;
 }
void main(){
 set_timer1(0); 
SETUP_TIMER_1(T1_INTERNAL  |T1_DIV_BY_8);
EXT_INT_EDGE(0,L_TO_H);
enable_interrupts(int_ext);
enable_interrupts(GLOBAL);
lcd_init();
bandera=0;
while (true){
  lcd_gotoxy(1,1);
   T=4.0*8.0/8000000.0;
   Periodo=T*tiempo;
   F=1/Periodo;
   printf(lcd_putc,"tiempo= %Lu",tiempo);
   printf(lcd_putc,"\nF= %FHz",F);
 }
 
}
 
Última edición por un moderador:
Mira el ejemplo adjunto, en simulación mide el ciclo activo desde el 12% hasta el 89%
La frecuencia de entrada es de 1 KHz y seguramente necesitarás adaptarlo a la frecuencia del equipo.
 

Adjuntos

  • 16F883 Obtener porcentaje del ciclo activo.rar
    91.8 KB · Visitas: 22
MUCHAS GRACIAS! me sirvió mucho y entendí un poco mas como hacerlo, ahora antes de seguir cambiando te consulto cuando deja de recibir pulsos tendría que ponerse en cero la frecuencia y el duty, no se como hacerlo! cuando recibe un pulso largo o tendría que quedar en 99% hasta que el pulso se termine y eso no se como hacerlo, te tengo que pagar un asado por lo que me ayudaste muchas gracias ya que hiciste que entienda mejor lo que estaba haciendo.:)
 

Adjuntos

  • Nueva carpeta (2).rar
    61.9 KB · Visitas: 11
Atrás
Arriba