avr的外部中断

关于AVR中断:

系统在正常运行主程序时,如果突然有一个重要的任务要马上处理,那么系统就要保存现在的工作,然后再去处理这个任务,执行这个重要任务完毕以后再返回原来的主程序继续运行,这就是中断。

主程序一旦进入中断服务程序,那么AVR芯片将自动的关闭全局中断,在这个期间不再执行其它的中断请求,直到中断程序结束以后芯片才自动的重新开放全局中断(注意,在这个期间某些中断请求可能会被丢弃,某些请求会留下中断请求标致,一旦当前的中断执行完毕,这个有中断标致的请求就有可能马上得到响应,如INT0的下降沿触发就会留下中断请求标致,而低电平触发就不会流下中断请求标致)。如果你想在执行中断服务程序时响应另外一个更重要的中断,那么就要在中断服务程序中加入一条打开全局中断的语句。

我们现在先来讨论外部中断

外部中断要要记得5个寄存器,分别是:

1.   status register -SREG        状态寄存器。而且外部中断关心的是它的Bit-7-I位,全局中断使能。置位时,使能全局中断。那些单独的中断,就是你要实现的那些中断,他们的使能由其他独立的控制寄存器控制,就比如说下面说的EIMSK等。如果我们对I0,则全部的中断是不可能发生了,就象一个总的开关一样,即使单独中断标志置位与否。I可以通过SEICLI指令来置位和清0

2.   External Interrupt Mask Register -EIMSK   外部中断屏蔽寄存器。 INT7 INT0 ' 1 ,而且状态寄存器 SREG I 标志置位,相应的外部引脚中断就使能了。

3.   External Interrupt Control Register A – EICRA   外部中断控制寄存器 ABits 7..0 ISC31, ISC30 ISC00, ISC00:外部中断 3 - 0 敏感电平控制位。详见datesheet。如果 SREG 寄存器的 I 标志和EIMSK 寄存器相应的中断屏蔽位置位,那么外部中断 3 - 0 引脚 INT3~INT0 引脚激活。需要注意的是,改变ISCn时,有可能发生中断。因此,建议首先在EIMSK里清除相应的中断使能位INTn,然后再改变ISCn。最后呢,千万不要忘记在重新使能中断之前,通过对EIFR的相应中断标志位INTFn写“ 1 ,使其清0

4.   External Interrupt Control Register B – EICRB   外部中断控制寄存器 BBits 7..0 ISC71, ISC70 - ISC41, ISC40:外部中断 7 - 4 敏感电平控制位。详见datesheet,它和EICRA可是不同的。检测信号跳变沿之前 MCU 首先对INT7:4引脚进行采样。如果选择了跳变沿中断或是电平变换中断(上升沿和下降沿都将产生中断),只要信号持续时间大于一个时钟周期,中断就会发生;否则无法保证触发中断。要注意由于 XTAL 分频器的存在, CPU 时钟有可能比 XTAL 时钟慢。若选择了低电平中断,低电平必须保持到当前指令完成,然后才会产生中断。而且只要将引脚拉低,就会引发中断请求。而且,同样需要象EICRA一样注意:改变 ISCn1/ISCn0 时一定要先通过清零 EIMSK 寄存器的中断使能位来禁止中断。否则在改变ISCn1/ISCn0的过程中可能发生中断。

5.   External Interrupt Flag Register – EIFR。外部中断标志寄存器。INT7:0引脚电平发生跳变时触发中断请求,并置位相应的中断标志INTF7:0 。如果SREG的位 I 以及 EIMSK 寄存器相应的中断使能位为 1 MCU 既跳转到中断例程。中断例程执行时标志被硬件清零。此外,标志位也可以通过写入 1 的方式来清零。若 INT7:0配置为电平触发,这些标志位总是为 ' 0 。在睡眠模式下,如果中断是禁止的,则这些引脚的输入缓冲器也是禁止的。这有可能产生逻辑电平的变化并置位 INTF3:0。更多信息请参考手册的“ 数字输入使能和睡眠模式 ”。

 

我们应该清楚的是:外部中断通过引脚 INT7:0 触发。只要使能了中断,即使引脚 INT7:0配置为输出,只要电平发生了合适的变化,中断也会触发。这个特点可以用来产生软件中断。通过设置外部中断控制寄存器 EICRA (INT3:0) EICRB (INT7:4),中断可以由下降沿、上升沿,或者是低电平触发。当外部中断使能并且配置为电平触发,只要引脚电平为低,中断就会产生。若要求 INT7:4 在信号下降沿或上升沿触发, I/O 时钟必须工作,如数据手册 P 33 时钟系统及其分布 说明的那样。 INT3:0 的中断条件检测则是异步的。也就是说,这些中断可以用来将器件从睡眠模式唤醒。在睡眠过程 ( 除了空闲模式 ) I/O 时钟是停止的。

