概述
中断系统的设置,是为了让CPU能对外界紧急事件进行实时处理
中断的过程是,当中断请求源发出中断请求时,CPU响应中断后,CPU先暂停当时正在执行的主程序,转而去处理中断服务程序,处理完后继续原来的工作
微型机一般允许多个中断源,当几个中断源同时发出中断时,CPU先响应最高优先级的中断
中断嵌套:CPU在处理中断时,外界产生了更高优先级的中断,CPU暂停当前中断,处理了更高优先级的中断后,在回来处理之前的中断,具有中断嵌套功能的系统叫多级中断系统,不具有的叫单级中断系统
如何使用中断
此52单片机一般有8个中断请求源,分别对应8个中断查询次序号(中断号),这些中断被硬件所调用,通过编写中断查询次序号的中断服务程序,就可以让CPU在响应中断时,执行具体的功能代码;4个外部中断INT0,INT1,INT2,INT3,3个定时器中断,定时器0中断,定时器1中断,定时器3中断,1个串口中断。
每一个中断源都可用软件独立地控制为允许中断或关闭中断,每一个中断源的中断优先级均可用软件设置
中断相关寄存器
中断相关的寄存器有:中断请求标志寄存器TCON和SCON,中断允许寄存器IE,中断优先级寄存器IP
TCON寄存器中IE0和IE1位是外部中断请求0和1的中断请求标志位,IT0和IT1位用于选择外部中断请求是负跳变触发,还是电平触发,IT置0为电平触发,即当加到INT上的外部中断请求输入信号为低电平时,将IE位置1,发出中断,CPU介入后,硬件将IE置0
IE寄存器对中断的允许和禁止实现两级控制,可位寻址,总的中断开关位EA(IE^7),EA置0,所有中断都无效,EA置1,中断源是否运行还要由低位的中断请求允许控制位的状态决定,置1对应中断源中断允许,置0中断无效,其他位ET0到ET2控制定时器0到2的溢出中断,ES控制串口,EX0到EX1控制外部中断0到1
中断开关如图
IP寄存器用于配置中断请求源的优先级,不同位配置不同中断请求源
优先级相同的多个中断,CPU的响应次序按照中断查询次序号来响应,0为最先,7为最低
中断请求源顺序如图
案例一:定时器中断控制闪灯
#include "reg52.h"
sbit ledblue =P3^7;
sbit ledyellow =P3^6;
void delay1000(){
int cnt=0;
TR0=1;
while(1){
if(TF0==1){
cnt++;
TF0=0; //定时器0爆表不中断,那么手动将TF0位置0
TL0=0x00;
TH0=0xDC;
}
if(cnt==100)break;
}
TR0=0;
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
TL0=0x00;
TH0=0xDC;
TL1=0x00;
TH1=0xDC;
}
void main(){
ledblue=1;
ledyellow=0;
ClockInit();
EA=1;
ET1=1;
TR1=1;
while(1){
ledblue=!ledblue;
delay1000();
}
}
void Lightyellow() interrupt 3 //定时器1每10ms爆表一次,爆表时TF1位置1,进入中断,TF1位自动置0,然后将cnt++,加到50次,即0.5s后,黄灯电平翻转
{ static int cnt=0;
cnt++;
TL1=0x00;
TH1=0xDC;
if(cnt==50){
ledyellow=!ledyellow;
cnt=0;
}
}
案例二:定时器中断控制SG90舵机切换角度转动
SG90舵机
SG90舵机需要的控制信号与一般的电平信号不同,他需要的控制信号是PWM信号,即占空比不同的方波信号
舵机接线为红线VCC,黑线GND,黄线PWM信号接收
SG90舵机有两个规格,180°类型的360°类型,对应PWM波的控制情况如图
180°版本 占空比越高,转动的角度越大,但是转动角度有些误差,需要微调,高电平时间大概90°要1570us,180°要2570us,2720us为最大角度(略微大于180°),220us为最小角度(略微小于0°);超过2730us,先转动到最大角度,然后按超出量多少,转动速度就是多少的转动速度转动一小会,然后再快速转动回最大角度,如此循环,小于220us同理,
360°版本
0到2.5%占空比,维持最快顺时针转速不变;2.5%到7.5%占空比,占空比越高,顺时针转速越慢;7.5%完全暂停;7.5%到12.5%占空比,占空比越高,逆时针转速越快;12.5%占空比往上,维持最快逆时针转速不变
SG90舵机还分为数字电机和模拟电机,数字电机,给一次PWM信号就能转动,模拟电机需要在一段时间内持续给PWM信号才能转动
我们采用的是180类型的模拟信号SG90舵机
注意:一般信号周期是固定的,对于控制不同仪器,可能信号周期会有所变化;而对于相应信号周期占空比可以变化,用来控制程度
什么是PWM
PWM是脉冲宽度调制,通过对一系列脉冲的宽度进行调制,通过调节占空比,等效出需要的模拟信号波形,相当于用调节高低电平的时间长度来等效模拟信号,PWM给出的信号仍然是数字的,简而言之,PWM是一种对模拟信号电平进行数字编码的方法,比如1s内给持续5v的电压信号,占空比60%,相当于是1s内给持续3v的电压信号,占空比20%,相当于1s内给持续1v的电压信号
PWM波有两个决定条件,一个是信号周期,另一个是占空比
信号周期:PWM波是由周期的占空比信号组成,信号周期就是一个占空比信号所占的时间长度
占空比:一个信号周期内,信号处于高电平状态的时间占整个周期的时间,比如方波的占空比就是50%
占空比不同,表示的模拟信号不同,输出的电压就不同,对应的舵机旋转角度就不同
PWM信号可以通过C52自带的硬件产生,也可以通过IO口软件模拟产生,精准度略差
如何控制舵机
PWM波的频率不能太高,一般50hz,即信号周期0.02s,信号周期用定时器来控制
频率高的话,周期就小,固定时间内接收到的信号数量就越多,频率低的话,周期就大,固定时间内接收到的信号数量就越少,但是固定时间内二者高低电平所占时间的比例是相同的,为占空比
占空比每提升2.5%,舵机就增加45°
在大于周期的一段时间内持续输出对应占空比的PWM波,电机就会转动相应角度
如何设定定时器定时的初值
因为定时器的初值由TH位和TL位设置,所以TH位可以等于(65536-定时时长/机器周期)/256得出,
TL位可以等于(65536-定时时长/机器周期)%256得出
注意:取模运算不可以用浮点数
PWM方波如何输出
方案1
用定时器0来输出周期占空比的高电平,定时器1来输出剩下周期时间的低电平。在电平跳变点(当前即定时器爆表)进入中断程序,来配置下一个定时器
将PWM波分为一段时间的高电平,一段时间的低电平,不断重复,起初打开定时器1,爆表后,进入中断程序,在中断程序中,设定输出高电平和定时器0的定时初值后,打开定时器0,结束中断程序,这样就输出了对应时间的高电平,等定时器0爆表后,进入中断程序,在中断程序中又设置输出低电平和定时器1的定时初值,然后结束中断程序
进入中断后要及时关闭当前定时器,再打开下一个定时器,这样保持定时器0运行一段时间,定时器1运行一段时间
代码
#include "reg52.h"
#include<intrins.h>
sbit ledb=P3^7;
sbit ledy=P3^6;
sbit sg90 =P1^6;
int flag=0;
void Delay2000() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
TL0=0x66;
TH0=0xbd;
TH1=0xfa;
TL1=0x9a;
EA=1;
ET0=1;
ET1=1;
}
void do1() interrupt 1
{
TR0=0;
sg90=0;
ledy=0;
ledb=1;
if(flag==0){
//TL1=0xcd;
//TH1=0xb9;
TH1=(65536-19500/1.085)/256;
TL1=(int)(65536-19500/1.085)%256;
}
if(flag==1){
//TL1=0x66;
//TH1=0xbd;
TH1=(65536-18500/1.085)/256;
TL1=(int)(65536-18500/1.085)%256; //取模不能用浮点数,需要强转
}
TR1=1;
}
void do2() interrupt 3
{
TR1=0;
sg90=1;
ledy=1;
ledb=0;
if(flag==0){//360°sg90舵机 2.5%占空比顺时针全速转动
// TL0=0x33;
// TH0=0xfe;
TH0=(65536-500/1.085)/256;
TL0=(int)(65536-500/1.085)%256;
}
if(flag==1){ //360°sg90舵机 7.5%占空比停止转动
// TL0=0x9a;
// TH0=0xfa;
TH0=(65536-1500/1.085)/256;
TL0=(int)(65536-1500/1.085)%256;
}
TR0=1;
}
void main(){
ledy=1;
ledb=0;
ClockInit();
TR1=1;
while(1){
flag=!flag; //切换占空比
Delay2000();
}
}
方案2
由于占空比每提升2.5%,舵机就增加45°,如果以45度为转动单位,那么可以将一个周期20ms秒分成40等分,每等分占0.5ms,每等分输出高电平或低电平
用一个变量cnt记录次数,爆表一次cnt++,将定时器爆表前可计时的时长定为0.5ms,每次爆表前持续输出高电平或者低电平,总共输出40次,代表一个周期;cnt自加到40后,cnt置0,代表循环
每增加2.5%的占空比,40次中,输出高电平的次数就多一次
代码
#include "reg52.h"
#include<intrins.h>
sbit sg90 =P1^6;
sbit ledb =P3^7;
sbit ledy =P3^6;
int cnt=0;
int jd;
void Delay2000() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
// TL0=0xff;
// TH0=0xb7;
TL1=0x33;
TH1=0xfe;
EA=1;
// ET0=1;
ET1=1;
}
void main(){
Delay2000();
ClockInit();
TR1=1;
while(1){
jd=3;
cnt=0;
TL1=0x33;
TH1=0xfe;
ledb=0;
ledy=1;
Delay2000();
jd=4;
cnt=0;
TL1=0x33;
TH1=0xfe;
ledb=1;
ledy=0;
Delay2000();
}
}
void do2() interrupt 3
{
cnt++;
if(cnt<=jd)sg90=1;
else sg90=0;
TL1=0x33;
TH1=0xfe;
if(cnt==40){
cnt=0;
}
}
案例三:超声波模块测距控制亮灯
超声波模块HC-SR04
通过发送和接收超声波,利用时间和声音传播速度计算出障碍物与模块的距离,测距范围2cm到400cm,精度为3mm
TRIG引脚,给予至少10us的高电平,产生发波指令,经过一小段时间产生8个40khz的超声波方波并发送出去,发送时,ECHO引脚由低电平跳转到高电平,当超声波反弹回来被接收时,ECHO引脚又高电平跳转到低电平
计算时间,ECHO引脚进入高电平时,打开定时器,ECHO引脚跳转会低电平时,关闭定时器,通过定时器的差值计算出超声波传播的时间,距离等于时间*340/2,定时器一次可计时71106us,最大测距为1208cm,所以满足400cm的测距范围
代码
#include "reg52.h"
sbit ledblue =P3^7;
sbit ledyellow =P3^6;
sbit Trig=P2^5;
sbit Echo=P2^6;
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void ClockInit(){
TMOD&=0xf0;
TMOD|=0x01;
TH0=0x00;
TH0=0x00;
}
void startHC(){
Trig=1;
Delay10us();
Trig=0;
}
void main(){
double dis=0;
double time=0;
ClockInit();
while(1){
startHC();
while(Echo==0);
TR0=1;
while(Echo==1);
TR0=0;
time=(TH0*256+TL0)*1.085;
dis=time*0.017;
if(dis<10)ledblue=0;
else ledblue=1;
TH0=0x00;
TL0=0x00;
}
}
终项目:感应开关盖垃圾桶
目标实现
1、测距控制垃圾桶开关盖
2、按键控制垃圾桶开关盖
3、振动控制垃圾桶开关盖
4、开关盖时蜂鸣器响应
需要的技术
1、垃圾桶开关盖需要舵机转动角度来支撑,舵机转动不同的角度需要不同占空比的PWM波,实现PWM波,则需要定时器0和定时器1分别产生相应时间的高低电平循环,需要用到定时器中断
2、振动控制开关盖,如果只是把振动产生的信号或到测距控制开关盖中,则有可能发生振动已经产生,信号也产生了,但是代码没有捕获到这个信号,当运行到判断部分时,振动信号已经消失了,所以需要用到外部中断,信号产生时同时发起外部中断,用一个变量记录下这个信号,下次运行到判断部分时,能检测到这个变量,则会控制开关盖文章来源:https://www.toymoban.com/news/detail-413751.html
外部中断IT0如果置0表示低电平触发,对于模块发出信号为低电平时会发出中断;置1表示下降沿触发,对于模块发出信号与高电平脉冲有效,因为发出脉冲后会跳变回低电平,跳回时发出中断文章来源地址https://www.toymoban.com/news/detail-413751.html
代码
#include "reg52.h"
#include<intrins.h>
sbit ledblue =P3^7;
sbit ledyellow =P3^6;
sbit Trig =P2^5;
sbit Echo =P2^6;
sbit sg90 =P1^6;
sbit key1 =P2^1;
sbit zd =P3^2; //振动
sbit beep =P2^4; //继电器开关,用于控制喇叭
int jd=0;
int jdbake=0;
int flag=1;
int soundflag=0;
int zd_mark=0;
void Delay2000ms() //@11.0592MHz
{
unsigned char i, j, k;
_nop_();
i = 15;
j = 2;
k = 235;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void Delay100ms() //@11.0592MHz
{
unsigned char i, j;
i = 180;
j = 73;
do
{
while (--j);
} while (--i);
}
void Delay10us() //@11.0592MHz
{
unsigned char i;
i = 2;
while (--i);
}
void startHC(){
Trig=1;
Delay10us();
Trig=0;
}
double getDis(){
double time=0;
TH2=0x00;
TL2=0x00;
startHC();
while(Echo==0);
TR2=1;
while(Echo==1);
TR2=0;
time=(TH2*256+TL2)*1.085;
return (time*0.017);
}
void ClockInit(){
TMOD&=0x00;
TMOD|=0x11;
EA=1;
ET0=1;
ET1=1;
TR1=1;
}
void Sound(){
int i=0;
beep=0;
for(i;i<3;i++){
Delay100ms();
}
beep=1;
i=0;
for(i;i<3;i++){
Delay100ms();
}
}
void Clock2Init(){
TH2=0x00;
TL2=0x00;
}
void EX0Init(){
EX0=1;//开启外部中断
IT0=0;//中断触发为低电平
}
void main(){
double dis=0;
Clock2Init();
ClockInit();
EX0Init();
while(1){
dis=getDis();
if(key1==0){
Delay100ms();
flag=!flag;
if(soundflag==0){
soundflag=0;
}else {
soundflag=!soundflag;
}
}
if(flag==1){
EX0=1;
ledyellow=1;
if(dis<10||zd_mark==1){
EX0=0;
jd=180;
ledblue=0;
if(jdbake!=jd){
Sound();
}
jdbake=jd;
Delay2000ms();
zd_mark=0;
EX0=1;
}
else {
jd=0;
jdbake=jd;
ledblue=1;
Delay100ms();
}
}else{
EX0=0;
jd=180;
if(soundflag==0){
Sound(); //按键后只响一声
}
soundflag=1;
Delay100ms();
ledyellow=0;
}
}
}
void Low() interrupt 1
{
TR0=0;
sg90=0;
if(jd==0){
// TL1=0xcd;
// TH1=0xb9;
TH1=(65536-(20000-500)/1.085)/256;
TL1=(int)(65536-(20000-500)/1.085)%256;
}
if(jd==180){
//TL1=0x66;
//TH1=0xbd;
TH1=(65536-(20000-2570)/1.085)/256;
TL1=(int)(65536-(20000-2570)/1.085)%256; //¼Çסȡģ²»¿ÉÒÔÓø¡µãÊý
}
TR1=1;
}
void High() interrupt 3
{
TR1=0;
sg90=1;
if(jd==0){//ת¶¯
// TL0=0x33;
// TH0=0xfe;
TH0=(65536-500/1.085)/256; //1570 90° 210最小度数
TL0=(int)(65536-500/1.085)%256;
}
if(jd==180){ //ÔÝÍ£
// TL0=0x9a;
// TH0=0xfa;
TH0=(65536-2570/1.085)/256; //2570 180° 2720最大度数
TL0=(int)(65536-2570/1.085)%256;
}
TR0=1;
}
void get_zdsignal() interrupt 0
{
zd_mark=1;
}
到了这里,关于51单片机——中断的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!