题
在该程序中,AM使用计时器中断在LED中骑自行车,如果有人按下开关,则应阻止第一个中断和触发第二个,第二个应该根据按下的开关来点亮LED。在这里,有点困惑的是什么中断。我推荐了一些用于PIN CHANGE中断的书,并写了一些用于设置PCMSK2的行。输出获得的是“最初,当按下开关时,所有LED都是循环的... LED骑自行车停止并重新开始(这意味着程序正在读取输入,只是不会触发第二个中断)。它不会停止。或暂停&随后不会点燃LED。”有人可以帮忙吗?
#include <avr/io.h>
#include <avr/interrupt.h>
#define PINK_MASK \
((1<<PINK0)|(1<<PINK1)|(1<<PINK2)|(1<<PINK3)|(1<<PINK4)|(1<<PINK5)|(1<<PINK6)|(1<<PINK7))
volatile unsigned int intrs, i=1;
void enable_ports(void);
void delay(void);
extern void __vector_23 (void) __attribute__ ((interrupt));
extern void __vector_25 (void) __attribute__ ((signal));
void enable_ports()
{
DDRB = 0xff; //PORTB as output for leds
PORTB = 0xff;
DDRK = 0x00; //PORTK as input from switches
PORTK |= PINK_MASK;
PCMSK2 = PINK_MASK; //ENABLE PCMSK2, Setting interrupts
PCICR = 0x04;
PCIFR = 0x04;
TCCR0B = 0x03; //Setting TIMER
TIMSK0 = 0x01;
TCNT0 = 0x00;
intrs = 0;
}
void __vector_23 (void)
{
intrs++;
if(intrs > 60)
{
intrs = 0;
PORTB = (0xff<<i);
i++ ;
if(i == 10 )
{
PORTB = 0xff;
i = 1 ;
}
}
}
void __vector_25 (void)
{
unsigned char switches;
switches = ((~PINK) & (PINK_MASK)); //Reading from switches
if(switches & (1<<PINK0))
PORTB = (PORTB<<PINK0);
else if (switches & (1<<PINK1))
PORTB = (PORTB<<PINK1);
else if (switches & (1<<PINK2))
PORTB = (PORTB<<PINK2);
else if (switches & (1<<PINK3))
PORTB = (PORTB<<PINK3);
else if (switches & (1<<PINK4))
PORTB = (PORTB<<PINK4);
else if (switches & (1<<PINK5))
PORTB = (PORTB<<PINK5);
else if (switches & (1<<PINK6))
PORTB = (PORTB<<PINK6);
else if (switches & (1<<PINK7))
PORTB = (PORTB<<PINK7);
}
int main(void)
{
enable_ports();
sei();
while(1)
{
}
}
感谢您的支持。
解决方案
AVR体系结构中的外部中断令人困惑,但并非不可能。我发现最好的资源是 AVR libc页面中断. 。我认为您的代码太复杂了,您想做什么。让我们从头开始:
#include <avr/io.h>
#include <stdint.h>
#include <avr/interrupt.h>
void main() {
sei();
while(1) {};
}
AVR LIBC实际上使处理中断无痛。在我链接到上面的页面中,每个AVR芯片上有所有受支持的中断向量的列表。假设您正在使用MEGA32,现在您想使用计时器中断LED闪烁。让我们添加到程序:
uint8_t led_state;
ISR(TIMER0_COMP_vect) {
led_state = ~led_state;
PORTB = led_state;
}
void setup_timer_interrupt() {
TCCR0B = 0x03;
TIMSK0 = 0x01;
TCNT0 = 0x00;
}
这应该闪烁LED PORTB
每次计时器中断发生时。请注意,应设置的方式是使用 ISR(...)
宏;这 __vector_...
您正在使用的电话被弃用,更令人困惑。
最后,如果我正确理解您的问题,您想使用一组开关来固定LED点亮。实际上,我不会为此使用外部中断,只需使用使用 PINK
期间 ISR(TIMER0_COMP_vect)
, ,但是如果您愿意,我们可以使用它。我们需要添加以下代码:
uint8_t switch_state;
void setup_switch_interrupt() {
// I'm assuming this code to enable external interrupts works.
DDRK = 0x00;
PORTK = 0xff;
PCMSK2 = 0xff; // set to all 1s
PCICR = 0x04;
PCIFR = 0x04;
}
ISR(INT0_vect) {
switch_state = PINK;
}
这做什么?我们将保持开关状态 switch_state
, ,每次读取外部中断射击时(我猜您都会在0-> 1和1-> 0过渡上进行此设置)。剩下的就是使LED输出取决于 switch_state
. 。我们将在计时器中断中进行此操作,因为那是我们到目前为止一直在切换LED的地方。新版本看起来像:
ISR(TIMER0_COMP_vect) {
led_state = ~led_state | switch_state;
PORTB = led_state;
}
那应该做到!
脚注: 我之前说过,使用外部中断来读取开关并不是真正的必要。这是因为您可以在计时器中断期间读取开关值 PINK
. 。你可以摆脱 switch_state
, setup_switch_interrupt()
, , 和 ISR(INT0_vect)
只是修改计时器中断就是这样:
ISR(TIMER0_COMP_vect) {
led_state = ~led_state | PINK;
PORTB = led_state;
}
这应该使程序变得更简单。
其他提示
无论如何,每次你 __vector_23
执行您正在骑自行车在分配给的LED中 PORTB
通过增加 i
. 。如果我明白您要做什么,您应该做的是递增 i
只有在 __vector_25
, ,当按下开关时。