I am making a digital clock based project, using an atmega328p
on a breadboard. I connected 4 buttons to the ADC3
channel, and I'm using INT0
as a trigger to start ADC conversion. I also enabled the TimerCounter1
to calculate the time.
I am having trouble with increasing the time using the increase button, because the setTime(3, 30)
function call is in the int main()
function and after pressing the button this function setTime(3, 30)
is getting executed again and again. This happens only when ISR(ADC_vect)
gets executed.
This is the part of my code I think is relevant:
xxx.ino
#include <avr/io.h>
int main()
{
Serial.begin(9600);
// PB5
DDRB |= (1<<DDB5);
// ### Want to see how many times these functions - __init__timer(), setTime(), __init__button() gets executed after the Interrupt ###
PORTB ^= (1<<PORTB5);
__init__timer();
//setTime(3, 30);
__init__button();
while(1)
{
}
return 0;
}
void __init__timer()
{
// Enable the global Interrupt
SREG |= (1<<7);
// Enable the output compare match on comapare A
TIMSK1 |= (1<<OCIE1A);
// Set TimerCounter1 in CTC mode
TCCR1A &= ~(1<<WGM10);
TCCR1A &= ~(1<<WGM11);
TCCR1B |= (1<<WGM12);
TCCR1B &= ~(1<<WGM13);
// Set the prescalr to 1024 so we get 15625 Hz pulses(counts) per second
TCCR1B |= (1<<CS10);
TCCR1B &= ~(1<<CS11);
TCCR1B |= (1<<CS12);
// Assign the OCR1A to 46875 (3 seconds)
OCR1A = 46875;
}
ISR(TIMER1_COMPA_vect)
{
Serial.println("ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled");
}
void __init__button()
{
// Select the voltage referance - AREF pin
ADMUX &= ~(1<<REFS1);
ADMUX &= ~(1<<REFS0);
// Select the input channel - ADC3
ADMUX |= (1<<MUX0);
ADMUX |= (1<<MUX1);
ADMUX &= ~(1<<MUX2);
ADMUX &= ~(1<<MUX3);
// Configure the ADCSRA registor
SREG |= (1<<7);
ADCSRA |= (1<<ADIE);
// Set the prescalar to 128 - 125KHz
ADCSRA |= (1<<ADPS0);
ADCSRA |= (1<<ADPS1);
ADCSRA |= (1<<ADPS2);
// Enable the INT0
EIMSK |= (1<<INT0);
EICRA |= (1<<ISC00);
EICRA |= (1<<ISC01);
ADCSRB &= ~(1<<ADTS0);
ADCSRB |= (1<<ADTS1);
ADCSRB &= ~(1<<ADTS2);
ADCSRA |= (1<<ADATE);
// This will start the conversion if trigger INT0 is pressed
ADCSRA |= (1<<ADEN);
}
ISR(ADC_vect)
{
if((ADC < 750) && (ADC > 600))
{
Serial.println("Button 1 -> PB5 toggled");
}
if((ADC < 500) && (ADC > 350))
{
Serial.println("Increase time button pressed... -> PB5 toggled");
// increaseTime();
}
if((ADC < 300) && (ADC > 200))
{
Serial.println("Decrease button pressed... -> PB5 toggled");
// decreaseTime();
}
if((ADC < 200) && (ADC > 100))
{
Serial.println("button 4 -> PB5 toggled");
}
}
And this is the Serial output:
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
Increase time button pressed... -> PB5 toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
Increase time button pressed... -> PB5 toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
Increase time button pressed... -> PB5 toggled
I⸮Increase time button pressed... -> PB5 toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
Increase time button pressed... -> PB5 toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
ISR(TIMER1_COMPA_vect) executed. -> PB5 Not toggled
Why are the instructions in the int main()
function executed again and again when ISR(ADC_vect)
gets executed, but not when ISR(TIMER1_COMPA_vect)
gets executed? The PB5
pin toggles only when ISR(ADC_vect)
gets executed.
Finally I found what was wrong - Why main()
function was executing again only when ISR(ADC_vect)
interrupt occurs.
Just like the answer above by @djph
said, main()
function only executes once and then it loops forever in while(1);
And when an interrupt occurs the program pause the current task and jump from the loop-while(1);
to the respective interrupt routine -ISR()
and after that the program jump back to the loop-while(1)
, means it will not execute the main()
function again after an ISR()
interrupt execution.
So, In my case the main()
function is executing again only if the ISR(ADC_vect) interrupt occurs. Why?
If we look at how I initialized the ADC ->
void __init__button()
function:
// Select the voltage referance - AREF pin
ADMUX &= ~(1<<REFS1);
ADMUX &= ~(1<<REFS0);
// Select the input channel - ADC3
ADMUX |= (1<<MUX0);
ADMUX |= (1<<MUX1);
ADMUX &= ~(1<<MUX2);
ADMUX &= ~(1<<MUX3);
// Configure the ADCSRA registor
SREG |= (1<<7);
ADCSRA |= (1<<ADIE);
// Set the prescalar to 128 - 125KHz
ADCSRA |= (1<<ADPS0);
ADCSRA |= (1<<ADPS1);
ADCSRA |= (1<<ADPS2);
// Enable the INT0
EIMSK |= (1<<INT0);
EICRA |= (1<<ISC00);
EICRA |= (1<<ISC01);
ADCSRB &= ~(1<<ADTS0);
ADCSRB |= (1<<ADTS1);
ADCSRB &= ~(1<<ADTS2);
//
ADCSRA |= (1<<ADATE);
// This will start the conversion if trigger INT0 is pressed
ADCSRA |= (1<<ADEN);
ADC Auto Trigger Enable Bit, The ADC will start a conversion on a positive edge of the selected trigger signal - which is INT0
.
ADCSRA |= (1<<ADATE);
// Enable the INT0
EIMSK |= (1<<INT0);
EICRA |= (1<<ISC00);
EICRA |= (1<<ISC01);
So that means if I press the button not only the ADC
interrupt will occur but also the INT0
interrupt will occur too, But in my code there is no ISR(INT0_vect)
routine. This is the problem...
After adding ISR(INT0_vect)
routine to my code the main()
function is not executing again when ISR(ADC_vect)
interrupt occurs,
ISR(INT0_vect)
{
// Do nothing
}
There may be better ways to do this but this works for me.
I don't know why main()
function executes again if that particular interrupt occurs of which we forget to add the respective routine - ISR()
to the code.
I think I do know now why main()
gets executed again -
If an unexpected interrupt occurs (interrupt is enabled and no handler is installed, which usually indicates a bug), then the default action is to reset the device by jumping to the reset vector.
ISR()
interrupts in detail : www.nongnu.org/avr-libc/user-manual/group__avr__interrupts
And this is the better way to handle empty interrupts -
EMPTY_INTERRUPT(INT0_vect);