Author Topic: Frequency counter with PIC16F877A  (Read 5650 times)

0 Members and 1 Guest are viewing this topic.

Offline BernhardTopic starter

  • Beginner
  • *
  • Posts: 4
  • Helpful? 1
Frequency counter with PIC16F877A
« on: May 02, 2011, 10:32:21 AM »
Hi. I'm working on a project to count the number of interruptions per second. I found this frequency counter schematic and modified the PIC program. Mainly the code counts the number of "1s" on RB0, convert it into decimal, then shows it on the common cathode ssd. The problem I have is showing the number of interruptions in digits because it is supposed to show 1s in 150us, then 10s in 150us, then 100s 150us after, etc... but it only refreshes all seven segment display at the same time. So I can see digit, only the display turned on.
Here is my code and schematic.

///////////////////////////////////////////////////////////////////////////////////////////////////////////
// Project :  Simple frequency counter using PIC16F877A, crystal frequency 4Mhz
// compiler : HITEC PICC
///////////////////////////////////////////////////////////////////////////////////////////////////////////


#define PIC_CLK 4000000
#include <pic.h>

///////////////////////////////////////////////////////////////////

__CONFIG(XT & WDTDIS & PWRTDIS & BORDIS & LVPDIS );

///////////////////////////////////////////////////////////////////

unsigned long   cntr ;          // number of RB0 transition
unsigned int    ovrflw ;          // number of timer0 overflows
unsigned long   x ;
unsigned int    y ;

///////////////////////////////////////////////////////////////////

