PIC 16f877a frequency counter

Discussion in 'Embedded Systems and Microcontrollers' started by dmta, Jun 18, 2013.

  1. dmta

    Thread Starter Member

    Mar 24, 2013
    32
    1
    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 ( (Unknown Language)):
    1. [CODE=rich]sbit LCD_RS at RB2_bit;
    2. sbit LCD_EN at RB3_bit;
    3. sbit LCD_D4 at RB4_bit;
    4. sbit LCD_D5 at RB5_bit;
    5. sbit LCD_D6 at RB6_bit;
    6. sbit LCD_D7 at RB7_bit;
    7. sbit LCD_RS_Direction at TRISB2_bit;
    8. sbit LCD_EN_Direction at TRISB3_bit;
    9. sbit LCD_D4_Direction at TRISB4_bit;
    10. sbit LCD_D5_Direction at TRISB5_bit;
    11. sbit LCD_D6_Direction at TRISB6_bit;
    12. sbit LCD_D7_Direction at TRISB7_bit;
    13.  
    14. int kk  = 0;
    15. int fr  = 0;
    16. int cnt = 0;
    17. int rit = 0;
    18. int acc = 0;
    19. int i   = 0;
    20. int fra[10];
    21.  
    22. char CN[10];
    23.  
    24. void interrupt() {
    25.  
    26.      if(INTCON.TMR0IF == 1){
    27.           fr = (cnt + kk*256)*(1000000)/(256*256); //4MHz crystal, 256 Timer0 increment rate
    28.          /*if(acc<10){         ///
    29.                fra[acc] = fr; ///Counted frequencies are put into an array
    30.                acc++;         ///
    31.           }
    32.           else if(acc >= 10){
    33.                acc = 0;
    34.                for(i=0;i<10;++i){       ///
    35.                    rit = rit + fra[i];  ///Average frequency is calculated
    36.                }                        ///
    37.           rit = rit/10;                 ///
    38.           }*/
    39.      cnt = 0;
    40.      kk  = 0;
    41.      INTCON.TMR0IF=0;
    42.      }
    43.  
    44.     if(INTCON.INTF == 1){
    45.          cnt++;
    46.          if(cnt>=256){
    47.               cnt = 0;
    48.               kk++;
    49.          }
    50.     INTCON.INTF = 0;
    51.     }
    52. }
    53.  
    54. void main() {
    55.  
    56.      Lcd_Init();
    57.      Lcd_Cmd(_LCD_CLEAR);
    58.      Lcd_Cmd(_LCD_CURSOR_OFF);
    59.      
    60.      PWM1_Init(1000);
    61.      PWM1_Set_Duty(100);
    62.      PWM1_Start();
    63.  
    64.      INTCON.GIE        = 1; //Enable Global Interrupt
    65.      INTCON.INTE       = 1; //Enable RB0/INT external Interrupt
    66.      INTCON.TMR0IE     = 1; //Enable TMR0 Overflow Interrupt
    67.      
    68.      OPTION_REG.T0CS   = 0; //Timer0 increments with Internal instruction cycle clock
    69.      OPTION_REG.PSA    = 0; //Prescaler is assigned to the Timer0 module
    70.      OPTION_REG.PS2    = 1; ////
    71.      OPTION_REG.PS1    = 1; ////Timer0 increments every 256 instruction cycles
    72.      OPTION_REG.PS0    = 1; ////
    73.      OPTION_REG.INTEDG = 1; //Interrupt on rising edge
    74.      
    75.      while(1){
    76.      
    77.            IntToStr(fr,CN);
    78.            Lcd_Out(1,1,CN); //Display the average frequency
    79.      
    80.      }
    81.  
    82. }[/i][/CODE][i][/i]
     
  2. ErnieM

    AAC Fanatic!

    Apr 24, 2011
    7,386
    1,605
    There's much room for improvement here, but to start write out how you are making your measurement. With no schematic and just some code I can't tell why you hit the interrupt routine (IRS) and what you are calculating. I would have to guess your expected frequency range, accuracy... everything.

    Inside the ISR you want to do a minimum, meaning don't do calculations there. Save off the value, reset for the next measurement, set a DONE flag, and exit. Your main loop checks the DONE flag, calculates, writes to display, resets DONE, and loops.

    Using INT over FLOAT makes for faster code. If you can't fit into an int use a long int. And since frequency is always positive use an unsigned int or long (which is also faster too)

    When computing don't compute anything you can per-compute, meaning don't divide by (256*256) divide by (14336). Dig thru that entire calculation and pull out anything that can be computed NOW and not every time you loop.

    Have to leave for work... I'm sure others will dog pile on your rabbit now.
     
Loading...