# Contar pulsos con CCP en modo captura



## ariel 37 (Mar 30, 2014)

Hola que tal amigos del foro !!!!! estoy leyendo tanto este foro que bueno aveces toca preguntar ja ja les escribo a ver si alguien me puede ayudar con lo siguiente( soy principiante autodidacta) y quiero hacer un cuenta vueltas pero usando el modulo ccp en modo de captura del pic 16f876a , ya hice uno haciendolo por interrupcion de timers y funciona  pero me dijeron que con el ccp es mucho mas facil y preciso, y quiero aprender a usarlo, el tema es que he leido lo que encontre sobre este tema pero no logro comprenderlo hay muchos ejemplos de medir ancho de pulso capturando el flanco de subida y despues el de bajada y haciendo la cuenta..... , pero lo que yo quiero supongo es medir el tiempo entre dos flancos de subida y eso pasarlo a rpm (revoluciones por minuto) mostrandolo en una lcd , pero se me ha hecho una ensalada terrible . Uso el compilador ccs si alguien me puede mostrar algun ejemplo sencillo o alguna pagina donde buscar les estare muy agradecido  Saludos !!!! ...


----------



## papirrin (Mar 31, 2014)

esta podria ser una forma de contarlos:

```
#include <16F876A.h>
#device adc=8
#FUSES NOWDT, HS, NOPUT, NOPROTECT, NODEBUG, NOBROWNOUT, NOLVP, NOCPD, NOWRT, RESERVED
#use delay(clock=20000000)
#include <lcd.c> 

int time,ltime;

#int_CCP1
void  CCP1_isr(void) 
{
 time= ccp_1-ltime;
 ltime=ccp_1;	
 clear_interrupt(int_ccp1);	
}

void main()
{
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);
 setup_ccp1(CCP_CAPTURE_RE);
 enable_interrupts(INT_CCP1);
 enable_interrupts(GLOBAL);

 lcd_init(); 
while(true){
lcd_gotoxy(1,2);
printf(lcd_putc,"%u s", time);
delay_us(50);
} 
}
```

en rc2 va el pulso a medir


----------



## ariel 37 (Mar 31, 2014)

Gracias Papirrin lo voy a probar y a desmenuzarlo para entenderlo bien y despues te cuento,muchas gracias por tu colaboracion  Saludos !!!!!!


----------



## Roos21 (Nov 11, 2014)

Hola. Estoy haciendo una medición a través de RB0 del tiempo del ancho de pulso de una señal cuadrada. 
Me gustaría que alguien me ayudara a realizar la medición a través del módulo CCP.
En el ejemplo que adjuntaré en Proteus aparecen dos señales desfasadas, las cuales al pasar por una compuerta XOR me resulta la señal cuadrada desfasada(5V, 60Hz).
Dicha señal es la cual quiero medir su ancho de pulso(t2-t1) pero no sé como hacerlo.
Tengo un código pero no se si está bueno.

Agradecería mucho que alguien me ayudara.



```
#include <16f877a.h>

#use delay(clock=4M)

#fuses HS,NOWDT
#include <LCD420D.C>

int16 TFB;                                     //Tiempo flanco de bajada
float PW;                                      //Valor final del ancho de pulso
int1 nuevopulso=0;                            //Entra otro pulso
int1 cambio=0;                          

#INT_EXT
void funcion_ext_int()
{                                              //Funcion Interrupcion
 if(cambio==0)                                 //Flanco de subida
 {
  set_timer1(0);                               //Inicializa TMR1
  ext_int_edge(0,H_TO_L);                      //Configura para flanco de bajada
  cambio=1;
 }
 else{
  TFB=get_timer1();                            //Valor del Timer 1 para flanco de bajada
  ext_int_edge(0,L_TO_H);                      //Configura para flanco de subida
  cambio=0;                                    //Control de cambio de flanco
  if(nuevopulso==0)                             //Fin de pulso
  {
   nuevopulso=1;                               //Pulso a calcular
  }
 }
}

void main(void)
{
 
 lcd_init();
 setup_timer_1(T1_INTERNAL|T1_DIV_BY_1);           //Configuracion TIMER1
 ext_int_edge(0,L_TO_H);                         //Configura para flanco de subida
 cambio=0;                                       //Control de cambio de flanco
 enable_interrupts(int_ext);                      //Habilitacion interrupcion RB0
 enable_interrupts(global);                       //Habilitacion general
 do
 {
  if(nuevopulso==1)                               //Si ¿nuevo pulso?
  {
   PW=TFB*1.0;                              //Ancho de pulso en us de TIMER1 a 4MHZ el T=1us*Timer1
    printf(lcd_putc,"\f");
   printf(lcd_putc,"\n\n\tPulso=%6.1fus",PW);      //Visualiza medida en LCD
   delay_ms(1000); 
  }
   nuevopulso=0;                                  //Pulso medido
 } 
     
      while(TRUE); 
}
```


----------



## callecuatro1976 (Jun 10, 2016)

papirrin dijo:


> esta podria ser una forma de contarlos:
> 
> ```
> #include <16F876A.h>
> ...


Este código esta contando los flancos de subida?
Como hago para contar de una señal los pulsos de subida mostrarlo en lcd y contar los de bajada y mostrarlo?


----------



## ruben90 (Jun 10, 2016)

No es mejor la interrupción de un timer? Arriba comentan que es mejor en modo captura, pero es debido al registro Timer1 (16 bits). Con el timer0 tienes 8 bits con un prescalar 1:256, y el registro prácticamente te regala la configuración, solo debes calcular el valor de TMR0. Si vas a contar un pulso no te recomiendo usar delays porque se pierde precisión. Mejor dale una leída al datasheet del PIC.


----------



## callecuatro1976 (Jun 11, 2016)

Yo quiero hacer de una señal cuadrada de una bobina que enciende y apaga tomar los flancos para medir duty con flancos ascendentes y cps con flancos descendente y me estoy volviendo loco para saber como medir cada flanco


----------



## callecuatro1976 (Jun 12, 2016)

Igual estoy errando porque el duty es el ancho del pulso que tengo que medir y los cps la cantidad.


----------



## ruben90 (Jun 12, 2016)

Quieres generar una señal cuadrada para conmutar una bobina? Y medir los flancos ascedentes y descendentes para asi obtener la frecuencian y a que duty cycle esta?
Y si vas a usar PIC, no es mejor usar el modulo CCP en modo PWM?


----------



## callecuatro1976 (Jun 12, 2016)

No generarla no! Tomar las mediciones de una señal   cuadrada y medir ancho de pulso y sacarlo como duty y la cantidad de pulsos como cps y ando mareado de como hacerlo.


----------



## ruben90 (Jun 12, 2016)

Y si proporcionas un diagrama? No sera mas fácil ayudarte? Pero bueno.

Solo debes contar los pulsos ascendentes ('1') o descendentes ('0') que ocurren en un segundo, y para obtener el duty cycle debes comparar voltajes, si 5V corrsponden al 100%, entonces 2.5V son el 50%.

En el libro Compilador CCS y Proteus biene un ejemplo de medir frecuencia con el módulo CCP del PIC, que coincidencia no?


----------



## callecuatro1976 (Jun 12, 2016)

Acá encontré algo que me puede servir


----------



## callecuatro1976 (Jun 18, 2016)

Esto estoy tratando de hacer contar los pulsos y mostrar el duty de la señal.


----------



## D@rkbytes (Jun 18, 2016)

Mira el ejemplo adjunto, tal vez te sirva.


----------



## callecuatro1976 (Jun 21, 2016)

Hola si me sirve! estoy tratando de adaptarlo a lo que necesito si podes mirar el ejemplo para decirme donde me equivoco no entiendo la parte de medir el duty


----------



## D@rkbytes (Jun 21, 2016)

callecuatro1976 dijo:


> ¿Si podéis mirar el ejemplo para decirme dónde me equivoco?


En todo. Si ya estás usando un microcontrolador, no necesitas el LM2907
El LM2907 es un conversor de *frecuencia* a *voltaje*, y con el microcontrolador puedes medir la frecuencia de una señal directamente y al mismo tiempo obtener el periodo. P = 1 / F


callecuatro1976 dijo:


> No entiendo la parte de medir el duty.


Para obtener el ciclo activo, necesitas medir el tiempo en nivel alto y el tiempo en nivel bajo, de los pulsos de entrada.
Al usar los timers, ésto lo podrás hacer hasta cierto limite de frecuencia, porque los timers desbordan.
(Para cambiar el factor de división cuando un timer desborda, se usan comparaciones.)

¿En sí, qué es lo que quieres hacer?
Si explicaras mejor el objetivo de tu proyecto, se te podría orientar mejor.


----------



## callecuatro1976 (Jun 22, 2016)

Estoy tratando de medir las veces que enciende Y apaga una máquina de tatuar y usan Lm2907 para tomar las variaciones de la línea negativa y usando esos pulsos que son un prende y apaga de la bobina miden el cps y el duty de la maquina


----------



## D@rkbytes (Jun 22, 2016)

Ok. Si dices que lo usan para eso, es porque deben usar otro medio que no es un microcontrolador.
El microcontrolador es para minimizar hardware y con él se puede sustituir al LM2907.

En fin, para lo que quieres hacer ya se te dieron las bases, sólo debes implementarlas en tu programa.


----------



## callecuatro1976 (Jun 22, 2016)

Te muestro la imagen de la fuente que me quiero armar,  los datos del lcd


----------



## D@rkbytes (Jun 22, 2016)

Eso es aún más fácil de hacer si el mismo instrumento genera la frecuencia.
Si conoces el rango para el registro CCPRXL, puedes mostrarlo como porcentaje con un simple cálculo.


----------



## callecuatro1976 (Jun 23, 2016)

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.


```
#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);
      
   }
}
```


----------



## callecuatro1976 (Jun 25, 2016)

Vuelvo con el caballo agotado, no cansado.
Éste código mide perfecto, sólo no logro medir el duty. ¿Me pueden dar una mano?

```
#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);
 }
}
 }
