C 中断服务程序在Mega88上执行两次

C 中断服务程序在Mega88上执行两次,c,interrupt,avr,atmel,C,Interrupt,Avr,Atmel,我一直在寻找这个问题的答案,但没有找到任何答案。当我的ISR被触发时,它会执行所有它认为完美的操作,然后在退出并返回到主循环之前,ISR会再次执行。一旦完成第二次循环,它就会返回到主循环。只有当我使用115V继电器操作中断时,才会发生这种情况 我正在尝试检测何时停电或何时恢复供电。我正在使用引脚变化中断来检测继电器是否闭合或断开。当电源断开时,继电器将断开并触发ISR。如果我将此设置连接到一个正常按钮或开关,所有功能都会根据需要工作,并且没有问题,只有当它连接到继电器时才有问题 以下是我的代码:

我一直在寻找这个问题的答案,但没有找到任何答案。当我的ISR被触发时,它会执行所有它认为完美的操作,然后在退出并返回到主循环之前,ISR会再次执行。一旦完成第二次循环,它就会返回到主循环。只有当我使用115V继电器操作中断时,才会发生这种情况

我正在尝试检测何时停电或何时恢复供电。我正在使用引脚变化中断来检测继电器是否闭合或断开。当电源断开时,继电器将断开并触发ISR。如果我将此设置连接到一个正常按钮或开关,所有功能都会根据需要工作,并且没有问题,只有当它连接到继电器时才有问题

以下是我的代码:(我知道我不需要cli,我只是一直在尝试一切)

ISR(PCINT2\u vect){
cli();
履行机构(PORTC,5);
_延迟时间(6000);
cbi(PORTC,5);
对于(延迟计数器=0;延迟计数器
我正在使用引脚变化中断来检测继电器是否闭合或断开
打开

不要这样做。说真的。不要试图将机械开关挂在中断引脚上以触发ISR

如果您坚持这样做,至少要确保开关的信号在击中µC的输入引脚之前在硬件中被适当地去抖动


此外,任何类型的等待(
\u delay_ms(6000);
)都不是人们希望在ISR中拥有的。代码失败的原因是:当信号反弹时,即使您在中断中等待6秒,也会再次设置标志(当您仍在ISR中时)。快速而肮脏的解决方案是在退出ISR之前重置标志

我认为有两个更好的解决方案:

  • 如果要在软件中执行此操作,只需在ISR例程中设置一个指示事件的变量。然后,在主循环(或函数)中,执行继电器的去抖动(10到100ms应该足够了)

  • 如果您想在硬件中实现这一点,只需将一个RC组合作为滤波器添加到引脚(C到地,R到继电器)。只需尝试一些组合,如100k和10µF

我个人的建议是: 两者都做;)

注释: -在中断例程中使用6秒延迟确实是一种不好的做法。更好的做法是:使用一个每隔10毫秒调用一次的计时器,如果设置了标志并且继电器指示断电,则增加一个计数器。如果继电器通电,则将标志和计数器重置为0。如果计数器达到600,则意味着断电时间超过6秒


玩得开心!

我自己也有这个问题,所以我决定回答它,尽管它是一个旧条目:

中断触发两次的原因是中断标志未重置。这是某些atmega类型的问题。您可以通过一条简单的线路来解决此问题:

在您的ISR中断功能的最末尾发布此消息:

PCIFR |= (1<<PCIF2);

PCIFR |=(1)您是否确实验证了输入引脚上的示波器是否达到了预期效果?该中断是由上升沿和下降沿触发的,因此,如果您获得了某种脉冲,这就解释了为什么会出现两次中断。@MattYoung是的,继电器闭合和断开时会有一种脉冲,但我一直未能来我想知道是否有人对如何去抖动有什么想法,因为我尝试过的一切都不起作用。脉冲周期和占空比是什么?所有这些6秒钟的延迟都在浪费大量处理器时间,他们是不是在尝试去抖动?
PCIFR |= (1<<PCIF2);