单片机-89C51部分:7、中断
飞书文档https://x509p6c8to.feishu.cn/wiki/A5gcwyL5giq1JOkkcsscn8eLnzf
一、中断的作用
中断是为使单片机具有对外部或内部随机发生的事件实时处理而设置的,中断功能的存在,很大程度上提高了单片机处理外部或内部事件的能力。它也是单片机最重要的功能之一,是我们学习单片机必须要掌握的。
为了能让大家更容易理解中断概念, 我们先来举一个生活事例:
你打开火,烧上一壶水。然后去洗衣服,在洗衣服的过程中,突然听到水壶发出水开的报警声,这时,你停止洗衣服动作,立即去关掉火,然后才回去继续洗衣服。 |
二、那中断是如何解决实际问题的呢?
回到按键章节,如果我们在while循环中,没有耗时的代码需要执行,这段代码是能够实时记录按键值的,但如果我们的程序设计复杂后,有耗时的任务需要处理,例如下方的Delay1ms(20000);延时20s,那在这20s内我们按下按键,芯片就无法读取到信号的变化了。
#include <reg52.h>sfr P4 = 0xe8; //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0E8H
sbit INT2 = P4^3;
sbit INT3 = P4^2;sfr XICON = 0xc0; //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0C0H
sbit PX3 = XICON^7;
sbit EX3 = XICON^6;
sbit IE3 = XICON^5;
sbit IT3 = XICON^4;
sbit PX2 = XICON^3;
sbit EX2 = XICON^2;
sbit IE2 = XICON^1;
sbit IT2 = XICON^0;sbit key1 = P4^3;
sbit led1 = P2^7;void delay_ms(unsigned int xms) //@12MHz
{unsigned int i, j;for(i=xms;i>0;i--){for(j=124;j>0;j--){}}
}void main()
{while(1){//当按键按下时灯切换if(key1 == 0){led1= ~led1;delay_ms(1000);}delay_ms(20000);}
}
这时候,我们就需要用中断的功能,帮我们实时记录。
三、51单片机的中断
STC89C5X 系列单片机提供了 8 个中断请求源,它们分别是:外部中断O(INT0)、外部中断 1(INT1)、外部中断 2(INT2)、外部中断 3(INT3)、定时器 0中断、定时器 1 中断、定时器 2 中断、串口(UART)中断。
外部中断:由外部引脚触发的中断
定时器中断:由定时器触发的中断
串口中断:通讯过程中发送或接收数据完毕触发的中断
外部中断
这个章节我们先来看下外部中断,也就是INT0、INT1、INT2、INT3。
下面这个框图很重要,它会给我们介绍,如果我们需要使用单片机的某个中断,需要配置哪些寄存器,我们通过框图、再结合寄存器表格和示例程序,就能知道怎么使用单片机中断。
中断寄存器
TCON.0/IT0:中断触发行为设置
IE0:外部中断0请求源,IE0=1外部中断向CPU请求中断,中断响应后,IE0=0。
不需要手动设置,由CPU处理即可。
EX0:外部中断0允许寄存器
EA:总中断允许寄存器
中断初始化
void exti0_init(void)
{IT2=1;//触发方式:下降沿EX2=1;//打开 INT2 的中断允许EA=1;//打开总中断
}
中断服务程序(回调函数)
//在中断函数中 exti0 是函数名,可自定义,interrupt 是一个关键字,表示 51 单片机中断。
//后面的“0”是中断号
//外部中断 0 中断号为 0
//定时器中断0,中断号为1
//外部中断 1,则中断号为 2。
void exti0() interrupt 0 //外部中断 0 中断函数
{//执行所需的功能
}
外部中断代码:
#include <reg52.h>sfr P4 = 0xe8; //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0E8H
sbit INT2 = P4^3;
sbit INT3 = P4^2;sfr XICON = 0xc0; //for 89C5xRC/RD+ series and 90C5xRc/RD+, location at 0C0H
sbit PX3 = XICON^7;
sbit EX3 = XICON^6;
sbit IE3 = XICON^5;
sbit IT3 = XICON^4;
sbit PX2 = XICON^3;
sbit EX2 = XICON^2;
sbit IE2 = XICON^1;
sbit IT2 = XICON^0;sbit key1 = P4^3;
sbit led1 = P2^7;void delay_ms(unsigned int xms) //@12MHz
{unsigned int i, j;for(i=xms;i>0;i--){for(j=124;j>0;j--){}}
}void exit2() interrupt 6
{//当按键按下时灯切换if(key1 == 0){led1= ~led1;delay_ms(1000);}
}void main()
{IT2 = 1; //设置中断触发条件为下降沿EX2 = 1; //运行中断2经过EA = 1; //使能中断while(1){delay_ms(20000);}
}
要注意:
标准的单片机头文件reg52.h是没有P4,我们可以参考工具自行添加。
中断优先级
每一个中断的优先级别均可用软件设置。高优先级的中断请求可以打断低优先级的中断,反之,低优先级的中断请求不可以打断高优先级及同优先级的中断。当两个相同优先级的中断同时产生时,将由查询次序来决定系统先响应哪个中断。
默认情况下所有中断优先级被设置为最高优先级3,当系统开启了多个中断,根据具体的业务设置对应的优先级即可。例如系统开启了外部中断INT0和INT1,默认情况下INT0的优先级是比INT1要高的,假设系统触发了INT0,INT0在执行中断服务程序时,INT1将不会被及时响应。 |
IP XICON IPH 中断优先级控制寄存器
IP、IPH - PX0H PX0
0b0000 0001
0b0100 0000
0*8+1*4+0*2+0*1 = 4
0*8+0*4+0*2+0*1=0
0x40
注意:
IPH这个寄存器是不可位寻址的,
如要想让PX0H这位置一的话,直接 PX0H=1;这个写法是错误的,因为它不能位寻址。
只能 IPH= 0x01(0000 0001)
//STC单片机的中断优先级需要设置IP和IPH寄存器,IP寄存器可以位操作,IPH只能寄存器操作 |
0x01是16进制的表示
在Keil C51中数不能直接以二进制形式赋值,所以需要设置寄存器某一位为1,用10进制或16进制显示,这里涉及到进制转换:
一个寄存器8位,相当于一个字节。
十进制:十进制是我们平常使用的数字系统,包含0到9这10个数字。
二进制:二进制是一种数值表示方式,只包含0和1两个数字。常常这样表示:0b0000 0000
十六进制:十六进制是一种数值表示方式,包含0到9和A到F这16个数字,常常这样表示0x01
A可以理解为十进制的10,B=11,C=12,D=13,E=14,F=15
二进制 | 二进制转十六进制 | 十六进制 | 十进制 | |
0b0000 0001 | 0*8+0*4+0*2+0*1=0 0*8+0*4+0*2+1*1=1 | 0x01 | 0×16¹+1×16⁰ 0×16+1×1 = 1 | 1 |
0b0000 0100 | 0*8+0*4+0*2+0*1=0 0*8+1*4+0*2+0*1=4 | 0x04 | 0×16¹+4×16⁰ 0×16+4×1 = 4 | 4 |
0b0001 0000 | 0*8+0*4+0*2+1*1=1 0*8+0*4+0*2+0*1=0 | 0x10 | 1×16¹+0×16⁰ 1×16+0×1 = 16 | 16 |
0b0001 1111 | 0*8+0*4+0*2+1*1=1 1*8+1*4+1*2+1*1=15=f | 0x1f | 1×16¹+f×16⁰ f=15 1×16+15×1 = 31 | 31 |