```


----------



## D@rkbytes (Jun 25, 2016)

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.


----------



## callecuatro1976 (Jun 25, 2016)

Entonces esta mal lo que hice de duty=tic*100/(tic+tic2) lo voy a ver mejor
También probé esto y nada


----------



## D@rkbytes (Jun 27, 2016)

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.


----------



## callecuatro1976 (Jun 27, 2016)

Ok voy a probar rb0 es el pin de la interrupción. Yo tengo el lcd por el puerto B con el Pic 16f883 puedo sacarlo por el puerto c las conexiones para lcd?


----------



## D@rkbytes (Jun 27, 2016)

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.


----------



## callecuatro1976 (Jun 28, 2016)

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

```
#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;
 }
 }
  
 
}
```


----------



## ruben90 (Jun 28, 2016)

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) { }*


----------



## callecuatro1976 (Jun 28, 2016)

Si saco la operación de la sentencia y cuenta mal


----------



## ruben90 (Jun 28, 2016)

No creo (si sigues una lógica no puedes equivocarte). Prueba lo siguiente,

```
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.


----------



## callecuatro1976 (Jun 28, 2016)

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.


----------



## D@rkbytes (Jun 30, 2016)

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.


----------



## callecuatro1976 (Jul 1, 2016)

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.


```
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
```


----------



## D@rkbytes (Jul 1, 2016)

Mide el pulso con la interrupción de RB0 con PulsIn.
Eso le dará mayor precisión a las lecturas.


----------



## callecuatro1976 (Jul 1, 2016)

Y como mido con count esta bien usar así los dos comandos?  Y porque el duty no va subiendo? Voy a cambiar midiendo por rb0 y veo como va gracias.


----------



## D@rkbytes (Jul 1, 2016)

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.
​
En PICBasic también lo puedes lograr, pero debes hacer uso de interrupciones y timers.


----------



## callecuatro1976 (Jul 2, 2016)

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!

```
#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);
 }
 
}
```


----------



## D@rkbytes (Jul 2, 2016)

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.


----------



## callecuatro1976 (Jul 2, 2016)

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.


----------



## D@rkbytes (Jul 2, 2016)

callecuatro1976 dijo:


> Cuando deja de recibir pulsos tendría que ponerse en cero la frecuencia y el duty, no sé como hacerlo.
> Cuando recibe un pulso largo o tendría que quedar en 99% hasta que el pulso se termine y eso no sé como hacerlo.


Son pocos cambios los que se tienen que hacer para eso.

Adjunto el programa con los cambios, y ahora ya muestra del 0 % al 100 %
El ciclo activo válido en simulación, ya es del 3 al 97 % a una frecuencia de 150 Hz.


----------



## callecuatro1976 (Jul 2, 2016)

Excelente trabajo muchas gracias!!! Voy a probarlo mañana temprano!


----------



## callecuatro1976 (Jul 4, 2016)

Hola estuve probando el programa muy bien, tengo una consulta ahora necesito adecuar la señal para que llegue bien cuadrada a la pata del pic me recomendaron un Smith trigger o un lm2907, con el lm2709 yo estuve probando usando el Smith que trae interno y no anduvo mal pero es difícil de estabilizar que integrado me recomiendan y lo otro que no logro resolver es cuando corto los pulsos no vuelve a cero queda en la ultima medición como se puede hacer cuando no recibe ningún pulso por unos microsegundos que quede en cero, el duty cuando sube la frecuencia tiene que bajar? o tendría que subir?


----------



## roberttorres (Jul 4, 2016)

callecuatro1976 dijo:


> Hola estuve probando el programa muy bien, tengo una consulta ahora necesito adecuar la señal para que llegue bien cuadrada a la pata del pic me recomendaron un Smith trigger o un lm2907, con el lm2709 yo estuve probando usando el Smith que trae interno y no anduvo mal pero es difícil de estabilizar que integrado me recomiendan y lo otro que no logro resolver es cuando corto los pulsos no vuelve a cero queda en la ultima medición como se puede hacer cuando no recibe ningún pulso por unos microsegundos que quede en cero, el duty cuando sube la frecuencia tiene que bajar? o tendría que subir?


Buenas.
Lo de poner a cero cuando se corta los pulsos, podrias activar una bandera para saber si hay señal. te paso un ejemplo:


----------



## D@rkbytes (Jul 4, 2016)

callecuatro1976 dijo:


> Ahora necesito adecuar la señal para que llegue bien cuadrada a la pata del pic, me recomendaron un Smith trigger o un lm2907


Puedes usar un Disparador Schmitt con transistores, con un amplificador operacional, o usar compuertas.


callecuatro1976 dijo:


> Lo otro que no logro resolver es cuando corto los pulsos no vuelve a cero queda en la ultima medición.
> ¿Cómo se puede hacer cuando no recibe ningún pulso por unos microsegundos que quede en cero?


No simules el circuito, mejor realiza pruebas físicamente, porque en proteus los pulsadores y botones dejan pasar las ondas cuadradas como si fueran resistencias.

El programa está realizado para que muestre 0 en ausencia de señal.


----------



## callecuatro1976 (Jul 4, 2016)

Estoy haciendo pruebas física con el Lm2907 tomo la medición pata1, uno pata 2 con pata 4 y un capacitor 10 nanos a masa,la salida a rb0 pata 8, pata 5 a masa, pata 11 preset a 9 volt y pata 10 a 5 volt, una resistencia de 10 k a pin rb0.

Funciona bien controlas por el preset el funcionamiento cuando corto los pulsos no se pone a cero mañana subo fotos de la placa que hice.


----------



## callecuatro1976 (Jul 5, 2016)

Quedo perfecto!  Funciona muy bien, solo un detalle que se debería cambiar que es el duty,  cuando sube la frecuencia debería subir también y si se pones en corto la salida se tendría que poner al 100% y estaría  terminado!


Entonces si calculamos ton*100/(ton+toff) me da la medición actual que cuando sube la frecuencia baja el duty
Si calculo toff*100/(toff+ON) funciona al revés o estoy equivocado?


----------



## callecuatro1976 (Jul 6, 2016)

Hola me trajeron una fuente hoy para probar la que estamos armando y era como pensamos, cuando sube la frecuencia y la tensión sube el duty! en la que estamos haciendo baja la probamos con misma bobina a la misma tensión y la que trajeron en 6 volt tenia una frecuencia de 160 Hz y un duty de 70% y la que estamos construyendo en 6 volt tenia una frecuencia de 163 Hz y un duty de 42% tengo que cambiar eso.

 Ahora no es que cuando mayor frecuencia menor trabajo?
  Como cambio para que me de al revés que suba el duty cuando sube la frecuencia?


----------



## D@rkbytes (Jul 6, 2016)

La frecuencia y el ciclo activo (Duty Cycle) son cosas diferentes.
El ciclo activo no tiene porque subir ni bajar cuando sube la frecuencia, y viceversa.
Se puede mantener el mismo ciclo activo aunque la frecuencia suba o baje.
O sea que la frecuencia se puede mantener en 160 Hz, con un ciclo activo que cambie del 1 % al 99 %
Y ésto como mencioné, es inverso, se puede variar la frecuencia y mantener el mismo ciclo activo.

Lo que puede estar pasando, es que ese equipo no esté realizando una lectura correcta y muestre un ciclo activo "proporcional" a la frecuencia.
Para verificar eso, necesitas un osciloscopio que cuente con frecuencímetro, o usar uno aparte.
Con eso podrás realizar una comprobación visual sobre las variaciones de frecuencia y ciclo activo, para determinar cuál de los equipos es el que está mostrando las lecturas de forma correcta.


----------



## callecuatro1976 (Jul 7, 2016)

Estube haciendo un montón de pruebas y el programa que tenemos esta bien solo mide al revés cuando sube la frecuencia baja el duty, como modificó para que mida que  cuando sube la frecuencia suba el duty?


