搜索
bottom↓
回复: 44

一个大家容易忽视的非常严重的中断小程序,请大家帮忙看看!

[复制链接]

出0入0汤圆

发表于 2010-8-18 00:59:47 | 显示全部楼层 |阅读模式
/************************************
实验环境:AT89S52,晶振12MHz,Keil任意版本。
第一个LED灯接在P1.0脚上,第二个LED灯接在P1.1脚上,key1按键接在P3.3脚上(中断1)。

问题1:按下key1按键一直不放手,可以产生中断,但led1还是会闪烁,不过间隔变长了,
       约1.4秒亮一次。不是说产生中断,会中止主程序的执行吗?转去处理中断程序,
       照道理,只要中断还在,led1灯永远是不会亮的啊!为什么led1灯还会亮呢?并
       且我一直是按着不松手,应该是一直产生中断啊,为什么灯还会亮呢?
问题2:没产生中断时,led1灯每隔100mS亮灭一次,为什么产生中断了,led1灯每隔
       约1.4秒亮灭一次。

程序在我的单片机实验过,请高手把程序写入AT89S52试试看,是不是也有这个问题。
还请高手帮忙解答,在此谢过了!(手按下按键长久时,绝对没有所谓的抖动。不要再对
我说,是因为没加去抖动程序造成的。)
************************************/
#include<reg52.h>
sbit led1=P1^0; //用于闪烁的灯
sbit led2=P1^1; //判断有没有进入中断程序,进入了灯会亮

/***********************************/
void delay(unsigned int z) //延时函数,z值是多少,就是多少mS
{
unsigned int x,y;
for (x=z;x>0;x--)
  for (y=110;y>0;y--);
}


/***********************************/
void aaa() interrupt 2 //中断程序,函数名aaa是随便取的
{
  led2=0;//进入中断,让led2灯亮,表示已经进入了中断程序
}

/***********************************/
void main(void) //主函数
{
  led1=1; //给led1赋初值,让灯灭
  EA=1; //打开全局中断,只有打开了全局中断,各个中断源才能使用。
  EX1=1;//打开外部中断1(即P3.3脚)

  while(1) //程序在此不停的循环,等待中断的发生
  {
    led1=!led1; //每次取反一次,让灯每隔100mS不停的亮和灭
    delay(100); //延时100mS,
    led2=1; //只要不进入中断程序,led2灯永远是灭的
  }
}

出0入21汤圆

发表于 2010-8-18 01:14:17 | 显示全部楼层
大概看了一下你程序,在中断里面怎么不清中断标志位呢,印象中51的中断标志必须由软件清0的吧(好久没用了记不清),如果真是这样,那问题就在这里了。至少你的问题2是一定会延时不准的。

出0入0汤圆

发表于 2010-8-18 01:14:27 | 显示全部楼层
中断程序结束了肯定要退出啊。。。中断时,从哪里退出主函数,中断函数走完后,就在哪里返回到主函数。。。

出0入0汤圆

 楼主| 发表于 2010-8-18 01:20:29 | 显示全部楼层
回复【2楼】yiminglei BI7KMT
中断程序结束了肯定要退出啊。。。中断时,从哪里退出主函数,中断函数走完后,就在哪里返回到主函数。。。
-----------------------------------------------------------------------

问题是我按下按键一直不放手,也就是说一直有中断存在,怎么会退出中断呢?问题就出在这里,搞不明白

出0入0汤圆

 楼主| 发表于 2010-8-18 01:23:20 | 显示全部楼层
回复【1楼】117433525 Owen
大概看了一下你程序,在中断里面怎么不清中断标志位呢,印象中51的中断标志必须由软件清0的吧(好久没用了记不清),如果真是这样,那问题就在这里了。至少你的问题2是一定会延时不准的。
-----------------------------------------------------------------------

什么叫“清中断标志位”我不明白,我一直想要的结果是按着按键不放时,灯是不会闪烁的,可中断发生了,灯还是闪烁不停,只是闪烁的间隔变长了而已。

出0入21汤圆

