CCS C Software and Maintenance Offers
FAQFAQ   FAQForum Help   FAQOfficial CCS Support   SearchSearch  RegisterRegister 

ProfileProfile   Log in to check your private messagesLog in to check your private messages   Log inLog in 

CCS does not monitor this forum on a regular basis.

Please do not post bug reports on this forum. Send them to support@ccsinfo.com

Problem with timer 1

 
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion
View previous topic :: View next topic  
Author Message
leejok2003
Guest







Problem with timer 1
PostPosted: Fri Dec 05, 2008 6:36 am     Reply with quote

Hi, I am a newbie in using PIC and writing its program. I am currently doing a heart beat sensor that display the heart beat result once the heart beat is read.
The idea is using timer1 and ccp1. The output becomes inaccurate when the internal timer 1 reset. I am using the no. of counts inside the timer1 subroutine times the period time (55500us) to get the pulse period and divide by 60s to get the no. of pulse in a minute. How can this problem be solved?
Code:

#include <18f4620.h>
#use delay(clock=20000000)
#fuses HS,NOWDT
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)

int count=0;
unsigned long int start_time, end_time,width,overflow_count,time;
float heart;


#int_TIMER1
TIMER1_isr()
{
    overflow_count=overflow_count+1; //increment whenever an overflow occurs
   
   
}

#int_CCP1
CCP1_isr()
{
   end_time = CCP_1;
   time= get_timer1();
   printf("\r\n timer= %lu", time);
 
   ++count;
   printf("\r\n count= %d", count);
   
   printf("\r\n overflow count= %lu",overflow_count);
   heart= 60000000/overflow_count/55500;
   printf("\r\n heart= %f",heart);

   overflow_count = 0;//clear overflow counts
   start_time = end_time;  //end time of this pulse is the start time for the next one

   
}

void main()
{
   setup_ccp1(CCP_CAPTURE_RE);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_4);//set timer1 to run at system clock/4
   enable_interrupts(INT_TIMER1);  //unmask Timer1 overflow interrupt
   enable_interrupts(INT_CCP1);    //unmask capture event interrupt
   enable_interrupts(global);      //enable all unmasked interrupts
   
   while(1);  //as usual, the main() function does nothing
}
Ttelmah
Guest







PostPosted: Fri Dec 05, 2008 9:43 am     Reply with quote

Start by taking the code out of the CCP interrupt. Simply record the count, and set a flag. Have your main loop, wait for this flag, make a copy of the recorded time, clear the flag, and then perform the maths/printing.
The problem is that printing, and airthmetic, are _slow_. Your code in the CCP interrupt, takes something well over 60mSec to execute, and probably nearer 100mSec. Though the interrupt flags can get set in this time, if it happens more than once for the CCP, the earlier count _will_ be lost. The chances of this happening increase as count values are larger (more characters to print).
You also have a problem with your arithmetic. Though 'heart' is a floating point value, the actual sum, contains only an int_16, and an int_32 constant. The arithmetic, will therefore be done using _integer_ arithmetic, and the printed value for heart will not be what you want.
Remember that division is always slower than multiplication, so better to multiply by 1.82E-5, which will force floating point arithmetic to be used, yet be quicker, than dividing by 55000.

Best Wishes
leejok2003
Guest







PostPosted: Fri Dec 05, 2008 1:05 pm     Reply with quote

Thanks for the advice, Ttelmah. But I don't understand about "taking the code out of the CCP interrupt", because I don't know how to set the flag. If you don't mind, can you help me with an example? I really appreciate it... Smile

Here is another code I was able to construct:
It manages to measure the input pulse but sensitivity is too weak...need help...
Code:

#include <18f4620.h>
#use delay(clock= 20 000 000)
#fuses HS, NOWDT
#use rs232(baud=9600, parity=N, xmit=PIN_C6, rcv=PIN_C7, bits=8)
 
float count1, count=0;
unsigned long int over, end_time, start_time, heart;

#int_TIMER1
TIMER1_isr()
{
 set_timer1(5000);
 over=over+1;
 count1= count/100000;
 count=over;
}


