1
\$\begingroup\$

Friendly Note: I am a beginner :)

Microcontroller: Atmega328p LED = PORTB0 BUTTON = PORTB1

Aim: To have the button generate a pin change interrupt request which runs an ISR that toggles PORTB0 HIGH and LOW, therefore toggling the LED ON and OFF.

Current Problem: The LED toggles ON but does not toggle OFF.

#include <avr/io.h> // header file file for input output pins
#include <util/delay.h> // header file for delay.
#include <avr/interrupt.h>

#define F_CPU 16000000UL

int main (void)
{
    DDRB |= (1<<PORTB0); //SETS LED TO OUTPUT
    PORTB |= (1<<PORTB1); // TURNS ON PULL UP RESISTOR FOR BUTTON

    //Set button interrupt
    PCMSK0 |= (1<<PCINT1); // PIN CHANGE MASK REGISTER FOR BUTTON
    PCICR |= (1<<PCIE0); // ENABLES PIN CHNAGE INTERRUPT

    sei(); //ENABLES ALL INTERRUPTS GLOBALLY (REQUIRED FOR ALL TYPES OF INTERRUPTS)

    while (1)
    {
      //Empty while loop
    }
}
ISR (PCINT0_vect) // INTERRUPT ROUTINE
{
    PORTB  ^= (1<<PORTB0); // TOGGLES LED ON OR OFF
}

I have tried using a switch statement aswell but this had the same result (only toggling the LED ON):

    #include <avr/io.h> // header file file for input output pins
    #include <util/delay.h> // header file for delay.
    #include <avr/interrupt.h>
    #define F_CPU 16000000UL
    #define DEBOUNCE_TIME 25

unsigned char button_state()
{
  if(!(PINB & 0x02)) {
    _delay_ms(DEBOUNCE_TIME);
    if (!(PINB & (0x02))) return 1;
    }
   return 0;
}

    int main (void)
    {
        DDRB |= (1<<PORTB0); //SETS LED TO OUTPUT
        PORTB |= (1<<PORTB1); // TURNS ON PULL UP RESISTOR FOR BUTTON

    unsigned char n_led = 1;

       while(1) {

  if (button_state()) 
  {
   switch(n_led){
   case 1:
     PORTB ^= (1<<PORTB0);
   break;
   case 2:
     PORTB ^= (1<<PORTB0);
   n_led=0; // reset case number
   break;
  }
    n_led++; // next case
 }
}
 return (0);
 }
\$\endgroup\$
3
  • 1
    \$\begingroup\$ maybe the LED is wired incorrectly, or the I/O pin failed ... it would really help if you asked a question \$\endgroup\$ – jsotola Dec 18 '20 at 6:03
  • 1
    \$\begingroup\$ Have you verified that the LED toggle and button detection work independently? You could send some output to the serial port for debugging. \$\endgroup\$ – StarCat Dec 18 '20 at 7:07
  • \$\begingroup\$ You might want to show how you wired that button up \$\endgroup\$ – Tom L. Dec 18 '20 at 19:10
0
\$\begingroup\$

I can't see anything wrong with your code (although you do rely on registers being in their reset state which may not be true) but I do have a couple of points:

  1. The pin change interrupt will occur if the pin either goes from low to high or high to low. Even if it worked as designed the led would change state both when you press the button and when you release it. You may not notice if you press and release the button quickly as the LED will end up in the same state.

  2. in general it is a bad idea to use pushbuttons directly to create an interrupt. Whenever a normal switch connects (or in some cases disconnects) it does not do so cleanly, it is likely to bounce and cause many transitions over a period of e few hundred microseconds to a few milliseconds. This is called "contact bounce".

A better approach that is normally used is to create a polling loop using a timer that runs at a few tens of Hertz to a few hundred times per second.

Within that timer ISR, you should create a state machine that polls the switch and performs the desired behaviour.

This is not suitable for waking up a processor from sleep but for that, it is acceptable to use the pin change interrupt bearing in mind that there may be multiple switch closures from a single button press.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.