找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 3474|回复: 9
收起左侧

在使用单片机中断的IE和EX,遇到中断结束后无法返回

[复制链接]
ID:338671 发表于 2019-4-21 17:34 | 显示全部楼层 |阅读模式
预先的设计想法
P1口接八个led,开关k1,k2分别接外部中断0 P3.2,和外部中断1 P3.3
程序执行的时候8是流水灯形式。
1)k1按下上下四个灯是交替闪烁10次
2)k2按下的是8个灯交替闪烁5次
3)设置优先级别

遇到的问题
1)在进入中断0的时候使用。可以正常返回主函数
IE0 = 0;关闭外部中断
在退出的时候使用
IE0= 1;开启外部中断0;
请看代码
  1. void exter0() interrupt 0
  2. {
  3.         uint tmp1;
  4.         int mun;
  5.         
  6.         IE0 = 0;//关闭外部中断0
  7.         tmp1 = 0xf0;
  8.         for(mun=0;mun<10;mun++)
  9.         {
  10. P1=tmp1;
  11.                 tmp1 =_crol_(tmp1,4);
  12.                 delay(500);
  13.         }
  14.         IE0 = 1;//开启外部中断0
  15. }
复制代码
2)在进入中断0的时候使用。不能正常返回主函数
IE1 = 0;关闭外部中断
在退出的时候使用
IE1= 1;开启外部中断0
  1. void exter1() interrupt 2
  2. {
  3.         int mun1;
  4.         
  5.         IE1= 0;//关闭外部中断1
  6.         for(mun1=0;mun1<5;mun1++)
  7.         {
  8.                 P1 = 0x00;
  9.                 delay(500);
  10.                 P1 = 0xff;
  11.                 delay(500);//这个延时必须要有,不然肉眼无法辨别出led灯有亮
  12.         }
  13.         IE1 = 1;//开启外部中断1
  14. }
复制代码
完整的错误代码
  1. #include<reg51.h>
  2. #include<intrins.h> //循环移位的头文件
  3. #define uint unsigned int

  4. void delay(int z)
  5. {
  6.         int i,j;
  7.         for(i=0;i<z;i++)
  8.         for(j=0;j<110;j++);
  9. }

  10. /* 中断函数的步骤
  11. 1)开启总中断EA
  12. 2) 开启对应的中断的允许位,外部中断0,对应EX0=1,外部中断1,对应EX1=1;
  13. 3)选择触发方式(跳沿触发=1,电平触发=0),外部中断0对应的是IT0=0,低电平有效。
  14.          外部中断1对应的是IT1=1,跳沿触发,高电平跳变成低电平有效
  15. 4)设置中断的优先级,如果不设置则按照系统默认的优先级别
  16. */
  17. void main()
  18. {
  19.   uint tmp;
  20.         
  21.    EA = 1;//开启总中断
  22.    EX0 = 1;//外部中断0允许位,置一表示允许
  23.    IT0 = 0;//外部中断0,选择电平触发,低电平有效
  24.    EX1 = 1;//外部中断1的允许位
  25.    IT1 = 1;//外部中断1,选择跳沿触发,电平由高到低的负跳变有效
  26.    PX0 = 0;//外部中断0,优先级别为低
  27.    PX1 = 1;//外部中断1,优先级别为高
  28.   tmp = 0xfe;
  29.         
  30.   while(1)
  31. {
  32.    P1 = tmp;
  33.   tmp=_crol_(tmp,1);
  34.   delay(500);
  35.   }
  36. }

  37. //外部中断0
  38. void exter0() interrupt 0
  39. {
  40.         uint tmp1;
  41.         int mun;
  42.         
  43.         IE0 = 0;//关闭外部中断0
  44.         tmp1 = 0xf0;
  45.         for(mun=0;mun<10;mun++)
  46.         {
  47.                 P1=tmp1;
  48.                 tmp1 =_crol_(tmp1,4);
  49.                 delay(500);
  50.         }
  51.         IE0 = 1;//开启外部中断0
  52. }

  53. //外部中断1
  54. void exter1() interrupt 2
  55. {
  56.         int mun1;
  57.         
  58.         IE1= 0;//关闭外部中断1
  59.         for(mun1=0;mun1<5;mun1++)
  60.         {
  61.                 P1 = 0x00;
  62.                 delay(500);
  63.                 P1 = 0xff;
  64.                 delay(500);//这个延时必须要有,不然肉眼无法辨别出led灯有亮
  65.         }
  66.         IE1 = 1;//开启外部中断1
  67. }
复制代码

我自己查资料之后发现IEx(IE0,IE1)是外部中断0和外部中断1的标志位。外部中断的中断允许位是EXx(EX0,EX1)修改。为了测试,我把外部中断1的代码修改如下,但是没有修改外部中断0
  1. //外部中断1
  2. void exter1() interrupt 2
  3. {
  4.         int mun1;
  5.         
  6.         EX1= 0;//关闭外部中断1
  7.         for(mun1=0;mun1<5;mun1++)
  8.         {
  9.                 P1 = 0x00;
  10.                 delay(500);
  11.                 P1 = 0xff;
  12.                 delay(500);//这个延时必须要有,不然肉眼无法辨别出led灯有亮
  13.         }
  14.         EX1 = 1;//开启外部中断1
  15. }
