目录
中断其实并不是那么吓人哦,一定要搞清楚各寄存器、中断口、中断源等示意图,后来你会发现其实就是根据你一开始的选择不断设置而已!
一、中断基础知识介绍
你知道中断是什么吗?它有哪些类型呢?
1、中断基础
中断系统:计算机执行某程序时,发生了紧急事件或有特殊请求,处理完毕后再重新执行程序的过程
中断类型: 中断分为外部中断及内部中断,外部中断可以由低电平或下降沿两种方式实现,而 内部中断则分为计数器模式和定时器模式。
中断流程: 中断请求->中断响应->中断处理->中断返回
**中断源示意图**:
小tip:后面中断相关代码都要根据该图设置,不是随意设置的,该图的掌握对中断而言至关重要哦!
2、寄存器
寄存器的使用与设置,是中断不可缺少的重要环节,它可用于控制中断开关、设置中断方式等等。
(1)IE寄存器
(2)TCON寄存器
小知识穿插(有关数据的输入/输出传送方式):
- 无条件传送方式 : 一方对另一方总是准备好的
- 查询传送方式 : 传送前一方先查询另一方状态,若已准备好就传送,否则就继续查询/等待
- 中断传送方式: 一方通过申请中断的方式与另一方进行数据传送
3、中断口的设置
一定要根据自己选择的中断方式与触发方式(或工作模式)结合图示选择中断入口,不可以自己随意设置!
二、外部中断的使用
不管是内部中断还是外部中断,上述内容中的寄存器与中断源示意图都需要熟练掌握哦,后面的程序均要结合其进行代码编写!
1、中断使用流程
- 允许中断(IE寄存器) 打开IE中断总开关 打开相应的中断开关(外部中断0或1)
- 配置中断方式(TCON寄存器) 选择中断方式为低电平还是下降沿
- 编写中断服务函数(写对应的中断入口)和主函数
2、中断代码
下降沿触发相关代码
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
sbit flag = P3^3; //对应P3^3的第二功能(外部中断1输入)
sbit key = P3^1; //中断1必须要使用P3^3,中断2必须使用P3^2
void delay(uint z)
{
uint x,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--);
}
void int1init()
{
EA=1; //打开EA总开关
EX1=1; //允许外部中断1中断
ET1=1; //外部中断1下降沿触发
}
void int1() interrupt 2
{
//该单片机中断口有问题,进了中断不会出来,只能加上该循环,正常情况可以不用
while(!key)
{
P2=~P2; //P2的状态按位取反
}
}
void main()
{
int1init(); //调用初始化函数进行初始化
while(1)
{
if(key==0)
{
delay(20);
if(key==0)
{
flag=1;
flag=0;
while(!key); //松手检测
}
}
}
}
三、内部中断的使用
1、相关知识介绍
51单片机有两个16位定时器/计数器: 定时器0(T0 引脚为P3^4) 定时器1(T1引脚为P3^5)
因此,定时器/计数器可以工作在如下不同模式:
**当定时器工作在定时器模式时** 每经过一个机器周期内部的16位计数寄存值加1,当这个寄存器装满时溢出
**当定时器工作在计数器模式** T0(P3^4) T1(P3^5) 每来一个脉冲寄存器加1
工作模式寄存器(用于调配上述寄存器工作模式)
2、中断使用流程
1、允许中断(IE寄存器) 打开IE中断总开关 2、启动定时/计数器(TCON控制器) TR0=1/TR1=1(T0/T1开始计数) 3、设置定时/计时器工作模式 调配定时/计时工作模式 调配8位/16位模 4、查询定时/计数器是否溢出(读TCON中TF位)
3、相关代码
定时器模式
#include "reg52.h"
sbit LA=P2^2;
sbit LB=P2^3;
sbit LC=P2^4;
sbit key1 = P3^0; //按键1
sbit key2 = P3^1; //按键2
unsigned char smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
void delay(unsigned int z)
{
unsigned int x,y;
for(x=z;x>0;x--)
for(y=120;y>0;y--);
}
void timefrist()
{
EA = 1; //打开总开关
ET0 = 1; //中断函数0的开关
TR0 = 1; //打开定时器0开关
TMOD = 0x01; //模式一,定时模式
TH0 = 0xED; //这里改值了,到上限就5ms(改初值)
TL0 = 0xFF;
//开关、模式、赋初值
}
unsigned char miao=0;
void DigDisplay(unsigned char h)
{
unsigned char a=h%10; //个位
unsigned char b=h/10; //十位
static unsigned char wei=0; //静态变量,就是函数执行完也不会抹去这个变量的值,在次使用函数值可以用(只有初值时才会初始的,后来不改变)
switch(wei) //这里重新布局,我们这里不断交换显示,用一次函数就显示一个,当快速多显示就动态显示
{
case 0: LA=1;LB=1;LC=1;P0 = smgduan[b];break; //wei值0与1不断交换,就动态显示
case 1: LA=0;LB=1;LC=1;P0 = smgduan[a];break;
}
wei++; //用过之后++
if(wei==2) //我们只要1与0不断交换,为2时就重新回0
{
wei = 0;
}
}
void timer0() interrupt 1
{
TH0 = 0xED; //重新定义5ms初始值
TL0 = 0xFF;
DigDisplay(miao); //显示,不断5ms显示就是动态显示
}
void main()
{
timefrist();
while(1)
{
if(key1==0) //为0,按键被按下
{
delay(20);
if(key1==0) //按键消抖
{
miao++; //全局miao加1,显示就会加1了
while(!key1); //松手检测
}
}
if(key2==0) //同理
{
delay(5);
if(key2==0)
{
miao--;
while(!key2);
}
}
}
}
小tips:定时器模式初值如何设置?
例如 5ms,5ms=5000us,5000/1.085(机器周期)=4608(次),65535-4608=60926; 将其换算为二进制为11101101 11111110,则高八位为0xED(TH0),低八位为0xFE(TL0)
计时模式
#include <reg52.h>
sbit LA=P2^2;
sbit LB=P2^3;
sbit LC=P2^4; //区段码位选
sbit key1=P3^0; //按键1
sbit key2=P3^1; //按键2
#define uchar unsigned char
#define uint unsigned int
uint data;
unsigned char code smgduan[17]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x7f,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
//延时函数
void delay(uchar z)
{
uchar x,y;
for(x=z;x>0;x--)
for(y=114;y>0;y--);
}
void timeint1() //定时器1中断初始化
{
EA = 1; //打开中断总开关
TR1 = 1;
TMOD = 0x10; //0001 0000(十六位定时器,TL1、TH1全用)
TH0=0xED;
TL0=0XFE; //设置初值为5ms
}
void display(data)
{
uint m,n;
m=data/10; //该数的十位数
n=data%10; //该数的个位数
static uchar wei = 0; //静态变量,函数执行完了之后数据不会抹去,下一次执行该函数还可以接着用
switch(wei)
{
case 0: LA=1;LB=1;LC=1; P0=smgduan[m]; break;
case 1: LA=0;LB=1;LC=1; P0=smgduan[n]; break;
}
wei++; //也就是说,每过10ms才会实现一次个位与十位的显示,但是速度极快,可以看成是动态显示
if(wei==2)
{
wei=0;
}
}
void timer1() interrupt 0
{
TH0=0xED;
TL0=0XFE; //重新设置初值为5ms
display(data); //显示数字,不断5ms即实现动态显示
}
void main()
{
timeint1();
while(1)
{
if(key1==0) //按键1被按下时为零
{
delay(20);
if(key1==0) //防误触
{
data++; //按键按下,秒数加1
while(!key1) //松手检测
}
}
if(key2==0) //按键2被按下时为0
{
delay(20);
if(key2==0) //防误触
{
data--; //按键按下,秒数减1
while(!key2) //松手检测
}
}
}
}