发表于 2010-8-18 01:25:28 | 显示全部楼层
猜想中断程序走完后,它可能还执行了一条指令,然后才再次响应中断的。单步跟踪一下试试。

出0入0汤圆

发表于 2010-8-18 01:33:03 | 显示全部楼层
回复【5楼】117433525 Owen
猜想中断程序走完后,它可能还执行了一条指令,然后才再次响应中断的。单步跟踪一下试试。

-----------------------------------------------------------------------

正解!

在退出中断函数(执行RETI)后,至少会执行一条指令才能再次响应中断请求

出0入21汤圆

发表于 2010-8-18 01:33:56 | 显示全部楼层
哈哈。。新搞程序吧,“中断标志位”这么重要的一个东东没有搞清楚,将来你要是想做中断查询怎么办。
把你的中断程序改为:
/***********************************/
void aaa() interrupt 2 //中断程序,函数名aaa是随便取的
{
  EX1=0; //清中断标志。这是那个标志位,忘了在那个寄存器里了,自己找一下。
  led2=0;//进入中断,让led2灯亮,表示已经进入了中断程序
}

你的程序中有EX1=1;//打开外部中断1(即P3.3脚) ,那EX1=0;就是清中断标志呀。

出0入0汤圆

发表于 2010-8-18 01:47:19 | 显示全部楼层
回复【7楼】117433525 Owen
哈哈。。新搞程序吧,“中断标志位”这么重要的一个东东没有搞清楚,将来你要是想做中断查询怎么办。
把你的中断程序改为:
/***********************************/
void aaa() interrupt 2 //中断程序,函数名aaa是随便取的
{
  ex1=0; //清中断标志。这是那个标志位,忘了在那个寄存器里了,自己找一下。
  led2=0;//进入中断,让led2灯亮,表示已经进入了中断程序
}
你的程序中有ex1=1;//打开外部中断1(即p3.3脚) ,那ex1=0;就是清中断标志呀。

-----------------------------------------------------------------------

EX1=0;是关闭外部中断1了

标准8051的外部中断不需要清中断标志,如果是边沿中断,在进入中断函数时标志会自动清除,

如果是电平中断,中断请求标志不会锁存,外部中断条件存在的话会始终有效

出0入0汤圆

发表于 2010-8-18 09:18:19 | 显示全部楼层
"大家容易忽视的非常严重的中断"
我可不这样认为,是你的思路没搞清楚。

出0入0汤圆

发表于 2010-8-18 09:28:40 | 显示全部楼层
回复【3楼】pxlpxlpxl
回复【2楼】yiminglei bi7kmt
中断程序结束了肯定要退出啊。。。中断时,从哪里退出主函数,中断函数走完后,就在哪里返回到主函数。。。
-----------------------------------------------------------------------
问题是我按下按键一直不放手,也就是说一直有中断存在,怎么会退出中断呢?问题就出在这里,搞不明白
-----------------------------------------------------------------------

LZ看来还是要多去看看书,你一直按键不放手,有没有中断产生的条件?

出0入147汤圆

发表于 2010-8-18 09:49:17 | 显示全部楼层
电平中断,按着不放手,中断标志位一直存在,但是,51单片机响应进入中断后,如果出现新的同等级的中断,还是会退出中断后,执行至少一条指令后才会响应新的中断
因此,你一直按住按键,那么在你执行delay(100);时,几乎每个一条指令后,就进一次中断,因此,LED2一直处于点亮状态,并且导致了delay(100)的时间大大延长,不是100ms,而是delay(100)函数里面的指令数乘以中断程序的指令数的总执行时间.因此,才会隔约1.4秒才闪烁.

所以,不是大家忽视了,是你压根就不了解中断的响应,执行流程

修改原因:改正51进中断的描述

出0入0汤圆

发表于 2010-8-18 10:36:43 | 显示全部楼层
这个情况我刚学外部中断时也遇到过,当时还困惑了一段时间

出0入0汤圆