复制代码
修改之后外部中断1和外部中断0都可以正常放回主函数。代码如下

  1. #include<reg51.h>
  2. #include<intrins.h> //循环移位的头文件
  3. #define uint unsigned int

  4. void delay(int z)
  5. {
  6.         int i,j;
  7.         for(i=0;i<z;i++)
  8.         for(j=0;j<110;j++);
  9. }

  10. /* 中断函数的步骤
  11. 1)开启总中断EA
  12. 2) 开启对应的中断的允许位,外部中断0,对应EX0=1,外部中断1,对应EX1=1;
  13. 3)选择触发方式(跳沿触发=1,电平触发=0),外部中断0对应的是IT0=0,低电平有效。
  14.          外部中断1对应的是IT1=1,跳沿触发,高电平跳变成低电平有效
  15. 4)设置中断的优先级,如果不设置则按照系统默认的优先级别
  16. */
  17. void main()
  18. {
  19.         uint tmp;
  20.         
  21.         EA = 1;//开启总中断
  22.         EX0 = 1;//外部中断0允许位,置一表示允许
  23.         IT0 = 0;//外部中断0,选择电平触发,低电平有效
  24.         EX1 = 1;//外部中断1的允许位
  25.         IT1 = 1;//外部中断1,选择跳沿触发,电平由高到低的负跳变有效
  26.         PX0 = 0;//外部中断0,优先级别为低
  27.         PX1 = 1;//外部中断1,优先级别为高
  28.         tmp = 0xfe;
  29.         
  30.         while(1)
  31.         {
  32.                 P1 = tmp;
  33.                 tmp=_crol_(tmp,1);
  34.                 delay(500);
  35.         }
  36. }

  37. //外部中断0
  38. void exter0() interrupt 0
  39. {
  40.         uint tmp1;
  41.         int mun;
  42.         
  43.         IE0 = 0;//关闭外部中断0
  44.         tmp1 = 0xf0;
  45.         for(mun=0;mun<10;mun++)
  46.         {
  47.                 P1=tmp1;
  48.                 tmp1 =_crol_(tmp1,4);
  49.                 delay(500);
  50.         }
  51.         IE0 = 1;//开启外部中断0
  52. }

  53. //外部中断1
  54. void exter1() interrupt 2
  55. {
  56.         int mun1;
  57.         
  58.         EX1= 0;//关闭外部中断1
  59.         for(mun1=0;mun1<5;mun1++)
  60.         {
  61.                 P1 = 0x00;
  62.                 delay(500);
  63.                 P1 = 0xff;
  64.                 delay(500);//这个延时必须要有,不然肉眼无法辨别出led灯有亮
  65.         }
  66.         EX1 = 1;//开启外部中断1
  67. }

复制代码

到了这里我就不明白是什么原因啦,难道是中断优先级的问题吗,我设置外部中断1的优先级别是高的,外部中断0的优先级别是低的



希望能得到热心大佬的帮助,谢谢啦






中断.png

Proteus.rar

27.22 KB, 下载次数: 2

回复

使用道具 举报

ID:338671 发表于 2019-4-21 17:56 | 显示全部楼层
压缩包里面的是仿真原理图
回复

使用道具 举报

ID:164602 发表于 2019-4-22 08:18 | 显示全部楼层
其实不是你说的那样。
IEx是外部中断的触发位,即当有外部中断时,这个位就由单片机置1,不是由程序置1。
在外部中断的服务函数中,只需要将其置0即可,不需要再置1,置1就相当于又产生了新的外部中断。
所以,你原来的程序,只需要IEx置0,不需要最后的置1操作就好了。
我已经试过的,没问题,可以返回。

另外:由于外部中断是用按键完成的,是按键,都是需要消抖的,你没有消抖的程序,所以可能中断会发生几次才能返回主函数,我试验时,按下外部中断1的按键最多产生过三次中断。

评分

参与人数 1黑币 +10 收起 理由
51danpianji111 + 10 很给力!

查看全部评分

回复

使用道具 举报

ID:424408 发表于 2019-4-22 11:41 | 显示全部楼层
对是硬件中断响应自动判断置位
回复

使用道具 举报

ID:123289 发表于 2019-4-22 12:16 | 显示全部楼层
初学者易犯的错:
中断处理程序执行时间过长!
在此期间其它比此更低级是中断都将无法响应,被执行!
回复

使用道具 举报

ID:338671 发表于 2019-4-22 12:21 | 显示全部楼层
HC6800-ES-V2.0 发表于 2019-4-22 08:18
其实不是你说的那样。
IEx是外部中断的触发位,即当有外部中断时,这个位就由单片机置1,不是由程序置1。
...

谢谢啦,我理解的按键消抖是做出实物的的时候才需要的,仿真的时候是不需要的。
回复

使用道具 举报

ID:462827 发表于 2019-4-22 13:36 | 显示全部楼层
你对中断理解得不太正确
回复

使用道具 举报

ID:518550 发表于 2019-4-22 14:01 | 显示全部楼层
中断需要的时间 程序不对
回复

使用道具 举报

ID:338671 发表于 2019-4-22 16:19 | 显示全部楼层
shuaishuaida 发表于 2019-4-22 14:01
中断需要的时间 程序不对

可不可,详细说一下呢
回复

使用道具 举报

ID:155507 发表于 2019-4-22 17:59 | 显示全部楼层
通常在中断子程序中是不调用延时子程序的,这样会增加中断处理时间,如果有其它低级中断了,就会延误响应中断了。

所以,中断子程序中不要写调用延时子程序,中断子程序也不要写得过长,处理过多的任务,要尽快处理后及时返回,如果中断一次有很多任务需要执行完全,可以在中断子程序中设置一个标志位,在主程序中查这个标志位,当标志为1时,就在主程序中完成这些任务,这样就不会影响其它中断源的中断,也不会使中断产生混乱。

如果延时函数时间过长,则下次中断有可能不会被触发,类似按键不灵敏,还有可能因为中断和主程序都在使用延时函数,而和此相关的寄存器的值没有保存,导致延时时间出错。

评分

参与人数 1黑币 +5 收起 理由
51danpianji111 + 5 赞一个!

查看全部评分

回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

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