unsigned char digit0, digit1, digit2, digit3;
const char ssd[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//SSD mask for common cathode type

///////////////////////////////////////////////////////////////////


unsigned char delayus_variable;

#if (PIC_CLK == 4000000)
    #define dly1u asm("nop")
    #define dly2u dly1u;dly1u
#endif

//*****
//delay routine


#if PIC_CLK == 4000000
    #define DelayDivisor 4
    #define WaitFor1Us asm("nop")
    #define Jumpback asm("goto $ - 2")
#endif


void decode(unsigned int value){

    digit3=value/1000;
    digit2=(value%1000)/100;
    digit1=(value%100)/10;
    digit0=(value%10);
}

 
void DelayUs(unsigned char x) {
   delayus_variable=(unsigned char)(x/DelayDivisor);
   WaitFor1Us;
}  


unsigned char delayus_variable;

void DelayBigUs(unsigned int cnt)
{
    unsigned char    i;

    i = (unsigned char)(cnt>>8);
    while(i>=1)
    {
        i--;
        DelayUs(253);
        CLRWDT();
    }
    DelayUs((unsigned char)(cnt & 0xFF));
}

void DelayMs(unsigned char cnt)
{
    unsigned char    i;
    do {
        i = 4;
        do {
            DelayUs(250);
            CLRWDT();
        } while(--i);
    } while(--cnt);
}

//this copy is for the interrupt function
void DelayMs_interrupt(unsigned char cnt)
{
    unsigned char    i;
    do {
        i = 4;
        do {
            DelayUs(250);
        } while(--i);
    } while(--cnt);
}

void DelayBigMs(unsigned int cnt)
{
    unsigned char    i;
    do {
        i = 4;
        do {
            DelayUs(250);
            CLRWDT();
        } while(--i);
    } while(--cnt);
}

void DelayS(unsigned char cnt)
{
    unsigned char i;
    do {
        i = 4;
        do {
            DelayMs(250);
            CLRWDT();
        } while(--i);
    } while(--cnt);
}
///////////////////////////////////////////////////////////////////

void display(){
    unsigned char i;
    for(i=0;i<5;i++){
        PORTD=0b00000001;
        PORTC=ssd[digit0];
  DelayUs(150);
        PORTD=0b00000010;
        PORTC=ssd[digit1];
  DelayUs(150);
        PORTD=0b00000100;
        PORTC=ssd[digit2];
 DelayUs(150);
        PORTD=0b00001000;
        PORTC=ssd[digit3];
 DelayUs(150);
    }
}

///////////////////////////////////////////////////////////////////
 
main(){
      TRISD=0b11110000;
    TRISC=0; //
     TRISB = 3 ;                 //input
///////////////////////

    OPTION = 0b11011000 ;       //no prescaler
       INTCON = 0b10110000 ;       //T0IF, INTF and GIE enabled  

while(1){
 if (RB1 == 1) y=(x/1000);        //for scaling Display to KHz

     else y=x;

        decode(y);                //Display frequency on Seven Segment Display
        display();

    }
}
///////////////////////////////////////////////////////////////////

/* * interrupt routine called 4000000/256 times by seconds :
* the timer TMR0 is increased each 4 clock cycles (quartz frequency is 16 Mhz),
* and overflows when reseting from 255 to 0,
* calling the interrupt procedure with bit T0IF set
* * also called on each RBO transition, with bit INTF set */

void interrupt isr(void){

    if ((INTF)){
        cntr++ ;                        // inc. transition counter
        INTF = 0 ;                       // clear interrupt flag to enable next call
    }
        else if(T0IF==1){
            ovrflw++ ;                  // inc. overflow counter
            T0IF = 0 ;                   // clear interrupt flag to enable next call on overflow
        }
            if (ovrflw > 3906)   {        // 4000000/ 4/ 256 = 3906.25
                   GIE = 0;
                   x=cntr;
                   cntr = 0 ;             // clear counters
                   ovrflw = 0 ;
                   INTCON = 0b10110000 ;  // T0IF, INTF and GIE enabled
               }
}


I added 330ohm resistors on every segment. Thanks for any help!




Offline vinniewryan

  • Full Member
  • ***
  • Posts: 56
  • Helpful? 2
Re: Frequency counter with PIC16F877A
« Reply #1 on: May 02, 2011, 03:16:55 PM »
Have you tested the outputs of the pins driving the display? Make sure your MCU's output pins to the display are working correctly by testing them with a scope, or in this case LED's may do. If your output's are all constantly high then something is wrong with the program. I dont have time to look over the program right now, so test the outputs, then test the segments of your display by powering them to make sure your display is not the cause of the problem. Check the datasheet for your PIC to make sure your pullups are configured correctly.

Offline Soeren

  • Supreme Robot
  • *****
  • Posts: 4,672
  • Helpful? 227
  • Mind Reading: 0.0
Re: Frequency counter with PIC16F877A
« Reply #2 on: May 02, 2011, 03:33:43 PM »
Hi,

This really ought to go into "Software", as I suppose you didn't change the schematic.

What exactly did you change in the code?
(It's likely the place where it went sour).
Regards,
Søren

A rather fast and fairly heavy robot with quite large wheels needs what? A lot of power?
Please remember...
Engineering is based on numbers - not adjectives

Offline BernhardTopic starter

  • Beginner
  • *
  • Posts: 4
  • Helpful? 1
Re: Frequency counter with PIC16F877A
« Reply #3 on: May 02, 2011, 05:11:16 PM »
I checked all connections including testing the seven segment wiring. I'm sure its a software problem and i guess it might be a small thing but i cant find it.
It included a header file called Delay.h with the delay routines. I tried to build all together gut got several errors, so I moved the Delay.h code to this main Source file and got no errors. I'm using Mplab.

Offline waltr

  • Supreme Robot
  • *****
  • Posts: 1,944
  • Helpful? 99
Re: Frequency counter with PIC16F877A
« Reply #4 on: May 02, 2011, 06:30:24 PM »
Have you run your code in the MPLAB Simulator?

Try breaking the code into sections to test.
Ensure that the output to the display does what you expect then do the counting.

Offline Soeren

  • Supreme Robot
  • *****
  • Posts: 4,672
  • Helpful? 227
  • Mind Reading: 0.0
Re: Frequency counter with PIC16F877A
« Reply #5 on: May 02, 2011, 08:39:16 PM »
Hi,

Might be a good idea to increase the delays to something detectable by eye temporarily.
It will mangle the rest of the functionality, but will be an easy way to get the mux'ing in place (just use dummy data while doing it).
Regards,
Søren

A rather fast and fairly heavy robot with quite large wheels needs what? A lot of power?
Please remember...
Engineering is based on numbers - not adjectives

 

SMF spam blocked by CleanTalk