单片机c51中断 — 中断嵌套实例IE0的置位和撤销

项目文件

文件

关于项目的内容知识点可以见专栏单片机原理及应用 的第五章,中断

 


根据下原理图,编程验证二级外部中断嵌套效果。其中K0定为低优先级中断源,K1为高优先级中断源。此外,利用发光二极管D1验证外部中断请求标志IE0在脉冲触发中断时候的硬件置位与撤销过程
在这里插入图片描述
 


  1. 先实现LED0:3只数码管可分别进行字符19的循环计数显示,其中主函数采用无限计数显示,KO和K1的中断函数则采用单圈计数显示。
  2. 由于K0的自然优先级(接INTO引脚)高于K1(接INT1引脚),故需要将K1的中断级别设为高优先级,即PX1=1,PX0=0
  3. 高级中断运行时,若有低级中断请求,则D1点亮;高级中断结束后,低级中断才能运行。
  4. 由于IEO 的撤销过程发生在 K0 响应中断的瞬间,故在 KO中断函数里将IEO值送 P3.0输出可验证这一过程。
    而IEO 的置位信息较难捕捉,可以利用“低级中断请求虽不能中止高级中断响应过程,但可保留中断请求信息”的原理进行,即在K1中断函数里设置输出IEO语句

一步一步写
先定义好字模和D1和延时函数

#include "reg51.h"
char led_mod[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,	  //led字模
				  0x7f,0x6f}; //显示字模	  
sbit D1=P3^0;  //原理图D1接P3_0
void delay(unsigned int time){//延时
	unsigned char j=255;	   
	for(;time>0;time--)
		for(;j>0;j--);
} 

先写主函数:

void main(){
	unsigned char i;
	TCON = 0x05;			  //脉冲触发方式

0x05是0000 0101 ——对应TCON寄存器的位
在这里插入图片描述
这样IT1和IT0为1,脉冲触发

上面说的

K0接INT0引脚,K1接INT1引脚,K1高级中断,优先级要设置高,即
PX1=1 ,PX0=0;

PX0=0;PX1=1;			  //INT1优先

然后继续

D1=1;P1=P2=0x40;		  //输出初值

D1=1 刚开始时候这样电平,D1灯是灭的,等于初始化

在这里插入图片描述

P1=P2=0x40;

这里用的 晶体管竟然还是共阴极的动态数码管

在这里插入图片描述
由他们各自连接的端口控制

0x40=0100 0000
这样就是P1和P2等于0 100 0000
显示是 -
对应LED1 2
LED0开始端口P0为高电压

在这里插入图片描述

继续写:

	IE=0x85;				  //开中断

这里是IE寄存器 为1000 0101
在这里插入图片描述
EA=1;EX1=1;EX0=1;
总中断允许;INT1中断允许;INT0允许

继续写:

while(1){
	    for(i=0;i<=9;i++){    //字符0-9无限循环
		   P0=led_mod[i];
		   delay(35000);	
		}
	     
	}
}

主函数中的循环, P0=led_mod[i]; led_mode是共阴极数码管0~9
所以LED0从0到9无限循环

主函数代码:

void main(){
	unsigned char i;
	TCON = 0x05;			  //脉冲触发方式
 	PX0=0;PX1=1;			  //INT1优先
	D1=1;P1=P2=0x40;		  //输出初值
	IE=0x85;				  //开中断
	while(1){
	    for(i=0;i<=9;i++){    //字符0-9无限循环
		   P0=led_mod[i];
		   delay(35000);	
		}
	     
	}
}

下面写中断函数

key0() interrupt 0 {	      //K0中断函数
	unsigned char i;
	D1=!IE0;					  //IE0状态输出 
	for(i=0;i<=9;i++){    	  //字符0-9循环1圈
		P2=led_mod[i];
		delay(35000);	
	}P2=0x40; 				  //结束符“-” 
}  

