Search code examples
cmicrocontrollerinterruptavratmega

Interrupt programming for AVR ATmega48


I have a small task to program the following using C, for an ATmega48 controller:

In the beginning, all (6) LEDs are turned on. When button SW1 is pressed, LEDs are only allowed to be turned off with the respective buttons. When button SW2 is pressed, LEDs are only allowed to be turned on with the respective buttons.

Here is what I came up with:

#define F_CPU 1000000UL
#include <asf.h>
#include <util/delay.h>

volatile unsigned char r,d;
ISR(INT0_vect)
{
    if (d = 0)
    {
        PORTB = PORTB | 1<<1;
        d = 1;
    }
    else
    {
        PORTB = PORTB | 0<<2;
        d = 0;         
    }
}
int main (void)
{
    d = 0;
    DDRC = 0x00;
    PORTC = 0xFF;
    DDRB= 0xFF;
    PORTB = 0x00;
    PCICR = 0b00000001;
    sei();
    while(1)
    {
        PCMSK0 = 0b00000100;
        while (d == 0) 
        {
            for (int i=0; i<6; i++)
            {
                if(!(PINC & (1<<i)))
                    PORTB = PORTB | i<<1;
            }
        }
        PCMSK0 = 0b00000010;
        while (d == 1)
        {
            for (int i=0; i<6; i++)
            {
                if(!(PINC & (1<<i)))
                    PORTB = PORTB | i<<0;
                r = r<<1;
            }
        }
    }
}

When I tried to simulate in Atmel AVR Studio, wrong LEDs were turning on when I pressed the respective buttons (e.g. LED2 for SW4), and interrupts never happened.

Please explain what I've done wrong, as I have already scoured several resources, and each one gives a different approach, which I fail to comprehend.


Solution

  • Though since you have not initialied interrupts in a proper way, These lines of code here which are not being executed at all, have two issues.

    if (d = 0)
    {
        PORTB = PORTB | 1<<1;
        d = 1;
    }
    else
    {
        PORTB = PORTB | 0<<2;
        d = 0;         
    }
    

    One issue that is clearly visible is: if (d = 0) does not check if d is equal to 0, instead it assigns 0 to d every single time.

    Are you trying to set and clear the pins? If yes, this is not the way it is supposed to be done. Usually in Embedded we set the pins this way: PORTB |= (1<<1); //you have got this right
    and clear the pins by PORTB &= ~(1<<1);


    You stated that interrupts never happened. It is then a valid conclusion that d remains 0 all the time and you loop in while (d == 0) {} all the time. So r is never modified unless from elsewhere/apart from the code you have shown. Does this r have any implementation related to GPIO for LEDs? If Yes, then you have to first fix the issues in interrupts.


    The reason behind interrupts never happened is that you have not initialized the External interrupts at all.

    You need to configure EICRA – External interrupt control register A register.

    enter image description here enter image description here enter image description here

    Then you need to configure the EIMSK – External interrupt mask register enter image description here

    Then you need to configure the EIFR – External interrupt flag register enter image description here


    Reading the datasheet always helps to understand the implementation details.