发表于 2010-8-18 10:41:28 | 显示全部楼层
回复【11楼】dreampet 原野
电平中断,按着不放手,中断标志位一直存在,但是,单片机响应进入中断后,会自动关闭全局中断,在退出中断后,执行至少一条指令后才会响应新的中断
因此,你一直按住按键,那么在你执行delay(100);时,几乎每个一条指令后,就进一次中断,因此,led2一直处于点亮状态,并且导致了delay(100)的时间大大延长,不是100ms,而是delay(100)函数里面的指令数乘以中断程序的指令数的总执行时间.因此,才会隔约1.4秒才闪烁.
所以,不是大家忽视了,是你压根就不了解中断的响应,执行流程
-----------------------------------------------------------------------

正解……

出0入0汤圆

发表于 2010-8-18 11:04:12 | 显示全部楼层
改为脉冲中断应该就好了!!

出0入0汤圆

发表于 2010-8-18 12:15:02 | 显示全部楼层
又是一个浮躁的技术人

出0入0汤圆

发表于 2010-8-18 12:40:35 | 显示全部楼层
楼主不要那么浮躁,把问题搞清楚再下结论

回复【11楼】dreampet 原野
电平中断,按着不放手,中断标志位一直存在,但是,单片机响应进入中断后,会自动关闭全局中断,在退出中断后,执行至少一条指令后才会响应新的中断
-----------------------------------------------------------------------

51的中断系统默认是允许嵌套的,也就是进入中断以后全局中断位并没有关闭(EA!=0)

出0入0汤圆

发表于 2010-8-18 12:45:46 | 显示全部楼层
楼上朋友也说了,51退出中断以后,至少要执行一条语句才会再次响应中断,利用这个特性,可以用一个外部中断做为单步调试

出0入168汤圆

发表于 2010-8-18 13:02:32 | 显示全部楼层
总算一直符合中断条件,中断程序执行完了也是要先退出的,退出后执行主程序一条指令后再进中断。
所以楼主的现象没有什么不对的。

出0入147汤圆

发表于 2010-8-18 13:56:43 | 显示全部楼层
回复【16楼】little Monkey
楼主不要那么浮躁,把问题搞清楚再下结论
回复【11楼】dreampet 原野
电平中断,按着不放手,中断标志位一直存在,但是,单片机响应进入中断后,会自动关闭全局中断,在退出中断后,执行至少一条指令后才会响应新的中断  
-----------------------------------------------------------------------
51的中断系统默认是允许嵌套的,也就是进入中断以后全局中断位并没有关闭(ea!=0)

-----------------------------------------------------------------------

呵,谢谢指正,是的,51系统进入中断后没有关闭EA,能响应高等级中断,但对于同级中断还是只能依序响应~

出0入0汤圆

发表于 2010-8-18 14:14:23 | 显示全部楼层
回复【15楼】xiaobendan 仲跻东
又是一个浮躁的技术人
-----------------------------------------------------------------------

楼主这样肯思考,能发现问题已经不错了,赞一个,毕竟人的修炼是需要时间和感悟的。我有时也和楼主一样,毕竟我们还年轻啊

出0入0汤圆

发表于 2010-8-18 14:20:45 | 显示全部楼层
如果楼主发现问题是虚心请教,而不是用那么肯定的态度去否定一个事物,那是值得表扬一下的。如果发现个小问题用这种哗众取宠的方式吸引眼球就太浮躁了

出0入0汤圆

发表于 2010-8-18 14:55:29 | 显示全部楼层
回复【20楼】d20062303732 lin
回复【15楼】xiaobendan 仲跻东
又是一个浮躁的技术人
-----------------------------------------------------------------------
楼主这样肯思考,能发现问题已经不错了,赞一个,毕竟人的修炼是需要时间和感悟的。我有时也和楼主一样,毕竟我们还年轻啊
-----------------------------------------------------------------------

同意!楼主已经凌晨了还在学习的精神是值得表扬的,至少那时我已经在梦中了。。。

(原文件名:外部中断请求的撤销1.png)


(原文件名:外部中断请求的撤销2.png)

出0入20汤圆

