|
|
View previous topic :: View next topic |
Author |
Message |
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
Frequency counting using PIC16F876A |
Posted: Wed Jul 07, 2010 8:26 am |
|
|
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
|
|
Posted: Thu Jul 08, 2010 12:11 am |
|
|
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
|
|
|
vsmguy
Joined: 13 Jan 2007 Posts: 91
|
|
Posted: Thu Jul 08, 2010 1:58 am |
|
|
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? |
|
|
|
|
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
|