打印
[AVR单片机]

AVR中断返回就复位?

[复制链接]
3951|6
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
ningling_21|  楼主 | 2009-12-17 09:39 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 ningling_21 于 2009-12-17 09:51 编辑

AVR MEGA8 芯片,C语言程序,为何打开T/C0中断后,不知为何中断返回就使程序复位?
程序的功能很简单,就是开始让三个灯依次亮,然后都熄灭,进入主循环后灯不亮,等待中断,中断里点亮一个灯,中断返回让这个灯熄灭;
现象:上电后,总是三个灯依次亮,又不停的在这段循环,就像程序不停被复位了。
还请指点迷津...
代码如下:
#include <iom8v.h>
#define uint unsigned int
#define uchar unsigned char
void delay_1ms(void);
void delay_nms(unsigned int n);
/*-------------------
主函数
----------------------*/
void main(void)  
{
uchar ik,ij;
uchar zifu[20]={"abcdefghijklmno"};
DDRB=0XFF;     // 初始化,依次点亮三个LED
PORTB=0XFF;
DDRD=0XFF;
PORTD=0XFF;
PORTB=0XFE;    //  LED1 亮
delay_nms(5000);
PORTB=0XFF;
PORTB=0XFD;    //  LED2 亮
delay_nms(5000);
PORTB=0XFF;
PORTD=0XDF;    //  LED3 亮
delay_nms(5000);
PORTD=0XFF;    //  LED1,2,3 全不亮
     // 定时器初始化
TCCR0=0X04;    // T/C0 时钟源 256分频
TIMSK=0X01;    // T/C0溢出中断使能;
TIFR =0X01;    // T/CO溢出标志位;
SREG =0X80;    //  开全局中断允许;
   

while(1)
{
delay_nms(5000);
PORTD=0xFF;
}
}
/*-------------------
TC0溢出中断服务函数
----------------------*/
interrupt[8] void timer0_overflow(void)
{
TIFR|=0X01;  //清除中断标志,也可以由硬件清除
PORTD=0XFD;  //点亮LED
}
/*-------------------
延时1毫秒函数
----------------------*/
void delay_1ms(void)
{
uint i;
for(i=0;i<150;i++)
{}
}
/*-------------------
延时n毫秒函数
----------------------*/
void delay_nms(unsigned int n) //n ms
{
uint i;
for(i=0;i<n;i++)
delay_1ms();
}

相关帖子

沙发
ningling_21|  楼主 | 2009-12-17 14:56 | 只看该作者
为何出现这样的情况?

使用特权

评论回复
板凳
wangwo| | 2009-12-17 21:44 | 只看该作者
本帖最后由 wangwo 于 2009-12-17 21:45 编辑

AVR复位和中断处理

AVR提供了几种不同的中断源。这些中断和复位向量在程序存储器空间内都有自己单独的程序向量。所有中断都被分配一个私有的使能位,要想使能某一中断,就要向其使能位写入逻辑1,而且要把状态寄存器中的全局中断使能位置1。
    程序存储器空间最低的一些地址,被默认定义为复位和中断向量。完整的向量列表见“中断”部分。该列表也决定了不同中断的优先级。地址越小,优先级越高。RESET具有最高的优先级,其次是INT0——外部中断请求0。详细讨论见“中断”部分。
    当某个中断产生时,全局中断使能位I被清零,所有中断都被禁止。用户程序可以向I位写入1,以实现中断嵌套。所有已使能的中断就可以中断当前的中断程序。当从中断指令——RETI——的执行返回时,I位被自动置位。
    基本上有两种类型的中断。第一种是由事件触发的,把中断标志置位。对于这些中断,程序计数器被引导到实际的中断向量,以执行中断处理程序,同时硬件把相应的中断标志清除。通过向要清除的标志位位置写一个逻辑1,也可以被清除中断标志。如果中断使能位被清除后,相应的中断条件发生时,中断标志将被设置,而后保持到中断被使能为止,或者由软件把标志清除。类似地,如果在全局中断使能位被清除后,一个或多个中断条件产生时,相应的中断标志将被设置,并保持到全局中断使能位被设置为止,然后按优先级顺序执行。
    第二种中断,只要中断条件存在,就会被触发。这些中断没有必要具有中断标志。如果中断条件在中断被使能前消失,那么中断将不被触发。
    当AVR从一个中断中退出时,它一般会返回主程序,并且执行再执行一条指令后,才会响应后续的中断。
    注意,当进入中断程序时状态寄存器不会自动保存,当从中断程序返回时,它也不会自动恢复。这必须由用户软件来完成。
    当使用CLI指令禁能中断时,中断将立即被禁能。当CLI指令执行后,将没有中断再被执行,即使中断在CLI执行的同时发生。下例所示为怎样使用CLI指令来避免在定时的EEPROM写时序期间避免产生中断。
汇编代码例子[/td]
  in      r16, SREG              ; 保存SREG值
  cli            ; 在定时程序中禁能中断
  sbi    EECR, EEMWE    ; 开始写入EEPROM
  sbi    EECR, EEWE
  out    SREG, R16            ; 恢复SREG值(I位)[/td]
C代码例子[/td]
  char    cSREG;
  cSREG = SREG;     /* 保存SREG值*/
  /* 在定时程序中禁能中断 */
  _CLI ();
  EECR  |= (1<<EEMWE);
  EECR  |= (1<<EEWE);        
  SREG  =  cSREG;                /* 恢复SREG值(I位) */

当使用SEI指令来使能中断时,紧跟在SEI后面的指令将在任何后续的中断前被执行,示例如下。


汇编代码例子[/td]
sei     ; 置位全局中断使能
sleep ; 进入休眠,等待中断
; 注意:将在任意中断前进入休眠[/td]
C代码例子[/td]
   _SEI();         /* 置位全局中断使能
   _SLEEP();  /* 进入休眠,等待中断 */
  /* 注意:将在任意中断前进入休眠 */

中断响应时间
    对于所有使能的AVR中断,中断执行响应最少为四个时钟周期。在四个时钟周期之后,实际中断处理程序的向量地址被执行。在这四个时钟周期内,程序指针(PC)被压入堆栈。该失量正常为一到中断程序的跳转,并且该跳转花费三个时钟周期。如果中断发生在一个多周期指令的执行期间,在中断被响应前,该指令要执行完毕。如果当MCU在休眠模式中有中断产生,那么该中断响应时间要再增加四个时钟周期。这是由于从选择的睡眠模式中唤醒需要启动时间。
    从中断处理程序返回需要四个时钟周期。在这四个时钟周期内,程序指针(两个字节)从堆栈中被弹出,堆栈指针加2,SREG的I位被置位。

使用特权

评论回复
地板
wangwo| | 2009-12-17 21:46 | 只看该作者
看看说不定会有点启发:)

使用特权

评论回复
5
ningling_21|  楼主 | 2009-12-18 20:13 | 只看该作者
看了,可惜帮助不大...

使用特权

评论回复
6
god_like| | 2009-12-19 00:53 | 只看该作者
学习了

使用特权

评论回复
7
杜专| | 2009-12-19 10:56 | 只看该作者
学习了

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

5013

主题

17735

帖子

51

粉丝