Interrupt on change and checking pin not working.

Thread Starter

lemario

Joined Jan 31, 2016
22
I have this code. What i am trying to do is using the interrupt function and then if gpi2 is positive, it blincks..

Right now i have a wire on gpi2 and every time i touch it the 'blinck()' goes of, or even a bump on my table makes it go off...

Any idea on how to fix it?



Pic: 12f683
Compiler: microC

Code:
int i = 0;
void blink(void)
{
    for(i = 0; i<4;i++)
    {
        GPIO.B0 = 1;
        delay_ms(100);
        GPIO.B0 = 0;
        Delay_ms(100);
    }
}

void interrupt(void)
{

    if(INTCON.GPIF == 1 && GPIO.B2 == 1 )
    {
        INTCON.GIE = 0;
        blink();
        INTCON.GPIF = 0;
        INTCON.GIE = 1;
    }
    else
    {
    }

}

void main() {
    TRISIO = 0b00000100;
    CMCON0 = 0x07;
    ANSEL = 0;
    ADCON0 = 0;

    INTCON.GIE = 1;
    INTCON.GPIE = 1;
    IOC.IOC2 = 1;
    while(1)
    {
    }
}
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
It looks like your IOC input (pin 5) is just floating around and picking up noise. You need to pull it up or down with a resistor (or use the weak pullup WPU2=1). Also, be sure to read the port before clearing the interrupt flag to clear the mismatch condtion.

During init, be sure to configure IOC, read the port and clear the interrupt flag before enabling interrupts.

You should have a .1uF cap at least across Vdd-Vss and a resistor in series with the LED 240-560 ohms should do it.

Eventually, you might want to rethink using IOC for this sort of thing.
 

Thread Starter

lemario

Joined Jan 31, 2016
22
@JohnInTX

So i need to put a resistor on the pink wire?

"Also, be sure to read the port before clearing the interrupt flag to clear the mismatch condtion."
Don't understand..

"You should have a .1uF cap at least across Vdd-Vss."
Don't understand(Vdd-Vss?)..

:/
 

JohnInTX

Joined Jun 26, 2012
4,787
@JohnInTX

So i need to put a resistor on the pink wire?

"You should have a .1uF cap at least across Vdd-Vss."
Don't understand(Vdd-Vss?)..

:/
Does this help?
P628small.jpg

Reread the datasheet section on Interrupt On Change. Each change of the input generates a 'mismatch' condition i.e. it doesn't match what the input value was before and interrupts the processor. As part of the interrupt routine, you have to read the port to store the new port value and clear the mismatch condition so it can detect another change from the new current value.

If all you want to do is detect the switch push and turn on the LED while it's pressed, you don't need (or want) to use interrupts. Just sample the switch in main and turn on the LED when it reads 0. Turn it off when it reads 1.

Even if you wanted to use interrupts, you would be better off using the standard INT function. In this case, INT would be set for a negative-going edge from the button input. IOC is really for other things. The name is misleading. Every interrupt happens on a 'change' of the interrupt pin. IOC allows you to interrupt when any (enabled) pin changes in either direction - not quite the same thing as a simple INT. IOC is most useful for things like quadrature encoders and the like. Not so much for things like this.
 
Last edited:

dannyf

Joined Sep 13, 2015
2,197
quite a few issues with your code and they are fundamental:

1) you have to clear the flag in the isr. in your code, what happens when B2 is low?
2) you don't need to prohibit interrupt in the isr - the chip does it for you.
3) you want your isr to be short -> yours is looping around, and for a long time.

the logic for your isr should look like something like this:

Code:
  if the pin state has changed {
    clear ioc flag;
    if the change is desired (positive edge for example) {
      set up the flag to execute blick();
    }
  }
 

Thread Starter

lemario

Joined Jan 31, 2016
22
@dannyf Thank you.
@JohnInTX So is it the best way for what i need a simple If statement and a while loop on main?

What if i have 10 buttons? Will that be still a good method of doing things?
 
Last edited:

JohnInTX

Joined Jun 26, 2012
4,787
AND or OR the inputs (depending on if they are active low or active high), and route the output to an edge triggered interrupt. In the interrupt, scan the input lines.
Or ADC inputs.
Makes sense but how do you scan 10 inputs with an 8 pin PIC? Also, I know how to do it with the ADC but you should elaborate for the TS if you bring it up.

@lemario re: 10 buttons.. You have to be more specific in describing the buttons' functions to get a good answer to that. 10 buttons could use 10 input lines or be placed in an XY matrix or be a part of a multi tap voltage divider that the ADC reads. It depends on the application. As a rule of thumb though, I prefer one input/one port line. Adding fancy AND/OR/magic dividers to a system frequently costs more than just buying a chip with enough IO in the first place.

So is it the best way for what i need a simple If statement and a while loop on main?
I think so. If all you want to do is play around and light the LED when the switch is pressed just do it in the main loop. When your requirements get more complex, then worry about more complex code. Simple is best.

This would be a good time to restate your problem telling us exactly what you want the LED to do when the switch is open, pressed, held and released.
 

Picbuster

Joined Dec 2, 2013
1,047
I have this code. What i am trying to do is using the interrupt function and then if gpi2 is positive, it blincks..

Right now i have a wire on gpi2 and every time i touch it the 'blinck()' goes of, or even a bump on my table makes it go off...

Any idea on how to fix it?



Pic: 12f683
Compiler: microC

Code:
int i = 0;
void blink(void)
{
    for(i = 0; i<4;i++)
    {
        GPIO.B0 = 1;
        delay_ms(100);
        GPIO.B0 = 0;
        Delay_ms(100);
    }
}

void interrupt(void)
{

    if(INTCON.GPIF == 1 && GPIO.B2 == 1 )
    {
        INTCON.GIE = 0;
        blink();
        INTCON.GPIF = 0;
        INTCON.GIE = 1;
    }
    else
    {
    }

}

void main() {
    TRISIO = 0b00000100;
    CMCON0 = 0x07;
    ANSEL = 0;
    ADCON0 = 0;

    INTCON.GIE = 1;
    INTCON.GPIE = 1;
    IOC.IOC2 = 1;
    while(1)
    {
    }
}
  1. void interrupt(void)
  2. {

  3. // if(INTCON.GPIF == 1 && GPIO.B2 == 1 ) //
  4. // replace line 4 with :
  5. if (INTCON.GPIF)
  6. {
  7. INTCON.GPIF = 0; // clear flag
  8. if (GPIO.B2) {valid_button } // use this to blink led in timer routine like led=!led; you can make it 50% on off or any other rate 20% on 80 off
  9. } // end of interrupt
  1. // {
  2. // INTCON.GIE = 0; // keep this in main
  3. // blink();
  4. // INTCON.GPIF = 0; // different place see above
  5. // INTCON.GIE = 1; // keep this in main
 

Thread Starter

lemario

Joined Jan 31, 2016
22
@JohnInTX I said 10 button just as an example.

I don't have any real project intended for this. I had just learned about interrupts and was trying to use them in something, but i guess buttons aren't the best for it. :)

Thanks to all who helped. :D
 
Top