# Interrupt works only once - PIC16F877a

In my code, I have two interruptions, one is coming from the overflow of the TMR0, and the other one is when a button is pressed.

this is the code in MikroC :

int compt = 0;
int seconds = 10 ;
int enable = 0;

void interrupt(){

if (INTCON.INTF) {
PORTD = 9;
enable = 1;
seconds = 10;
INTCON.INTF = 0;
}

if (INTCON.TMR0IF) {
compt++;
INTCON.TMR0IF  = 0;
TMR0 = 0x06;
}
}

void main() {

TRISB = 0x01;
PORTB = 0;

PORTD = 0;
TRISD = 0x00;

INTCON = 0xB0;
OPTION_REG = 0x44;
TMR0 = 0x06;

while(1){

if (compt == 625){
if (enable) seconds--;
compt = 0;
}

if (seconds > 0 && enable == 1) {
PORTD = seconds;
PORTB.RB1 = 1;
}  else {
enable = 0;
PORTB.RB1 = 0;
PORTD = 0;
}

}

}


what I am trying to achieve with my code is as the following :

When I press one of the push buttons, the countdown starts and the LED illuminates until the countdown ends, and if the user pressed the button while the countdown still didn't hit 0, it starts over, until the countdown hits 0 again, then the LED should turn off.

What I'm facing here, is that the interruption from IRB0 works only once, the second time I press the button, nothing happens.

I am not sure if the TMR0F has something to do with that or not, tried many things, but couldn't make it to work.

I Hope that you could see something i didn't notice, and help me.

• This should be on stack overflow. Anyways from what it looks like the interrupt is still being triggered after the first press. Your if statements however are stopping it. You never change INTCON.INTF or INTCON.TMR0IF back to initial value. It is always 0. Jan 20 '19 at 20:45
• @deathismyfriend, I don't think so, cause the flag should always be cleared, otherwise the interruption routine never ends Jan 20 '19 at 20:51
• Without seeing the rest of the code I can't really tell what is happening. Were does the above get reset ? Also where is the interrupt call initialized. Jan 20 '19 at 20:57
• @deathismyfriend It is about microcontroller firmware and even has a schematic. It should not be posted on SO where people don't even know the meaning of pull-up, but it should remain here, where it is perfectly on-topic. Jan 21 '19 at 12:52
• @Bouzaid There may be a good reason for having several buttons connected to the same input, but be aware that the wire length may have an impact on reliability. See for instance: arduino.stackexchange.com/questions/13072/…
– mic
Jan 22 '19 at 8:10

Many problems.

• I did all that and nothing happened, the problem was in the resistor bellow the push buttons, I changed it from 10K to 1K here the complete new schematics. i.imgur.com/P6KQ3to.png for the debounce, in the real project, I'm going to use a flip-flop, just to clarify Jan 21 '19 at 13:39
• @Bouzaid 10k will work just fine and the value is not critical at all. If changing resistor solved the problem, then the original resistor was badly soldered or something. You still need to do everything mention in this answer, no way around it. Jan 21 '19 at 14:08

There are some low level problems with your code that have to be handled first. These problems have the potential to break your code even if the logic would otherwise seem correct.

• Variables that are shared between the interrupt service routine (ISR) and the main program code should be declared volatile. In your case that is all three of them:

volatile int compt = 0;
volatile int seconds = 10;
volatile int enable = 0;


Volatile tells the compiler that a variable can change in between different accesses even if the code does not appear to modify it. This prevents certain reads and writes being optimized away because the optimizer does not understand there's an ISR working with those same variables asynchronously.

• The C standard requires a int to be at least 16-bit. Your PIC, however, is a 8-bit device. This means manipulating a int will be a non-atomic operation. Non-atomic operations require multiple CPU instructions to complete. A interrupt could be triggered in the middle of such a operation which would cause either the ISR to see a (corrupt) intermediate value of the variable or the ISR modifying the variable while the main code was in the middle of doing an operation on it, possibly corrupting it.

A possible solution to this is to use a mutex or turn off interrupts during any relevant non-atomic operation.

• The size of int doesn't matter, that's a myth. You can get non-atomic access no matter the size. See electronics.stackexchange.com/a/409570/6102 Jan 21 '19 at 13:18
• @Lundin True, edited the answer. Jan 21 '19 at 13:34
• the problem was in the physical aspect, the resistor that lays bellow the bush button has too much resistance (10K), I changed it to 1K and everything worked perfectly. without the use of volatile global variables. Jan 21 '19 at 13:36
• @Bouzaid Still, I would take the gentle-person's advice and make a habit of using them. Jan 21 '19 at 13:37
• @Bouzaid The fact that it happens to work does not mean it's not a problem. That's the thing with C. Broken code can appear to work, until it doesn't. Jan 21 '19 at 13:37