发表于 2010-8-18 16:19:55 | 显示全部楼层
这与清中断标志无关。硬件自动清了!主要原因是:MCU反复产生中断,让DELAY程序的延时放大了N倍所致!

出0入0汤圆

发表于 2010-8-18 19:25:11 | 显示全部楼层
5楼6楼已经给出正确答案,其他人嘛....建议各位去看标准的51手册中断一章.

出0入0汤圆

 楼主| 发表于 2010-8-18 20:11:53 | 显示全部楼层
下班回来看到很多高手的解答,我一直都很感动,有批评的有鼓励的,我都欣然接受,小弟我在此谢过各位师傅了。
我刚刚学单片机有12天了,碰到最难的不是什么C语言的运算,而是单片机的中断系统和定时器/计数器的概念,上面
的问题困扰我4天,我也不停的写啊,改啊,做实验啊,一直不得其解,所以才上论坛请求帮助。
    综合上面各位的所述,我都详细的看过,想过了,现在好像明白了一个步骤(也不知道是不是明白了),就是说:
就算我一直按着按键不放手,中断只执行一次就会退出(按着不放手也要退出),去主程序里面再执行一个指令后,马上
又响应中断,再次进入中断程序,然后又执行一次再退出(此时手还按着不放),如此周而复始......。是这样子吗,我
的表述不知道各位高手能不能看明白?

出0入0汤圆

 楼主| 发表于 2010-8-18 20:25:18 | 显示全部楼层
好,那我再分析我刚才所讲的:“一直按着按键不放手,中断只执行一次就会退出(按着不放手也要退出),去主程序里面再执行一个指令后,马上又响应中断,再次进入中断程序”

我在程序里再加一条指令来验证一下中断程序到底会不会退出(手一直按着不放的情况下):

sbit key1=P3^3; //在开头先进行位定义
.
.
.
void aaa() interrupt 2 //中断程序,函数名aaa是随便取的
{
  led2=0;//进入中断,让led2灯亮,表示已经进入了中断程序
  while(key1==0); //如果检测到外部中断的按键按着不放,就一直不停的循环,直到放手。
}

注意,我加了这条指令while(key1==0)之后,如果不放手,闪烁灯就不闪了,也就是说程序从始至终都在中断程序里面运行,
并没有退出来。把程序写入AT89S52中运行,事实果真如此,闪烁灯不再闪烁了。

当然,这个实验我可能还并没有想周全,只是想验证一下中断程序到底会不会退出来。

出0入54汤圆

发表于 2010-8-18 21:12:22 | 显示全部楼层
楼主,你25楼的描述是对的。

出0入147汤圆

发表于 2010-8-18 23:00:05 | 显示全部楼层
楼主 你的25楼理解是对的
但是 到26楼的时候又钻牛角尖了,while (key1==0); 是个死循环,不管你把它放到那,只要条件满足了,执行一辈子它也不会退出来。

出0入0汤圆

 楼主| 发表于 2010-8-18 23:33:52 | 显示全部楼层
回复【28楼】dreampet 原野
楼主 你的25楼理解是对的
但是 到26楼的时候又钻牛角尖了,while (key1==0); 是个死循环,不管你把它放到那,只要条件满足了,执行一辈子它也不会退出来。
-----------------------------------------------------------------------

唉,说得也是啊,我想也是这样子的!我明白了,看来还没有完完全全地掌握C51的精髓。我会努力的。谢谢大家!

出0入0汤圆

发表于 2010-8-19 00:07:47 | 显示全部楼层
【28楼】 dreampet 原野

积分:513
派别:
等级:------
来自:潮州->深圳->西安->深圳->??
楼主 你的25楼理解是对的
但是 到26楼的时候又钻牛角尖了,while (key1==0); 是个死循环,不管你把它放到那,只要条件满足了,执行一辈子它也不会退出来。  
   


楼主没钻牛角尖,他只是想看看之前中断到底退出来没有,基于他当前的知识用这种方法没什么不合理的.
要说不合理,这个帖子本身就不合理,手册上一句话没看,引出一大串热闹,而且几乎人人有份.

