Continue to Site

Welcome to our site!

Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

  • Welcome to our site! Electro Tech is an online community (with over 170,000 members) who enjoy talking about and building electronic circuits, projects and gadgets. To participate you need to register. Registration is free. Click here to register now.

PIC 16f877a frequency counter

Status
Not open for further replies.

dmta

Member
Hi all,

I am trying to make a frequency counter and wrote some code. I wanted to use a frequency averaging part to make things more accurate. But when I run the code with the averaging part it acts funny (at frequencies close to 10kHz).

Also please give me some pointers to the variable declaration (eg int, float etc) as I am pretty sure me using "int" is wrong. Furthermore the way I am doing the calculations, is there a better/faster way of doing them.

I'm using a PIC16F877A with 4MHz crystal.

Regards

Code:
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;
sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

int kk  = 0;
int fr  = 0;
int cnt = 0;
int rit = 0;
int acc = 0;
int i   = 0;
int fra[10];

char CN[10];

void interrupt() {

     if(INTCON.TMR0IF == 1){
          fr = (cnt + kk*256)*(1000000)/(256*256); //4MHz crystal, 256 Timer0 increment rate
         /*if(acc<10){         ///
               fra[acc] = fr; ///Counted frequencies are put into an array
               acc++;         ///
          }
          else if(acc >= 10){
               acc = 0;
               for(i=0;i<10;++i){       ///
                   rit = rit + fra[i];  ///Average frequency is calculated
               }                        ///
          rit = rit/10;                 ///
          }*/
     cnt = 0;
     kk  = 0;
     INTCON.TMR0IF=0;
     }

    if(INTCON.INTF == 1){
         cnt++;
         if(cnt>=256){
              cnt = 0;
              kk++;
         }
    INTCON.INTF = 0;
    }
}

void main() {

     Lcd_Init();
     Lcd_Cmd(_LCD_CLEAR);
     Lcd_Cmd(_LCD_CURSOR_OFF);
     
     PWM1_Init(1000);
     PWM1_Set_Duty(100);
     PWM1_Start();

     INTCON.GIE        = 1; //Enable Global Interrupt
     INTCON.INTE       = 1; //Enable RB0/INT external Interrupt
     INTCON.TMR0IE     = 1; //Enable TMR0 Overflow Interrupt
     
     OPTION_REG.T0CS   = 0; //Timer0 increments with Internal instruction cycle clock
     OPTION_REG.PSA    = 0; //Prescaler is assigned to the Timer0 module
     OPTION_REG.PS2    = 1; ////
     OPTION_REG.PS1    = 1; ////Timer0 increments every 256 instruction cycles
     OPTION_REG.PS0    = 1; ////
     OPTION_REG.INTEDG = 1; //Interrupt on rising edge
     
     while(1){
     
           IntToStr(fr,CN);
           Lcd_Out(1,1,CN); //Display the average frequency
     
     }

}
 
You're counting INT0 interrupts one at a time, that's really going to limit your upper max freq and is the first time I've seen it done that way. Also IRQ routines should be fast.
Normally folks count with TIMER1 connected to the external frequency source. Better yet a PIC with a gated timer input makes frequency counting accurate and easy.

PS instead of base 10 math (takes lots of CPU overhead) how about 8 samples as you can just shift right 3 times to divide by 8 (very fast) >>3
 
hi thank you blueroomelectronics for your reply. As you said now i'm trying with the TIMER1 register. I wrote a code to count the pulses input to the CCP1 pin but I'm doing omething wrong. Can you please take a look at it ?

Code:
sbit LCD_RS at RB2_bit;
sbit LCD_EN at RB3_bit;
sbit LCD_D4 at RB4_bit;
sbit LCD_D5 at RB5_bit;
sbit LCD_D6 at RB6_bit;
sbit LCD_D7 at RB7_bit;
sbit LCD_RS_Direction at TRISB2_bit;
sbit LCD_EN_Direction at TRISB3_bit;
sbit LCD_D4_Direction at TRISB4_bit;
sbit LCD_D5_Direction at TRISB5_bit;
sbit LCD_D6_Direction at TRISB6_bit;
sbit LCD_D7_Direction at TRISB7_bit;

void main() {

     int total = 0;
     int max   = 0;

     char CN[10];
     char CB[10];
     
     TRISC.F2 = 1;

     Lcd_Init();
     Lcd_Cmd(_LCD_CLEAR);
     Lcd_Cmd(_LCD_CURSOR_OFF);
     
     CCP1CON.CCP1M3 = 0;
     CCP1CON.CCP1M2 = 1;
     CCP1CON.CCP1M1 = 0;
     CCP1CON.CCP1M0 = 1;
     
     INTCON.CCP1IE = 1;
     
     while(1){
     
          total = CCPR1H*256 + CCPR1L;
          if (total == 0b1111111111111111){
               CCPR1H = 0;
               CCPR1L = 0;
          }
          IntToStr(total,CN);
          Lcd_Out(1,1,CN);
          
          if(max<total){
               max = total;
          }
          
          IntToStr(max,CB);
          Lcd_Out(2,1,CB);
     
     }

}
 
Where's the timebase clock (a Timer, perhaps TIMER2)?

You need a counter (timer1) and a timebase (timer2). Timer1 counts external pulses on RC0 or T1CKI. You've got to rewire your circuit (PS post your schematic)

Also use <<8 instead of *256 for speed!
 
Status
Not open for further replies.

Latest threads

Back
Top