![](templates/subSilver/images/CCSLogo.jpg) |
![CCS C Software and Maintenance Offers](templates/subSilver/images/forumAd6.jpg) |
View previous topic :: View next topic |
Author |
Message |
Fredrik Guest
|
12F675 Interrupt problems |
Posted: Wed Nov 19, 2003 11:31 am |
|
|
I have tried a whole day now to get the PIC12F675 to wake up from sleep using an external interrupt. The interrupt appears to be working but not in a way it is supposed to. What i want to do is to execute a code to do some calculations and then go into sleep mode. And then do the same thing whwn woken up with the ext.int. However the interrupt appears to be generated two times internally everytime I generate one externaly.
Heres the (non working) code so far:
Code: | #include <12F675.h>
#fuses INTRC_IO,PUT,NOWDT,NOPROTECT,NOMCLR, BROWNOUT
#use delay(clock = 4000000)
// IO pins
#bit gpio5 =0x05.5
#bit gpio4 =0x05.4
#bit gpio3 =0x05.3
#bit gpio2 =0x05.2
#bit gpio1 =0x05.1
#bit gpio0 =0x05.0
#use fast_io(a)
#byte ADCON0 = 0x1F // A/D
#byte ANSEL = 0x9F // A/D config
#byte CMCON = 0x19 // Comparators
main()
{
ADCON0 = 0; // ADC off
ANSEL = 0; // GPIO pins 0,1,2 and 4 set to all digital
CMCON = 7; // Comparators off
// Setup i/o
set_tris_a(0b001100); //GP0,1,4,5 output; 2,3 input
gpio5 = 0;
gpio4 = 1; //turn on LED on gp4
gpio1 = 0;
gpio0 = 0;
delay_ms(1000);
gpio4 = 0;
// Set timer0 not to use GP2
setup_counters(rtcc_internal, rtcc_div_2);
ext_int_edge(L_TO_H);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);;
while(true)
{
delay_ms(1000);
gpio5 = !gpio5; //toggle LEDs just to test that program is running
delay_cycles(5);
delay_ms(1000);
sleep();
}// main loop
}// main
#int_ext
void ext_isr(void)
{
//-- Wake up from sleep --
gpio1 = !gpio1; // Test to see if isr is executed
delay_ms(100);
}// ext_isr |
The ext_int_edge appear to have no effect what so ever. The interrupt is triggered on any edge. On startup the gpio4 led is blinking. And then the gpio5 led is lit. On interrupt the gpio1 led is blinking and then gpio4 also. Then gpio5 led is lit. As if the cpu is restarted.
If i cause an ext interrupt and keep the input low the cpu will flash the leds gpio1 and gpio4 in a toggling mode, until the ext input is put high. Then the gpio5 led is lit.
What i want is that the the ext.int is only triggered on a L_TO_H edge and only to execute to code until sleep(), and not restarting completley. This ofcourse could be done in a polling mode, but I need the cpu to be in a low power mode between interrupts.
What to do? What is wrong with the code? Please help!
/Fredrik |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
Re: 12F675 Interrupt problems |
Posted: Wed Nov 19, 2003 12:02 pm |
|
|
Fredrik wrote: | I have tried a whole day now to get the PIC12F675 to wake up from sleep using an external interrupt. The interrupt appears to be working but not in a way it is supposed to. What i want to do is to execute a code to do some calculations and then go into sleep mode. And then do the same thing whwn woken up with the ext.int. However the interrupt appears to be generated two times internally everytime I generate one externaly.
Heres the (non working) code so far:
Code: | #include <12F675.h>
#fuses INTRC_IO,PUT,NOWDT,NOPROTECT,NOMCLR, BROWNOUT
#use delay(clock = 4000000)
// IO pins
#bit gpio5 =0x05.5
#bit gpio4 =0x05.4
#bit gpio3 =0x05.3
#bit gpio2 =0x05.2
#bit gpio1 =0x05.1
#bit gpio0 =0x05.0
#use fast_io(a)
#byte ADCON0 = 0x1F // A/D
#byte ANSEL = 0x9F // A/D config
#byte CMCON = 0x19 // Comparators
main()
{
ADCON0 = 0; // ADC off
ANSEL = 0; // GPIO pins 0,1,2 and 4 set to all digital
CMCON = 7; // Comparators off
// Setup i/o
set_tris_a(0b001100); //GP0,1,4,5 output; 2,3 input
gpio5 = 0;
gpio4 = 1; //turn on LED on gp4
gpio1 = 0;
gpio0 = 0;
delay_ms(1000);
gpio4 = 0;
// Set timer0 not to use GP2
setup_counters(rtcc_internal, rtcc_div_2);
ext_int_edge(L_TO_H);
enable_interrupts(INT_EXT);
enable_interrupts(GLOBAL);;
while(true)
{
delay_ms(1000);
gpio5 = !gpio5; //toggle LEDs just to test that program is running
delay_cycles(5);
delay_ms(1000);
sleep();
}// main loop
}// main
#int_ext
void ext_isr(void)
{
//-- Wake up from sleep --
gpio1 = !gpio1; // Test to see if isr is executed
delay_ms(100);
}// ext_isr |
The ext_int_edge appear to have no effect what so ever. The interrupt is triggered on any edge. On startup the gpio4 led is blinking. And then the gpio5 led is lit. On interrupt the gpio1 led is blinking and then gpio4 also. Then gpio5 led is lit. As if the cpu is restarted.
If i cause an ext interrupt and keep the input low the cpu will flash the leds gpio1 and gpio4 in a toggling mode, until the ext input is put high. Then the gpio5 led is lit.
What i want is that the the ext.int is only triggered on a L_TO_H edge and only to execute to code until sleep(), and not restarting completley. This ofcourse could be done in a polling mode, but I need the cpu to be in a low power mode between interrupts.
What to do? What is wrong with the code? Please help!
/Fredrik |
The first thing to remember, is that the global interrupt enable, does not need to be set to 'wake up' from interrupts. The act of waking up, is independant of the normal interrupt handling. Hence your code will wake up, and execute the next instructions after the sleep, then interrupt, and call your handler. Because there is a significant latency after wake up, and calling the interrupt, the code may allready have entered the 'delay_ms(1000)' routine, which because it is called both inside and outside the interrupt, will have the interrupts disabled. Hence this will execute first, then the handler will toggle bit 1, wait 100mSec (get rid of this, interrupt handlers should be short), then return. It will then carry on executing the rest of the main loop.
So, get rid of the interrupt handler completely, and just have the INTF bit defined, clear it, execute the sleep, then have the code you want executed following this instruction. Loop back to the instruction to clear the INTF bit to wait for the next edge. So:
#bit INTF 0xB.1
Then in the main, loop as:
ext_int_edge(L_TO_H);
INTF=0;
enable_interrupts(INT_EXT);
gpio5 = !gpio5; //toggle LEDs just to prove that program is running
while (true) {
INTF=0;
sleep();
gpio1=!gpio1;
delay_ms(100);
}// main loop
This may give a result closer to what you want.
Best Wishes |
|
![](templates/subSilver/images/spacer.gif) |
Fredrik Guest
|
|
Posted: Thu Nov 20, 2003 2:12 am |
|
|
Yes now it works much better. In my defense: The delays where only there for debug. Thanks for the help and the explanation!
/ Fredrik |
|
![](templates/subSilver/images/spacer.gif) |
Ttelmah Guest
|
|
Posted: Thu Nov 20, 2003 3:15 am |
|
|
Fredrik wrote: | Yes now it works much better. In my defense: The delays where only there for debug. Thanks for the help and the explanation!
/ Fredrik |
The key thing, is the extremely long latency in an interrupt response when 'waking'. This is only visible in one timing diagram on the chips data sheet, but is about four instruction times. This allows the interrupt response to be in a completely 'unexpected' location (in one of the data sheets for older chips, the latency is only one instruction, and MicroChip recommend adding a 'nop' after the sleep, if you want to call an interrupt handler this way, to avoid this type of problem...).
It is one of those faults, that you have to have 'met yourself'...
Good luck |
|
![](templates/subSilver/images/spacer.gif) |
|
|
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
|