View previous topic :: View next topic |
Author |
Message |
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
Panic Button Application |
Posted: Fri Sep 04, 2020 9:51 am |
|
|
Hey guys, I thougt of a panic button for a card I built. I want to stop the program there whenever button is pressed and continue on second press. What is most efficient way to implement this? I'm thinking using ext_int and make it stuck in it. and hoping PIC won't reset in there since wdt is off.
Would something like this work?
Code: |
#INT_EXT HIGH CLEAR_FIRST
void ext_int_routine(void){
static int1 ext_int_flag=0;
ext_int_flag=!ext_int_flag;
while(ext_int_flag){
delay_cycles(1);
}
}
|
And also there will be timer interrupts too in working code, so I'm planning to save timer values and stop timers in this function, also reload and restart them on second press. _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Fri Sep 04, 2020 10:51 am |
|
|
Naked sure you add some form of hardware debounce to the button. Small
capacitor across it. Otherwise you have almost certainty that it will
trigger multiple times. |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Tue Sep 08, 2020 3:06 am |
|
|
Yes you surely right, I already have installed debounce parts beforehand.
I tried the code I mentioned but it is not working, it seems allergic to while loop in an interrupt routine. Code stops working completely on start. But if I comment out while lines from routine, then it works ok.
So it seems I can not get the code to stuck in an interrupt routine.
Can I have some advice ? How can I pause/unpause a program using a button connected to RB0? _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Tue Sep 08, 2020 4:14 am |
|
|
No, the problem is it can never get out.
Think about it. First time the interrupt fires, ext_int_flag is zero.
Gets set to 1 (so now TRUE). Starts looping. How is it ever going to exit?.....
What you need is:
Code: |
#INT_EXT HIGH CLEAR_FIRST
void ext_int_routine(void){
static int1 ext_int_flag=0;
ext_int_flag=!ext_int_flag;
while(ext_int_flag)
{
if (interrupt_active(INT_EXT)) //interrupt has triggered again
return; //exit the interrupt if so (this will mean code will be called again
}
}
|
Understand, interrupts are not called inside other interrupts. So sitting
inside a loop inside the interrupt, nothing except a reset will get you out.
Hence you have to write an 'exit route' from the interrupt. |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Tue Sep 08, 2020 1:30 pm |
|
|
Well, but I thought CLEAR_FIRST option does that trick by clearing interrupt flag before entering the function. So I thought interrupt could be fired again since flag is cleared. And so, if button is pressed second time and when routine is called again, ext_int_flag toggled to 0 again.
Or at least that was what I hoped for _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Wed Sep 09, 2020 12:59 am |
|
|
The CLEAR_FIRST clear the interrupt, so yes, it will re-trigger, but the
handler cannot be called, since you are already inside the handler.
The chip does not support 're-entrancy' (where a routine is called inside
itself). Hence as I show, you can test for the interrupt being re-triggered,
and exit the routine (which will then result in the routine being called
again). |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Wed Sep 09, 2020 4:51 am |
|
|
Unfortunately still not working, I tried many ways I could think of like do-while loop, while looop, if-goto loop and for loop. I checked interrupt flag as loop breaker in them but none of them are worked.
Program does not start as soon as I changed normal loop to a possible infinite loop in code. For example;
This is not doing anything useful but code starts and works with this
Code: | #INT_EXT HIGH CLEAR_FIRST
void ext_int_routine(void){
clear_interrupt(INT_EXT);
static int1 ext_int_flag=0;
ext_int_flag=!ext_int_flag;
if(ext_int_flag){
for(int8 looper=0;looper<2;looper++){
delay_cycles(1);
}
}
} |
But after changing it to a possible infinite loop, this code does not start.
Code: | #INT_EXT HIGH CLEAR_FIRST
void ext_int_routine(void){
clear_interrupt(INT_EXT);
static int1 ext_int_flag=0;
ext_int_flag=!ext_int_flag;
if(ext_int_flag){
for(int8 looper=0;looper<2;looper++){
delay_cycles(1);
if(!interrupt_active(INT_EXT)){
looper=0;
}else{
break;
}
}
}
} |
So, I tried but it seems like compiler really dont want a code that possibly would stay in an interrupt routine. I stopped trying this and used another way compitable with my main code to pause the program.
But I still wonder if it was possible.
Ah, another thing I thought of about pausing the flow of program is; adding an infinite loop in to program which can not be called normally and swapping it's line number and saved program counter on interrupt routine. Unfortunately I dont know how to get line numbers and could not try it but I would like to know if anyone knows. _________________ There is nothing you can't do if you try
Last edited by elcrcp on Wed Sep 09, 2020 7:17 am; edited 1 time in total |
|
|
Gabriel
Joined: 03 Aug 2009 Posts: 1067 Location: Panama
|
|
Posted: Wed Sep 09, 2020 5:50 am |
|
|
How long is your main loop time?
If your total main loop time is 100ms for example, and the process being controlled is not super fast, you can set a flag and then call a function on the main code with the waiting loop.
Basically your maximum time from button press to full stop will be a maximum of 100ms... this would work for filling a water tank, not so much for protecting a finger in a band saw or an airbag in a car.
G. _________________ CCS PCM 5.078 & CCS PCH 5.093 |
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Wed Sep 09, 2020 7:30 am |
|
|
Gabriel wrote: | How long is your main loop time?
If your total main loop time is 100ms for example, and the process being controlled is not super fast, you can set a flag and then call a function on the main code with the waiting loop.
Basically your maximum time from button press to full stop will be a maximum of 100ms... this would work for filling a water tank, not so much for protecting a finger in a band saw or an airbag in a car.
G. |
No no, it is not about a especial program I was looking for a general way. I did find a way to pause my main loop but what I was looking was to halt the program at anywhere of the program and contiue from there. _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Wed Sep 09, 2020 7:32 am |
|
|
I just tested this on a debug board, and it runs perfectly.
Code: |
#include <18F4520.h>
#device ADC=10
#device HIGH_INTS=TRUE
#FUSES NOWDT
#use delay(crystal=20000000)
//basic test setup
#use RS232(UART1, baud=9600, ERRORS)
#INT_EXT HIGH CLEAR_FIRST
void ext_int_routine(void){
static int1 ext_int_flag=FALSE;
ext_int_flag=!ext_int_flag;
if (ext_int_flag)
{
for(int8 looper=0;looper<2;looper++)
{
delay_cycles(1);
if(!interrupt_active(INT_EXT))
{
looper=0;
}
else
{
return;
}
}
}
}
void main()
{
setup_adc_ports(NO_ANALOGS, VSS_VDD);
if (interrupt_active(INT_EXT))
clear_interrupt(INT_EXT);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);
while(TRUE)
{
printf("In main\n");
delay_ms(500);
}
}
|
|
|
|
elcrcp
Joined: 11 Mar 2016 Posts: 62 Location: izmir / Turkey
|
|
Posted: Wed Sep 09, 2020 9:52 am |
|
|
Ttelmah wrote: | I just tested this on a debug board, and it runs perfectly.
Code: |
>> if (interrupt_active(INT_EXT)) <<
>> clear_interrupt(INT_EXT); <<
|
|
So this was the missing key it written in manual that you need to use clear_interrupt() in code but I was using it in interrupt routine. It actually needed before enabling interrupt. Now it is working. Thanks a lot _________________ There is nothing you can't do if you try |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Wed Sep 09, 2020 10:00 am |
|
|
That's actually a 'read the data sheet' one.
It warns you there that depending on how the signalling is sequenced.
the external interrupt may be set at boot.... |
|
|
jeremiah
Joined: 20 Jul 2010 Posts: 1349
|
|
Posted: Wed Sep 09, 2020 10:41 am |
|
|
You probably don't even need the IF before the clear. Just clear it. If the interrupt is active, then it will clear it. If the interrupt is already clear, the clear_interrupts doesn't waste more time than doing the IF followed by the branch instruction.
Last edited by jeremiah on Wed Sep 09, 2020 11:00 am; edited 1 time in total |
|
|
Ttelmah
Joined: 11 Mar 2010 Posts: 19518
|
|
Posted: Wed Sep 09, 2020 10:49 am |
|
|
Dead right. |
|
|
|