View previous topic :: View next topic |
Author |
Message |
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
CCP2 capture problem |
Posted: Thu Apr 10, 2008 9:34 pm |
|
|
I am using CCP setup to capture a rising edge but it seems to be very inacurate. Am i doing something wrong?
here is my code. when i have tested it the serial isr have not been used.
i used a frequency generator for the interupt varing from 10 to 1000 Hz of a motor RPM of 600 to 60000 RPM.
Code: | #include <16F877a.H>
#device icd=true
#fuses HS, NOWDT, NOPROTECT, BROWNOUT, PUT, NOLVP
#use delay(clock = 4000000)
#use rs232(baud = 19200, xmit=PIN_C6, rcv = PIN_C7, ERRORS)
#include <Variables.c>
#include <Flex_LCD420.c>
#include <Initialize.c>
#include <Button_Scan.c>
#include <Display_LCD.c>
#include <Serial_Output.c>
#include <Sort_Input.c>
#include <Set_PID.c>
#include <Flash_LED.c>
#include <input.c>
#include <string.h>
//=====================================================================
#int_rda
void serial_isr()
{
i = 0;
for(i = 0; i < 32; i++) // if Set i upper limit to Serial_Array_Size(21) then will
//exit as soon as full and do not need return
{
value = getc();
Serial_Input[i] = value;
}
Display_Update = 1; // Update LCD
}
#int_ccp2
void isr()
{
Rise = CCP_2; // Capture rising edge
if (Rise < 125)
{Rise = 125;}
if (Rise > 60000)
{Rise = 60000;}
Actual_Speed = 75000/Rise; // [ 60s * (clock/4) / div_by ] / Pulse - must devide by 100 coz of rounding next line
Actual_Speed = Actual_Speed * 100; // Rounding to nearest 100
if (Actual_Speed != Old_Speed)
{ Speed_Update = 1;
PWM_Update = 1; }
Old_Speed = Actual_Speed;
set_timer1(0); // Reset timer
}
//=====================================================================
void main()
{
setup_timer_1(T1_INTERNAL|T1_DIV_BY_8);
setup_timer_2(T2_DIV_BY_16, 155, 1); //(1/4000000)*4*16*156=400.6Hz PWM
setup_ccp1(CCP_PWM); // Configure CCP1 as a PWM
setup_ccp2(CCP_CAPTURE_RE); // Configure CCP2 to capture fall
enable_interrupts(int_rda);
enable_interrupts(INT_CCP2);
enable_interrupts(GLOBAL);
Initialize();
while(1)
{
Flash_LED();
Button_Scan(); // Scan button matrix
if (Speed_Update == 1)
{
Display_LCD();
Speed_Update = 0;
}
if (Display_Update == 1)
{
Sort_Input_Array();
Display_LCD();
Serial_Output_Array();
Display_Update = 0;
}
if (PWM_Update == 1)
{
Set_PID();
set_pwm1_duty(PWM_Duty);
PWM_Update = 0;
}
}
} |
|
|
|
PCM programmer
Joined: 06 Sep 2003 Posts: 21708
|
|
Posted: Fri Apr 11, 2008 12:10 am |
|
|
You're not using interrupts in the normal way. Interrupts are supposed
to be a short, quick event that doesn't delay the main process or
other interrupts. But in your #int_rda routine, you lock-up the PIC
inside the routine for 32 character times. That's about 16 ms. You can't
service any other interrupts (such as the CCP) during that time.
Your CCP interrupt has some time-consuming math operations in it.
Look at the Ex_Sisr.c example file, to see how to get one character
for each RDA interrupt, and put it into a buffer.
Most of the CCP code could be moved to main().
http://www.ccsinfo.com/forum/viewtopic.php?t=29963 |
|
|
umka
Joined: 28 Aug 2007 Posts: 99 Location: New Zealand
|
|
Posted: Sat Apr 12, 2008 2:02 am |
|
|
Cheers PCM
so this is the code that i got working accurately.
Code: | #int_ccp2
void CCP2_isr()
{
Current_CCP2 = CCP_2; // Capture rising edge
ISR_CCP2_Delta = Current_CCP2 - Old_CCP2;
Old_CCP2 = Current_CCP2;
CCP2_Update = 1; // Set Flag
}
|
and then i do the RPM calculation in a the main routine when the CCP2_Update flag has been set
Code: | void Calculate_Speed()
{
disable_interrupts(GLOBAL);
Main_CCP2_Delta = ISR_CCP2_Delta;
enable_interrupts(GLOBAL);
Actual_Speed = 750000/Main_CCP2_Delta; // [ 60s * (clock/4) / div_by ]
Actual_Speed = Actual_Speed * 10; // Rounding to nearest 10
if (Actual_Speed != Old_Speed)
{ PWM_Update = 1; }
Old_Speed = Actual_Speed;
CCP2_Update = 0;
}
|
do i need to do the disable interupts then get int16 value and store as new variable and then enable interupts. |
|
|
|