|
|
View previous topic :: View next topic |
Author |
Message |
Guest
|
16F877A external interrupt and timer0 |
Posted: Wed Nov 02, 2005 12:16 am |
|
|
I apologize if the answer to this is readily available somewhere...I did a search, but couldn't find what I needed.
I'm currently writing a program that should interrupt when a button is pressed. Among other things, the program should count how many seconds the button was held down for while it is in the ISR. To do this, I start a timer in main that increments a seconds variable every second. I have an ISR for when the button is pressed and within it is a while loop that is valid while the button is pressed. The current seconds count is stored before and after the while loop in two different variables. The problem is that when it enters the ISR for the button, it stops the timer from interrupting and therefore doesn't increment the seconds counter. In the manual for CCS there is a clear_interrupt function but the version that I'm using doesn't seem to have it.
Any ideas on how to clear the interrupt when it gets into the button ISR so that the timer continues to run? I've tried setting 0x0B.1 to 0, but that doesn't seem to do anything.
I've heard that it isn't the best practice to remain in an ISR for too long, but it seemed appropriate in this case, because I don't want anything in main to run while the button is held down.
Any suggestions on how to keep the timer running or how to eliminate the need to have so much code in the ISR would be greatly appreciated |
|
|
Ttelmah Guest
|
|
Posted: Wed Nov 02, 2005 3:18 am |
|
|
Connect the button to one of the PORTB pins that supports 'interrupt on change', rather than the normal interrupt input. Then when you get the interrupt, read the state of the pin (which resets this interrupt source), and if the voltage reflects this being a 'make' condition, reset the timer. If instead it reflects a 'release' condition, read the timer, and you now know how long the button was pressed for, without having tohave stayed inside the interrupt.
If you may need longer time intervals than the hardware timer supports, have a seperate 'carry' register, and an interrupt when the timer reaches it's terminal count, which increments this.
You can also do the same with the normal interrupt input, by changing the interrupt 'direction', with something like:
Code: |
#int_ext
void button_edge(void) {
if (input(PIN_B0)) {
//Here the signal is high
ext_int_edge(H_TO_L);
//Assuming this is the 'idle' state
//read the timer here, save it, and set a
//flag that the key has been released
}
else {
ext_int_edge(L_TO_H);
//Assuming this is the 'active' state
//reset the timer here.
}
}
|
Obviously you need to set up a suitable timer, and read/clear it where shown (assuming that the key pulls the signal 'low' - otherwise the locations of these operations will need to be swapped).
Best Wishes |
|
|
Guest
|
|
Posted: Wed Nov 02, 2005 12:26 pm |
|
|
I was actually in the process of trying that very same thing when I posted my original message. The problem with that is that is that the whole structure of my program will need to be changed.
The way the program should work is that the main loop performs various functions that take some amount of time to complete. As soon as the external interrupt is trigged, the main loop should stop what it's doing and run a different function. While the button that triggered the interrupt is held down, it should keep track of how long the button is pressed as well as count the number of times PIN_C0 changes.
In the way you suggested, after the button is initially pressed, it will return back to the main loop and continue where it left off, even though the button is still pressed. What should happen is that the main loop doesn't continue until after the button is released. |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 03, 2005 3:54 am |
|
|
What you do in the main loop, is entirely up to you.
Simply have a global 'flag' called something like 'waiting_for_key', and as soon as you see the starting 'edge', set this in the interrupt. Then in the main, have it poll this flag, and when it changes,start executing the other code. When the 'release' event is seen, clear the flag, and return to the normal code.
Best Wishes |
|
|
Guest
|
|
Posted: Thu Nov 03, 2005 12:58 pm |
|
|
I assume you mean something like this?
while(1)
{
if(EXT_FLAG)
isr_function();
else
run_other_stuff();
}
and then have the #INT_EXT function set the EXT_FLAG. The problem with that is that is run_other_stuff() is in the process of running (which takes a while to run), then isr_function() won't get run until run_other_stuff() is finished. I would like isr_function() to run as soon as the interrupt is set rather than waiting for for run_other_stuff() to complete.
I've come up with a solution that involved making run_other_stuff() not take so long and so far it seems to be working. |
|
|
Guest
|
|
Posted: Thu Nov 03, 2005 12:59 pm |
|
|
I assume you mean something like this?
while(1)
{
if(EXT_FLAG)
isr_function();
else
run_other_stuff();
}
and then have the #INT_EXT function set the EXT_FLAG. The problem with that is that is run_other_stuff() is in the process of running (which takes a while to run), then isr_function() won't get run until run_other_stuff() is finished. I would like isr_function() to run as soon as the interrupt is set rather than waiting for for run_other_stuff() to complete.
I've come up with a solution that involved making run_other_stuff() not take so long and so far it seems to be working. |
|
|
Ttelmah Guest
|
|
Posted: Thu Nov 03, 2005 4:10 pm |
|
|
The other thing you can do, is to add a test inside 'run other stuff', and exit early, if the receiving flag gets set.
Basically there should never really be any need toever stay for long inside a routine, if you use hardware timers, split operations like ADC reads, again using timers to sequence the parts, etc. etc.. It does come down to designing your flow to ensure you test the flag often enough.
Best Wishes |
|
|
|
|
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
|