|
|
View previous topic :: View next topic |
Author |
Message |
asseel
Joined: 13 Jun 2009 Posts: 6
|
long division |
Posted: Sat Jun 13, 2009 4:57 pm |
|
|
Hi, I'm a new member
I wrote my project code using capture command to find the time between two positive edge of square pulses. I declared long type parameter to represent the difference between two times that have been captured, but I can't calculate the parameters inverted (1/parameter), it always gives zero.
Here is my code
Code: |
#include <16F877.h>
#include <STDLIB.H>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay(clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
int1 flag;
long rise1,rise2,period, rate;
#int_ccp1
void isr()
{
if (flag==0)
{
rise1 = CCP_1;
flag=1;
}
else
if (flag==1)
{
rise2 = CCP_1;
period=rise2-rise1;
flag=0;
}
}
void main()
{
flag=0;
setup_ccp1(CCP_CAPTURE_RE); // Configure CCP1 to capture rise
setup_timer_1(T1_INTERNAL); // Start timer 1
enable_interrupts(INT_CCP1); // Setup interrupt on risining edge
enable_interrupts(GLOBAL);
while(TRUE) {
delay_ms(1000);
printf("\r period in us is %lu ", period);
// rate = 1 / period ;
// rate = ldiv(1, period);
// printf("\r rate is us %lu ", rate);
}
}
|
I used ex_CCPMP.c to help me in writing my code.
Thanks. |
|
|
asseel
Joined: 13 Jun 2009 Posts: 6
|
|
Posted: Sat Jun 13, 2009 6:37 pm |
|
|
hi its me again
I solve the previous problem by divide 1000000 over the parameter(1000000/parameter => "the result was very small so give0"and because the measured time is in us)
but now I have another problem that at low frequencies (below 15HZ) the calculation of the frequency (1/period) is incorrect.
Note:
I use 4MHz clock.
Period =difference between two captured time.
Please help me as soon as possible
Thanks |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Jun 14, 2009 12:33 am |
|
|
Yes, it's 16 Bit integer arithmetic, not a pocket calculater utilizing float numbers.
A 1 us period measurement has a range of 65.535 ms respectively 15.26 Hz. The range must be extended to measure lower frequencies. Because the used PIC has only 16 Bit timers, it's a bit complicated, involving e.g. a timer interrupt and a counter for period high word. A special issue results from the possibility of a timer captured after an overflow that hasn't been yet counted in the timer interrupt.
As another comment, rate must be of int32 type to give always correct results in your division. Long is int16 by default in CCS C. |
|
|
asseel
Joined: 13 Jun 2009 Posts: 6
|
|
Posted: Sun Jun 14, 2009 8:18 am |
|
|
Quote: |
The range must be extended to measure lower frequencies |
That supposed to minimize the delay (clock), or what?
How can I do that?
I try to minimize it to 2Mhz and the program works correct up to 7 Hz, with need to divide by 2 each time. |
|
|
FvM
Joined: 27 Aug 2008 Posts: 2337 Location: Germany
|
|
Posted: Sun Jun 14, 2009 11:19 am |
|
|
You should clarify your measurement specification, in case of frequency measurement intended range and resolution. I simply assumed that you want to keep the 1 µs period resolution but extend the period range above 65 ms. Then you have to count timer overflows and process the counter in the period and frequency calculation. |
|
|
asseel
Joined: 13 Jun 2009 Posts: 6
|
|
Posted: Sun Jun 14, 2009 2:17 pm |
|
|
thank you FvM
unfortunately I'm not expert and can not understand every thing you state above, i do search in this forum and i found this post:
http://www.ccsinfo.com/forum/viewtopic.php?t=906
its seem such as my problem, the timer overflowed before the CCP1 interrupt occur, so i have readings (for small frequencies < 2 Hz) give wrong captured values .
i understand from your talk that i have to extend timer 1 to 24 bit timer to avoid this problem, and i try to use the PCM programmer code here:
Code: |
//------------------------------------------------------------
// MACROS
// This macro allows us to insert a byte into the specified
// offset of a 16 or 32 bit variable. Example:
// *BytePtr(temp_long, 2) = 0x55;
// If temp_long is 0, the above line will make it become:
// 0x00550000
#define BytePtr(var, offset) (char *)(&var + offset)
// The Timer1 interrupt increments an 8-bit variable which
// extends the timer to 24 bits. We need this so we can
// avoid having to switch the Timer pre-scaler between "low"
// and "high" rpm ranges.
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}
//------------------------------------------------------
// When we get a CCP interrupt, read the CCP register and
// save it in a global variable.
#int_ccp1
void ccp1_isr(void)
{
char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp = 0;
// Set flag to indicate that we did a capture.
gc_capture_flag = TRUE;
current_ccp = (int32)CCPR1_REG; // Read the current CCP
// Get local copy of the timer ext.
timer_ext_copy = gc_timer1_extension;
// Check if a Timer1 interrupt is pending. If so, check if
// the CCP capture occurred before or after the Timer rolled
// over. We can tell if it occurred after it rolled over, if
// the CCP's MSB is zero. ie., if the CCP is somewhere between
// 0x0000 and 0x00FF.
// We know that we can just check if the MSB = 0x00, because
// it takes about 30 us to get into this ISR. (Using a 4 Mhz
// crystal on a 16F628). The timer increments at 1 us per
// count, so 0xFF = 255 us.
// Actually, to be safer, I'll give it 2 MSB counts, which is
// 511 us. That way, if I lengthen any of the other ISR's,
// we'll still be able to detect the roll-over OK.
// If the timer did roll over after we got a CCP interrupt,
// then we need to increment the timer extension byte, that we
// save. We have to do that because the CCP interrupt has
// priority, and so it executes before the Timer isr can
// execute and increment the extension.
// (Designing the code with the priority switched doesn't help.
// You still have the same type of problem. With CCP first,
// the fix is easier).
//
// Was CCP captured after Timer1 wrapped ?
// If so, increment the copy of the timer ext.
if(TMR1IF_BIT)
{
if(*BytePtr(current_ccp, 1) < 2)
timer_ext_copy++;
// 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_BIT = 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;
// Because we're using unsigned math, we don't have to worry
// if the current value is less than the old. The result is
// always the absolute value of the difference. The only way
// there could be a problem is if the new CCP value had rolled
// over twice. But with a 24-bit value, and a Timer
// pre-scalar of 1, that's 16.7 seconds. That's way beyond any
// practical value.
// Edited on Jan. 2, 2004: There was a bug in this routine,
// because I was promoting a 24-bit value to a 32-bit data type,
// but the upper byte was always left = 0. This caused a problem
// with the 32-bit subtraction when the 24-bit value rolled over past 0.
// Kenny spotted this error and provided a fix in a PM to me.
// I have commented out the original line, and inserted his fix, below.
//g32_ccp_delta = current_ccp - old_ccp;
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;
}
|
but many errors occur, i have lack of understanding of this criteria and i don't know how to use it.
my code again:
Code: |
#include <16F877.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay (clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
int1 flag,f;
long rise1,rise2,period,frq,in;
int32 rate;
int8 count;
#int_ccp1
void isr()
{
if (flag==0)
{
rise1 = CCP_1;
flag=1;
}
else
if (flag==1)
{
rise2 = CCP_1;
period=rise2-rise1;
flag=0;
}
}
void main()
{
flag=0;
f=0;
count=0;
setup_ccp1(CCP_CAPTURE_RE); // Configure CCP1 to capture rise
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8); // Start timer 1
enable_interrupts(INT_CCP1); // Setup interrupt on risining edge
enable_interrupts(GLOBAL);
while(TRUE) {
delay_ms(1000);
printf("\r period in us is %lu ", period);
rate =125000/period;
printf("\r rate is %lu ", rate);
}//while
}//main
|
i try to translate it onto:
Code: |
#include <16F877a.h>
#fuses XT,NOWDT,NOPROTECT,NOLVP
#use delay (clock=4000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7)
#define Byteptr(var,offset)(char *) (&var +offset)
int1 flag, cap_flag;
long rise1,rise2,period;
int32 rate;
int count;
#int_ccp1
void ccp1_isr()
{
/*char timer_ext_copy;
int32 current_ccp;
static int32 old_ccp=0;
cap_flag=1;
current_ccp= (int32)CCPR1_REG;
timer_ext_copy= count;
if (TMR1IF_BIT)
{
if(*Byteptr(current_ccp,1)<2)
timer_ext_copy++;
count++;
TMR1IF_BIT=0;
}//if (TMR1IF_BIT)
*Byteptr(current_ccp,2)=timer_ext_copy;
g32_ccp_delta= (current_ccp> old_ccp)? current_ccp - old_ccp : current_ccp+(0x10000000 - old_ccp);
*/
if (flag==0)
{
rise1 = CCP_1;
flag=1;
}
else
if (flag==1)
{
rise2 = CCP_1;
period=rise2-rise1;
flag=0;
}
}
/*
#INT_TIMER1
void timer1_isr()
{
count++;
}
*/
void main()
{
flag=0;
count=0;
setup_ccp1(CCP_CAPTURE_RE); // Configure CCP1 to capture rise
setup_ccp2(CCP_CAPTURE_FE);
setup_timer_1(T1_INTERNAL); // Start timer 1
enable_interrupts(INT_CCP1); // Setup interrupt on risining edge
enable_interrupts(GLOBAL);
while(TRUE) {
delay_ms(1000);
printf("\r period in us is %lu ", period);
rate =1000000/period;
printf("\r rate is %lu ", rate);
}
}
|
errors like :
Quote: | undefined identifier CCPR1_REG | appear
i know maybe this seem stupid a bit
thank you |
|
|
|
|
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
|