Search code examples
cavratmega

Setting up Interrupts on atmega328 in pure C


I am currently working on an Arduino Uno Board and I am trying to write it in pure C without the use of Arduino's Libraries.

My project which I am working should work like this:

  • Set LEDs PB0 to BP7 ON and OFF.

  • Set interrupt on PD2 connected to a Button.

  • When the Button is pressed the LEDs should STOP (pause).

  • When the Button is pressed Again the LEDs should turn ON again
    starting from the last LED which was OFF.

To be more precise:

  • The function play() is called
  • LEDs are starting to blink one after other
  • If I press the BUTTON the play() function should STOP

This means that if the LED connected to PB3 was last LED ON, when I press the Button again the function play() should continue from PB4.

Here is what I have so far:

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

#include <avr/io.h>
#include <avr/interrupt.h>
#include <util/delay.h>

void play( void );

volatile uint8_t buttonWasPressed = 0;
const unsigned char LEDS[] = { PB0, PB1, PB2, PB3, PB4, PB5 };

int main(void)
{
    DDRB = 0xFF;  /// Set PORTB as OUTPUT

    DDRD  |=  ( 1 << PD7 );     /// Set PIN7 IN DDRD as INPUT
    PORTD &= ~( 1 << PD7 );     /// Set PIN7 on PORTD to LOW
    DDRD  &= ~( 1 << PD2 );     // Clear the PD2 pin and set PD2 (PCINT0 pin) now as input
    PORTD |= (1 << PD2);        // Set PIN PD2 as INPUT with pull-up enabled

    EICRA |= (1 << ISC00);      // set INT0 to trigger on ANY logic change
    EIMSK |= (1 << INT0);       // Turns on INT0
    sei();                      // turn on interrupts

    while(1)
    {
        play();
    }
}

ISR (INT0_vect)
{

    uint8_t buttonState = PIND & ( 1 << PD2 );
    if ( buttonState )
    {
        if ( buttonWasPressed == 0 )
        {
            PORTD ^= ( 1 << PD7 );  /// SET PIN 4 IN PORT B TO LOW
            _delay_ms( 200 );
            buttonWasPressed = 1;   /// update button state
        }
    }
    else                            /// The button is not pressed
    {
        buttonWasPressed = 0;       /// Update the button state
    }
}

void play( void )
{
    for ( uint8_t i = 0 ; i < 6 ; i++ )
    {
        PORTB |= ( 1 << LEDS[i] );  ///Turn LED ON
        _delay_ms( 250 );
        PORTB &= ~( 1 << LEDS[i] ); ///Turn LED OFF
        _delay_ms( 250 );
    }
}

At this point the function play() runs forever and if I press the Button the LED connected to PD7 goes ON and OFF.


Solution

  • Try something like this.

    #ifndef F_CPU
    #define F_CPU 16000000UL
    #endif
    
    #include <avr/io.h>
    #include <avr/interrupt.h>
    #include <util/delay.h>
    
    void play( unsigned int a );
    ISR (INT0_vect);
    
    volatile uint8_t buttonWasPressed = 0;
    const unsigned char LEDS[] = { PB0, PB1, PB2, PB3, PB4, PB5 };
    unsigned int ledNum = 0;
    
    int main(void)
    {
        DDRB = 0xFF;  /// Set PORTD as OUTPUT
    
        DDRD  |=  ( 1 << PD7 );     /// Set PIN7 IN DDRD as INPUT
        PORTD &= ~( 1 << PD7 );     /// Set PIN7 on PORTD to LOW
        DDRD  &= ~( 1 << PD2 );     // Clear the PD2 pin and set PD2 (PCINT0 pin) now as input
        PORTD |= (1 << PD2);        // Set PIN PD2 as INPUT with pull-up enabled
    
        EICRA |= (1 << ISC00);      // set INT0 to trigger on ANY logic change
        EIMSK |= (1 << INT0);       // Turns on INT0
        sei();                      // turn on interrupts
    
        while(1)
        {
            if(buttonWasPressed == 1)
                play(ledNum);
    
        }
    }
    
    ISR (INT0_vect)
    {
    
        uint8_t buttonState = PIND & ( 1 << PD2 );
        if ( buttonState )
        {
            if ( buttonWasPressed == 0 )
            {
                PORTD ^= ( 1 << PD7 );  /// SET PIN 4 IN PORT B TO LOW
                _delay_ms( 200 );
                buttonWasPressed = 1;   /// update button state
            }
        }
        else                            /// The button is not pressed
        {
            buttonWasPressed = 0;       /// Update the button state
        }
    }
    
    void play( unsigned int a )
    {
        for ( uint8_t i = a ; i < 6 ; i++ )
        {
            PORTB |= ( 1 << LEDS[i] );  ///Turn LED ON
            _delay_ms( 250 );
            PORTB &= ~( 1 << LEDS[i] ); ///Turn LED OFF
            _delay_ms( 250 );
            ledNum=i;
        }
    }
    

    by defining a variable to save which LED it was on then whenever it is resumed it will start from the last lit LED. check it out. Change if there is anything. I just gave the idea. hope it helps :)