上面的多为数据手册里面的内容。也许我们回有几个困惑。

1.   为何AVR 写“ 1 也能清0呢,这不是很奇怪嘛。你可以参考下面几个网页

         http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=749852

http://www.ouravr.com/bbs/bbs_content.jsp?bbs_sn=691118&bbs_page_no=1&bbs_id=1000

http://www.c51bbs.com/c51bbs/topic1/c51bbs17322.htm

但最终呢,真正的原因是在AVR-GCC的帮助文档avr-libc本来就有的,FAQ24Why are (many) interrupt flags cleared by writing a logical 1? 当然,你的E文要好地。

参见如下说明:

Why are (many) interrupt flags cleared by writing a logical 1?

 

Usually, each interrupt has its own interrupt flag bit in some control register, indicating the specified interrupt condition has been met by representing a logical 1 in the respective bit position. When working with interrupt handlers, this interrupt flag bit usually gets cleared automatically in the course of processing the interrupt, sometimes by just calling the handler at all, sometimes (e. g. for the U[S]ART) by reading a particular hardware register that will normally happen anyway when processing the interrupt.

From the hardware's point of view, an interrupt is asserted as long as the respective bit is set, while global interrupts are enabled. Thus, it is essential to have the bit cleared before interrupts get re-enabled again (which usually happens when returning from an interrupt handler).

 

Only few subsystems require an explicit action to clear the interrupt request when using interrupt handlers. (The notable exception is the TWI interface, where clearing the interrupt indicates to proceed with the TWI bus hardware handshake, so it's never done automatically.)

 

However, if no normal interrupt handlers are to be used, or in order to make extra sure any pending interrupt gets cleared before re-activating global interrupts (e. g. an external edge-triggered one), it can be necessary to explicitly clear the respective hardware interrupt bit by software. This is usually done by writing a logical 1 into this bit position. This seems to be illogical at first, the bit position already carries a logical 1 when reading it, so why does writing a logical 1 to it clear the interrupt bit?

 

The solution is simple: writing a logical 1 to it requires only a single OUT instruction, and it is clear that only this single interrupt request bit will be cleared. There is no need to perform a read-modify-write cycle (like, an SBI instruction), since all bits in these control registers are interrupt bits, and writing a logical 0 to the remaining bits (as it is done by the simple OUT instruction) will not alter them, so there is no risk of any race condition that might accidentally clear another interrupt request bit. So instead of writing

 

TIFR |= _BV(TOV0); /* wrong! */

simply use

TIFR = _BV(TOV0);

2.   只要使能了中断,即使引脚 INT7:0配置为输出,只要电平发生了合适的变化,中断也会触发.这句怎么理解?答:也就是说,你打开了中断int0int1,同时这两个管脚定义为输出,然后,你使用软件设置这两个管脚的输出电平,当满足中断条件时,中断就发生了。这不就是软件中断吗?

3.   在配置了外部中断控制寄存器、屏蔽寄存器、标志寄存器后,是否还需要设置IO口为输入端口呢?答:是的,不过IO口上电时就默认是输入了,可以不写这条指令。补充,设置成输出也照样产生中断。它用PINx读。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
ATmega64微控制器有6个外部中断,被标记为INT0到INT5。这些中断可以被外部信号触发,例如按键按下或传感器检测到的事件。以下是ATmega64外部中断的一些基本信息: - 每个外部中断都有一个触发器引脚,引脚编号为INT0到INT5。 - 可以通过将引脚与外部信号连接来触发中断。 - 中断可以使用下降沿、上升沿、或任意电平触发。 - 中断服务例程必须在中断向量表中定义,并且必须使用特殊的语法定义。 以下是一个简单的代码示例,演示如何在ATmega64上使用外部中断: ```c #include <avr/io.h> #include <avr/interrupt.h> int main(void) { DDRD &= ~(1 << PD2); // 设置 PD2 为输入 PORTD |= (1 << PD2); // 启用 PD2 上拉电阻 EICRA |= (1 << ISC00); // 设置 INT0 中断为上升沿触发 EIMSK |= (1 << INT0); // 启用 INT0 中断 sei(); // 启用全局中断 while (1) { // 主循环代码 } return 0; } ISR(INT0_vect) { // 在这里处理 INT0 中断 } ``` 在这个例子中,我们将PD2设置为输入,并启用了它的上拉电阻。然后,我们将INT0中断设置为上升沿触发,并启用了该中断。我们还启用了全局中断,并在主循环中等待中断事件发生。 当PD2引脚检测到上升沿时,INT0中断将会触发,跳转到ISR(INT0_vect)中断服务例程中执行。在这个例子中,我们只是在中断服务例程中打了一个断点,以便在调试时能够检查中断是否正常工作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值