View previous topic :: View next topic |
Author |
Message |
Guest
|
Low frequency counting problem |
Posted: Mon Feb 22, 2010 2:32 pm |
|
|
I'm a new user of CCSC. My compiler version is 4.068. I found a code for counting very low pulses. (Frequency will be 0.5Hz-3Hz) But this code doesn't work under 10Hz. Where is my mistake? How can I fix it?
Code: |
#include <16F877.H>
#fuses XT, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, bits=8)
int16 isr_ccp_delta;
#int_ccp1
void ccp1_isr(void)
{
int16 current_ccp;
static int16 old_ccp = 0;
current_ccp = CCP_1; // From 16F877.H file
isr_ccp_delta = current_ccp - old_ccp;
old_ccp = current_ccp;
}
//=======================
void main()
{
int16 current_ccp_delta;
int16 frequency;
set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
setup_ccp1(CCP_CAPTURE_RE);
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
while(1)
{
disable_interrupts(GLOBAL);
current_ccp_delta = isr_ccp_delta;
enable_interrupts(GLOBAL);
frequency = (625000L + (int32)(current_ccp_delta >>1)) / current_ccp_delta;
// Display the calculated frequency.
printf("\n\r%lu Hz\n\r", frequency);
delay_ms(500);
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
|
Guest
|
|
Posted: Mon Feb 22, 2010 2:58 pm |
|
|
Ok I found a code. But I couldn't understand some points:
Code: |
#define BytePtr(var, offset) (char *)((char*)&var + offset)
and
g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);
|
Could you explain these code?
Thanks.... |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Mon Feb 22, 2010 3:27 pm |
|
|
The first one allows you to write to a specified byte in a 16 or 32 bit
variable that is an "lvalue" (i.e., the variable is on the left side of an
assignment).
The 2nd one is a fix for a sign-extension problem when doing 24-bit
math in 32-bit variables. |
|
|
Guest
|
|
Posted: Thu Feb 25, 2010 11:41 am |
|
|
I have found a code for frequency counting. But this code doesn't work in real hardware. Could you show my mistake?
Code: |
#include <18F452.H>
#fuses HS,NOWDT, PUT, BROWNOUT, NOLVP // 20 MHz xtal
#use delay(clock=20000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#priority CCP1, TIMER1
#define BytePtr(var, offset) (char *)((char*)&var + offset)
#byte PIR1 = 0xF9E
#bit TMR1IF = PIR1.0
int8 gc_timer1_extension = 0;
int8 gc_capture_flag = FALSE;
int32 g32_ccp_delta;
//------------------------------------------------------
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}
//------------------------------------------------------
#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;
gc_capture_flag = TRUE;
current_ccp = (int32)CCP_1;
// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension;
if(TMR1IF)
{
if(*BytePtr(current_ccp, 1) < 2) // Was CCP captured after Timer1 wrapped?
timer_ext_copy++; // If so, inc the copy of the timer ext.
// Since we know a timer interrupt is pending, let's just
// handle it here and now. That saves a little load off
// the processor.
gc_timer1_extension++; // Increment the real timer extension
TMR1IF = 0; // Then clear the Timer1 interrupt
}
// Insert the timer extension into the proper place in the 32-bit
// CCP value.
// ie., Insert it into location "EE" as follows: 0x00EEnnnn
// (nnnn = the CCP).
*BytePtr(current_ccp, 2) = timer_ext_copy;
g32_ccp_delta = (current_ccp > old_ccp) ? current_ccp - old_ccp : current_ccp + (0x1000000 - old_ccp);
// Save the current ccp value for next time.
old_ccp = current_ccp;
}
//=======================
void main()
{
set_timer1(0);
setup_timer_1(T1_INTERNAL | T1_DIV_BY_1);
setup_ccp1(CCP_CAPTURE_RE);
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
while(true)
{
float frequency;
int32 current_ccp_delta;
if(gc_capture_flag == TRUE)
{
disable_interrupts(GLOBAL);
current_ccp_delta = g32_ccp_delta;;
enable_interrupts(GLOBAL);
frequency = (5000000L / (float)current_ccp_delta);
printf("%4.2f\n\r", frequency);
gc_capture_flag = FALSE;
}
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Feb 25, 2010 11:45 am |
|
|
What device is providing the input signal to the CCP1 pin ?
What is the frequency of the input signal ?
What are the voltage levels of the signal ?
What is the duty cycle of the signal ?
Is the signal a rectangular waveform, or sinusoidal ?
Is the signal a clean, continuous, frequency signal ? |
|
|
Guest
|
|
Posted: Thu Feb 25, 2010 2:10 pm |
|
|
1-Heart beat signal (From analog circuit)
2-Frequency will be 0.5Hz - 4Hz
3-The voltage level will be 0 to 4-4.5 V
4-Approximately %50
5-It likes rectangular signal
6-The Signal has some noise but not too much. |
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Thu Feb 25, 2010 3:30 pm |
|
|
It works for me. I connected a B&K Function Generator (model 4011)
to pin C2 of my PicDem2-Plus board. This is the CCP1 input pin. I also
connected the ground lead from the B&K to the ground on the PicDem2-
Plus board. I set the B&K to output a square wave signal at 1 Hz, with
CMOS (0 to 5v) logic levels.
Then I slowly turned the Coarse adjustment frequency knob on the B&K
so it increased the frequency of the signal going to the PIC. Here is
what I see on the TeraTerm window on my PC:
Quote: |
0.99
1.00
1.00
1.00
1.00
0.99
0.99
0.99
0.99
1.00
1.03
1.40
1.55
1.70
1.88
2.02
2.15
2.22
2.32
2.47
2.48
2.71
3.07
3.35
3.62
3.79
3.96
4.22
4.54
4.96
5.46
5.77
5.80
5.80
5.79
5.79
|
That's correct. The frequency goes up. Also, my oscilloscope has a
built-in frequency counter. It verifies that the signal is about 5.78 Hz.
So, it's all working. I tested this with the PCH compiler, vs. 4.104. |
|
|
|