项目文件

文件

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

 


根据下原理图,编程验证二级外部中断嵌套效果。其中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一直在变

 


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

视频:

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