|
|
View previous topic :: View next topic |
Author |
Message |
Markdem
Joined: 24 Jun 2005 Posts: 206
|
Measuring period without ccp |
Posted: Sun Mar 15, 2015 1:50 am |
|
|
Hi All,
I need to measure a pulse width without using the ccp (already in use by PWM). So I come up with this:
Code: |
//// Compiler Version: CCS 5.025 ////
#include <18F2685.h>
#fuses HS,NOWDT,PUT,NOPROTECT,NOLVP,NOMCLR
#use delay(clock=20M)
int16 period;
int1 timerRunning;
int1 timerReady;
#INT_EXT
void isr_ext()
{
if(timerRunning)
{
period = get_timer0();
timerReady = 1;
}
else
{
timerRunning = 1;
set_timer0(0);
}
}
void main()
{
setup_ccp1(CCP_PWM);
setup_timer_2(T2_DIV_BY_1, 199, 1);
setup_timer_0(T0_INTERNAL | T0_DIV_16);
ext_int_edge(H_TO_L);
enable_interrupts(global);
set_pwm1_duty(0);
while(1)
{
period = 0;
timerRunning = 0;
timerReady = 0;
enable_interrupts(INT_EXT);
while(timerReady == 0);
disable_interrupts(INT_EXT);
delay_ms(3000);
}
} |
The input into B0 is nice and stable, with periods between 8ms and 70ms. The period only changes when I make it change and I can see it on my scope.
I am setting a breakpoint on the delay_ms(3000) and reading the period var in MPLAB.
Problem is the timer comes back with seemingly random numbers (last 5 readings I got were 2629, 8982, 6678, 43454, 452). I think for a period of 65ms I should get back ~20000? If I change the code to just count the pulses for one second I get numbers that make sense so I think the ext_int is working ok, just my timer code is not quite right.
Can anyone see what I am doing wrong?
Thanks |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Sun Mar 15, 2015 2:31 am |
|
|
CCP...
One problem is 'what happens if there is an interrupt when the system is not reading'?.
Think about it. The interrupt is disabled, _but the hardware is still running_.
You delay for three seconds, and then if the interrupt has fired in this time, when you enable the interrupt, the interrupt is immediately called (the flag is still set). This could happen up to 3 seconds after the actual event, so you get a garbage reading.
Code: |
while(1)
{
period = 0;
timerRunning = 0;
timerReady = 0;
clear_interrupt(INT_EXT); //need to clear the interrupt before enabling
enable_interrupts(INT_EXT);
while(timerReady == 0);
disable_interrupts(INT_EXT);
delay_ms(3000);
}
|
|
|
|
Mike Walne
Joined: 19 Feb 2004 Posts: 1785 Location: Boston Spa UK
|
|
Posted: Sun Mar 15, 2015 4:46 am |
|
|
So, you're not measuring pulse width, but the period of a regularly repeating pulse stream.
What are:-
1) Period range to measure.
2) Required accuracy/resolution.
3) Update rate?
Mike |
|
|
Markdem
Joined: 24 Jun 2005 Posts: 206
|
|
Posted: Mon Mar 16, 2015 2:16 am |
|
|
Ttelmah wrote: | CCP...
One problem is 'what happens if there is an interrupt when the system is not reading'?.
Think about it. The interrupt is disabled, _but the hardware is still running_.
You delay for three seconds, and then if the interrupt has fired in this time, when you enable the interrupt, the interrupt is immediately called (the flag is still set). This could happen up to 3 seconds after the actual event, so you get a garbage reading.
Code: |
while(1)
{
period = 0;
timerRunning = 0;
timerReady = 0;
clear_interrupt(INT_EXT); //need to clear the interrupt before enabling
enable_interrupts(INT_EXT);
while(timerReady == 0);
disable_interrupts(INT_EXT);
delay_ms(3000);
}
|
|
Sir, I indebted to you . Works perfect.
I knew it was something simple and I learnt something new today too. I always assumed that the disable_interrupts disabled the interrupt not just the handler.
Thanks |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19506
|
|
Posted: Mon Mar 16, 2015 2:35 am |
|
|
This is actually a key realisation. It's why (for instance) it is possible to 'poll' an interrupt. Using the hardware to record that an event has happened, and then just testing the interrupt flag. You'll see quite a few threads about this.
The actual design is 'multi layer'.
The hardware triggers a flag (in this case INT_EXT).
Then there is an enable bit (this is what is set by the enable/disable for the individual interrupt).
Then there is a global enable bit.
The handler is called when all three are TRUE. The enable/disable, just turns of the enable flag, not the recording of the event.
This is also vitally important, since otherwise if (for instance) you had serial interrupts, and disabled these momentarily, so that the serial interrupt wouldn't take place while doing a critical timing, if the hardware recording was turned off, any character actually received in this moment, would be lost. Instead what happens is the hardware records that a character is waiting, and as soon as the interrupts are re-enabled, the handler gets called.
It's also how multiple interrupts can be used. If you realise that the hardware automatically disables interrupts (ignoring hardware priorities), when the handler is called, then again interrupts would be lost, if this stopped the actual recording of events.
With this knowledge, it makes using interrupts make a lot more sense!... |
|
|
|
|
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
|