#int_CCP1
CCP1_isr()
{
   end_time = CCP_1;
   printf("\r\n overflow count= %1.5f",count1);
   heart= 6/count1/250;
   printf("\r\n heart= %lu",heart);
   start_time = end_time;  //end time of this pulse is the start time for the next one
   over = 0;//clear overflow counts
}


void main()
{
   setup_ccp1(CCP_CAPTURE_RE);
   setup_timer_1(T1_INTERNAL|T1_DIV_BY_2);//set timer1 to run at system clock/4
   enable_interrupts(INT_TIMER1);  //unmask Timer1 overflow interrupt
   enable_interrupts(INT_CCP1);    //unmask capture event interrupt
   enable_interrupts(global);      //enable all unmasked interrupts
 
   while(1); 
   {
   
   }
}
Ttelmah
Guest







PostPosted: Fri Dec 05, 2008 3:05 pm     Reply with quote

I'm not going to write your code for you, but will give you a tiny example:
Code:

int1 CCP_Has_updated=FALSE;
int16 CCP_time;

#int_CCP1
void CCP1_isr(void) {
   CCP_Time=CCP_1;
   CCP_Has_updated=TRUE;
}

//then in main

   int16 local_CCP;


   while (TRUE) {
       while (CCP_has_updated==FALSE);
       local_CCP=CCP_TIME;
       CCP_has_updated=FALSE;
       //Now perform your maths here using the local copy.

Treat as a 'mantra'. _Keep interrupt service routines quick_. Unless you absolutely know what you are doing, and know you have time to do it, never perform any but the most basic integer arithmetic inside an ISR, and don't print in ISR's.

Best Wishes
Ttelmah
Guest







PostPosted: Fri Dec 05, 2008 3:15 pm     Reply with quote

As a further comment. Where do you get 55000uSec from?.
20Mhz clock
Internal clock 5MHz.
Timer running off this /4 = 1.25MHz. 0.8uSec/cycle
Timer1 counts to 65536. Total for overflow = 65536*.8 = 52428.8uSec.

Best Wishes
leejok2003
Guest







PostPosted: Mon Dec 08, 2008 8:58 am     Reply with quote

Thanks again Ttelmah...now I have a question:
set_timer1(value)

How to determine the value? I mean how does this "value" affect the sampling rate? Thanks again.
leejok2003
Guest







PostPosted: Mon Dec 08, 2008 9:01 am     Reply with quote

Ttelmah wrote:
As a further comment. Where do you get 55000uSec from?.
20Mhz clock
Internal clock 5MHz.
Timer running off this /4 = 1.25MHz. 0.8uSec/cycle
Timer1 counts to 65536. Total for overflow = 65536*.8 = 52428.8uSec.

Best Wishes


Smile I just choose a random value close to the real value...just for the sake of testing...
Ttelmah
Guest







PostPosted: Mon Dec 08, 2008 10:04 am     Reply with quote

The timer _counts_.
You get an interrupt, when it counts from 65535, and 'wraps' back to '0'.
The 'set' number, loads the specified number into the counter.
The counter then carries on counting _from_ this loaded number.

There are a lot of caveats though.
First, if you load a value inside an ISR, you have to remember that it takes time to get into the ISR. So if (for instance), you wanted 5000 counts, then an interrupt, you could 'pre-load' the counter with 65536-5000. The problem though is that depending on the clock speed being used, you may well find that a number of counts have already occurred when you preload. This then means you get an interval of 5000+ this number of counts. One way partially 'round' this, is to add value to the counter, rather than just preloading. This still leaves the error of the time between reading the current count, and loading the new one, but is slightly better.
Second problem is that when you load the number, the 'prescaler' (the little counter 'in front' of the main one, that divides the incoming clock), is automatically reset to 0. This introduces yet more error...
Generally, it is much 'better', to not preload the counter. Instead work out a way of either allowing for the timing errors in software (a search here, will find a nice way of using simple integer arithmetic, to generate an accurate RTC, using count values that are not even subdivisions of a second), or change the clock rate to make the divisions work - this is why you will find some projects using clocks like 16.384MHz, which are nicely binary divisible.

Best Wishes
Display posts from previous:   
Post new topic   Reply to topic    CCS Forum Index -> General CCS C Discussion All times are GMT - 6 Hours
Page 1 of 1

 
Jump to:  
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