----------



## D@rkbytes (Jul 7, 2016)

Entonces hazlo proporcional, pero estarás realizando un engaño.


----------



## callecuatro1976 (Jul 7, 2016)

Estoy pensando como hacerlo para que vaya subiendo cuando sube la tensión y la frecuencia lo que no se es como cuando lo pones en corto el duty queda al 99%


----------



## D@rkbytes (Jul 7, 2016)

callecuatro1976 dijo:


> Estoy pensando como hacerlo para que vaya subiendo cuando sube la tensión y la frecuencia


A eso es a lo que me refiero con que vas a realizar un engaño.
Eso no es medir el ciclo activo, sino un voltaje o frecuencia.


callecuatro1976 dijo:


> Lo que no sé es como cuando lo pones en corto, el duty queda al 99%


if(input(pin_xx)==x) duty = 99;


----------



## callecuatro1976 (Jul 8, 2016)

Lo que pensaba es si ahora mido y cuando la frecuencia sube baja el duty y estoy así duty = ton*100/(ton+toff) si cambio a duty=toff*100/(toff+ton) no tendría que mostrar la medición a revés?


----------



## callecuatro1976 (Jul 8, 2016)

Efectivamente darkbytes funciona de maravillas y marca el duty sube y todo! Muchas gracias por todo lo que me enseñaste me queda hacer una buena fuente y ver bien tema de ruidos y porque de repente muestra 3450 de la nada y muestra varias ZZZ o oscila de 48 a 58 todo tema de ruidos me parece.


----------



## callecuatro1976 (Jul 9, 2016)

Una consulta mas se puede sacar promedios de las mediciones del duty y frecuencia para que sea más estable?  Como haría para sacarlos?


----------



## D@rkbytes (Jul 9, 2016)

Posiblemente, no lo he hecho en ciclo activo, pero debe ser igual que obtener otro promedio.
Busca por aquí en el Foro, cómo obtener una lectura promedio.


----------



## callecuatro1976 (Jul 9, 2016)

Si lo estube viendo pero esta todo basado adc, eso lo entiendo pero con respecto a esto como lo hago


----------



## D@rkbytes (Jul 9, 2016)

De la misma forma, lo que vas a manejar son variables, no registros.
No importa si es para un valor del ADC, el procedimiento para promediar es el mismo.


----------



## callecuatro1976 (Jul 10, 2016)

Estos es a lo que me refiero no se como aplicar la manera de sacarlo si en la medición del timer o cuando tengo la frecuencia resuelta.


----------



## D@rkbytes (Jul 10, 2016)

Realizar 500 veces la lectura del conversor ADC, no se me hace buena idea, aparte de que se puede producir el desborde de la variable contenedora.

Si quieres que la lectura se muestre más estable, usa el Timer 0 porque ya se está usando el Timer1.
Usa el desborde del Timer para incrementar una variable, y cuando llegue a x número, realizas la lectura del ADC.


----------



## callecuatro1976 (Jul 11, 2016)

```
#include <16f883.h>
#device ADC=10
#use     delay(internal = 8MHz)
#define  LCD_DATA_PORT getenv("SFR:PORTC")
#include <lcd.c>
#define led PIN_B5
int1 flagHayDatos=0; 
float const ticks_us = 4.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Interno)
//float const ticks_us = 8.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Cristal)
 int8 flancos;
int8 flag_flanco;
int16 periodo1,periodo2,periodo3;
int16 tiempo_alto,tiempo_bajo,tiempo_total;
float us_alto,us_bajo,us_total;
float frecuencia;
#INT_EXT
void sdi_externa_RB0 (void)
{
   flancos++;                          // Incrementar la variable "flancos"
   
   if(!flag_flanco)                    // Si el flanco del pulso es bajo...
   {
      if(flancos == 1)                 // Si el conteo de flancos es 1...
      {
         set_timer1(0);                // Limpiar el Timer 1
         periodo1 = get_timer1();      // "periodo1" tendrá el tiempo del pulso en alto.
      }
      if(flancos == 3)                 // Si el conteo de flancos es 3...
         periodo3 = get_timer1();      // "periodo3" tendrá el tiempo del pulso en alto.
         
         EXT_INT_EDGE(H_TO_L);         // Establecer la interrupción por flanco de bajada.
         flag_flanco = 1;              // Indicar que el próximo flanco será de bajada.
   }
   else                                // Caso contrario. (Pulso en estado alto)...
   {
      periodo2 = get_timer1();         // "periodo2" tendrá el valor del pulso en bajo.
      EXT_INT_EDGE(L_TO_H);            // Establecer la interrupción por flanco de subida.
      flag_flanco = 0;                 // Indicar que el próximo flanco será de subida.
       if(flagHayDatos==0){       // Si los datos anteriores han sido procesados ...
      flagHayDatos=1;          // Indico que ya hay nuevos datos de flancos para calcular
    }
   }
    if(flancos > 2)flancos = 0;         // Si la variable "flancos" llega a 3, ponerla a 0.
}
 void main()
{
long int var1=0, var2=0, var3=0;
 float valor, valor1,valor2;
   float duty;
   int8 porcentaje;
   
 setup_adc_ports(sAN1|sAN3);
 setup_adc(ADC_CLOCK_INTERNAL );
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   enable_interrupts(int_ext);
   ext_int_edge(0,L_TO_H);
   enable_interrupts(global);
   
   lcd_init();
   
   #ZERO_RAM   // Limpiar RAM. (Variables en 0)
   
   while (true)
   {
   
 
  for(var1=0;var1<50;var1++)
  {
    valor=valor+ get_timer1();
    delay_us(62);  
  }
   periodo1=valor/50;
   
    for(var2=0;var2<50;var2++)
  {
    valor1=valor1+ get_timer1();
    delay_us(62);  
  }
   periodo2=valor/50;
    for(var3=0;var3<50;var3++)
  {
    valor2=valor2+ get_timer1();
    delay_us(62);  
  }
   periodo3=valor/50;
   
    if(flagHayDatos==1){
    output_HIGH(led);
      if((periodo3 > periodo2) && (periodo2 > periodo1))
      {
         tiempo_alto = periodo2 - periodo1;                 // Obtener el periodo del pulso en estado alto.
         tiempo_bajo = periodo3 - periodo2;                 // Obtener el periodo del pulso en estado bajo.
         tiempo_total = tiempo_alto + tiempo_bajo;          // Obtener el periodo de la frecuencia.
         us_alto = ticks_us * tiempo_alto;                  // Obtener el periodo en microsegundos del pulso en alto.
         us_bajo = ticks_us * tiempo_bajo;                  // Obtener el periodo en microsegundos del pulso en bajo.
         us_total = ticks_us * tiempo_total;                // Obtener los microsegundos en total de la frecuencia.
         frecuencia = 1 / (us_total / 1000000);             // Obtener la frecuencia.
         duty = ((float) tiempo_bajo / (float)(tiempo_bajo + tiempo_alto));
         porcentaje = (duty * 100) + 0.5; // Físicamente el + 0.5 puede no ser necesario. (Ajusta desviación pero consume ROM)
      } 
       flagHayDatos=0; 
    }
      lcd_gotoxy(1,1);
      printf(lcd_putc,"CPS:%03.0fHz",frecuencia);
      lcd_gotoxy(1,2);
      printf(lcd_putc,"DUTY:%02u%c",porcentaje,0x25);
       flagHayDatos=0; 
       
      delay_ms(100); // Retardo para disminuir parpadeos en la pantalla. (No afecta interrupción externa.)
      if(flagHayDatos==0){
      frecuencia = 0;
      porcentaje=0;
      output_low(led);
      }
      
    }
}
```
 El adc me funciona bien, las variaciones las tengo en las muestras de frecuencia y duty es aquí que estoy haciendo un lio bárbaro con el promedio


----------



## D@rkbytes (Jul 11, 2016)

Sinceramente no encuentro la complicación a algo tan sencillo como obtener un promedio.
Ya te mencioné sobre otra forma de obtener lecturas más estables.


----------



## callecuatro1976 (Jul 11, 2016)

No me doy idea de como aplicarlo para la frecuencia y el duty te agradecería una mano con un ejemplo.


----------



## D@rkbytes (Jul 12, 2016)

Adjunto el código con lo expuesto, usando el Timer 0.
No sé si se consiga buena estabilidad físicamente de ésta forma, pero te puede dar ideas.


----------



## callecuatro1976 (Jul 12, 2016)

No me funciono las mediciones no son estables, seguiré intentando la forma de promediar.


----------



## D@rkbytes (Jul 13, 2016)

Estuve haciendo pruebas físicamente con el programa que adjunto, y fueron satisfactorias.
La frecuencia se mantiene estable y el ciclo activo cambia conforme éste varíe.

Te vuelvo a recomendar que uses un osciloscopio y un frecuencímetro, porque tal vez las señales que estás tratando de leer, no son estables.
Así, por más que quieras estabilizar eso por software, no lo vas a conseguir.


