NerdKits - electronics education for a digital generation

You are not logged in. [log in]

NEW: Learning electronics? Ask your questions on the new Electronics Questions & Answers site hosted by CircuitLab.

Microcontroller Programming » Interrupt Problem

January 03, 2012
by missle3944
missle3944's Avatar

Hi all,

I'm a little confused on this interrupt code. I've tried it on both 168 and 328p. It is supposed to fire an interupt when pc3 is tied to ground. For some reason it never detects the button change. I've been scratching my head at this for hours. I know it is probably something simple or something. I just don't know. Here's the code.

#define F_CPU 14745600

#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
//
// PC4 -- LED anode

void init_interrupt(){
 PCICR |= (1<<PCIE1); //set up interrupt values  This will pcint values 23-16 to fire the interrupt.

PCMSK1 |= (1<<PCINT11); //This will mask the other pins so that only PC5 fires the interrupt.
}

int main() {
  // LED as output
  DDRC |= (1<<PC4);
  DDRC &= ~(1<<PC3);
init_interrupt(); 
  // loop keeps looking forever
  while(1) {
    // turn on LED
    PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(100);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(100);

  }
sei();

 }
 ISR(PCINT1_vect){
      if (PINC&(1<<PC3)){
 PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(2000);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(2000);
    //delay for 500 milliseconds to let the light stay on
    PORTC |= (1<<PC4);

}
return 0;

}
January 03, 2012
by JimFrederickson
JimFrederickson's Avatar

I haven't used 'external interrupts', and I haven't looked through your code yet.

But...

On the 'hardware side' do you have a pull-up resistor in place?

I am guessing that you would need to have the 'pin pulled-up to a logic 1' and then 'ground it through the switch' to create the event detected by the Microcontroller.

I think, although I am not sure, you can use the internal pull-up resister on the Microcontroller.

If nothing else, it is a good thing to know if the pull-ups are there already...

January 03, 2012
by pcbolt
pcbolt's Avatar

missle -

I think the problem is the "sei();" statement. I could be wrong but it looks like it will never be executed after the infinite while loop. I don't know if the interrupt routine should be placed above the rest of the code or not but it's worth a try.

January 04, 2012
by missle3944
missle3944's Avatar

I got it to work

Thanks PCBolt!

-Dan

January 04, 2012
by JKITSON
JKITSON's Avatar

Missle...

What did you do to make it work? I am trying to use interrupt's on my Tractor Pull Sled and am having problems with my mind understanding them...

Thanks for some info...

Jim

January 04, 2012
by missle3944
missle3944's Avatar

Jim,

All I did was just place the sei(); outside the while loop. But make sure you have an external pullup resistor to make it work better on the switch. Heres the working code.

#define F_CPU 14745600

#include <avr/io.h>
#include <inttypes.h>
#include <avr/interrupt.h>

#include "../libnerdkits/delay.h"
#include "../libnerdkits/lcd.h"

// PIN DEFINITIONS:
//
// PC4 -- LED anode

void init_interrupt(){
 PCICR |= (1<<PCIE1); //set up interrupt values  This will pcint values 23-16 to fire the interrupt.

PCMSK1 |= (1<<PCINT11); //This will mask the other pins so that only PC5 fires the interrupt.
}

int main() {
  // LED as output
  DDRC |= (1<<PC4);

      DDRC &= ~(1<<PC3);
    init_interrupt(); 
      // loop keeps looking forever
sei();

while(1) {
        // turn on LED
        PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(100);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(100);

  }

 }
 ISR(PCINT1_vect){
      if (PINC&(1<<PC3)){
 PORTC |= (1<<PC4);

    //delay for 500 milliseconds to let the light stay on
    delay_ms(2000);

    // turn off LED
    PORTC &= ~(1<<PC4);

    //delay for 500 milliseconds to let the light stay off
    delay_ms(2000);
    //delay for 500 milliseconds to let the light stay on
    PORTC |= (1<<PC4);

}
return 0;

}

-Dan

January 04, 2012
by pcbolt
pcbolt's Avatar

Dan -

Really glad to help. I realize your experimenting right now but if you want to use more than one interrupt, or if you want better response time in your main program, you'd be better off spending as little time as possible inside your interrupt service routine. All you'd really have to do is modify a global variable called say "delay_time" to 2000, then every time you call "delay_ms(100)" you can substitute "delay_ms(delay_time)". Of course if you want it to revert back to 100ms you can set delay_time to 100 at the beginning of each while loop (or after every two or three while loops). Another thing you can use is the XOR function to blink the light. As you know, PORTC |= (1<<PC4) turns the LED on and PORTC &= ~(1<<PC4) turns it off, but PORTC ^= (1<<PC4) always toggles it from whatever state it's in.. on to off, off to on (^ is the XOR operator). Your while loop then boils down to just two statements - delay_ms(100); PORTC ^= (1<<PC4); Onwards and upwards....

January 05, 2012
by JKITSON
JKITSON's Avatar

Thanks Missle & Pcbolt.

Will try and implement the code & ideas..

Jim

Post a Reply

Please log in to post a reply.

Did you know that you need to think about wires differently when you're transmitting signals more than a few inches? Learn more...