Duda código frecuenciometro con PIC 18F4550

Hola a todos, estoy montando un frecuenciometro con el PIC 18F4550 y leds RGB. Pero primero estoy haciendo la simulación en protheus con un LCD y luego adaptare el código para los leds. El problema es que nunca se me ha dado muy bien el tema de programar y no se si estoy configurando bien el timer0, que en este caso es de 16 bits.
Os dejo un ejemplo del código haber si encontráis algún fallo, a y utilizo el compilador CCS. Si puedo dejo una imagen del circuito.

Código:
#include <18F4550.h>
#fuses HS,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP,PUT
#use delay(clock=16000000)
//#include <usb_bootloader.h>
#use standard_io(D)
#include <LCD_.C>
int b=0;
int c=1;
#int_ext
#int_RTCC
void  RTCC_isr(void)
   {
      b=256;
   }

void main(void)
{
   setup_timer_0(RTCC_INTERNAL|RTCC_DIV_1);
   set_timer0(65536-50000);
   enable_interrupts(int_ext);
   enable_interrupts(global);
   int a=0;
   c=0;
   output_toggle(PIN_D0);
   lcd_iniciar();
   delay_ms(1000);
   printf(lcd_putc,"\fFRECUENCIOMETRO");
   while(1)
      {
         delay_ms(1000);
         a=c+b;
         printf(lcd_putc,"\fFREC=%i Hz",a);
         b=0;
         c=0;
      }     
}
 
Última edición por un moderador:
te paso un enlace bueno, una grandiosa pagina.
http://picmania.garcia-cuervo.net/tecnicas_en_c_1.php

Por lo que estas haciendo bien, algo si, pero mal tambien. no se ni que es a, ni b, ni c, ni por que habilitas la interrupcion externa si luego no la usas. Tratas de usar la interrupcion del timer 0 llamandola rtcc pero no la habilitas, no tendrias que usarla, simplemente usar el timer para contar el tiempo, tomar su valor y ponerlo a 0 cada vez que se de un flanco de subida. luego ese tiempo dependiendo de la velocidad a la que estes trabajando multiplicarlo o dividirlo para obtener la frecuencia, y ya mostrarla por el LCD por ejemplo
 
Gracias, por la aportación en cuanto puedo me miro la pagina que me comentas y la verdad que si que estoy perdido con el código. La cuestión es que encontré un código para un pic 16 y hice unas modificaciones para mi pic y compilador ya que no era el mismo y de momento he llegado hasta lo que has visto.
Gracias por tu ayuda.
 
Buenas,

Que es exactamentelo que te pasa? Que fallo observas?

Tambien te digo que proteus no va bien si necesitas mucha velocidad ("se pierde como corras mucho"), me ha pasado con multiplexacion de displays.

A la hora de calcular frecuencia, vigila que el timer0 no te desborde y te salte la interrupcion, es decir, si intentas contar un afrecuencia muy baja, el timer0 contara tanto rato que desbordara los 16 bits y el programa te dara errores, me explico? Si eso pasa, debes bajar la velocidad del reloj interno del pic.

Otra cosa, yo trabajo en CC5X, no en CCS, aunque la teoria sera la misma.

Talue!
 
Hola a todos y agradecer a Limbo por sus aportes que me han ayudado mucho y el enlace que paso es muy interesante. Vamos al grano, al final buscando por internent en un foro del compilador CSS, encontre un codigo que lo he utilizado como base para hacer como yo lo queria. Este codigo consta de un pequeño programa que es el que e editado y luego una libreria que es el que cuenta la frecuencia y lo envia al programa principal.

Mi idea final es montar el circuito con unos leds rgb en la salida, pero como los ejemplos funciona con lcd, opte por montarlo primero con lcd y luego cuando funcionase bien simularlo con los leds. El programa con el circuit lcd funciona perfectamente, pero el problema cuando lo hagos con los leds no me funciona bien. Lo hago con else if y siempre me salta a la función por defecto y yo y varios amigos no vemos el fallo. Enlazo un documento con fotos del circuito y codigos. Haber si alguien me puede ayudar, que no me puedo sacar el proyecto de la cabeza, gracias de antemano.

