0

I am using atmega328P , as it shown in the attached picture when the interruption is executed , the program doesn't turn back to the main to execute the rest of the program ? i made 2 functions ; one to blink led in portC and the other in PORT D the Led in PORT D (interruption) is working fine but the Led for PORT C in the main is not executed is there a problem ??

#ifndef F_CPU
#define F_CPU 16000000UL
#endif

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

#define ACK 0x01 

void portc_led(void)
{
    PORTC|=(1<<5);
    _delay_ms(100);
    PORTC=(0<<5) ;
    _delay_ms(100);
    PORTC|=(1<<5);
    _delay_ms(100);
    PORTC=(0<<5) ;
    _delay_ms(100);
}

void portd_led(void)
{
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
    PORTD|=(1<<7);
    _delay_ms(1000);
    PORTD=(0<<7) ;
    _delay_ms(100);
}


int main(void)
{

    DDRB |= (1<<2)|(1<<3)|(1<<5);    // SCK, MOSI and SS as outputs
    DDRB &= ~(1<<4);                 // MISO as input

    SPCR |= (1<<MSTR);               // Set as Master
    SPCR |= (1<<SPR0)|(1<<SPR1);     // divided clock by 128
    SPCR |= (1<<SPIE);               // Enable SPI Interrupt
    SPCR |= (1<<SPE);                // Enable SPI


    DDRC= 0xFF ; // set PORT C as output 
    DDRD = 0xFF ;
    sei();

    spi_send_data(ACK);

    portc_led();

}



ISR(SPI_STC_vect)
{
    portd_led();

}

2 Answers2

0

You have two conceptional errors in your code:

  1. As long as the interrupt service routine is running, the main function can not run.

  2. After portc_led(), the main() functions returns. Depending on the runtime environment of your compiler system (presumably some GCC) it finally runs in an endless loop, doing nothing. Only the interrupts keep triggering.

the busybee
  • 10,755
  • 3
  • 13
  • 30
  • I agree about the first pont , I am not expecting the routine and the main will be executed at the same time , I am expecting that after this line : spi_send_data(ACK); the interruption will start , and once it is finished , the sfw will turn back to the main and execute portc_led(); is my understanding correct ? – Jbeli_ahmed Jun 19 '20 at 21:29
  • So you are saying that `portd_led()` is executed once, and `portc_led()` not at all? Anyway, you should consider to edit your question and describe exactly what you expect, and what you get. – the busybee Jun 20 '20 at 20:11
0

first of all your code will have a compile Error! because you don't provide a reference to spi_send_data function

but let us imagine that you include it above this piece of code

analyse your code

you say that

interruption is executed , the program doesn't turn back to the main

the program execution path definitely will ruturn to main routine... where will it go ?! :) the code will execut the portc_led function one time (and only one time) maybe before interrupt or maybe after interrupt or maybe interrupt happen in between the function ... so maybe portc_led alredy excuted happen befor interupt but you did not see it becuse it executed in only 400 ms !! and after finsh interupting nothing to do just wait for other interupt ! ..

simple solution : try to change the 100ms delay in portc_led to bigger delay and you will see ...

little advices for improve practicing techniques

  1. look at this code PORTB=(0<<5) equivalent to portB=0b00000000 when you try to clear single bit in register you clear all register's bits ! which is not good ...use this code PORTB&=~(1<<5) for clear single bit which make bitwaise & between portc and 0b11101111 only change single bit and keep other bits as it is
  2. always in interrupt routine make it small as much as you can ... just raise a flags and handle it in the main loop ... read more way you should make it small routine
  3. your program dose not have a mian loop !! (sometimes called super loop).. this loop is simply an infinity loop come after initalization of your systerm and run over and over ... some compiler add empty infinity loop at the end of main routine and other compiler dose not add ... it's a good practice to have a main loop in the main routine even if you not use it ! To keep your program alive

modify the code

not that the following code will not excute blancking in parallel (simultaneously) it will excute them in series (not simultaneously).. if you like to have a parallel blanking use timer interupt in portc_led insted of delay /or use an RTOS (a little bit advanced topic)


#ifndef F_CPU
#define F_CPU 16000000UL
#endif

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

#define ACK 0x01

volatile char spi_interupt_flag = 0;


void portd_led(void)
{
    // this will blank led in pd7 for 3 sec
    for(char i=0;i<6;i++){  
        PORTD^=(1<<PD7) ; // toggle pd7
        _delay_ms(500); // you will see 500 ms blank
    }
}


int main(void)
{

    DDRB |= (1<<2)|(1<<3)|(1<<5);    // SCK, MOSI and SS as outputs
    DDRB &= ~(1<<4);                 // MISO as input

    SPCR |= (1<<MSTR);               // Set as Master
    SPCR |= (1<<SPR0)|(1<<SPR1);     // divided clock by 128
    SPCR |= (1<<SPIE);               // Enable SPI Interrupt
    SPCR |= (1<<SPE);                // Enable SPI


    DDRC= 0xFF ; // set PORT C as output
    DDRD = 0xFF ;
    sei();

    spi_send_data(ACK); // this code will make compile error if you not provide a source for implementation

    
    
    while(1){
        if (spi_interupt_flag)
        {
            //this code only execute when data received from SPI
            portd_led(); //do whatever you want to do for handle it
            spi_interupt_flag = 0; //reset the flag again
        }
        PORTC^=(1<<PC5); //toggle pc5 for ever
        _delay_ms(1000); // pc5 will toggle every 1 sec unless ther is interupt 
    }

}



ISR(SPI_STC_vect)
{
    // just set a flag for handle interrupt in main     
    spi_interupt_flag = 1;
}


Ibram Reda
  • 1,882
  • 2
  • 7
  • 18