CH6中断的应用.docx
《CH6中断的应用.docx》由会员分享,可在线阅读,更多相关《CH6中断的应用.docx(15页珍藏版)》请在冰豆网上搜索。
CH6中断的应用
课题名称
第六章第一节中断的应用
计划学时
2课时
内容分析
知识点:
中断的概念、中断子程序的编写方法、单一外部中断的应用、外部中断INT1、中断优先级、键盘中断
教学目标及要求
理解中断的概念,认识MCS-51的中断构成,掌握外部中断INT0和INT1的编程方法,两级中断中会设定中断优先级,了解键盘中断的原理
重点及措施
教学重点:
中断优先级的设定和外部中断的应用
难点及措施
教学难点:
中断优先级的设定和外部中断的应用
教学方式
教学采用教师课堂讲授为主,使用多媒体教学方式,学生讨论、交流与提问。
教
学
过
程
一、引入
前两章我们介绍了51系列单片机的4个I/O的输入输出操作,今天我们开始一章新的内容—中断。
在这一章我们首先要理解什么是中断,进而会编写相应的中断子程序。
本章的重难点都在中断子程序的编写。
二、新授
1、计算机中的中断
为了处理更紧急的事件或其他设备的的请求,计算机暂停当前程序运行,转去执行被申请程序,待程序执行完后,再继续原程序运行。
2、中断的优点
计算机与其他设备多任务同时工作、分时操作。
提高了计算机的利用率。
实时处理控制系统中的各种信息,提高了计算机的灵活性。
使计算机及时处理故障等突发事件,提高了可靠性。
3、MCS-51中断源
MCS-51有五个中断源,
1)INT0(P3.2)、INT1(P3.3):
外部中断0、1
IE0、IE1中断请求标志位,(IE0/IE1)=1时,表示外部中断0或外部中断1
向CPU申请中断。
CPU响应中断时,硬件清除(IE0/IE1)=0。
2)T0(P3.4)、T1(P3.5):
定时器0、1中断源。
TF0、TF1中断请求标志位,(IF0/IF1)=1时,定时器0或定时器1向CPU申请中断。
CPU响应中断时,硬件清除(IF0/IF1)=0。
3)(P3.0)(P3.1):
串口发送/接收中断源。
共用一个中断源RI/TI=1时,串口向CPU申请中断。
CPU响应中断时,必须由软件清除RI/TI=0。
中断编号
中断源名称
中断向量地址
-
系统复位(Reset)
0x0000
0
第一个外部中断INT0
0x0003
1
第一个定时器/计数器中断TF0
0x000B
2
第二个外部中断INT1
0x0013
3
第二个定时器/计数器中断TF1
0x001B
4
串行口中断RI/TI
0x0023
5
第三个定时器/计数器中断(8x52)TF2/EXF2
0x002B
4、8x51/8x52中断向量表
当系统产生中断时,5个中断源的中断请求标志分别由特殊功能寄存器TCONSCON的相应位来锁存。
是否能响应中断由寄存器IE和IP来确定。
6.1认识89S51的中断
中断流程
IE寄存器
IP寄存器
自然优先等级
不同优先等级下,程序执行的流程:
TCON寄存器
中断设置
6.2中断子程序
1、interruptm修饰符
interruptm是C51函数中非常重要的一个修饰符,这是因为中断函数必须通过它进行修饰。
在C51程序设计中,当函数定义时用了interruptm修饰符,系统编译时把对应函数转化为中断函数,自动加上程序头段和尾段,并按MCS-51系统中断的处理方式自动把它安排在程序存储器中的相应位置。
在该修饰符中,m的取值为0~31,对应的中断情况如下:
0——外部中断01——定时/计数器T0
2——外部中断13——定时/计数器T1
4——串行口中断5——定时/计数器T2其它值预留。
2、usingn修饰符
修饰符usingn用于指定本函数内部使用的工作寄存器组,其中n的取值为0~3,表示寄存器组号。
对于usingn修饰符的使用,注意以下几点:
(1)加入usingn后,C51在编译时自动的在函数的开始处和结束处加入以下指令。
{
PUSHPSW;标志寄存器入栈
MOVPSW,#与寄存器组号相关的常量
……
POPPSW;标志寄存器出栈
}
(2)usingn修饰符不能用于有返回值的函数,因为C51函数的返回值是放在寄存器中的。
如寄存器组改变了,返回值就会出错。
3、编写MCS-51中断函数注意如下:
(1)中断函数不能进行参数传递,如果中断函数中包含任何参数声明都将导致编译出错。
(2)中断函数没有返回值,如果企图定义一个返回值将得不到正确的结果,建议在定义中断函数时将其定义为void类型,以明确说明没有返回值。
(3)在任何情况下都不能直接调用中断函数,否则会产生编译错误。
因为中断函数的返回是由8051单片机的RETI指令完成的,RETI指令影响8051单片机的硬件中断系统。
如果在没有实际中断情况下直接调用中断函数,RETI指令的操作结果会产生一个致命的错误。
(4)如果在中断函数中调用了其它函数,则被调用函数所使用的寄存器必须与中断函数相同。
否则会产生不正确的结果。
(5)C51编译器对中断函数编译时会自动在程序开始和结束处加上相应的内容,具体如下:
在程序开始处对ACC、B、DPH、DPL和PSW入栈,结束时出栈。
中断函数未加usingn修饰符的,开始时还要将R0~R1入栈,结束时出栈。
如中断函数加usingn修饰符,则在开始将PSW入栈后还要修改PSW中的工作寄存器组选择位。
(6)C51编译器从绝对地址处产生一个中断向量,其中m为中断号,也即interrupt后面的数字。
该向量包含一个到中断函数入口地址的绝对跳转。
(7)中断函数最好写在文件的尾部,并且禁止使用extern存储类型说明。
防止其它程序调用。
【例22】编写一个用于统计外中断0的中断次数的中断服务程序
externintx;
voidint0()interrupt0using1
{
x++;
}
中断系统对话框
实例6-3-1目标:
主程序正常执行时,P1所连接的八个LED将闪烁。
按INT0按钮开关,则进入中断状态,P1所连接的八个LED将变成单灯左移,而左移3圈(从最左边到最右边为1圈)后,恢复中断前的状态,程序将继续执行八灯闪烁的功能。
/*ch06-3-1.c-INT0中断实验*/
//==声明区===================================
#include//定义8x51暂存器
#defineLEDP1//定义LED接至Port1
voiddelay1ms(int);//声明延迟函数
voidleft(int);//声明单灯左移函数
main()//主程序开始
{//EA=1;
//EX0=1;
IE=0x81;//准许INT0中断
LED=0x00;//初值=00000000,灯全亮
while
(1)//无穷循环,程序一直跑
{delay1ms(250);//延迟250*1m=0.25s
LED=~LED;//LED反相
}//while循环结束
}//主程序结束
/*INT0的中断子程序-单灯左移3圈*/
voidmy_int0(void)interrupt0//INT0中断子程序开始
{unsignedsaveLED=LED;//储存中断前LED状态
left(3);//单灯左移3圈
LED=saveLED;//写回中断前LED状态
}//结束INT0中断子程序
/*延迟函数,延迟约x1ms*/
voiddelay1ms(intx)//延迟函数开始
{inti,j;//声明整数变数i,j
for(i=0;ifor(j=0;j<120;j++);//计数120次,延迟1ms
}//延迟函数结束
/*单灯左移函数,执行x圈*/
voidleft(intx)//单灯左移函数开始
{inti,j;//声明变数i,j
for(i=0;i{LED=0xfe;//初始状态=11111110,最右灯亮
for(j=0;j<7;j++)//j循环,左移7次
{delay1ms(250);//延迟250*1m=0.25s
LED=(LED<<1)|0x01;//左移1位後,LSB设为1
}//j循环结束
delay1ms(250);//延迟250*1m=0.25s
}//i循环结束*/
}//单灯左移函数结束
在本实验里,若希望中断时,这八个LED变成是霹雳灯,来回各三圈,才返回主程序,程序应如何更改?
6-3-2INT1实验
主程序正常执行时,七段显示器将从0开始正数到9(循环),每0.5秒增加1。
按INT1按钮开关,则进入中断状态,则七段显示器将从9开始闪烁倒数到0(一圈后结束中断),每0.5秒减少1。
/*ch06-3-2.c-INT1中断实验*/
//==声明区====================================
#include//定义8x51暂存器
#defineSEGP0//定义七节显示器接至Port0
voiddelay1ms(int);//声明延迟函数
/*声明七节显示器驱动信号阵列(共阳)*/
unsignedcharcodeTAB[]={0xc0,0xf9,0xa4,0xb0,0x99,//数字0-4
0x92,0x83,0xf8,0x80,0x98};//数字5-9
//==主程序=====================================
main()//主程序开始
{inti;//声明i变数(计数值)
IE=0x84;//准许INT1中断(6-4页)
while
(1)//无穷循环,程序一直跑
{for(i=0;i<10;i++)4//显示0-9(上数)
{SEG=TAB[i];//显示数字至七节显示器
delay1ms(500);//延迟5001m=0.5s
}
}//for循环结束
}//主程序结束
//==子程序===================================
/*INT1的中断子程序-数字闪烁倒数9-0*/
voidmy_int1(void)interrupt2//INT1中断子程序开始
{inti;//声明i变数(计数值)
for(i=9;i>=0;i--)//for循环显示9-0(下数)
{SEG=TAB[i];//显示数字至七节显示器
delay1ms(250);//延迟5001m=0.5s
SEG=0xff;//关闭七节显示器
delay1ms(250);//延迟5001m=0.5s
}//for循环结束
}//结束中断子程序
/*延迟函数,延迟约x*1ms*/
voiddelay1ms(intx)//延迟函数开始
{inti,j;//声明整数变数i,j
for(i=0;ifor(j=0;j<120;j++);//计数120次,延迟1ms
}//延迟函数结束
思考:
1)在本实验的仿真中,若要在输出口里看到0、1、2…9的变化,而非0~9的七段显示器驱动信号,应如何修改程序?
unsignedcharcodeTAB[]={0,1,2,3,4,5,6,7,8,9};
在KEILC的调试环境的P0口中观察结果
2)若在本实验的电路里,将原本的共阳极七段显示器,改采用共阴极七段显示器,则程序应如何更改?
unsignedcharcodeTAB[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
voidmy_int1(void)interrupt2//INT1中断子程序开始
{inti;//声明i变数(计数值)
for(i=9;i>=0;i--)//for循环显示9-0(下数)
{SEG=TAB[i];//显示数字至七节显示器
delay1ms(250);//延迟5001m=0.5s
SEG=0x00;//关闭七节显示器
delay1ms(250);//延迟5001m=0.5s
}//for循环结束
}
6-3-3两个外部中断实验
1)主程序正常执行时,P1所连接的八LED将闪烁
2)按INT0按钮开关,则进入INT0中断状态,P1所连接的八个LED将变成单灯左移,而左移3圈(从最左边到最右边为1圈)后,恢复中断前的状态,程序将继续执行八灯闪烁的功能。
3)按INT1按钮开关,则进入INT1中断状态,P1所连接的八个LED将变成单灯右移,而右移3圈(从最左边到最右边为1圈)后,恢复中断前的状态,程序将继续执行八灯闪烁的功能。
4)单灯左移(INT0)中断的优先级较单灯右移(INT1)中断的优先级高
/*ch06-3-3.c-两个外部中断实验*/
//==声明区===================================
#include//定义8x51暂存器
#defineLEDP1//定义LED接至Port1
voiddelay1ms(int);//声明延迟函数
voidleft(int);//声明单灯左移函数
voidright(int);//单灯右移函数开始
//==主程序===================================
main()//主程序开始
{IE=0x85;//准许INT0,INT1中断
IP=0x01;//设定INT0具有最高优先权(6-5页)
LED=0x00;//初值=00000000,灯全亮
while
(1)//无穷循环,程序一直跑
{delay1ms(250);//延迟2501m=0.25s
LED=~LED;//LED反相
}//while循环结束
}//主程序结束
//==子程序===================================
/*INT0的中断子程序-单灯左移3圈*/
voidmy_int0(void)interrupt0//INT0中断子程序开始
{unsignedsaveLED=LED;//储存中断前LED状态
left(3);//单灯左移3圈
LED=saveLED;//写回中断前LED状态
}//结束INT0中断子程序
/*INT1的中断子程序-单灯右移3圈*/
voidmy_int1(void)interrupt2//INT1中断子程序开始
{unsignedsaveLED=LED;//储存中断前LED状态
right(3);//单灯右移3圈
LED=saveLED;//写回中断前LED状态
}//结束INT1中断子程序
/*延迟函数,延迟约x1ms*/
voiddelay1ms(intx)//延迟函数开始
{inti,j;//声明整数变数i,j
for(i=0;ifor(j=0;j<120;j++);//计数120次,延迟1ms
}//延迟函数结束
/*单灯左移函数,执行x圈*/
voidleft(intx)//单灯左移函数开始
{inti,j;//声明变数i,j
for(i=0;i{LED=0xfe;//初始状态=11111110,最右灯亮
for(j=0;j<7;j++)//j循环,左移7次
{delay1ms(250);//延迟2501m=0.25s
LED=(LED<<1)|0x01;//左移1位後,LSB设为1
}//j循环结束
delay1ms(250);//延迟2501m=0.25s
}//i循环结束*/
}//单灯左移函数结束
/*单灯右移函数,执行x圈*/
voidright(intx)//单灯右移函数开始
{inti,j;//声明变数i,j
for(i=0;i{LED=0x7f;//初始状态=01111111
for(j=0;j<7;j++)//j循环,右移7次
{delay1ms(250);//延迟25010m=0.25s
LED=(LED>>1)|0x80;//右移1位後,MSB设为1
}//j循环结束
delay1ms(250);//延迟2501m=0.25s
}//i循环结束*/
}//单灯右移函数结束
思考:
1)在本实验里,“IP=0x01”表示之中断优先级较高,则进行调试/仿真时,先中断,LED由右而左3圈;若还没结束之前,启动INT1中断,将会有什么变化?
同样地,先INT1中断,LED由左而右3圈;若还没结束INT1之前,启动中断,将会有什么变化?
2)若希望INT1中断的优先等级高于程序中断的优先等级,应如何修改?
修改完成后,再进行一次第1题的实验。
IP=0X04;
三、小结
本节讲述了中断的概念,MCS-51的中断的构成,重点理解中断子程序的编写方法。
思考题和习题
思考与习题:
1完成6-3-1外部中断INT0的仿真电路图,并编程实现。
2思考:
中断服务子程序和前面普通子程序的编写方法的区别
教
学
后
记