Código:
#include <18F4550.h>
#fuses HS,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP,PUT,XT,BROWNOUT,NOLVP
#use delay(clock=16000000)
#use standard_io(C)
//#use standard_io(D)

#include "count_18f.c"

void main()
{
int16 result;

   while(1) 
   {
      output_low(PIN_D7);
      result = count(PIN_B0, 1000);
   
   if(result>1&&result<99)
   
      {
       output_low(PIN_C0);
       //delay_ms(100);
      }
    else if(result>100&&result<199)
    
      {
       output_low(PIN_C1);
       //delay_ms(100);
      }    
    else if (result>200&&result<399)
    
      {
       output_low(PIN_C2);
       //delay_ms(100);
      }
    else (result>400&&result<599)
      { 
       output_low(PIN_C4);
       //delay_ms(100);
      }
    else if(result>=600&&result<=999)
      {
       output_low(PIN_C5);  
      }
   else if(result>=1000&&result<=1999)
      {
       output_low(PIN_C6); 
      }
    else if(result>=2000&&result<=3999)
      {
       output_low(PIN_C7);
      }
    else if(result>=4000&&result<=6999)
      {
       output_low(PIN_D0);   
      }
    else if(result>=7000&&result<=9999)
      {
       output_low(PIN_D1);  
      }
   else 
      {
       output_low(PIN_D2);
      }
   delay_ms(100);
   } 
}
 

Adjuntos

  • Esquemas y codigo.zip
    201.1 KB · Visitas: 40
hola Titu85, prueba con esto.
Código:
#include <18F4550.h>
#fuses HS,NOBROWNOUT,NOWDT,NOPROTECT,NOLVP,PUT,XT,BROWNOUT,NOLVP
#use delay(clock=16000000)
#use standard_io(D)
#define LCD_DATA_PORT getenv("SFR:PORTD")
#include <LCD.C>
//#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, ERRORS)

//#include "count_18f.c"
#define BYTE_PTR(x) &(int8 *)(x)

#define COUNT_DELAY ((int16)(getenv("CLOCK") / 80000))

// ASM definitions
#define W  0
#define F  1

// Status Register Bits
#define Z  2
#define C  0

// Register addresses (18F)
#byte INDF0  = 0xFEF
#byte STATUS = 0xFD8
#byte FSR0H  = 0xFEA
#byte FSR0L  = 0xFE9



