![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
ELCouz
Joined: 18 Jul 2007 Posts: 427 Location: Montreal,Quebec
|
Input Capture.... |
Posted: Fri Feb 20, 2015 5:25 pm |
|
|
I've seen that many things have changed (compiler wise) since my last project with CCP in 2007 (somewhere around V4.045)...
Now on the PIC24HJ128GA010 I have 5 Input Capture module...
Do this old code (for v3 wrote by PCM Programmer, to read signal frequency) still apply to the current gen compiler (v5.042):
Code: |
#include <18f2553.h>
#fuses HSPLL,PLL3,CPUDIV1,NOWDT,NOPROTECT,NOLVP,NODEBUG,NOMCLR
#use delay(clock=48000000)
#use rs232(baud=9600,parity=N,xmit=PIN_C6,rcv=PIN_C7,bits=8)
#define BytePtr(var, offset) (char *)(&var + offset)
#byte PIR1 = 0xF9E
#bit TMR1IF = PIR1.0
#byte CCPR1_REG = 0xFBE
#byte T1CON = 0x8F
// This global variable holds the time interval
// between two consecutive rising edges of the
// input signal.
int16 isr_ccp_delta;
int32 g32_ccp_delta;
char gc_timer1_extension;
BOOLEAN gc_capture_flag;
#int_timer1
void timer1_isr(void)
{
gc_timer1_extension++;
}
// When a rising edge occurs on the input signal,
// the CCP1 will 'capture' the value of Timer1
// at that moment. Shortly after that, a CCP1
// interrupt is generated and the following isr
// is called. In the isr, we read the 'captured'
// value of Timer1. We then subtract from it the
// Timer1 value that we 'captured' in the previous
// interrupt. The result is the time interval
// between two rising edges of the input signal.
// This time interval is then converted to a frequency
// value by code in main().
#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)CCP_1; // 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(interrupt_active(INT_TIMER1))
{
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
clear_interrupt(INT_TIMER1); ; // 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;
}
//=======================
void main()
{
int32 current_ccp_delta;
int16 frequency;
clear_interrupt(INT_TIMER1);
enable_interrupts(INT_TIMER1);
delay_us(20);
// Setup Timer1 and CCP1 for Capture mode so that
// we can measure the input signal's frequency.
// The input signal comes from the CCP2 pin, which
// is connected to the CCP1 pin with a wire.
set_timer1(0);
setup_timer_1(T1_EXTERNAL|T1_DIV_BY_1|T1_CLK_OUT);
setup_ccp1(CCP_CAPTURE_RE);
// Clear the CCP1 interrupt flag before we enable
// CCP1 interrupts, so that we don't get an unwanted
// immediate interrupt (which might happen).
clear_interrupt(INT_CCP1);
enable_interrupts(INT_CCP1);
enable_interrupts(GLOBAL);
while(1)
{
// Now calculate the frequency.
// Get a local copy of the latest ccp delta from the isr.
// We have to disable interrupts when we read a global
// isr variable that is larger than a single byte.
disable_interrupts(GLOBAL);
current_ccp_delta = g32_ccp_delta;
enable_interrupts(GLOBAL);
// To calculate the frequency of the input signal,
// we take the number of clocks that occurred
// between two consecutive edges of the input signal,
// and divide that value into the number of Timer1
// clocks per second. Since we're using a 4 MHz
// crystal, the Timer1 clock is 1 MHz (Timer1 runs
// at the instruction cycle rate, which is 1/4 of the
// crystal frequency). For example, suppose the
// the input waveform has a frequency of 244 Hz.
// 244 Hz has a period of about 4098 usec.
// Timer1 is clocked at 1 MHz, so between two
// consecutive rising edges of the input signal,
// it will count up by 4098 clocks. To find the
// frequency, we divide 4098 into the number of
// clocks that occur in 1 second, which is 1000000.
// This gives 1000000 / 4098 = 244 Hz.
if(gc_capture_flag == TRUE)
{
frequency = (int16)((32768L + (current_ccp_delta >> 1)) / current_ccp_delta);
printf(" %lu Hz ", frequency);
gc_capture_flag = FALSE;
delay_ms(1000);
}
else
{
printf(" No signal ");
delay_ms(1000);
}
}
}
|
I've seen new functions like #use capture / get_capture
Any example snippet of code for the "new features" to read the frequency (PIC24 compatible) ?
Thank you very much! _________________ Regards,
Laurent
-----------
Here's my first visual theme for the CCS C Compiler. Enjoy! |
|
![](templates/subSilver/images/spacer.gif) |
ELCouz
Joined: 18 Jul 2007 Posts: 427 Location: Montreal,Quebec
|
|
![](templates/subSilver/images/spacer.gif) |
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Sat Feb 21, 2015 12:18 am |
|
|
I noticed that I don't have the ex_capture.c file. I guess you only get it if
you have the PCD compiler.
I looked at the .LST file and I note that the #use capture() library doesn't
use interrupts for the PCM and PCH compilers. It does it by software
polling of the CCP interrupt flag in the PIR1 register. So I have to say
my "old" code is better.
The code below is a simple demo of #use capture() and #use pwm().
If the signal is not present, the code will stay stuck in a while() loop
forever. But it does work. Here is the output on the TeraTerm window:
Code: |
Start
500.0 Hz
500.0 Hz
500.0 Hz
500.0 Hz
500.0 Hz
500.0 Hz
500.0 Hz
|
Code: | #include <18F4620.h>
#fuses INTRC_IO, BROWNOUT, PUT, NOWDT
#use delay(clock=4M)
#use rs232(baud=9600, UART1, ERRORS)
// Setup CCP1 to capture on the rising edge
// of the input signal on Pin C2. Run Timer1
// with a divisor of 1, by selecting "FASTEST".
#use capture(CCP1, FASTEST, CAPTURE_RISING)
// Use CCP2 to generate a 500 Hz test signal
// on Pin C1. Connect it to the CCP1 input
// with a jumper between pins C2 and C1.
#use pwm(CCP2, FREQUENCY=500, DUTY=50)
//===================================
void main()
{
int16 first_timer_value;
int16 second_timer_value;
int16 capture_time;
float frequency;
printf("Start\n\r");
first_timer_value = 0;
second_timer_value = 0;
capture_time = 0;
while(TRUE)
{
while(!get_capture_event());
first_timer_value = get_capture_time();
while(!get_capture_event());
second_timer_value = get_capture_time();
capture_time = second_timer_value - first_timer_value;
frequency = (float)(getenv("CLOCK")/4) / capture_time;
printf("%7.1f Hz \n\r", frequency);
delay_ms(1000);
}
} |
|
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|