我正在制作一个基于数字时钟的项目,在面包板上使用
atmega328p
。我将 4 个按钮连接到 ADC3
通道,我使用 INT0
作为启动 ADC 转换的触发器。我还启用了TimerCounter1
来计算时间。
我在使用增加按钮增加时间时遇到了麻烦,因为
setTime(3, 30)
函数调用在int main()
函数中并且在按下按钮后这个函数setTime(3, 30)
被一次又一次地执行。只有当 ISR(ADC_vect)
被执行时才会发生这种情况。
这是我认为相关的代码部分:
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 4 so we get 5/16 = 0.31v step size
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");
}
}
这是串行输出:
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
为什么
int main()
函数中的指令在ISR(ADC_vect)
执行时反复执行,而在ISR(TIMER1_COMPA_vect)
执行时却不执行? PB5
引脚仅在 ISR(ADC_vect)
被执行时切换。
任何函数中的代码按顺序从函数开始到结束运行一次。对于你的
main()
函数,它到达无限循环,并永远留在那里。
中断(以及附加到它们的调用向量的函数)是被乱序调用的“特殊”代码段。也就是说,它们会在需要运行时中断正常的程序流(例如发生定时器比较时),然后将 CPU 立即返回到原来的位置。
在您的情况下,无限循环点的指令流最终会达到
的效果loop:
nop ; do absolutely nothing
rjmp loop ;go back to the "loop" label
如果发生中断,执行路径基本上如下所示:
loop:
rjmp interrupt ;to the interrupt
(... interrupt here ...)
return here ; back from interrupt
nop ; do absolutely nothing
rjmp loop ;go back to the "loop" label