int16 count(int16 ccs_pin, int16 period) 
{
int8 const bitmask_table[] = {0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
int16 io_port;   
int8  bitmask;
int16 R0;
int16 R1;
int16 R2;
int16 R3;
int32 loop_count;

// These variables are used in the ASM code
// and must be located in the same RAM bank.
#locate R0      = 0x30
#locate R1      = 0x32
#locate R2      = 0x34
#locate R3      = 0x36
#locate io_port = 0x38 
#locate bitmask = 0x3A  // *** Changed to 0x3A for 18F version ***

// Extract the Port address and bitmask from
// the CCS pin number.
io_port = ccs_pin >> 3;
bitmask = bitmask_table[ccs_pin & 7];

// Set the pin to be an input pin.
output_float(ccs_pin);

// Calculate the number of loop iterations to do.
loop_count = _mul(period, COUNT_DELAY);

// Put loop_count into R0 (msb), R2+1 (mid), R2 (lsb)
R0 = make8(loop_count, 2);  // msb
(int8)R2 = make8(loop_count, 1);  // Get mid into  R2
R2 <<= 8;  // Move mid into R2+1
(int8)R2 = make8(loop_count, 0); // lsb

#asm   
    movf    io_port, W      ; Get port lsb
    movwf   FSR0L
    movf    BYTE_PTR(io_port) +1, W   ; Get port msb
    movwf   FSR0H
    incf    R0, F              ; Bump up high and mid for dec
    incf    BYTE_PTR(R2) +1, F
    clrf    R1                 ; Zero counter
    clrf    BYTE_PTR(R1) +1
    movf    INDF0, W 
    andwf   bitmask, W         ; Isolate it
    movwf   R3                 ; Save starting state as last

countloop:                     ; 20 usec loop (at 4 MHz)
    nop                        ; 1
    movf    INDF0, W           ; 1
    andwf   bitmask, W         ; 1 Isolate it
    movwf   BYTE_PTR(R3) +1    ; 1 Save state
    xorwf   R3, W              ; 1 Compare with last time
    andwf   BYTE_PTR(R3) +1, W ; 1 Only count high states
    xorwf   bitmask, W         ; 1 Flip for next test
    btfsc   STATUS, Z          ; 1 / 2
    incf    R1, F              ; 1 / 0 Count pulse
    btfsc   STATUS, Z          ; 1 / 2
    incf    BYTE_PTR(R1) +1, F ; 1 / 0
    movf    BYTE_PTR(R3) +1, W ; 1 Set new last state
    movwf   R3                 ; 1
    decf    R2, F              ; 1 Count time
    btfsc   STATUS, Z          ; 1 / 2
    decf    BYTE_PTR(R2) +1, F ; 1 / 0
    btfsc   STATUS, Z          ; 1 / 2
    decfsz  R0, F              ; 1 / 2
    goto    countloop          ; 2 / 0
    movf    R1, W              ; Result to W
#endasm

return(R1);  // R1 holds the result
}



//======================================
void main()
{
int16 result;

   while(true) 
   {
      output_low(PIN_D7);
      result = count(PIN_B0, 1000);
      output_d(255);
      output_c(255);
   
   if(result>1&&result<99)
   
      {
       output_low(PIN_C0);
       //delay_ms(100);
      }
    else if(result>100&&result<199)
    
      {
       output_low(PIN_C1);
       //delay_ms(100);
      }    
    else if (result>200&&result<399)
    
      {
       output_low(PIN_C2);
       //delay_ms(100);
      }
    else if(result>400&&result<599)
      { 
       output_low(PIN_C4);
       //delay_ms(100);
      }
    else if(result>=600&&result<=999)
      {
       output_low(PIN_C5);  
      }
    else if(result>=1000&&result<=1999)
      {
       output_low(PIN_C6); 
      }
    else if(result>=2000&&result<=3999)
      {
       output_low(PIN_C7);
      }
    else if(result>=4000&&result<=6999)
      {
       output_low(PIN_D0);   
      }
    else if(result>=7000&&result<=9999)
      {
       output_low(PIN_D1);  
      }
   else 
      {
       output_low(PIN_D2);
      }
   delay_ms(100);
   } 
}
 
Gracias Saint_, por tu aportación, he visto que has unido la librería con el código y alguna modificación mas he visto. Me lo estuve mirando anoche, pero sigue haciendo lo mismo, que solo entra en la función por defecto y es muy raro porque mira que me lo he mirado con varios amigos y no hay manera.

Pero de momento lo voy a dejar aparcado, por que esto es solo una parte de mi proyecto y de momento lo dejare con el lcd, que funciona y si luego me sobra tiempo, cuando acabe con la parte principal, mirare haber si puedo conseguir que funcione. Igualmente muchas gracias por dedicarme tiempo, te lo agradezco mucho.

Ya que estoy aquí me gustaría comentar una consulta fácil, con un int16 puedo hacer que se comporte como un float? Si en la operación yo pongo esto: result= (result(float)/1000); y en el printf le pongo la '%f' . Con esto me tendría que funcionar no.

Muchas gracias a todos los foreros y saludos.
 
Hola Titu85, cuando revise el programa no había mas problema que el de:
* si inicialmente se tenia una frecuencia de 1Khz, se encendía el led correspondiente, cuando se cambiaba la frecuencia (por ejemplo 50Hz) también se encienda el led correspondiente, pero quedaba encendido el led anterior o anteriores de las mediciones anteriores, por eso es que le aumente en código que apaga los leds después de obtener el valor de result ,para cada caso en la variable result siempre se tenia el valor correcto de la frecuencia.

el modo en que funciona el programa es:
1) inicia el programa
2) enciende el led situado en el pin 7 de portd
3) entra a la funcion count(PIN_B0, 1000); y apaga los leds previamente encendidos
4) después de 1s., se obtiene el entero equivalente a la frecuencia en la variable result
5) pasa por los distintos If y else-If y enciende el led correspondiente según el intervalo definido.
6) repite desde el paso 2.
... "asi que aun no veo cual es el problema", al menos yo lo vi funcionar así.


