EmbeddedRelated.com
Forums

Counting pulses from external interrupts(falling edge mode) .

Started by FINETECH February 1, 2011
/* #Microprocessor: RCM2020 with XTAL: 9.216Mhz
#Purpose: Counting pulses from external interrupts(falling edge mode).

#Problem:
How to lock the data in "count" variable, I want the data changes only occur when there is change in pulse from high to low (falling edge), so that the resulting data sequence, not random, such as: 0,1,2,3,4,5,... This program produces output as follows: 0,2,8,29,30,... As it is the repetitive pulse or there may be bounching pulse.

On the hardware that is in PE4, I add for 10K Ohm resistor PullUp to VCC, so the default voltage of PE4 is High. External interrupt will occur when PE4 connect with GND(falling edge).

# Thank you for your assistance.
*/
#class auto

void my_isr();

long count;

void initial_ports(){
WrPortI(SPCR,&SPCRShadow,0x84); // setups Port A to output (cable downloader)
WrPortI(PEDR,&PEDRShadow,0x00); // set Port E as input
}

void initial_external_interrupt(){
SetVectExtern2000(1, my_isr);
SetVectExtern2000(1, GetVectExtern2000());

// x x INT1B INT0B INT1A INT0A Enb_INT1 Enb_INT0
// 0 0 1 0 0 0 0 1 = 0x21 rising
// 0 0 0 1 0 0 0 1 = 0x11 falling
// 0 0 1 1 0 0 0 1 = 0x31 both
//
// bit 1,0(Enb_INT1/En_INT0) -> 00=dissabled
// -> 01=pri 1 (I'm used this)
// -> 10=pri 2
// -> 11=pri 3
//
// bit 3,2(INT1A PE1/INT0A PE0) -> 00=dissabled
// -> 01ling
// -> 10=rising
// -> 11=both
//
// bit 5,4(INT1B PE5/INT0B PE4) -> 00=dissabled
// -> 01ling (I'm used this)
// -> 10=rising
// -> 11=both
//

// enable external INT0 on PE4, falling edge , priority 1
WrPortI(I0CR, &I0CRShadow, 0x11);
}

int main(){
initial_ports();
initial_external_interrupt();

count =0;

while(1){
costate{

// Problem in here (resulting random "count" as 0,2,8,29,30..
// I want sequence output as 0,1,2,3,4,5.., Counting will
// occur when PE4 connect with GND (falling edge)
printf("count %ld", count);

waitfor(DelaySec(1));
}
}
WrPortI(I0CR, &I0CRShadow, 0x00); // disable external interrupt 0
// external interrupt 0 Interrupt Service Routine
nodebug root interrupt void my_isr(){
count++;
}

It looks like you are suffering from contact debounce. You may think you are
only closing the switch once but the rabbit is actually seeing several
pulses as the switch contacts bounce. You may need to add a small delay
timer to only capture the first transition then ignore the rest for a short
period of time (20mS say)

Thanks

Duncan

From: r... [mailto:r...] On
Behalf Of FINETECH
Sent: Tuesday, February 01, 2011 10:25 AM
To: r...
Subject: [rabbit-semi] Counting pulses from external interrupts(falling edge
mode) .

/* #Microprocessor: RCM2020 with XTAL: 9.216Mhz
#Purpose: Counting pulses from external interrupts(falling edge mode).

#Problem:
How to lock the data in "count" variable, I want the data changes only occur
when there is change in pulse from high to low (falling edge), so that the
resulting data sequence, not random, such as: 0,1,2,3,4,5,... This program
produces output as follows: 0,2,8,29,30,... As it is the repetitive pulse or
there may be bounching pulse.

On the hardware that is in PE4, I add for 10K Ohm resistor PullUp to VCC, so
the default voltage of PE4 is High. External interrupt will occur when PE4
connect with GND(falling edge).

# Thank you for your assistance.
*/

#class auto

void my_isr();

long count;

void initial_ports(){
WrPortI(SPCR,&SPCRShadow,0x84); // setups Port A to output (cable
downloader)
WrPortI(PEDR,&PEDRShadow,0x00); // set Port E as input
}

