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 CCS Technical Support

Measuring pulse width with int_ext

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



Joined: 05 Oct 2007
Posts: 31

View user's profile Send private message

Measuring pulse width with int_ext
PostPosted: Fri Feb 08, 2008 5:17 pm     Reply with quote

Hi, I'm trying to measure how long a pulse is by using the INT0 interrupt on RB0. Here is what I have so far:
Code:


#include <18F8722.h>
#device ADC=10
#include <stdio.h>
#include <math.h>
#include <ctype.h>
#include <stdlib.h>
#fuses HS,NOWDT,NOLVP
#use delay(clock=10000000)
#use rs232(baud=9600, xmit=PIN_C6, rcv=PIN_C7, parity=N, bits=8)
#use standard_io(B)
#use standard_io(D)
#use standard_io(E)

#define   ENABLE      PIN_B0

void main()
{

long time;
float time2;
int count   =   0;

ext_int_edge(H_TO_L);
enable_interrupts(int_ext);
enable_interrupts(global);

while(1)
  {


  }
}

#int_rtcc
void timer_int(void)
{
   count   =   count + 1;
   clear_interrupt(int_rtcc);
}

#int_ext
void pulse_width(void)
{
   int state   =   0;
   state      =   input(ENABLE);   
   
   if(state   ==   0)
   {   
      enable_interrupts(int_rtcc);   
      setup_timer_0(RTCC_INTERNAL|RTCC_DIV_128);
      set_timer0(0);
      printf("H TO L\r");
      clear_interrupt(int_ext);
      ext_int_edge(L_TO_H);
   }
   if(state   ==   1)
   {
      time   =   get_timer0();
      set_timer0(0);
      time2 = ((float)(count * 3.36) + (float)(0.0000512 * time));
      printf("L TO H\r");
      printf("Count = %d\r",count);
      printf("Time  = %lu\r",time);
      printf("Time taken = %f\r",time2);
      clear_interrupt(int_ext);
      count   =   0;
      time   =   0;
      ext_int_edge(H_TO_L);
      disable_interrupts(int_rtcc);
   }
}


The timing seems to work fine if i keep on continuously sending a pulse by means of a switch (high to low to high to low and so on). However if i pause at high for sometime (stop the continuos on/off), the next time I go from high to low (start timer) and low to high(read timer), the timing is incorrect. It seems like the count keeps on counting even though I disable int_rtcc. I am also reseting the timer after reading. Anyone have any idea what I'm missing here?
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Feb 08, 2008 6:14 pm     Reply with quote

1) Never use printf in an interrupt service routine. Interrupts are supposed to be handled as quick as possible At 9600 baud every character you send will use 1ms. That's way too long, even sending 1 character is taking ages in terms of computer speed. Now you are blocking other interrupts and that could well be the reason for your wrong readings. Normal way to attack this issue is by setting a flag in your interrupt routine and then have the main() loop test for this flag.

2) inside the ext-interrupt you don't have to clear int_ext. The compiler does this already for you.

3) Do you really have to use floats? On the 8-bit PIC a float takes several hundreds of computer cycles to calculate. Often you can use a much faster alternative like scaled integers (also called fixed point arithmetic).

4) It's better to reset the count variable when you start the timer interrupt, not when you have finished the measurement. Now your first measurement is using uninitialized data.

5) Determining the interrupt state by sampling the input is dangerous. Ever heard of switch bouncing? It's better to use a global state variable.

6) At the end of the measurement you disable the timer interrupt but the timer is still running. This means that as soon as you enable the interrupt for the next measurement the timer most likely will have overflown and has the interrupt-request flag already set. A timer interrupt is generated immediately and your timed value is wrong.

7) just a hint, but why not use the 16-bit timer1? You can get a higher timer resolution at less processor overhead.

As your program is now, there is no need at all to use the external interrupt and your program could be simplified a lot. An example of such an approach is given in ex_pulse.c in the CCS examples directory.

Another approach for measuring the time of a signal is given in the CCS examples EX_STWTx.C where x is the timer number. These examples have the timer set to count seconds and they just count the number of timer interrupts. No need to use floating point arithmetic and easy to change for millisecond resolution.
The Timer0 example is 8 bit. Timer1 is 16-bit for higher resolution. And the 8-bit Timer2 has the advantage of an additional compare register making it possible to tweak the interrupt rate to an exact second (or millisecond) interval.
cypher



Joined: 05 Oct 2007
Posts: 31

View user's profile Send private message

PostPosted: Fri Feb 08, 2008 6:25 pm     Reply with quote

Thanks lot for all the helpful hints. I actually think timer 0 is 16 BIT on the PIC18s. But thats ok, I can change it to timer1 as well. I think I know what the problem is and you also mention it in number 6 of your comments. Yes, you are correct, I tried putting in a printf statement in my int_rtcc isr and it gets called straight away when I go from high to low again after 3.36 sec of waiting. Hence the timer has overflown once already. But it only overlows once.

Is there a way to stop the timer, I thought resetting the timer again to 0 will work as well, but it doesn't. Any way to stop it?
cypher



Joined: 05 Oct 2007
Posts: 31

View user's profile Send private message

PostPosted: Fri Feb 08, 2008 6:40 pm     Reply with quote

Ok so I just cleared the interrupt flag set by int_rtcc and its working now! So I guess to stop the timer, you would essentially just clear the flag. Thanks a lot.
ckielstra



Joined: 18 Mar 2004
Posts: 3680
Location: The Netherlands

View user's profile Send private message

PostPosted: Fri Feb 08, 2008 6:57 pm     Reply with quote

Quote:
I actually think timer 0 is 16 BIT on the PIC18s
You are right, on the PIC18 it is 16-bit default and can be configured to run in 8-bit mode.

Quote:
Is there a way to stop the timer, I thought resetting the timer again to 0 will work as well, but it doesn't. Any way to stop it?
Setting the timer to 0 is doing just that. The timer is reset to 0 and continuous counting from there. To stop the timer use:
Code:
setup_timer_0(RTCC_OFF);

In your timer you want to do both: Stop the timer and clear the timer interrupt. In that sequence (or an interrupt could be generated in between the commands).
cypher



Joined: 05 Oct 2007
Posts: 31

View user's profile Send private message

PostPosted: Fri Feb 08, 2008 7:34 pm     Reply with quote

Thanks, I got it to work!
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