Por otro lado, para mostrar una numero flotante, hay que usar una variable del tipo flotante ya que si se quiere mostrar un entero como si fuera flotante en el mejor delos casos el compilador mostrara un error.

El modo para el caso seria.
int16 result;
float resultado;

...
resultado=result/1000.0;
printf("texto %f",resultado);

...
 
Hola llevo tiempo liado con este proyecto, ya he conseguido que el codigo funcione decentemente y en la simulación me funciona perfectamente. El problema es cuando descargo el programa al pic y en las comprobaciones, metiendo la señal de un generador de frecuencias no atina ninguna frecuencia.

Me han comentado de montar un pequeño circuito con un amplificador operacional con mucha ganancia, para adaptar la señal de analogica a digital. Haber si alguien me puede ayudar o darme una pista, si voy mal encaminado o no. Os dejo un enlance con una imagen del montaje en el protheus.

Saludos y gracias a todos por ser tan grandes.
 
Respecto a la preguntaba que hacia sobre el montaje de A.O, monte uno que he visto un montaje de un frecuenciometro, que si no me equivoco era un seguidor de tensión con un LM384, pero sin exito en la simulación. Voy a probar con un ANI, pero no se que ganancia le tengo que dar ire probando.

Gracias y un saludo.
 

Adjuntos

  • Frecuenciometro pic.jpg
    Frecuenciometro pic.jpg
    102.1 KB · Visitas: 15
Hola foreros.
Aquí estamos dando alegría a la electrónica.
Después de varias comprobaciones y peleas con el frecuencímetro, he decidido cambiar de código, ya que en las pruebas reales había mucha diferencia de frecuencia entre lo que metía y me imprimía en el lcd y no me veía capacitado de hacer modificaciones con el assembler.

El código que he utilizado es para un PIC 16F877A, y he hecho unas modificaciones para que funcionen a mi gusto.
Lo único que tengo son unas dudas del código que me gustaría aclarar.

Para empezar la frecuencia que le entra por el pin c0, me imprime la mitad, me explico si le meto 1 Khz me imprime 500 Hz. Lo he solucionado multiplicando la variable por dos, pero no lo quiero dejar así.
Creo que el problema de este hecho, es que el timer del pic 16 es de 8 bits y el del 18 de 16 bits, pero tampoco pondría la mano en el fuego, que fuese por eso.
Y también tengo un par de dudas en unas instrucciones, el "set_tris_c(0x00);" tengo entendido que se utiliza para marcar el inicio de la escritura, pero no lo acabo de entender. Y luego la función "#byte portc=0x07" aquí no sé cual es su función y por mucho que he buscado no he encontrado nada.
Os dejo el código que estoy utilizando y el link de pagina de donde he sacado la información.

http://www.pic-tronics.com/Frequency-Counter-Using-PIC16F877A.php

Os agradecería mucho cualquier comentario o ayuda.
Saludos.

Código:
#include <18F4550.h> 
#fuses HS,NOWDT,NOCPD,NOLVP,NOPROTECT
#use delay(clock=16000000)
#use standard_io(D)     
#include <LCD_.C>  

#byte portc=0x07

unsigned int16 valor=0;
float freq=0;

void main()
{
   set_tris_c(0x00);
   lcd_iniciar();      
   delay_ms(100);     
   lcd_posicionar(5,1);
   printf(lcd_putc,"THEREMIN");
   output_low(PIN_D0); 

   while(1)
   {
      set_timer1(0);   
      setup_timer_1(t1_external | T1_DIV_BY_1);
      delay_ms(500);
   
      setup_timer_1(T1_DISABLED);
      valor=get_timer1();
      valor=valor*2;
      if(valor<=1000)
         {
            lcd_posicionar(5,2);
            printf(lcd_putc,"FREC=%LU HZ",valor);
            delay_ms(100);
         }
      else
         {
            freq=(float)valor/1000;     
            lcd_posicionar(5,2);
            printf(lcd_putc,"FREC=%.1fKhz",freq);     
            delay_ms(100);
         }   
            
   }
}
 
Última edición por un moderador:
Atrás
Arriba