出0入0汤圆

发表于 2010-8-19 08:05:00 | 显示全部楼层
回复【25楼】pxlpxlpxl
    下班回来看到很多高手的解答,我一直都很感动,有批评的有鼓励的,我都欣然接受,小弟我在此谢过各位师傅了。
我刚刚学单片机有12天了,碰到最难的不是什么c语言的运算,而是单片机的中断系统和定时器/计数器的概念,上面
的问题困扰我4天,我也不停的写啊,改啊,做实验啊,一直不得其解,所以才上论坛请求帮助。
    综合上面各位的所述,我都详细的看过,想过了,现在好像明白了一个步骤(也不知道是不是明白了),就是说:
就算我一直按着按键不放手,中断只执行一次就会退出(按着不放手也要退出),去主程序里面再执行一个指令后,马上
又响应中断,再次进入中断程序,然后又执行一次再退出(此时手还按着不放),如此周而复始......。是这样子吗,我
的表述不知道各位高手能不能看明白?
-----------------------------------------------------------------------

中断执行后,返回主程序,,不是间隔一个指令的时间再进中断,而是好几个周期,,并且,C编译器还执行了,入栈出站等过程,,,

出0入0汤圆

发表于 2010-8-19 08:25:30 | 显示全部楼层
回复【10楼】jiabin1024
-----------------------------------------------------------------------

应该是这么回事。

出0入0汤圆

发表于 2010-8-19 08:28:08 | 显示全部楼层
回复【24楼】rainyss
-----------------------------------------------------------------------

我也这样认为。

出0入0汤圆

发表于 2010-8-19 10:34:17 | 显示全部楼层
对技术就是要"钻",LZ还是不错的!
另外再试着用边沿触发的方式试试.

出0入0汤圆

发表于 2010-8-19 10:57:24 | 显示全部楼层
【34楼】 shengy213
积分:59
派别:
等级:------
来自:
对技术就是要"钻",LZ还是不错的!
另外再试着用边沿触发的方式试试.  
 


边沿触发和电平触发是什么,区别在哪里,供计楼主这会儿是蒙的.楼主的动手能力不错,钻研精神也不缺,缺的是理论基础知识.

十几年前的人学单片机时没什么动手机会,只好把书看了一遍又一遍,理论知识自然不缺,现在时代不同了,阿猫阿狗看上5分钟实验板的说明书,也可以上板实操,美其名曰"做实验",其实就是瞎折腾,运气好就做通了,就自认为成功了,运气不好做不通时则上论坛或QQ群问,总能有人帮忙,如此的学习方式,理论基础如何能提高?

一个技术人员,如果没有理论基础,那就是一民科,我是这么认为.大家在乐呵农民造飞碟造永动机的时候,偶尔也应往自已事上看看,防止五十步笑百步.

以上言论没有BS楼主之意,我BS所有光动手不看书人.

出0入4汤圆

发表于 2010-8-19 14:10:31 | 显示全部楼层
51系列单片机是将主时钟分频12作为程序时钟。中断检测是12个时钟的哪个位置记不清了。如中断是电平方式(低电平)进入中断后,自动清中断标志位。虽有中断嵌套但自已优先级是一样,不会自已打入自已。总是运行完中断服务程序后,并总是执行一条指令。
边沿触发方式同样。所有就有楼主的情况产生。

出0入0汤圆

发表于 2010-8-19 16:30:21 | 显示全部楼层
回复【35楼】rainyss  
【34楼】 shengy213
积分:59
派别:
等级:------
来自:
对技术就是要"钻",lz还是不错的!
另外再试着用边沿触发的方式试试.  
 