----------



## callecuatro1976 (Jul 13, 2016)

Si estuve trabajando bastante con esto y funciona muy bien, la señal entrante es muy baja y ruidosa! se mantiene estable y funciona, hay un solo problema que no se porque lo hace, estas midiendo ejemplo 146hz 58% duty y de golpe te tira 3457hz y queda colgado ahí puse capacitores  por todos lados y lo hace pocas veces pero lo hace es ruido tendría que ver la placa de hacerla con mas masa, saludos


----------



## D@rkbytes (Jul 14, 2016)

callecuatro1976 dijo:


> Hay un solo problema que no sé por qué lo hace.
> Estás midiendo, ejemplo; 146 Hz. 58% duty y de golpe te tira 3457 Hz y queda colgado ahí.


Posiblemente tengas que cambiar los parámetros del Timer 1 para centrar el conteo alrededor de esa frecuencia.


----------



## callecuatro1976 (Jul 14, 2016)

Lo que hice fue cambiar las variables para que cuando hay algún pico así no se pase, con la variable int no se pasa de 225, los parámetros no se como hacerlo, funciona muy bien lo único son esos picos que mete la bobina.

Y estoy tratando de colocar un mensaje de alerta cuando los amper llegan a 2,5 tendría que borrar la pantalla y mostrar "alerta"   y cuando baje volver como estaba
If(adc > 200) {
Printf (lcd_putc"alerta" ;
}
Else if (Adc>=200)


----------



## D@rkbytes (Jul 14, 2016)

Usa un bucle de retención hasta que el valor de los amperes se estabilice.
Por ejemplo:
while (amps > x)
{
    lcd_putc("\f    !Alerta!    ");
    lcd_gotoxy(1,2);
    printf(lcd_putc,"%f Amps.",amps);
    delay_ms(x);
}


----------



## callecuatro1976 (Jul 15, 2016)

Si lo arme asi,  cuando supera los 2,5 amper da la alerta, ahora cuando bajan los amper no vuelve a su posición original porque?

set_adc_channel(3); 
delay_us(20); 
amper=0;
for(var2=0;var2<300;var2++)
{
amper=amper+ read_adc();
delay_us(62); 
}
valor2 = amper / 300;
valor2 = valor2 * 19 / 1023;


lcd_gotoxy(11,2);
printf(lcd_putc,"%4.1f",valor2);

while (valor2 > 2.5)
{
lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"%f amper."valor2);
delay_ms(100);


----------



## papirrin (Jul 15, 2016)

porque el valor de la variable "valor2", no se actualiza dentro del bucle. entra y nunca sale... 

falta algo como esto dentro del bucle:



> amper=amper+ read_adc();
> delay_us(62);
> }
> valor2 = amper / 300;
> valor2 = valor2 * 19 / 1023;



o cambiar el algoritmo.


----------



## D@rkbytes (Jul 15, 2016)

Para hacerlo más sencillo, se puede crear la rutina de lectura del conversor y llamarla dentro del bucle.


----------



## callecuatro1976 (Jul 15, 2016)

Puedo poner while (read_adc ()>2.5)???


----------



## papirrin (Jul 15, 2016)

callecuatro1976 dijo:


> Puedo poner while (read_adc ()>2.5)???


 no lo creo, porque estas haciendo operaciones para sacar el amperaje, podrias hacer 

read_adc ()> a la equivancia en bits de 2.5A

o 

while (read_adc ()>100) donde 100 corresponde a 2.5 amperios por ejemplo, no tengo idea de a cuanto equivale.

otra seria hacer una rutina de funcion....


----------



## callecuatro1976 (Jul 16, 2016)

while (valor2 >= 2.5){if (valor2 <2.4){break;}

lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"valor superado!");
delay_ms(100);
valor2=0;


 ahí casi estoy me falta limpiar bien la pantalla


----------



## papirrin (Jul 16, 2016)

en ese algoritmo no tiene mucho sentido el while, si utilizas solo la condicional es suficiente o sea
if(valor2 >=2.5){ 
lcd_putc("\f !Alerta! ");
lcd_gotoxy(1,2);
printf(lcd_putc,"valor superado!");
delay_ms(100);}


----------



## roberttorres (Jul 16, 2016)

callecuatro1976 dijo:


> while (valor2 >= 2.5){if (valor2 <2.4){break;}
> 
> lcd_putc("\f !Alerta! ");
> lcd_gotoxy(1,2);
> ...



Creo, que como dijo el compañero D@rkbytes seria mas sencillo que crearas la rutina de lectura y conversión y lo llamaras desde tu bucle de alerta.
Te paso un ejemplo de voltimetro con alerta cuando llega a los 1 Ampers.:


----------



## callecuatro1976 (Jul 17, 2016)

Me sirvió muchas gracias! 

Ahora este ejemplo de voltimetro la medición de los amper la toma en proporción de la tension o es conveniente poner una resistencia shunt? 
Y por otro lado se ejecuta más rápido los programas usando funciones, que escribiendo el código a lo largo como lo hacía yo.


----------



## D@rkbytes (Jul 17, 2016)

En cualquier microcontrolador se toma la tensión que ingresa al conversor para realizar diversas operaciones.
Si tomas de referencia 5 voltios como nivel máximo, tendrás que realizar un circuito que entregue un voltaje a su salida dentro de ese rango.
Y la amplificación se tendrá que calcular partiendo del nivel de voltaje que entregue el sensor que uses.

El tiempo de ejecución no mejora realizando funciones o sub rutinas fuera de bucle.
Eso depende de la frecuencia de operación y del tiempo que se tarden en ejecutar las instrucciones.
Si mejoran la estructura del programa porque sirven para optimizar procesos, pero la ventaja principal es que pueden ser llamadas en varias partes del programa sin tener que volver a escribir la misma rutina.


----------



## callecuatro1976 (Jul 20, 2016)

Funciona todo perfecto, lo único sigo con el problema de la medición de la frecuencia que pega saltos y no logro estabilidad hay manera de disminuir el ruido por software? O voy a tener que promediar frecuencia y duty antes de mostrarlo de alguna manera que no afecte la medición y la pregunta es como?


----------



## D@rkbytes (Jul 20, 2016)

¿Y ya revisaste que la frecuencia de entrada es estable?


----------



## callecuatro1976 (Jul 20, 2016)

No es estable varía bastante pero me desconcierta que esta 2 minutos midiendo bien y de golpe me tira la medición al máximo de la variable


----------



## ruben90 (Jul 20, 2016)

Determina cierto tiempo para mostrar el valor, cada 1seg, 10seg, 1min, etc. Puedes usar el mismo modulo ccp para realizar el conteo.


----------



## callecuatro1976 (Jul 21, 2016)

No hay otra solución mejor que promediar, tenía problemas con el adc y promediando quedo perfecto,  el tema como promedio cuando ya tengo el dato de la frecuencia y el duty para mostrar el valor  Correcto,  si lo hago del timer no me da el valor! Es un lio!


----------



## papirrin (Jul 21, 2016)

No recuerdo bien el hilo del tema pero sugeriría dar lectura de los filtros pasa bajos.  Podría servir.


----------



## callecuatro1976 (Jul 22, 2016)

Probé y no cambia nada anda bien pero esos cambios bruscos no los puedo sacar


----------



## ruben90 (Jul 22, 2016)

Es que el promediar puede traer problemas, una vez lo intente con una interface que procesaba datos por RS232, el muestreo era bajo (cada 20 muestras), y se generaban lecturas muy alejadas una de otra. Si mostraba un 35 bajaba a 25, y como era temperatura el descenso debía ser lineal (1 o 2 grados de diferencia). Luego me di cuenta que algunas veces no llegaban los datos y lo contaba como 0, y eso afectaba la media de la muestra. Posiblemente ese sea el problema.


----------



## D@rkbytes (Jul 22, 2016)

También  se debe tener en cuenta que antes de realizar el promedio, se tiene que limpiar la variable que lleva la suma.
Esto es para evitar que se desborde cuando ya contiene datos anteriores.
Esa puede ser la causa de que a veces se muestre un valor más alto.

Y por lo que menciona ruben90, prefiero no realizar promedios.
Un Timer me ha servido bien para mostrar los datos periódicamente.

Si el problema se presenta con la frecuencia, se puede hacer esa lectura aparte, con el Timer 0 como contador externo.
Tal vez de esa forma se consiga evitar esos desbordes repentinos.


----------



## callecuatro1976 (Jul 23, 2016)

Si yo intente promediar con el ciclo for y los valores no son reales esto me esta volviendo loco, pero de apoco lo vamos a sacar.


----------



## callecuatro1976 (Jul 24, 2016)

Una pregunta aparte del tema hay algún ejemplo de usar 2 líneas del lcd como una y mostrar el voltimetro más grande?


----------



## papirrin (Jul 24, 2016)

puedes comprar un glcd y las haces del tamaño que gustes y no se ve feo


----------



## callecuatro1976 (Jul 25, 2016)

Ya probé el filtro pasa bajo y nada no se puede evitar que la señal entre ruidosa y se vuelve loco el duty y la frecuencia voy a ver si puedo subir un vídeo


----------



## papirrin (Jul 25, 2016)

recapitulemos, esto no deberia ser tan complicado creo XD...

¿tienes el esquema del circuito en cuestion?¿podrias publicarlo? le di una hojeada y no vi nada o me lo salte, y me parece que la mejor opcion para eso seria usar el lm2907... por la cuestion que puedes fijar un offset. 

si publicas el esquema podriamos hacerlo juntos.


----------



## callecuatro1976 (Jul 26, 2016)

asi es la conexión que hice usando el lm2907 funciona muy bien lo único son los cambios repentinos de la medición .


----------



## papirrin (Jul 26, 2016)

yo pondria un divisor resistivo para que en el pin 10 me dieran unos 2.5V como offsetv y probaria 
mas o meno asi:


la idea es que tomes un punto de la frecuencia que sea estable.


----------



## callecuatro1976 (Jul 26, 2016)

Si no se me ocurrió yo le ponía 5 volt como referencia y alimentos el integrado con 9 volt


----------



## papirrin (Jul 26, 2016)

pues prueba alimentandolo con 5v y pon ese divisor resistivo  que de 2.5v XD... deberia funcionar. ademas prueba con los 9v

y quizas con el pin4 se pueda hacer lo mismo pero con 1v... no se.

como te comento es agarrar puntos estables.


----------



## callecuatro1976 (Jul 26, 2016)

Estube probando y con el divisor resistido llevándolo  a 2,5 volt estuvo más estable,  la conexión de la pata 3 no funciona, y va mejor con 9 volt, ahora colocando un motor de 12 volt el duty tendría que estar al 100% ya que es todo su ciclo, ni enciende y apaga como las bobinas, eso no lo hace debería mostrarlo pero no es tan importante


----------



## papirrin (Jul 26, 2016)

y si pones un potenciometro multivueltas y vas viendo donde es mas estable en lugar de que sean 2.5



> ahora colocando un motor de 12 volt el duty no tendría que estar al 100% ya que es todo su ciclo no enciende y apaga como las bobinas, eso no lo hace


eso no lo entendi, es bueno o malo?


----------



## callecuatro1976 (Jul 26, 2016)

Si voy hacer eso, otra cosa es la pata 11 la medición se puede regulas bien, voy a colocar un preset multivuelta para calibrar mejor, vamos mejor


----------



## papirrin (Jul 26, 2016)

oye de donde sacas la señal que va al lm2907?


----------



## callecuatro1976 (Jul 27, 2016)

De una máquina de tatuar que son 2 bobinas que enciende y apaga constanteme y ese prende y apaga son los pulsos, una onda muy ruidosa y de baja señal


----------



## papirrin (Jul 27, 2016)

y que accionan esas bobinas ? algun trasnsistor? puedes poner fotos,?


----------



## callecuatro1976 (Jul 27, 2016)

Ahí te subo las fotos trabajan ebtre 6 y 12 volt


----------



## papirrin (Jul 27, 2016)

ya voy entendiendo XD, como que a ese sistema le faltaria algo como un diodo volante, red snubber o algo asi, porque eso deberia ser muy ruidoso en terminos electricos. la verdad me gustaria recomendarte y hacer pruebas pero no tengo nada que me pudiera servir para experimentar y verlo en el osciloscopio.

pero podriamos indagar un poco como eliminar esos ruidos. estamos en contacto y si encuentras algo me gustaria que nos lo compartieras.


----------



## callecuatro1976 (Jul 27, 2016)

Si uso dos diodos enfrentados y de ahí tomo la señal todo esta funcionando muy bien ló único son esos picos altos, debe ser la bobina


----------



## callecuatro1976 (Ago 4, 2016)

Va tomando forma me falta la caja y la fuente,  se podría hacer una fuente tipo buck con un mosfet y manejarlo con el Pic con pulsadores voy a ir probando


----------



## callecuatro1976 (Ago 24, 2016)

Hola! Volví con una consulta quiero mostrar el porcentaje del ciclo alto 
Stl = ciclo_alto;
Porcentaje1 = (Stl * 100);
Y muestro porcentaje1 en el lcd y no me muestra nada porque?


----------



## papirrin (Ago 24, 2016)

Pon mas información del codigo que usas finalmente, puede ser que desborde las variables


----------



## callecuatro1976 (Ago 25, 2016)

```
#include <16f883.h>
#device ADC=10
#use delay(internal = 8MHz)
#define LCD_DATA_PORT getenv("SFR:PORTC")
#include <lcd.c>
#define led PIN_B5
int1 flagHayDatos=0; 
float const ticks_us = 4.0; // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Interno)
//float const ticks_us = 8.0; // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Cristal)
int8 flancos;
int8 flag_flanco;
int16 periodo1,periodo2,periodo3;
int16 tiempo_alto,tiempo_bajo,tiempo_total;
float us_alto,us_bajo,us_total;
float frecuencia;
#INT_EXT
void sdi_externa_RB0 (void)
{
flancos++; // Incrementar la variable "flancos"

if(!flag_flanco) // Si el flanco del pulso es bajo...
{
if(flancos == 1) // Si el conteo de flancos es 1...
{
set_timer1(0); // Limpiar el Timer 1
periodo1 = get_timer1(); // "periodo1" tendrá el tiempo del pulso en alto.
}
if(flancos == 3) // Si el conteo de flancos es 3...
periodo3 = get_timer1(); // "periodo3" tendrá el tiempo del pulso en alto.

EXT_INT_EDGE(H_TO_L); // Establecer la interrupción por flanco de bajada.
flag_flanco = 1; // Indicar que el próximo flanco será de bajada.
}
else // Caso contrario. (Pulso en estado alto)...
{
periodo2 = get_timer1(); // "periodo2" tendrá el valor del pulso en bajo.
EXT_INT_EDGE(L_TO_H); // Establecer la interrupción por flanco de subida.
flag_flanco = 0; // Indicar que el próximo flanco será de subida.
if(flagHayDatos==0){ // Si los datos anteriores han sido procesados ...
flagHayDatos=1; // Indico que ya hay nuevos datos de flancos para calcular
}
}
if(flancos > 2)flancos = 0; // Si la variable "flancos" llega a 3, ponerla a 0.
}
void main()
{
long int var1=0, var2=0, var3=0;
float valor, valor1,valor2;
float duty;
int8 porcentaje;

setup_adc_ports(sAN1|sAN3);
setup_adc(ADC_CLOCK_INTERNAL );
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
enable_interrupts(int_ext);
ext_int_edge(0,L_TO_H);
enable_interrupts(global);

lcd_init();

#ZERO_RAM // Limpiar RAM. (Variables en 0)

while (true)
{


for(var1=0;var1<50;var1++)
{
valor=valor+ get_timer1();
delay_us(62); 
}
periodo1=valor/50;

for(var2=0;var2<50;var2++)
{
valor1=valor1+ get_timer1();
delay_us(62); 
}
periodo2=valor/50;
for(var3=0;var3<50;var3++)
{
valor2=valor2+ get_timer1();
delay_us(62); 
}
periodo3=valor/50;

if(flagHayDatos==1){
output_HIGH(led);
if((periodo3 > periodo2) && (periodo2 > periodo1))
{
tiempo_alto = periodo2 - periodo1; // Obtener el periodo del pulso en estado alto.
tiempo_bajo = periodo3 - periodo2; // Obtener el periodo del pulso en estado bajo.
tiempo_total = tiempo_alto + tiempo_bajo; // Obtener el periodo de la frecuencia.
us_alto = ticks_us * tiempo_alto; // Obtener el periodo en microsegundos del pulso en alto.
us_bajo = ticks_us * tiempo_bajo; // Obtener el periodo en microsegundos del pulso en bajo.
us_total = ticks_us * tiempo_total; // Obtener los microsegundos en total de la frecuencia.
frecuencia = 1 / (us_total / 1000000); // Obtener la frecuencia.
duty = ((float) tiempo_bajo / (float)(tiempo_bajo + tiempo_alto));
porcentaje = (duty * 100) + 0.5; // Físicamente el + 0.5 puede no ser necesario. (Ajusta desviación pero consume ROM)
} 
flagHayDatos=0; 
}
lcd_gotoxy(1,1);
printf(lcd_putc,"CPS:%03.0fHz",frecuencia);
lcd_gotoxy(1,2);
printf(lcd_putc,"DUTY:%02u%c",porcentaje,0x25);
flagHayDatos=0; 

delay_ms(100); // Retardo para disminuir parpadeos en la pantalla. (No afecta interrupción externa.)
if(flagHayDatos==0){
frecuencia = 0;
porcentaje=0;
output_low(led);
}

}
}
```

estoy usando este codigo


----------



## callecuatro1976 (Ago 28, 2016)

Se podría agregar una fuente así, con dos pulsadores que moverán de 0 a 5 volt,  un operacional para amplificar y tener de 0a 18 volt?  Y tendría que hacerlo por el pwm como saco el pulso por otro puerto que no sea el c?


----------



## callecuatro1976 (Sep 3, 2016)

Hola amigos del foro volví para pedir su ayuda con el código que estoy armando funciona bien , lo que no logro hacer es mostrar de 0 a 18 el voltaje el pwm ya pude poner los pulsadores me falta ajústalo mas fino


----------



## D@rkbytes (Sep 6, 2016)

No entendí el por qué de esas banderas para lo que pretendes hacer.
Por favor, cuando solicites ayuda, da más detalles y describe con comentarios tu programa.
Te adjunto el programa con los cambios.


----------



## callecuatro1976 (Sep 6, 2016)

Muchas gracias por tu tiempo y dedicación en este foro, tu ayuda no tiene  precio.
Voy a probar como va y te cuento. ¡Gracias por enseñar! 

---------- Actualizado ----------

Te consulto una cosa más.
¿En vez de TIP35 podría colocar un mosfet como en la imagen que te adjunto, o un regulador de la línea LM317, LM22677, o alguno de esa línea funcionaria igual? 

Saludos.


----------



## D@rkbytes (Sep 6, 2016)

Mejor usa un transistor bipolar. El TIP35 soporta 25 Amperes, lo cual se me hace excesivo y no creo que necesites más.
Si es para controlar el motor de una máquina para tatuar, con un TIP41 (6 Amps.) puede ir bien.


----------



## callecuatro1976 (Sep 7, 2016)

Hola te consulto antes de cambiar algo y después que no me ande, hice las pruebas y me paso de casualidad que se me apagó y me vuelve el voltimetro a cero como hago para modificar que quede la tensión que marcó con los pulsadores?  Hay que usar la memoria?


----------



## D@rkbytes (Sep 7, 2016)

Pues si, pero te recomiendo que uses un pulsador para guardar los datos.
Ya que si almacenas los datos con cada cambio, después de 1,000,000 escrituras, la memoria se irá dañando.
Si lo piensas usar así, haz un promedio de uso para determinar el tiempo de vida.


----------



## callecuatro1976 (Sep 7, 2016)

Ok voy a ver como lo implementó o en vez de leer por adc ya marcar la tensión y que salga por el pwm y no usaría la memoria,  es correcto?


----------



## D@rkbytes (Sep 7, 2016)

callecuatro1976 dijo:


> Ok. Voy a ver como lo implemento, o en vez de leer por adc ya marcar la tensión y que salga por el pwm y no usaría la memoria, ¿es correcto?


No entendí absolutamente nada.
Pero, lo que tienes que guardar es el valor de la variable "ciclo_activo" y al iniciar el programa debes leer ese valor y asignarlo a la variable.


----------



## callecuatro1976 (Sep 8, 2016)

Mi ides era ya asignar la tensión con los pulsadores no leerla del adc,  si coloco con el pulsador 15 volt que el pwm saque la proporción a 15 volt, 

18 volt = máximo pwm
0 volt = mínimo pwm
Y que los pulsadores se muevan en ese rango 
Y avance 1,1 1,2  1,3 y sale saque la tensión 

Lo voy haciendo y subo,gracias


----------



## D@rkbytes (Sep 8, 2016)

Eso que mencionas, es lo que exactamente hace el programa que subí.
Pero yo aproveché uno de los canales ADC de ese PIC para leer el voltaje.


----------



## callecuatro1976 (Sep 8, 2016)

Si tenes razón! Como le agrego dos pulsadores más así apretando por 3 segundo tengo 2 memorias y puedo tener dos voltajes diferentes y cada ves que apretó por 3 segundo puedo guardar el valor y trabajo con eso?


----------



## D@rkbytes (Sep 8, 2016)

Con un contador y un bucle, pero si tienes más pines de sobra, no le encuentro sentido a eso.


----------



## callecuatro1976 (Sep 8, 2016)

Sí, estoy haciendo un lio con los pulsadores.

---------- Actualizado ----------

A ésto es a lo que me refería sobre el voltaje.
Si se puede hacer algo así, y que cuando se deje el botón apretado, suba más rápido.
Y con respecto a la memoria, estoy tratando de hacerlo.


----------



## D@rkbytes (Sep 9, 2016)

Pues no lo veo correcto.
De esa forma no estarás mostrando el voltaje de salida.
Ten en cuenta que la carga presenta una resistencia que provocará una caída de tensión y el programa estará indicando un voltaje que calculas por software, pero ese voltaje no será el que está presente en el momento.
Aparte, en el programa estás usando el ADC 4 y no lo tienes conectado en ninguna parte del esquema.

No entiendo por qué estás modificando un proyecto que se te está dando funcional, por algo que no tiene sentido.


----------



## callecuatro1976 (Sep 9, 2016)

Porque estoy trabado con el tema de las memorias y no encuentro la manera que cuando se apaga vuelve a cero. El proyecto que hiciste es muy bueno. Solo necesito que me de la forma de guardar 2 datos así no es tedioso empezar de cero cada vez que se apaga, la opción mejor es usar el adc.


----------



## D@rkbytes (Sep 9, 2016)

En el _post #121_ te expliqué cómo hacerlo, y la verdad es muy sencillo.
Es algo tan básico, que es una de las primeras cosas que se deben saber al programar microcontroladores.

Ahora, si quieres algo más elaborado, puedes sensar el voltaje de alimentación del microcontrolador y guardar los datos cuando ese voltaje esté por debajo de 5 V.
O sea, establecer un voltaje de referencia antes de que ocurra el BOR (Brown-Out Reset)
El compilador de CCS por defecto siempre desactiva éste fuse, así que dependiendo el PIC, podrá operar hasta por debajo de unos 3.3 V.
Así que tienes un amplio rango para poder fijar una histéresis y no provocar falsas lecturas.


----------



## callecuatro1976 (Sep 10, 2016)

ok es algo si como lo estoy haciendo


void memoria()
{
if (!input(PIN_A2))
{
write_eeprom (00,voltaje);
}
else if (!input(PIN_A2))
{

voltaje=read_eeprom(00);
lcd_gotoxy(11,1);
printf(lcd_putc,"%4.1fV ",voltaje);
}
}


----------



## D@rkbytes (Sep 10, 2016)

No. Muy mal, y no estás prestando atención a lo que te mencioné.


D@rkbytes dijo:


> Lo que tienes que guardar es el valor de la variable  "ciclo_activo" y al iniciar el programa debes leer ese valor y asignarlo  a la variable.


¿Por qué se debe guardar el valor de la variable "ciclo_activo"?
Porque el valor de esa variable es lo que define el ciclo activo del PWM y por ende el voltaje de salida.
Así que guardar y leer la variable "voltaje", no tiene relevancia porque el ciclo activo determina el voltaje.

Ahora, ¿por qué leer la variable "ciclo_activo" al iniciar el programa?
Porque justo en ese momento es cuando se requiere saber que valor tenía anteriormente.
Por lo tanto, el programa al iniciar ya tendrá un valor con el cual ajustar el ciclo activo del PWM, y ésto se verá inmediatamente reflejado en el voltaje de salida.

Recuerda ésto:
Para programar debes tener noción e imaginación sobre el acontecimiento de eventos.


----------



## callecuatro1976 (Sep 11, 2016)

void memoria()
  {
  if (!input(PIN_A2))  // si apreto pin a2 por 1 segundo guardo el dato
  {
      delay_ms(1000);
     write_eeprom(00,ciclo_activo ); // guardo el dato ciclo activo

  }
 if (!input(pin_a2)) // si preciono pin a2 leo el dato en la posicion de la memoria
{

     valor =read_eeprom(00); // paso el dato a la variable valor 

}

 lcd_gotoxy(11,1);
      printf(lcd_putc, "%4.1fV ",valor); // muestro el dato en lcd remplazando el dato del adc
  }

 Si tenes razón , probé de esta manera hacerla la función y me parece que esta mal.


----------



## roberttorres (Sep 11, 2016)

callecuatro1976 dijo:


> void memoria()
> {
> if (!input(PIN_A2))  // si apreto pin a2 por 1 segundo guardo el dato
> {
> ...


Buenas.
Vamos a ver si entiendo , lo que quieres hacer es que al pulsar el botón por un segundo guarde el valor del voltaje en la memoria y al pulsarlo nuevamente lea la memoria y despliegue nuevamente ese voltaje.
Si es asi, tu código esta mal, recuerda que los micros ejecutan las instrucciones de forma lineal,o sea que tu segunda instruccion de leer la memoria no se ejecutara.
Te paso un ejemplo con tu codigo para que lo pruebes y analizes:

```
void memoria()
{     
 int8 cont;     
   if(input(pin_a2)==0){
          while(!input(pin_a2)){
          cont++;
          delay_ms(10);
          if (cont >80){
          write_eeprom(00,ciclo_activo ); // guardo el dato ciclo activo
         delay_ms(50);
	lcd_gotoxy(2,1);
         printf(lcd_putc, "\fMEMORIA GRABADA");
         delay_ms(1000);
         CONT = 0;
          }
          }
           ciclo_activo =read_eeprom(00); // paso el dato a la variable ciclo_activo
           lcd_gotoxy(2,1);
           printf(lcd_putc, "\fMEMORIA LEIDA");
           delay_ms(1000);
           printf(lcd_putc,"\f"); 
           cont=0;
            delay_ms(50);
             establecer_ciclo(ciclo_activo);
            }
}
```

PD: En este ejemplo al pulsar el botón conectado al Pin A2 por un segundo o mas guarda el valor del ciclo_activo, y al pulsarlo solo una vez sin dejarlo presionado lee la memoria y despliega el voltaje.


----------



## D@rkbytes (Sep 11, 2016)

roberttorres dijo:


> PD: En este ejemplo, al pulsar el botón conectado al Pin A2 por un segundo o más, guarda el valor del ciclo_activo, y al pulsarlo sólo una vez sin dejarlo presionado, lee la memoria y despliega el voltaje.


Por ahí va la cosa. Pero, ¿Qué caso tiene leer el valor del ciclo activo guardado en la EEPROM, si durante ese periodo, el valor del ciclo activo no se a perdido y también está previamente asignado?
Como corroboración, es comprensible, pero también redundante.

La importancia de leer el valor guardado del ciclo activo, radica más que nada, al iniciar el programa.
Pero aquí ocurre otro detalle, en dado caso de que no ocurra un corte eléctrico, el equipo siempre arrancará con el motor encendido, puesto que posiblemente quede almacenado un valor diferente al mínimo para el ciclo activo del PWM.
Aquí entra en juego otro factor a guardar y posteriormente comparar, que sería el factor tiempo.


----------



## callecuatro1976 (Sep 12, 2016)

Voy a probarlo gracias por su tiempo.


----------



## roberttorres (Sep 12, 2016)

D@rkbytes dijo:


> Por ahí va la cosa. Pero, ¿Qué caso tiene leer el valor del ciclo activo guardado en la EEPROM, si durante ese periodo, el valor del ciclo activo no se a perdido y también está previamente asignado?
> Como corroboración, es comprensible, pero también redundante.


Es cierto Tenes razón, solo tiene que guardar en la EEprom el ciclo activo, para que pueda volver a desplegar el voltaje en caso que la equipo se haya apagado.



> La importancia de leer el valor guardado del ciclo activo, radica más que nada, al iniciar el programa.
> Pero aquí ocurre otro detalle, en dado caso de que no ocurra un corte eléctrico, el equipo siempre arrancará con el motor encendido, puesto que posiblemente quede almacenado un valor diferente al mínimo para el ciclo activo del PWM.
> Aquí entra en juego otro factor a guardar y posteriormente comparar, que sería el factor tiempo.


El ejemplo que subí hace exactamente eso, al encender el equipo, lo hace con el ciclo activo en 1, y al pulsar el boton conectado al pin_A2 y vuelve a desplegar el voltaje guardado, que es lo que entendí que el compañero quiere hacer.
Subo la simulacion y el codigo implementado:


----------



## callecuatro1976 (Sep 12, 2016)

Funciona muy bien! Como hago para que cuando dejo apretado suba o baje más rápido el voltaje y se puede poner un buzzer cuando se apreta un pulsador?


----------



## D@rkbytes (Sep 12, 2016)

Similar a lo que comenté en el post #125, con un bucle y un contador.
Y si se cumple el conteo predeterminado, actualizas el periodo del retardo por un tiempo menor.


----------



## callecuatro1976 (Sep 13, 2016)

Hola estoy probando y me encuentro que con el oscilador interno a 8mhz me da problema, con la lectura de los pulsadores , y todavía ando mareado con el contador 
void memoria()
{ 
int8 cont; esta variable se declara para alojar los datos de la memoria? 
if(input(pin_a2)==0){ apretó pin a2 
while(!input(pin_a2)){ while no entiendo que hace
cont++; contador asciende 
delay_ms(10);
if (cont >80){ contador mayor de 80
write_eeprom(00,ciclo_activo ); // guardo el dato ciclo activo
delay_ms(50);
lcd_gotoxy(2,1);
printf(lcd_putc, "\fMEMORIA GRABADA");
delay_ms(1000);
CONT = 0; y el conatdor a 0

claro yo nunca lo iba hacer andar si no entiendo bien como funciona, el contador para que hacienda o baje mas rápido el voltaje no se como hacerlo, subo lo que hicimos hasta aca


----------



## callecuatro1976 (Sep 16, 2016)

Ya casi esta me falta un poco de ayuda para que corra mejor el programa, ya sube y baja rápido pero no logro reflejar la muestra en el adc, lo demás funciona bien no se si estoy aplicando bien las memorias pero hace lo que necesito.


----------



## roberttorres (Sep 16, 2016)

callecuatro1976 dijo:


> Ya casi esta me falta un poco de ayuda para que corra mejor el programa, ya sube y baja rápido pero no logro reflejar la muestra en el adc, lo demás funciona bien no se si estoy aplicando bien las memorias pero hace lo que necesito.


Buenas.
No puedo compilar tu código porque falta el la librería "Flex_lcd416.c", pero te paso tu codigo con algunas modificaciones para que lo pruebes:

```
#include <16f883.h>
#device ADC=10
#use     delay(internal = 8MHz)                           
#include <flex_lcd416.c>
#define led PIN_B5
#include <internal_eeprom.c>


int1 flagHayDatos=0; 
float const ticks_us = 4.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Interno)
//float const ticks_us = 8.0;          // microsegundos por Tick del Timer 1 @ 8 MHz. (Osc. Cristal)
long int var1=0, var2=0;
int8 flancos;
int8 flag_flanco;
int16 periodo1,periodo2,periodo3;
int16 tiempo_alto,tiempo_bajo,tiempo_total;
float us_alto,us_bajo,us_total, valor,volt,valor2,amper, duty;
   int porcentaje,porcentaje1;
   int frecuencia;
   
int16 valor_adc;
   float voltaje;
int8 porcentaje2,  ciclo_activo=1;
void voltaje(void);
   
   
   
#INT_EXT
void sdi_externa_RB0 (void)
{
   flancos++;                          // Incrementar la variable "flancos"
   
   if(!flag_flanco)                    // Si el flanco del pulso es bajo...
   {
      if(flancos == 1)                 // Si el conteo de flancos es 1...
      {
         set_timer1(0);                // Limpiar el Timer 1
         periodo1 = get_timer1();      // "periodo1" tendrá el tiempo del pulso en alto.
      }
      if(flancos == 3)                 // Si el conteo de flancos es 3...
         periodo3 = get_timer1();      // "periodo3" tendrá el tiempo del pulso en alto.
         
         EXT_INT_EDGE(H_TO_L);         // Establecer la interrupción por flanco de bajada.
         flag_flanco = 1;              // Indicar que el próximo flanco será de bajada.
   }
   else                                // Caso contrario. (Pulso en estado alto)...
   {
      periodo2 = get_timer1();         // "periodo2" tendrá el valor del pulso en bajo.
      EXT_INT_EDGE(L_TO_H);            // Establecer la interrupción por flanco de subida.
      flag_flanco = 0;                 // Indicar que el próximo flanco será de subida.
       if(flagHayDatos==0){       // Si los datos anteriores han sido procesados ...
      flagHayDatos=1;          // Indico que ya hay nuevos datos de flancos para calcular
    }
   }

   if(flancos > 2)flancos = 0;         // Si la variable "flancos" llega a 3, ponerla a 0.
}


void establecer_ciclo (int8 ciclo)
{
   
 
   set_pwm1_duty(ciclo);   // Establecer el ciclo activo
   lcd_gotoxy(10,3);
   // Obtener el porcentaje del ciclo activo.
   porcentaje2 = (ciclo / 24.5) *10;
   // Mostrar el porcentaje del ciclo activo para la carga.
   printf(lcd_putc,"C:%03u%c",porcentaje2,37);
   voltaje();       
     
}

void voltaje (void)
{
int16 valor_adc;
float voltaje;
 set_adc_channel(10); // Establecer la lectura del canal ADC 10
   delay_us(50);
   valor_adc = read_adc(); // Tomar la lectura del voltaje.
   voltaje = ((valor_adc * 20.0) / 1023);
  lcd_gotoxy(1,1);
  printf(lcd_putc,"%4.1fV ",voltaje);
    lcd_gotoxy(1,2);
   printf(lcd_putc,"C:%03u%c",porcentaje2,37);
delay_ms(30);
}  

void pulsadores() 
{   
   if (input(PIN_A0)==0)
   {
    while(!input(pin_a0)){
      ciclo_activo ++;  // Incrementar el ciclo activo.
      if (ciclo_activo > 249) ciclo_activo = 249;   // No permitir que el ciclo activo suba de 249
      delay_ms(10);
      establecer_ciclo(ciclo_activo);
   }
   }
   if (input(PIN_A1)==0)
   {
    while(!input(pin_a1)){
      ciclo_activo --;  // Disminuir el ciclo activo.
      delay_ms(10);
       if (ciclo_activo <= 1) ciclo_activo = 2;  // No permitir que el ciclo activo baje de 1
      establecer_ciclo(ciclo_activo);
   }
   
}
}

   
void memoria()
{
 int8 cont;     
   if(input(pin_a2)==0){
          while(!input(pin_a2)){
          cont++;
          delay_ms(10);
          if (cont >80){
          write_eeprom(00,ciclo_activo ); // guardo el dato ciclo activo
         delay_ms(50);
    lcd_gotoxy(2,1);
         printf(lcd_putc, "\fMEMORIA GRABADA");
         delay_ms(1000);
         CONT = 0;
          }
          }
           ciclo_activo =read_eeprom(00); // paso el dato a la variable ciclo_activo
           lcd_gotoxy(2,1);
           printf(lcd_putc, "\fMEMORIA LEIDA");
           delay_ms(1000);
           printf(lcd_putc,"\f"); 
           cont=0;
            delay_ms(50);
             establecer_ciclo(ciclo_activo);
            }
}  

  void memoria1()
{     
 int8 cont;     
   if(input(pin_a3)==0){
          while(!input(pin_a3)){
          cont++;
          delay_ms(10);
          if (cont >80){
          write_eeprom(01,ciclo_activo ); // guardo el dato ciclo activo
         delay_ms(50);
    lcd_gotoxy(2,1);
         printf(lcd_putc, "\fMEMORIA GRABADA");
         delay_ms(1000);
         CONT = 0;
          }
          }
           ciclo_activo =read_eeprom(01); // paso el dato a la variable ciclo_activo
           lcd_gotoxy(2,1);
           printf(lcd_putc, "\fMEMORIA LEIDA");
           delay_ms(1000);
           printf(lcd_putc,"\f"); 
           cont=0;
            delay_ms(50);
             establecer_ciclo(ciclo_activo);
            }
} 
  

void main()
{
     
 setup_ccp1(CCP_PWM);
   setup_timer_2(T2_DIV_BY_4,249,1);   // 1000 Hz. @ 4 MHz.
   set_pwm1_duty(1);                   // Ciclo activo al mínimo
   
   setup_adc_ports(sAN10|san4);
   setup_adc(ADC_CLOCK_INTERNAL);
   
   setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
   enable_interrupts(int_ext);
   ext_int_edge(0,L_TO_H);
   enable_interrupts(global);
 
   
   lcd_init();
    establecer_ciclo(ciclo_activo);
   #ZERO_RAM   // Limpiar RAM. (Variables en 0)

  
   
   while (true)
   {
   
   pulsadores(); 
   memoria();
   memoria1();
   voltaje();
    if(flagHayDatos==1){
    output_HIGH(led);
      if((periodo3 > periodo2) && (periodo2 > periodo1))
      {
         tiempo_alto = periodo2 - periodo1;                 // Obtener el periodo del pulso en estado alto.
         tiempo_bajo = periodo3 - periodo2;                 // Obtener el periodo del pulso en estado bajo.
         tiempo_total = tiempo_alto + tiempo_bajo;          // Obtener el periodo de la frecuencia.
         us_alto = ticks_us * tiempo_alto;                  // Obtener el periodo en microsegundos del pulso en alto.
         us_bajo = ticks_us * tiempo_bajo;                  // Obtener el periodo en microsegundos del pulso en bajo.
         us_total = ticks_us * tiempo_total;                // Obtener los microsegundos en total de la frecuencia.
         frecuencia = 1 / (us_total / 1000000);             // Obtener la frecuencia.
         duty = ((float) tiempo_bajo / (float)(tiempo_bajo + tiempo_alto));
          porcentaje = (duty * 100) + 10; // Físicamente el + 0.5 puede no ser necesario. (Ajusta desviación pero consume ROM)       
      } 
       flagHayDatos=0; 
    }
      lcd_gotoxy(10,1);
      printf(lcd_putc,"Hz:%03u ",frecuencia);
       if(porcentaje < 3)porcentaje = 0;
      if(porcentaje > 95)porcentaje = 99;
    
      lcd_gotoxy(10,4);
      printf(lcd_putc,"Duty:%02u%% ",porcentaje );
    
      
       flagHayDatos=0; 
       
      delay_ms(100); // Retardo para disminuir parpadeos en la pantalla. (No afecta interrupción externa.)
      if(flagHayDatos==0){
      frecuencia = 0;
      porcentaje=0;
      porcentaje1=0;
      output_low(led);
      }
      
      
   
   // set_adc_channel(10); // Establecer la lectura del canal ADC 10
   //   delay_us(20);
   //   valor_adc = read_adc(); // Tomar la lectura del voltaje.
      
     
   //   voltaje = ((valor_adc * 20.0) / 1024);
   //   
   //      lcd_gotoxy(1,1);
  // lcd_putc("Volt   "); 
  //lcd_gotoxy(1,2);
  //    printf(lcd_putc,"%4.1fV ",voltaje);   
 
  
  
  set_adc_channel(4); 
    delay_us(30);
   amper=0;
  for(var2=0;var2<300;var2++)
  {
    amper=amper+ read_adc();
    delay_us(62);  
  }

  valor2 = amper / 300;
  valor2 = valor2 * 21 / 1023;

  lcd_gotoxy(10,2);
  printf(lcd_putc,"A:%4.1f",valor2); 
  delay_ms(50);
   }
}
```


----------



## callecuatro1976 (Sep 16, 2016)

si perdón te subo el código con la librería, voy a probar el cambio que hiciste , saludos


----------



## callecuatro1976 (Sep 18, 2016)

Hola lo probé en físico y se tilda o muestra solo volt y la carga que puede ser?


----------



## callecuatro1976 (Sep 19, 2016)

Volví a pedir ayuda no me funciona las memorias cuando presionó el pulsador graba y lee siempre,  no logro hacer que grabe cuando presionó 5 segundos y lea con el mismo pulsador cuando presionó 1 segundo


----------



## roberttorres (Sep 20, 2016)

callecuatro1976 dijo:


> Volví a pedir ayuda no me funciona las memorias cuando presionó el pulsador graba y lee siempre,  no logro hacer que grabe cuando presionó 5 segundos y lea con el mismo pulsador cuando presionó 1 segundo



Buenas.
Disculpa el codigo que te pase habia un error de calculos, solo tienes que aumentar la variable cont en tus rutinas de memoria, (tienes que aumentar o disminuir para obtener el tiempo deseado). Asi:

```
int16 cont;     
   if(input(pin_a3)==0){
          while(!input(pin_a3)){
          cont++;
          [COLOR="Red"][B]delay_ms(1);
          if (cont1 >5000){[/B][/COLOR]
          write_eeprom(01,ciclo_activo ); // guardo el dato ciclo activo
         delay_ms(50);
```

Tambien note que las variables:





> int porcentaje,porcentaje1;
> int frecuencia;


se desbordan al aumentar la frecuencia debes ver eso tambien.
Por ultimo te paso el ejemplo con modificaciones, tal vez tenga errores, no he tenido tiempo para analizar mejor, modifique también la libreria del lcd pero no lo he probado fisicamente.


----------



## callecuatro1976 (Sep 21, 2016)

No me funciono me da errores por todos lados


----------



## callecuatro1976 (Sep 23, 2016)

Hola vuelvo a consultar, si quiero sacar los pulsadores y poner un encoder tendría que usar otro timer más como el timer0 del pic16f886 y contar los pulsos para controlar el pwm?


----------



## wasausky (Abr 14, 2017)

en  EL BASIC  se puede hacerlo de una sencilla manera hay una funcion COUNT pero como podria pasarlo al ccs ¿copiando el lenguaje en essamber? es lo unico que se me ocurre por que no necesita de un modulo para hacer esta funcion o alguien entiende su funcionamiento para hacer mas efectivo un pic y no necesitar de un pic con ccp que solo por un pin puede ejecutar esta funcion bueno e intentado hacerlo pero solo me llega hasta 200 hz pero en el BASIC ES 60 KHZ y se dice que los pics pueden llegar al orden de los MHZ seria cuention de que un sabio en los dos compiladores dara su respuesta


----------



## Nuyel (Abr 14, 2017)

Contar pulsos? usas la entrada de reloj y el temporizador configurado a reloj externo, con eso directamente incrementas el contador con los pulsos, lo de medir el tiempo si está más complicado por que hay que sincronizar dos temporizadores.

El otro método es por interrupciones y se limita a que tan rápido puede el PIC procesar las cuentas en la CPU.


----------

