CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to CCS Technical Support

Frequency counting using PIC16F876A

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

Frequency counting using PIC16F876A
PostPosted: Wed Jul 07, 2010 8:26 am     Reply with quote

I am trying to make a frequency counter using a PIC16F876A clocked by a 20Mhz XTAL.

The target is to design a system that has a resolution of 1LSB upto 1MHz. It is not necessary though that the PIC achieve this in isolation.

For example, if the PIC can count accurately till 100Khz, I would connect it to a 75HC4059 so that I can divide the original signal before connecting it to the PIC CCP1

Here is the core logic that I have managed so far:

Code:
#define START_OF_READING  0
#define MIDDLE_OF_READING    1
#define END_OF_READING   2

#define SAMPLE_COUNT 2

// being explicit about the types ( for quick readability )

unsigned int8 stateOfReading;

unsigned int8 timer1Overflow;

unsigned int16 uiCount, uiCountBefore, uiCountAfter, uiCountStart;

//int1 state = 0;
//#define printf

// Fires when timer1 overflows
#int_TIMER1
void  TIMER1_isr(void)
{
   ++timer1Overflow;

   //output_bit( PIN_C0, (state = !state));
}

#int_CCP1
void  CCP1_isr(void)
{
   /*
   output_bit( PIN_C0, state );
   state = !state;
   //*/
   uiCountStart = get_timer1();

   if ( stateOfReading == START_OF_READING )   // first edge has arrived
   {
      stateOfReading = MIDDLE_OF_READING;
      timer1Overflow = 0;
      set_timer1 ( 0 );     // restart timer on this edge
   }
   else if ( stateOfReading == MIDDLE_OF_READING ) // second edge has arrived
   {
      uiCountBefore = get_timer1();
      uiCount = CCP_1; // get capture value. *Theoretically* should be same as writing iCount = get_timer1(); ( Practically though, it never is even close ? Does the timer1 value get copied into CCP1 AFTER the ISR is serviced )
      uiCountAfter = get_timer1();

      stateOfReading = END_OF_READING;   // prevent further processing during this interrupt
   }
}



The driver:

Code:
void main()
{
   setup_adc_ports(NO_ANALOGS);

   setup_spi(SPI_SS_DISABLED);
   setup_timer_2(T2_DISABLED,0,1);
   setup_comparator(NC_NC_NC_NC);
   setup_vref(FALSE);

   setup_timer_1( T1_INTERNAL | T1_DIV_BY_4 );
   //setup_timer_1( T1_INTERNAL );

   setup_ccp1( CCP_CAPTURE_RE | CCP_CAPTURE_DIV_4 ); // Configure CCP1 to capture every 4th rising edge\
   //setup_ccp1( CCP_CAPTURE_RE );

   enable_interrupts(INT_TIMER1);
   enable_interrupts(INT_CCP1);
   //enable_interrupts(GLOBAL);
   disable_interrupts( GLOBAL );
   
   stateOfReading = END_OF_READING; // We don't want to set this to either START_OF_READING or MIDDLE_OF_READING - as that would let the ISR code execute

   unsigned int8 dx = 0;

   while( TRUE )
   {
      unsigned int32 totalTicks = 0;

      for ( dx = 0; dx < SAMPLE_COUNT; ++dx )
      {
         stateOfReading = START_OF_READING; // allow ISR to execute
         enable_interrupts( GLOBAL );

         while ( stateOfReading != END_OF_READING );

         disable_interrupts( GLOBAL );
         
         printf ( "[%d] timer1Overflow = %d, uiCount = %Lu/%Lu/%Lu/%Lu\r\n", dx, timer1Overflow, uiCountStart, uiCountBefore, uiCount, uiCountAfter  );

         totalTicks += ( 0x10000 * timer1Overflow ); /* Every overflow -> 65536 ticks */
         totalTicks += uiCountStart;
      }

      printf ( "RAW totalTicks = %Ld\r\n", totalTicks );

      totalTicks /= SAMPLE_COUNT;
   }
}


Once I connect this to a 100Hz signal, this is what I expect:

100Hz period = 10^4uS

As we have divided timer1 by 4, its resolution is 0.8uS and thus would give 10^4/0.8 = 12500 ticks

The CCP1 ISR being configured to fire after every 4th edge, the timer1 should have 4 times the above value = 4*12500 = 50000 ticks

50k ticks is well below 65536 ticks of timer1 and hence, at this sample freq., timer 1 should never overflow.

This is the output I get once I run my code:

Code:
[0] timer1Overflow = 3, uiCount = 3387/3392/3377/3396
[1] timer1Overflow = 3, uiCount = 3387/3392/3377/3396
RAW totalTicks = 399990


As we can see, timer1 overflowed 3 times ( = 3 * 65536 ticks ) and even after that counted up to 3387
This means, the sampling freq. triggered 3 * 65536 + 3387 = 199995 ticks

At 0.8uS for timer1, 199995 ticks = 6.25Hz

This is 16 times less than the actual frequency!

What is going wrong?
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

PostPosted: Thu Jul 08, 2010 12:11 am     Reply with quote

Did I make the code too complicated for people to understand?

:-(

I can try and make it simpler, shorter and well commented.
PCM programmer



Joined: 06 Sep 2003
Posts: 21708

View user's profile Send private message

PostPosted: Thu Jul 08, 2010 12:28 am     Reply with quote

Partly, but mainly it's that there are already several multi-page threads
on using the CCP to measure frequency:
http://www.ccsinfo.com/forum/viewtopic.php?t=33153
http://www.ccsinfo.com/forum/viewtopic.php?t=29963
http://www.ccsinfo.com/forum/viewtopic.php?t=36852
http://www.ccsinfo.com/forum/viewtopic.php?t=38013
I didn't want to do it over again.
vsmguy



Joined: 13 Jan 2007
Posts: 91

View user's profile Send private message Visit poster's website

PostPosted: Thu Jul 08, 2010 1:58 am     Reply with quote

I get it :-(

Do we have any details about the technique of measuring freq. in excess of internal core freq. using the timer0 "self clocking" technique ( input signal is gated and an extra pin is used to clock the prescale register ) on this forum ?

I wanted to read a good writeup on this technique so I could try it out.

Also - I believe that there is a max 40nS limit to timer0 pin which limits the freq. that can be measured by the PIC to 25Mhz?
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot vote in polls in this forum


Powered by phpBB © 2001, 2005 phpBB Group