边沿触发和电平触发是什么,区别在哪里,供计楼主这会儿是蒙的.楼主的动手能力不错,钻研精神也不缺,缺的是理论基础知识.
十几年前的人学单片机时没什么动手机会,只好把书看了一遍又一遍,理论知识自然不缺,现在时代不同了,阿猫阿狗看上5分钟实验板的说明书,也可以上板实操,美其名曰"做实验",其实就是瞎折腾,运气好就做通了,就自认为成功了,运气不好做不通时则上论坛或qq群问,总能有人帮忙,如此的学习方式,理论基础如何能提高?
一个技术人员,如果没有理论基础,那就是一民科,我是这么认为.大家在乐呵农民造飞碟造永动机的时候,偶尔也应往自已事上看看,防止五十步笑百步.
以上言论没有bs楼主之意,我bs所有光动手不看书人.
-----------------------------------------------------------------------
赞同!理论是实践的基础,实践又是理论的补充,相辅相成,缺一不可!

出0入0汤圆

 楼主| 发表于 2010-8-19 19:24:12 | 显示全部楼层
回复【35楼】rainyss
【34楼】 shengy213  
积分:59
派别:
等级:------
来自:
对技术就是要"钻",lz还是不错的!  
另外再试着用边沿触发的方式试试.   
   
边沿触发和电平触发是什么,区别在哪里,供计楼主这会儿是蒙的.楼主的动手能力不错,钻研精神也不缺,缺的是理论基础知识.
十几年前的人学单片机时没什么动手机会,只好把书看了一遍又一遍,理论知识自然不缺,现在时代不同了,阿猫阿狗看上5分钟实验板的说明书,也可以上板实操,美其名曰"做实验",其实就是瞎折腾,运气好就做通了,就自认为成功了,运气不好做不通时则上论坛或qq群问,总能有人帮忙,如此的学习方式,理论基础如何能提高?
一个技术人员,如果没有理论基础,那就是一民科,我是这么认为.大家在乐呵农民造飞碟造永动机的时候,偶尔也应往自已事上看看,防止五十步笑百步.
以上言论没有bs楼主之意,我bs所有光动手不看书人......
-----------------------------------------------------------------------


对35楼的中肯的批评,并一针见血的道出了我的软肋所在,我诚恳的接受您的意见。
确实我刚刚学C语言和单片机才10来天,还有很多知识点并没有掌握到。书本上也没有非常清楚的说明白有些知识点,我碰到不明白的难点时,也很难在书本上找到答案,只有一次次用笔把各种变量的变化记录在纸上,并通过单片机反复实验,才会弄明白其中的要点,都是心里感悟出来的,而这些东西,在书本上是找不到的,书本上的知识只是一个大概的指导方向,很多细节要自己去实验并掌握的。

出0入0汤圆

 楼主| 发表于 2010-8-19 19:30:50 | 显示全部楼层
现在我已经不在这个中断上的问题继续缠绕了,我在进行下一步的知识点的学习,但我会利用学到的东西来验证前面的结论,因此,前面各位大虾的讨论对我的帮助很大。

当然,我还是希望大家在这个贴子上继续讨论,给像我这样的菜鸟一个学习的机会,让小虾们少走弯路。

出0入0汤圆

发表于 2010-8-22 13:19:26 | 显示全部楼层
怎么没有提前看这个帖子啊!我也碰到了这个问题想了两天还没有想出来。
理论太差了啊!

出0入0汤圆

发表于 2011-3-20 22:42:00 | 显示全部楼层
好贴啊

出0入0汤圆

发表于 2012-1-29 23:34:54 | 显示全部楼层
默认是外中断级别最高的,while (key1==0); 不跳出来的话,那肯定不会执行别的啦!
你是一下改改中断的优先级别,就不一样了!

出0入0汤圆

发表于 2012-2-3 21:15:25 | 显示全部楼层
回复【35楼】rainyss
-----------------------------------------------------------------------

觉得这位朋友说的不错,我发现现在不少人在学习的时候缺乏专研精神!!碰到问题。不自己想!也不想着自己去弄明白!第一选择就是到处问人!这个习惯特别不好!往往在自己研究中会学到更多知识,而,随便就跑去问人,第一印象不深,不理解。第二,失去了发现新知识的机会。。

出0入0汤圆

发表于 2012-2-18 23:37:13 | 显示全部楼层
又学习了
回复【13楼】xyzhang_yjs08  
-----------------------------------------------------------------------
回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-5-8 01:01

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表