key0() interrupt 0 { //K0中断函数
定义中断服务函数
这里的0是中断号
在这里插入图片描述
这样才能对应是哪个中断

	unsigned char i;
	D1=!IE0;					  //IE0状态输出 
	for(i=0;i<=9;i++){    	  //字符0-9循环1圈
		P2=led_mod[i];
		delay(35000);	
	}P2=0x40; 				  //结束符“-” 

D1=!IE0; D1初始值为1,D1对应着INT0的中断请求标志IE0的非
这里为啥取非?

因为D1对应的灯D1端口为0时候亮
所以IE0=1中断开始,D1亮可以作为一个判断v

然后单圈灯

for(i=0;i<=9;i++){    	  //字符0-9循环1圈
		P2=led_mod[i];
		delay(35000);	
	}P2=0x40; 				  //结束符“-” 

就亮了循环一圈

‼️‼️ 总体看:
按下K0后
在这里插入图片描述
INT0端口变为低电压,传给INT0非为低电压
这里要看IE0是哪种模式(脉冲还是电平)
image-20220411212730641
TCON = 0x05; //脉冲触发方式
所以为1变0为负跳变脉冲所以为1变0为负跳变脉冲
在这里插入图片描述
IE0置1,中断开始

中断服务函数

流程图:
在这里插入图片描述

如果错误请指出,大致总结下

K1也是这样,但是K1是优先级为高在这个例子中

因为项目总代码:

#include "reg51.h"
char led_mod[] = {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,	  //led字模
				  0x7f,0x6f}; //显示字模	  
sbit D1=P3^0;
void delay(unsigned int time){//延时
	unsigned char j=255;	   
	for(;time>0;time--)
		for(;j>0;j--);
} 
key0() interrupt 0 {	      //K0中断函数
	unsigned char i;
	D1=!IE0;					  //IE0状态输出 
	for(i=0;i<=9;i++){    	  //字符0-9循环1圈
		P2=led_mod[i];
		delay(35000);	
	}P2=0x40; 				  //结束符“-” 
}  

key1() interrupt 2 {          //K1中断函数
	unsigned char i;
	for(i=0;i<=9;i++){    	  //字符0-9循环1圈
		D1=!IE0;				  //IE0状态输出
		P1=led_mod[i];
		delay(35000);	
	}P1=0x40; 				  //结束符“-” 
}

void main(){
	unsigned char i;
	TCON = 0x05;			  //脉冲触发方式
 	PX0=0;PX1=1;			  //INT1优先
	D1=1;P1=P2=0x40;		  //输出初值
	IE=0x85;				  //开中断
	while(1){
	    for(i=0;i<=9;i++){    //字符0-9无限循环
		   P0=led_mod[i];
		   delay(35000);	
		}
	     
	}
}

现象:

LED0无限循环

按下K0,INT0中断开始,进入中断函数key0,len1循环一圈
按下K1,INT1中断开始,进入中断函数key1,len2循环一圈

因为K1的定义的中断优先级高,所以如果K0中断运行的时候
点击K1,K1中断优先,等K1结束才能到K0中断

最终,中断时候中断函数下面的LED0的循环亮暂时没到中止

观察D1的信息
D1开始为1.灭的

中断函数中定义D1=!IE0
IE0是INT0的中断标志,当INT0中断运行时候
IE0=1
所以D1=0; 亮
在K1中断中也有这个
但是它是在for内部
D1一直在变

 


结果:
在这里插入图片描述

视频:

  • 4
    点赞
  • 34
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
51单片机可以通过外部中断来进行计数,具体步骤如下: 1. 配置中断引脚为外部中断模式,可以使用P3口的INT0和INT1引脚,或者P1口的T0和T1引脚。 2. 初始化中断相关的寄存器,包括IE(中断使能寄存器)、IP(中断优先级寄存器)和TCON(定时器/计数器控制寄存器)等。 3. 编写中断服务程序,当外部中断发生时,会自动跳转到中断服务程序中执行。 4. 在中断服务程序中对计数器进行操作,可以使用一个全局变量来保存计数值。 5. 在主程序中定时读取计数器的值,可以使用定时器或者延时函数来控制读取的时间间隔。 6. 在需要重置计数器时,可以在主程序中设置一个标志位,当标志位被置位时,将计数器清零。 示例代码如下: ```c #include <reg52.h> #include <intrins.h> sbit INT0 = P3^2; // 外部中断0引脚 unsigned int count = 0; // 计数器 void init_interrupt() { EA = 1; // 开启总中断 EX0 = 1; // 开启外部中断0 IT0 = 1; // 配置为下降沿触发 } void isr_int0() interrupt 0 { count++; // 计数器加1 } void main() { init_interrupt(); // 初始化中断 while(1) { // 定时读取计数器的值,可以使用定时器或者延时函数 _nop_(); // 空指令,延时一段时间 _nop_(); _nop_(); _nop_(); printf("count = %d\n", count); // 重置计数器 if(/*条件*/) { count = 0; } } } ``` 注意:在使用P3口的INT0和INT1引脚时,需要将P3口的其他引脚设置为输入模式,否则可能会影响中断的触发。同时,需要注意中断服务程序的执行时间,尽量保持短暂,不要阻塞主程序的执行。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值