void initial_external_interrupt(){
SetVectExtern2000(1, my_isr);
SetVectExtern2000(1, GetVectExtern2000());

// x x INT1B INT0B INT1A INT0A Enb_INT1 Enb_INT0
// 0 0 1 0 0 0 0 1 = 0x21 rising
// 0 0 0 1 0 0 0 1 = 0x11 falling
// 0 0 1 1 0 0 0 1 = 0x31 both
//
// bit 1,0(Enb_INT1/En_INT0) -> 00=dissabled
// -> 01=pri 1 (I'm used this)
// -> 10=pri 2
// -> 11=pri 3
//
// bit 3,2(INT1A PE1/INT0A PE0) -> 00=dissabled
// -> 01ling
// -> 10=rising
// -> 11=both
//
// bit 5,4(INT1B PE5/INT0B PE4) -> 00=dissabled
// -> 01ling (I'm used this)
// -> 10=rising
// -> 11=both
//

// enable external INT0 on PE4, falling edge , priority 1
WrPortI(I0CR, &I0CRShadow, 0x11);
}

int main(){
initial_ports();
initial_external_interrupt();

count =0;

while(1){
costate{

// Problem in here (resulting random "count" as 0,2,8,29,30..
// I want sequence output as 0,1,2,3,4,5.., Counting will
// occur when PE4 connect with GND (falling edge)
printf("count %ld", count);

waitfor(DelaySec(1));
}
}
WrPortI(I0CR, &I0CRShadow, 0x00); // disable external interrupt 0

// external interrupt 0 Interrupt Service Routine
nodebug root interrupt void my_isr(){
count++;
}
With a simple switch and a pull up is easy to obtain a clear signal, without debounce. Looking in your code, count variable is declared as long, so it's a multibyte variable. You must declare as "shared long" (similar to volatile in K&R C), so compiler assumes that:

1-Must disable interrupts before reads variable from mem.
2-Each time compiler reads var from mem, it must *really* read from mem.

Also, you shouldn't assume that variable value is maintained inside a function, because between every two assembler instructions an interrupt may fall, so count var is updated.

--- In r..., "Duncan Sinclair" wrote:
>
> It looks like you are suffering from contact debounce. You may think you are
> only closing the switch once but the rabbit is actually seeing several
> pulses as the switch contacts bounce. You may need to add a small delay
> timer to only capture the first transition then ignore the rest for a short
> period of time (20mS say)
>
>
>
> Thanks
>
> Duncan
>
>
>
> From: r... [mailto:r...] On
> Behalf Of FINETECH
> Sent: Tuesday, February 01, 2011 10:25 AM
> To: r...
> Subject: [rabbit-semi] Counting pulses from external interrupts(falling edge
> mode) .
>
>
>
>
>
> /* #Microprocessor: RCM2020 with XTAL: 9.216Mhz
> #Purpose: Counting pulses from external interrupts(falling edge mode).
>
> #Problem:
> How to lock the data in "count" variable, I want the data changes only occur
> when there is change in pulse from high to low (falling edge), so that the
> resulting data sequence, not random, such as: 0,1,2,3,4,5,... This program
> produces output as follows: 0,2,8,29,30,... As it is the repetitive pulse or
> there may be bounching pulse.
>
> On the hardware that is in PE4, I add for 10K Ohm resistor PullUp to VCC, so
> the default voltage of PE4 is High. External interrupt will occur when PE4
> connect with GND(falling edge).
>
> # Thank you for your assistance.
> */
>
> #class auto
>
> void my_isr();
>
> long count;
>
> void initial_ports(){
> WrPortI(SPCR,&SPCRShadow,0x84); // setups Port A to output (cable
> downloader)
> WrPortI(PEDR,&PEDRShadow,0x00); // set Port E as input
> }
>
> void initial_external_interrupt(){
> SetVectExtern2000(1, my_isr);
> SetVectExtern2000(1, GetVectExtern2000());
>
> // x x INT1B INT0B INT1A INT0A Enb_INT1 Enb_INT0
> // 0 0 1 0 0 0 0 1 = 0x21 rising
> // 0 0 0 1 0 0 0 1 = 0x11 falling
> // 0 0 1 1 0 0 0 1 = 0x31 both
> //
> // bit 1,0(Enb_INT1/En_INT0) -> 00=dissabled
> // -> 01=pri 1 (I'm used this)
> // -> 10=pri 2
> // -> 11=pri 3
> //
> // bit 3,2(INT1A PE1/INT0A PE0) -> 00=dissabled
> // -> 01ling
> // -> 10=rising
> // -> 11=both
> //
> // bit 5,4(INT1B PE5/INT0B PE4) -> 00=dissabled
> // -> 01ling (I'm used this)
> // -> 10=rising
> // -> 11=both
> //
>
> // enable external INT0 on PE4, falling edge , priority 1
> WrPortI(I0CR, &I0CRShadow, 0x11);
> }
>
> int main(){
> initial_ports();
> initial_external_interrupt();
>
> count =0;
>
> while(1){
> costate{
>
> // Problem in here (resulting random "count" as 0,2,8,29,30..
> // I want sequence output as 0,1,2,3,4,5.., Counting will
> // occur when PE4 connect with GND (falling edge)
> printf("count %ld", count);
>
> waitfor(DelaySec(1));
> }
> }
> WrPortI(I0CR, &I0CRShadow, 0x00); // disable external interrupt 0
>
> // external interrupt 0 Interrupt Service Routine
> nodebug root interrupt void my_isr(){
> count++;
> }
>

--- In r..., "Duncan Sinclair" wrote:
>
> It looks like you are suffering from contact debounce. You may think you are
> only closing the switch once but the rabbit is actually seeing several
> pulses as the switch contacts bounce. You may need to add a small delay
> timer to only capture the first transition then ignore the rest for a short
> period of time (20mS say)
>
>
>
> Thanks
>
> Duncan
>
>
>
> From: r... [mailto:r...] On
> Behalf Of FINETECH
> Sent: Tuesday, February 01, 2011 10:25 AM
> To: r...
> Subject: [rabbit-semi] Counting pulses from external interrupts(falling edge
> mode) .
>
>
>
>
>
> /* #Microprocessor: RCM2020 with XTAL: 9.216Mhz
> #Purpose: Counting pulses from external interrupts(falling edge mode).
>
> #Problem:
> How to lock the data in "count" variable, I want the data changes only occur
> when there is change in pulse from high to low (falling edge), so that the
> resulting data sequence, not random, such as: 0,1,2,3,4,5,... This program
> produces output as follows: 0,2,8,29,30,... As it is the repetitive pulse or
> there may be bounching pulse.
>
> On the hardware that is in PE4, I add for 10K Ohm resistor PullUp to VCC, so
> the default voltage of PE4 is High. External interrupt will occur when PE4
> connect with GND(falling edge).
>
> # Thank you for your assistance.
> */
>
> #class auto
>
> void my_isr();
>
> long count;
>
> void initial_ports(){
> WrPortI(SPCR,&SPCRShadow,0x84); // setups Port A to output (cable
> downloader)
> WrPortI(PEDR,&PEDRShadow,0x00); // set Port E as input
> }
>
> void initial_external_interrupt(){
> SetVectExtern2000(1, my_isr);
> SetVectExtern2000(1, GetVectExtern2000());
>
> // x x INT1B INT0B INT1A INT0A Enb_INT1 Enb_INT0
> // 0 0 1 0 0 0 0 1 = 0x21 rising
> // 0 0 0 1 0 0 0 1 = 0x11 falling
> // 0 0 1 1 0 0 0 1 = 0x31 both
> //
> // bit 1,0(Enb_INT1/En_INT0) -> 00=dissabled
> // -> 01=pri 1 (I'm used this)
> // -> 10=pri 2
> // -> 11=pri 3
> //
> // bit 3,2(INT1A PE1/INT0A PE0) -> 00=dissabled
> // -> 01ling
> // -> 10=rising
> // -> 11=both
> //
> // bit 5,4(INT1B PE5/INT0B PE4) -> 00=dissabled
> // -> 01ling (I'm used this)
> // -> 10=rising
> // -> 11=both
> //
>
> // enable external INT0 on PE4, falling edge , priority 1
> WrPortI(I0CR, &I0CRShadow, 0x11);
> }
>
> int main(){
> initial_ports();
> initial_external_interrupt();
>
> count =0;
>
> while(1){
> costate{
>
> // Problem in here (resulting random "count" as 0,2,8,29,30..
> // I want sequence output as 0,1,2,3,4,5.., Counting will
> // occur when PE4 connect with GND (falling edge)
> printf("count %ld", count);
>
> waitfor(DelaySec(1));
> }
> }
> WrPortI(I0CR, &I0CRShadow, 0x00); // disable external interrupt 0
>
> // external interrupt 0 Interrupt Service Routine
> nodebug root interrupt void my_isr(){
> count++;
> }
>
Thank you Mr Duncan, for your assistance. This program now, can counting pulse in sequence mode, according suggestions from you. I add a delay in External ISR, as follows:

/////////////////////////////////////////////////////////
// OLD EXTERNAL ISR
// external interrupt 0 Interrupt Service Routine
/////////////////////////////////////////////////////////
nodebug root interrupt void my_isr(){
count++;
}

/////////////////////////////////////////////////////////
// NEW EXTERNAL ISR WITH DELAY 1 SECOND
// external interrupt 0 Interrupt Service Routine
/////////////////////////////////////////////////////////
nodebug root interrupt void my_isr(){
costate{
count++;

// add delay 1 second for to prevent bounching.
waitfor(DelayMs(1000));

}
}
/////////////////////////////////////////////////////////

Thanks & Best Regards,

Yudha

Putting any sort of delay like that inside an interrupt service routine is not the best idea.

It may appear to be working, but it may be having all sorts of unexpected effects during that 1 second. (I'm actually surprized the code runs).

Some tips....

Debouncing typically only requires about 100-200 mS. This will reduce the impact.

The need to debounce switch inputs can be reduced if you use a Schmitt Trigger input gate (eg: 74ACT14).

Rather than just doing a waitfor.... Implement the delay by recording the current time, adding 200mS to it (as a hold-off time) and then exiting the ISR. Then when the ISR runs next time, check to make sure that the current time is greater than the Hold-Off time. If it is, count again, if it's not, just reuturn without counting.

This will minimize the impact on the rest of your program.

Phil.

> /////////////////////////////////////////////////////////
> // NEW EXTERNAL ISR WITH DELAY 1 SECOND
> // external interrupt 0 Interrupt Service Routine
> /////////////////////////////////////////////////////////
> nodebug root interrupt void my_isr(){
> costate{
> count++;
>
> // add delay 1 second for to prevent bounching.
> waitfor(DelayMs(1000));
>
> }
> }
> /////////////////////////////////////////////////////////
>
> Thanks & Best Regards,
>
> Yudha
>

--- In r..., "ourcoolhouse" wrote:
>
> Putting any sort of delay like that inside an interrupt service routine is not the best idea.
>
> It may appear to be working, but it may be having all sorts of unexpected effects during that 1 second. (I'm actually surprized the code runs).
>
> Some tips....
>
> Debouncing typically only requires about 100-200 mS. This will reduce the impact.
>
> The need to debounce switch inputs can be reduced if you use a Schmitt Trigger input gate (eg: 74ACT14).
>
> Rather than just doing a waitfor.... Implement the delay by recording the current time, adding 200mS to it (as a hold-off time) and then exiting the ISR. Then when the ISR runs next time, check to make sure that the current time is greater than the Hold-Off time. If it is, count again, if it's not, just reuturn without counting.
>
> This will minimize the impact on the rest of your program.
>
> Phil.
> > /////////////////////////////////////////////////////////
> > // NEW EXTERNAL ISR WITH DELAY 1 SECOND
> > // external interrupt 0 Interrupt Service Routine
> > /////////////////////////////////////////////////////////
> > nodebug root interrupt void my_isr(){
> > costate{
> > count++;
> >
> > // add delay 1 second for to prevent bounching.
> > waitfor(DelayMs(1000));
> >
> > }
> > }
> > /////////////////////////////////////////////////////////
> >
> > Thanks & Best Regards,
> >
> > Yudha
>

Thanks for your tips, Mr Phil. This program has worked perfectly without error. I'm used, costate{... waitfor(DelayMs(1000));}

nodebug root interrupt void my_isr(){
costate{
count++;
// add delay 1 second for to prevent bounching.
waitfor(DelayMs(1000));
}
}

Thanks & Best Regards,
Yudha

On 2/3/2011 12:43 PM, FINETECH wrote:
> Thanks for your tips, Mr Phil. This program has worked perfectly without error. I'm used, costate{... waitfor(DelayMs(1000));}
>
> nodebug root interrupt void my_isr(){
> costate{
> count++;
> // add delay 1 second for to prevent bounching.
> waitfor(DelayMs(1000));
> }
> }
>
> Thanks & Best Regards,
>

That is dangerous and probably the worst solution I have seen.

Why not debouce the input via an R/C filter?

If it is only about one second per pulse, then it is eaiser to use a
timer interrupt to poll the pin changing.

--
------
Scott G. Henion, Consultant
Web site: http://SHDesigns.org
Rabbit libs: http://shdesigns.org/rabbit/
------

Scott....

Just so you know, I did NOT recommend the solution below.....
I don't want to be painted with that brush...

I recommened tracking the interrupt event time, and discarding rapid pulses.

Phil.

--- In r..., Scott Henion wrote:
>
> On 2/3/2011 12:43 PM, FINETECH wrote:
> > Thanks for your tips, Mr Phil. This program has worked perfectly without error. I'm used, costate{... waitfor(DelayMs(1000));}
> >
> > nodebug root interrupt void my_isr(){
> > costate{
> > count++;
> > // add delay 1 second for to prevent bounching.
> > waitfor(DelayMs(1000));
> > }
> > }
> >
> > Thanks & Best Regards,
> > That is dangerous and probably the worst solution I have seen.
>
> Why not debouce the input via an R/C filter?
>
> If it is only about one second per pulse, then it is eaiser to use a
> timer interrupt to poll the pin changing.
>
> --
> ------
> Scott G. Henion, Consultant
> Web site: http://SHDesigns.org
> Rabbit libs: http://shdesigns.org/rabbit/
> ------
>

Yudha

When you post a question to a forum, you want an answer, but it's also an opportunity to learn from some of the more experienced users out there.

As Scott and I have both warned, that delay in your ISR is a really bad idea.

It may be working now, but if you add more to this program it may blow up in a blink of an eye. We're both just trying to save you a LOT of grief.

Phil.

--- In r..., "FINETECH" wrote:
>
> --- In r..., "ourcoolhouse" wrote:
> >
> > Putting any sort of delay like that inside an interrupt service routine is not the best idea.
> >
> > It may appear to be working, but it may be having all sorts of unexpected effects during that 1 second. (I'm actually surprized the code runs).
> >
> > Some tips....
> >
> > Debouncing typically only requires about 100-200 mS. This will reduce the impact.
> >
> > The need to debounce switch inputs can be reduced if you use a Schmitt Trigger input gate (eg: 74ACT14).
> >
> > Rather than just doing a waitfor.... Implement the delay by recording the current time, adding 200mS to it (as a hold-off time) and then exiting the ISR. Then when the ISR runs next time, check to make sure that the current time is greater than the Hold-Off time. If it is, count again, if it's not, just reuturn without counting.
> >
> > This will minimize the impact on the rest of your program.
> >
> > Phil.
> >
> >
> >
> >
> > > /////////////////////////////////////////////////////////
> > > // NEW EXTERNAL ISR WITH DELAY 1 SECOND
> > > // external interrupt 0 Interrupt Service Routine
> > > /////////////////////////////////////////////////////////
> > > nodebug root interrupt void my_isr(){
> > > costate{
> > > count++;
> > >
> > > // add delay 1 second for to prevent bounching.
> > > waitfor(DelayMs(1000));
> > >
> > > }
> > > }
> > > /////////////////////////////////////////////////////////
> > >
> > > Thanks & Best Regards,
> > >
> > > Yudha
> > >
> >
> Thanks for your tips, Mr Phil. This program has worked perfectly without error. I'm used, costate{... waitfor(DelayMs(1000));}
>
> nodebug root interrupt void my_isr(){
> costate{
> count++;
> // add delay 1 second for to prevent bounching.
> waitfor(DelayMs(1000));
> }
> }
>
> Thanks & Best Regards,
> Yudha
>

All..

I would not use the delay in the ISR. I now use additional hardware such as a Schmitt trigger IC74LS14, and I've succeeded. Thanks All for your suggestions.
Thanks & Best Regards,

Yudha

--- In r..., "ourcoolhouse" wrote:
>
> Yudha
>
> When you post a question to a forum, you want an answer, but it's also an opportunity to learn from some of the more experienced users out there.
>
> As Scott and I have both warned, that delay in your ISR is a really bad idea.
>
> It may be working now, but if you add more to this program it may blow up in a blink of an eye. We're both just trying to save you a LOT of grief.
>
> Phil.
>
> --- In r..., "FINETECH" wrote:
> >
> >
> >
> >
> >
> > --- In r..., "ourcoolhouse" wrote:
> > >
> > > Putting any sort of delay like that inside an interrupt service routine is not the best idea.
> > >
> > > It may appear to be working, but it may be having all sorts of unexpected effects during that 1 second. (I'm actually surprized the code runs).
> > >
> > > Some tips....
> > >
> > > Debouncing typically only requires about 100-200 mS. This will reduce the impact.
> > >
> > > The need to debounce switch inputs can be reduced if you use a Schmitt Trigger input gate (eg: 74ACT14).
> > >
> > > Rather than just doing a waitfor.... Implement the delay by recording the current time, adding 200mS to it (as a hold-off time) and then exiting the ISR. Then when the ISR runs next time, check to make sure that the current time is greater than the Hold-Off time. If it is, count again, if it's not, just reuturn without counting.
> > >
> > > This will minimize the impact on the rest of your program.
> > >
> > > Phil.
> > >
> > >
> > >
> > >
> > > > /////////////////////////////////////////////////////////
> > > > // NEW EXTERNAL ISR WITH DELAY 1 SECOND
> > > > // external interrupt 0 Interrupt Service Routine
> > > > /////////////////////////////////////////////////////////
> > > > nodebug root interrupt void my_isr(){
> > > > costate{
> > > > count++;
> > > >
> > > > // add delay 1 second for to prevent bounching.
> > > > waitfor(DelayMs(1000));
> > > >
> > > > }
> > > > }
> > > > /////////////////////////////////////////////////////////
> > > >
> > > > Thanks & Best Regards,
> > > >
> > > > Yudha
> > > >
> > >
> >
> >
> > Thanks for your tips, Mr Phil. This program has worked perfectly without error. I'm used, costate{... waitfor(DelayMs(1000));}
> >
> > nodebug root interrupt void my_isr(){
> > costate{
> > count++;
> > // add delay 1 second for to prevent bounching.
> > waitfor(DelayMs(1000));
> > }
> > }
> >
> > Thanks & Best Regards,
> >
> >
> > Yudha
>