
2.3 相关知识
2.3.1 数组
数组是一组有相同类型数据的有序集合。数码管显示段选码表、LED点阵显示字形码表,对传感器的非线性参数进行补偿时的表格可以用数组表示。数组必须先定义后使用,同一数组中的元素具有相同的数据类型、相同的数组名和不同的下标。
1.一维数组的定义与引用
1)一维数组的定义
一维数组的定义为:
<存储类型> 类型说明符 数组名 [常量表达式];
“存储类型”包括static、extern和auto,可缺省,缺省时与变量处理格式相同。
“类型说明符”说明数组元素的数据类型,可以是整型、字符型等。
“数组名”是整个数组的标识符,它的命名与变量相同。在说明一个数组后,系统会在内存中分配一段连续的空间用于存放数组元素。
“常量表达式”指明了数组的长度,即数组中元素的个数。它必须用方括号“[ ]”括起来,不能含有变量,必须是一个整型值。
例如:int ab[3];∥它表示数组名为ab,有3个整形元素,数组元素在内存中的存放顺序如图2-1所示。

图2-1 一维数组元素存放图
2)一维数组的引用
在C51中,使用数值型数组时,只能逐个应用数组元素而不能一次引用整个数组。数组元素的引用是通过数组名和下标来实现的,一维数组中数组元素的引用形式是:
数组名[下标表达式]
“下标表达式”表示了数组中的某个元素的顺序序号,数组元素的下标总是从0开始的。若数组长度为m,第一个元素的下标为0,最后一个为m-1。下标表达式可以是任何整型常量、整型变量,或返回整型量的表达式。
例如,对数组ab[3]的引用分别为ab[0]、ab[1]、ab[2]。通过数组元素的引用,数组元素就可以进行赋值和算术运算以及输入和输出操作。
例如:
#include <reg51.h>
main( )
{
unsigned char n,ab[3];
for(n=0;n<2;n++)
ab[n]=n;
ab[2]=5;
}
本程序使ab[0]、ab[1]、ab[2]分别赋值为0、1、5。
3)一维数组的初始化
一维数组的初始化可通过以下几种形式。
①对数组全部元素初始化,例如:static int b[3]={0,1,2};。
②可以只给一部分元素赋值,例如:static int b[3]={0,1};,后面元素自动赋0。
③如果想使一个数组中全部元素值为“0”,例如:static int b[3]={0,0,0};对static数组不赋初值,系统会对所有数组元素自动赋以“0”值,即static int b[3];。
④在对全部数组元素赋初值时,可以不指定数组长度。例如 static int b[ ]={0,1,2},在括号中有3个数,系统就会据此自动定义b数组的长度为3。
2.二维数组的定义与引用
1)二维数组的定义
定义二维数组的一般形式为:
类型说明符 数组名[常量表达式1][常量表达式2]
例如:int b[2][2];
定义一个名为b的2行2列的整型数据数组。b数组中的元素在内存中的排列顺序为按行存放,如图2-2所示。

图2-2 二维数组元素存放图
2)二维数组的引用
二维数组元素的引用与一维数组元素的引用相似,其形式为:
数组名[下标表达式1][下标表达式2]
下标表达式也可以是任何整型常量、整型变量,或返回整型量的表达式。
若二维数组第一维的长度为n,第二维的长度为m,第一个元素的下标为[0][0],最后一个下标为[n-1][m-1]。
3)二维数组的初始化
①在定义二维数组时,分行对各元素赋初值,第一个{}内元素赋给第一行的元素,第二个{}内元素赋给第二行的元素,以此类推。
例如:
int b[2][2]={{1,4}{2,3}};
②可以将所有的值写在一个大括号内,按数组在内存中排列的顺序对各元素赋值。
例如:int b[2][2]={1,4,2,3};
③可以只对部分元素赋值,其余元素自动为“0”。
例如:int b[2][2]={{1}{4}};
这时,b[0][0]的值为1,b[0][1]的值为0,b[1][0]的值为4,b[1][1]的值为0。
④如果对全部元素都赋值,则定义数组时第一维长度可以省略。
例如:int a[2][2]={{1,2},{3,4}};等价于int a[ ][2]={{1,2 },{3,4}};
3.字符数组
用来存放字符数据的数组称为字符数组。字符数组中的每个元素就是一个字符,既具有普通数组的一般性质,又具有某些特殊性质。
1)字符数组的定义与初始化
(1)字符数组的定义。字符数组的定义与数值型数组的定义相类似,它的一般形式为:
char 字符数组名[字符长度];
例如:char ch[2];
定义了一个名为ch,长度为2的字符数组。注意,字符数组中的每个元素只能存放一个字符,例如:
ch[0]=‘A’;
ch[1]=‘H’;
(2)字符数组的初始化。
方法一:是通过为每个数组元素指定初值字符来实现。
例如:char a [3]={‘0’,‘1’,‘n’};
如果赋初值的个数大于数组长度,则作语法错误处理;如果提供的初值个数与预定的数组长度相同,在定义时可以省略数组长度,系统会自动根据初值个数确定数组长度。如果初值个数小于数组长度,则只将这些字符赋给数组中前面那些元素,其余的元素自动定为空字符(即‘\0’)。
方法二:是用字符串常量对字符数组初始化。例如:
char ch[]=“china”;
2)字符数组的引用
字符数组的引用和数值数组相类似,形式为:
数组名 [下标]
3)字符串和字符串结束标志
字符串是指若干有效字符的序列,字符串不能存放在一个变量中,只能存放在一个字符型数组中,为了测定字符串的实际长度,在C51中规定以‘\0’字符作为字符串结束标志,在字符数组中占一个空间位置。在字符串常量末尾,编译系统会自动加上‘\0’作为结束符。
例如:static char a[2]={“25”};经赋值后 mum数组中各元素的值为:
由于空字符作为结束标志,因此,说明字符数组长度时,应为所需长度加1。
2.3.2 LED显示
LED(Light Emitting Diode),即发光二极管,是一种半导体固体发光器件,它是利用固体半导体芯片作为发光材料,当两端加上正向电压,半导体中的载流子发生复合引起光子发射而产生光。LED可以直接发出红、黄、蓝、绿、青、橙、紫、白色的光。
1.LED数码管显示
LED数码显示器是由若干个发光二极管组成的,当发光二极管导通时,相应的点或线段发光,将这些二极管排成一定图形,控制不同组合的二极管导通,显示出不同的字形,常作数码显示用,根据公共引脚接供电和地的连接方式为共阴和共阳两种,单个数码管外观和结构如图2-3所示,7、8脚为公共脚。

图2-3 数码管结构图
LED数码管中各段发光二极管的伏安特性与普通二极管相类似,只是正向压降大,正向电阻较大,启辉电流1~2mA,最大电流10~30mA、动态平均电流4~5mA,接高于7.5V电压时要接限流电阻。
显示时,必须在8位段选线(a、b、c、d、e、f、g、dp)上加上相应的电平组合,即一个8位数据,这个数据叫字形码(又叫字符的段选码),通常用的段选编码规则如表2-1所示(不用小数点,则七段LED数码管)。
表2-1 七段LED段选码

显示时,显示的内容与输入的字形码(段选码)是不一致的,在显示时需把待显示的数字转换成相应的字形码,这个过程叫译码。译码有硬件译码和软件译码两种方法。硬件译码时常用74LS47、74LS48、74LS49、74LS164等译码电路实现。软件译码常用查表法实现。
1)静态显示
静态显示是数码管的相应笔段一直处于点亮状态,因此功耗大,而且占用硬件资源多,几乎只能用在显示位数极少的场合。在数码管的abcdefg引脚上输入段选码输入段码,公共脚3(8)输入或接对应电平,保持不变,数码管将一直显示对应段码的内容。
例如:下面程序实现在共阳数码静态显示L。
#include<reg51.h>
sbit LINE=P1^0;
main( )
{
while(1)
{
P2=0xd3; ∥ L字形码 11100011
LINE =1;
}
}
2)动态显示
动态显示是多只数码管共享段选线,依次输出段选码,同时逐位进行扫描(依次为数码管的公共端加合适的显示电平),数码管处于亮和灭的交替之中,利用人眼的视觉惰性,实现显示的方式,占用硬件资源少,功耗小,但是,扫描周期必须控制在视觉停顿时间内,否则会出现闪烁或跳动现象。
例如,用P1口作段选码输出,P2口作位选控制,2位数据轮流显示,程序如下:
#include<reg51.h>
unsigned char seg[]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0xc0};
void delay(unsigned int i)
{
unsigned int j,k;
for(j=0;j<i;j++)
for(k=0;k<120;k++)
;
}
main( )
{
while(1)
{
P2=0xff;
P1=seg[0]; ∥显示1位
P2=0xfd;
delay(1);
P2=0xff; ∥显示2位
P1=seg[1];
P2=0xfb;
delay(1);
}
}
实现数码管显示10。
2.LED点阵显示
LED点阵显示器以发光二极管为像素,结构如图2-4所示,点阵引脚及实物如图2-5所示。按内部电路结构和外形规格分共阳与共阴两种。

图2-4 点阵结构图

图2-5 点阵引脚及实物图
它用高亮度发光二极管芯阵列组合后,用环氧树脂和塑模封装而成,具有高亮度、功耗低、引脚少、视角大、寿命长、耐湿、耐冷热、耐腐蚀等特点。
LED点阵显示器可显示红、黄、绿、橙等颜色,按显示颜色多少分为单色和双色两类,规格有4×4、4×8、5×7、5×8、 8×8、16×16、24×24、40×40等多种。根据像素的数目分为单基色、双基色、三基色等。单基色点阵只能显示固定色彩,如红、绿、黄等单色。双基色和三基色点阵显示内容的颜色,由像素内不同颜色发光二极管点亮组合方式决定,如红绿都亮时可显示黄色。如果用脉冲方式控制二极管的点亮时间,则可实现256或更高级灰度显示,即可实现真彩色显示。
由于LED管芯大多为高亮度型,因此某行或某列的单体LED驱动电流可选用窄脉冲,但其平均电流应限制在20mA内,多数点阵显示器的单体LED的正向压降约在2V左右,但大亮点∮10的点阵显示器单体LED的正向压降约为6V。
LED点阵显示器单块使用时,既可代替数码管显示数字,也可显示各种中西文字、符号、图形。若用多块点阵显示器组合,则可构成大屏幕显示器。
在实际应用中一般采用动态显示方式,动态显示采用扫描的方式工作,由峰值较大的窄脉冲驱动,从上到下逐次不断地对显示屏的各行进行选通,同时又向各列送出表示图形或文字信息的脉冲信号,反复循环以上操作,就可显示各种图形或文字信息。
如图2-6所示,在8×8点阵的行线上依次输入如下字形码:
0EFH,83H,0ABH,83H,0ABH,83H,0EEH,0E0H
同时在8×8点阵的列线上轮流输入高电平,则可以在8×8共阳LED点阵上显示汉字“电”。

图2-6 汉字点阵示意图
用P0口作字符数据输出端口,P2口作扫描控制字输出,显示程序如下:
#include<reg51.h>
unsigned char Font[8]={ 0xEF,0x83,0x0AB,0x83,0xAB,0x83,0xEE,0xE0};
unsigned char rank[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f};
/ ***************延迟函数************ /
void delay(unsigned char time)
{
unsigned char i;
for(i=0;i<time;i++)
;
}
/ **************显示函数*************** /
void display(unsigned char dat,unsigned char rank)
{
P2=0xff;
P1=dat; ∥输出字形码
P2=rank;
delay(200);
}
/ **************主函数*************** /
main( )
{
unsigned char i;
while(1)
{
for(i=0;i<8;i++)
display(Font[i],rank[i]);
}
}
3.案例:编程数码管显示门牌号
1)编程要求
编写程序显示自己教室的3位门牌编号。
2)编程思路
首先分别求出3位数门牌编号的各位存入数组。数据处理的程序流程图如图2-7所示,然后,以动态显示方式,从数组中读出每一位数据并译码显示,一位数据译码显示程序流程图如图2-8所示,主程序流程图如图2-9所示。

图2-7 数据处理程序流程图

图2-8 译码显示一位数据流程图

图2-9 门牌编号显示主程序流程图
3)设计程序
根据流程图设计程序,参考程序如下:
#include<reg51.h>
unsigned char seg_dm[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
unsigned char display_dat[3];
/ **************延迟函数************ /
void delay(unsigned int time)
{
unsigned int i,j;
for(i=0;i<time;i++)
for(j=0;j<120;j++)
;
}
/ **************数据处理函数************ /
change_dat(int bj_dat)
{
display_dat[0]=bj_dat/100;
display_dat[1]=bj_dat%100/10;
display_dat[2]=bj_dat%100%10;
}
/ ************显示一位数据函数************ /
display(unsigned char dat,unsigned char bit_code)
{
P2=0xff; ∥关断
P1=seg_dm[dat]; ∥输出dat的段码
P2=bit_code; ∥输出位码
delay(10); ∥延迟
}
/ ************门牌编号显示函数************ /
main( )
{
change_dat(308); ∥处理门牌编号308
while(1)
{
display(display_dat[0],0xfe); ∥显示门牌编号
display(display_dat[1],0xfd);
display(display_dat[2],0xfb);
}
}
4.案例:编程在8×8点阵上显示汉字
1)编程要求
编写程序在8×8点阵上轮流显示汉字“中国”。
2)编程思路
首先以“大”字形码构建数组,然后以一定速度依次读出显示即可,主程序流程图如图2-10所示。

图2-10 主程序流程图
3)设计程序
根据流程图设计程序,参考程序如下:
#include<reg51.h>
unsigned char Font[32]={0x00,0x7C,0x54,0xFF,0x55,0x55,0x7D,0x3, ∥电
0x10,0x90,0x91,0xBF,0xFE,0xD0,0x90,0x10, ∥子
0x29,0xFF,0x29,0x51,0x5F,0xF2,0x5D,0x51, ∥技
0x22,0x24,0x38,0xFF,0xFF,0xAC,0xE6,0x22 ∥术
};
unsigned char rank[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; ∥列控制码
/ **************延迟函数************ /
void delay(unsigned int time)
{
unsigned int i,j;
for(i=0;i<time;i++)
for(j=0;j<120;j++)
;
}
/ **************显示一列函数************ /
void display(unsigned char dat,unsigned char rank)
{
P2=0xff;
P1=dat;
P2=rank;
delay(1);
}
/ **************主函数************ /
main( )
{
unsigned char i,j,k;
while(1)
{
for(j=0;j<4;j++)
for(k=0;k<200;k++) ∥每个字显示200次
for(i=0;i<8;i++)
display(Font[i+8*j],rank[i]);
}
}
2.3.3 MCS-51单片机中断系统
1.中断
1)中断的概念
计算机在执行程序的过程中,当出现CPU以外的某种情况,由服务对象向CPU发出中断请求信号,要求CPU暂时停止当前程序的执行,转去执行其他相应的处理程序,待其他程序执行完毕后,再继续执行原来被停止的程序。这种程序在执行过程中被中间打断的情况称为“中断”。
“中断”后所执行的相应的处理程序称为中断服务或中断处理函数,原来正常运行的程序称为主程序。主程序被断开的位置(或地址)称为“断点”。引起中断的事件或装置称为中断源。中断源的服务请求称为中断请求。
调用中断服务程序的过程类似于调用函数,其区别在于调用函数在程序中是事先安排好的,而何时调用中断服务程序事先却无法确定,因为“中断”的发生是由外部因素决定的。
2)中断的功能
(1)分时操作。中断可以解决CPU与外设之间速度不一致的矛盾,使CPU和外设同时工作。CPU在启动外设工作后,继续执行主程序,同时外设也在工作,每当外设做完一件事就发出中断申请,请求CPU中断它正在执行的程序,转去执行中断服务程序,中断处理完之后,CPU恢复执行主程序。这样,提高了CPU的效率。
(2)实时处理。在实时控制中,现场的各种参数、信息均随时间和现场而变化。这些外界部件可根据要求随时向CPU发出中断申请,请求CPU及时处理,如中断条件满足,CPU就响应,进行相应的处理,从而实现实时处理。
(3)故障处理。针对难以预料的情况或故障,如断电、存储出错、运算溢出等,可通过中断系统由故障源向CPU发出中断请求,再由CPU转到相应的故障处理程序进行处理。
2.MCS-51的中断系统
1)中断系统的组成
MCS-51中断系统由4个与中断相关的特殊功能寄存器(TCON、SCON、IE、IP)、中断入口、中断顺序查询逻辑电路等组成,如图2-11所示。

图2-11 MCS-51中断系统内部结构示意图
当中断发生时,相应中断源的中断标志位置“1”,如果相应中断源和中断允许总控制位被允许,CPU就会响应中断请求。
2)中断源
MCS-51共有5个中断源,两个外部中断(/INT0、/INT1),两个定时器益处中断(T0 溢出、T1 溢出)和一个串行口中断。
3)中断的允许与禁止
MCS-51系列单片机的5个中断源,都是可屏蔽中断,其中断系统内部设有一个专用寄存器IE,用于控制CPU对各中断源的开放或屏蔽。IE寄存器各位定义如下:
EA:总中断允许控制位。EA = 1,开放所有中断; EA = 0,禁止所有中断。
ES:串行口中断允许位。ES = 1,允许串行口中断;ES = 0禁止串行口中断。
ET1:定时器T1中断允许位。ET1 = 1,允许T1中断;ET1 = 0,禁止T1中断。
EX1:外部中断1(INT1)中断允许位。EX1 = 1,允许外部中断1(INT1)中断;EX1 = 0,禁止外部中断1中断。
ET0:定时器T0中断允许位。ET0 = 1,允许T0中断;ET0 = 0,禁止T0中断。
EX0:外部中断0(INT0)中断允许位。EX0 = 1,允许外部中断0中断;EX0 = 0,禁止外部中断0(INT0)中断。
8051单片机系统复位后,IE中各中断允许位均被清0,即禁止所有中断。只有用指令设定EA=1和相应中断源允许位=1,才能打开。
例如,只允许TI中断,设置为:IE=0x88;。
4)中断优先级寄存器IP
MCS-51系列单片机的5个中断源划分为2个中断优先级。专用寄存器IP为中断优先级寄存器,IP中的每一位均可由软件来置1或清0,且1表示高优先级,0表示低优先级,其格式如下:
PS:串行口中断优先控制位。PS = 1,设定串行口为高优先级;PS = 0,设定串行口为低优先级。
PT1:定时器T1中断优先控制位。PT1 = 1,设定时器T1中断为高优先级;PT1 = 0,设定时器T1中断为低优先级。
PX1:外部中断1中断优先控制位。PX1 = 1,设定外部中断1为高优先级;PX1 = 0,设定外部中断1为低优先级。
PT0:定时器T0中断优先控制位。PT0 = 1,设定时器T0中断为高优先级;PT0 = 0,设定时器T0中断为低优先级。
PX0:外部中断0中断优先控制位。PX0 = 1,设定外部中断0为高优先级;PX0 = 0,设定外部中断0为低优先级。
当系统复位后,IP低5位全部清0,所有中断源均设定为低优先级。可通过编程确定高、低优先级。例如,要设定串行口中断为最高优先级,则设置IP=0x10;。
如果几个同一优先级的中断源,同时向CPU申请中断,CPU 通过内部硬件查询逻辑,按自然优先级顺序确定先响应哪个中断请求。自然优先级由硬件形成,顺序如表2-2所示。
表2-2 MCS-51系列单片机中断优先级

多个中断源,如果程序中没有中断优先级设置指令,则按自然优先级进行排列。实际应用中,常把IP寄存器和自然优先级相结合使用。
当CPU响应某一中断时,若有更高优先级的中断源发出中断请求,则CPU能中断正在进行的中断服务程序,并保留程序的断点,响应高级中断,高级中断处理结束以后,再继续进行被中断的中断服务程序,其示意图如图2-12所示,这个过程称为中断嵌套。如果发出新的中断请求的中断源的优先权级别,与正在处理的中断源同级或更低时,CPU不会响应这个中断请求,直至正在处理的中断服务程序执行完以后,才能去处理新的中断请求。

图2-12 中断嵌套流程图
3.中断处理过程
中断处理过程可分为中断响应、中断处理和中断返回三个阶段。
1)中断响应
中断响应是CPU对中断源中断请求的响应,包括保护断点和将程序转向中断服务程序的入口地址。CPU响应中断请求,必须满足以下条件。
①有中断源发出中断请求。
②中断总允许位EA=1。
③申请允许中断的中断源。
满足以上基本条件,CPU一般会响应中断,但若有下列任何一种情况存在,则中断响应会受到阻断。
①CPU正在响应同级或高优先级的中断。
②当前指令未执行完。
③正在执行RETI中断返回指令或访问专用寄存器IE和IP的指令。
若存在上述任何一种情况,中断查询结果即被取消,CPU不响应中断请求,而在下一机器周期继续查询中断。
如果中断请求被阻断,则中断响应时间将延长。例如,一个同级或更高级的中断正在进行,则附加的等待时间取决于正在进行的中断服务程序的长度。如果正在执行的一条指令还没有进行到最后一个机器周期,则附加的等待时间为1~3个机器周期(因为一条指令的最长执行时间为4个机器周期)。如果正在执行的指令是RETI指令或访问IE或IP的指令,则附加的等待时间在5个机器周期之内。
若系统中只有一个中断源,则中断响应时间为3~8个机器周期。
2)中断响应过程
中断响应过程包括保护断点和将程序转向中断服务程序的入口地址。首先,中断系统通过自动调用指令(LACLL),该指令将自动把断点地址压入堆栈保护(不保护累加器A、状态寄存器PSW和其他寄存器的内容),然后,将对应的中断入口地址装入程序计数器PC,程序转向该中断入口地址,执行中断服务程序。MCS-51系列单片机各中断源的入口地址由硬件事先设定,其入口地址如表2-3所示。
表2-3 MCS-51系列单片机中断源的入口地址

3)中断返回
CPU响应中断请求后即进入中断服务程序,在中断返回前,应撤除该中断请求,否则会引起重复中断。MCS-51各中断源中断请求撤消的方法各不相同,中断请求的撤除分别如下。
①定时器中断请求的撤除。对于T0或T1溢出中断,CPU在响应中断后即由硬件自动清除其中断标志位TF0或TF1,无需采取其他措施。
②外部中断请求的撤除。对于边沿触发的外部中断0或1,CPU在响应中断后由硬件自动清除其中断标志位IE0或IE1,无需采取其他措施。
对于电平触发的外部中断,其中断请求撤除方法较复杂。因为对于电平触发外中断,CPU在响应中断后,硬件不会自动清除其中断请求标志位IE0或IE1,同时,也不能用软件将其清除,所以,在CPU响应中断后,应立即撤除/INT0或/INT1引脚上的低电平,否则会引起重复中断。
③串行口中断请求的撤除。对于串行口中断,CPU在响应中断后,硬件不能自动清除中断请求标志位TI、RI,必须在中断服务程序中用软件将其清除。
4.中断服务函数与寄存器组定义
C51编译器通过扩展关键字interrupt,可将函数转化为中断服务函数,这时C51自动为函数加上汇编码中断程序头段和尾段,并根据中断号找到中断入口地址,它的一般形式为:
函数类型 函数名(形式参数表)[interrupt n] [using n]
①关键字interrupt后面的n是中断号,表2-4为8051中断号与中断向量(中断入口地址)。
表2-4 8051中断号与中断向量

关键字interrupt不允许用于外部函数。
②关键字using n 可以指定在函数内部使用的寄存器组,n的取值为0~3,分别对应8051单片机片内RAM中使用的4个不同的工作寄存器组。
2.3.4 外部中断源
1.外部中断源概述
/NT0 的中断请求由P3.2脚输入,/INT1的中断请求由P3.3脚输入。外部中断0中断号为0,入口地址为 0003H,外部中断1中断号为2,入口地址为 0013H。
2.外部中断源的控制寄存器的设置
外部中断触发方式、中断的禁止与允许、优先级的高低,由中断请求、中断允许、中断优先级3个方面的寄存器控制。
1)触发方式设置
外部中断源的触发方式有电平触发和边沿触发两种,通过定时和外部中断控制寄存器TCON的IT0和IT1位设定, TCON的结构如下:
IT0、IT1分别为外部中断0(/INT0)和外部中断1(INT1)触发方式选择位。当设定IT0(IT1)为“0”时,为电平(低电平)触发方式;当设定IT0(IT1)为“1”时,为边沿(下降沿)触发方式。
IE0、IE1为分别为外部中断0(/INT0)和外部中断1(INT1)的中断标志位。当INT0(INTI)输入信号有效,引发了中断,IE0(IE1)由硬件置位,标志位为“1”,否则复位为“0”。
例如,设置外部中断0(/INT0)为边沿方触发式,外部中断1(/INT1)为电平方触发式,设置如下:
TCON=0X01; ∥设置的二进制码为00000001(其他位未用时设置为0)
2)中断源的允许与禁止
外部中断源的允许与禁止,通过对中断允许寄存器IE中EA、EX0、EX1三位进行设置。IE结构如下:
EA:总中断允许控制位。
EX1:外部中断1(/INT1)中断允许位。EX1 = 1,允许外部中断1中断;EX1 = 0,禁止外部中断1中断。
EX0:外部中断0(/INT0)中断允许位。EX0 = 1,允许外部中断0中断;EX0 = 0,禁止外部中断0中断。
例如,设置/INT0为允许,/INT1 为禁止,设置如下:
IE=0X81; //设置的二进制码为00000001(其他位未用时设置为0)
或:“EA=1;EX0=1;EX1=0;”。
3)优先级的设置
外部中断源优先级由优先级寄存器IP的PX0、PX1进行设定,IP的结构如下:
PX1:外部中断1中断优先控制位。PX1 = 1,外部中断1为高优先级;PX1 = 0,外部中断1为低优先级中断。
PX0:外部中断0中断优先控制位。PX0 = 1,外部中断0为高优先级中断;PX0 = 0,外部中断0为低优先级中断。
例如,设定外部中断1为最高优先级,设置为:“IP=0X04;”。
3.外部中断源的扩展
8051单片机只有两个外部中断请求输入端/INT0和/INT1,在实际应用中,若外部中断源超过两个,则需扩充外部中断源。常用以下两种方法扩展中断源。
①用定时计数器扩展中断源。例如,在键盘程序设计中常用定时器溢出产生中断,在中断程序用查询方式识别按键。
②中断和查询相结合扩展中断源。外部中断引入端通过一个与门,连接至外部中断输入端(/INT0或/INT1脚),同时,利用并行输入端口作为多个中断源的识别端口,当外部中断引入端全部为高时,与门输出高,没有中断申请;当外部中断引入端中任何一个由高变低时,与门输出将由高变低,产生中断申请信号,CPU即可以响应中断,其电路图如图2-13所示。

图2-13 一个外中断扩展成多个外中断的电路图
4.外部中断源设置流程
外部中断的应用主要是对中断源进行初始化准备与中断服务程序的设计。其中中断源初始化就是在主程序中设置外部中断源的触发方式、允许中断、设置优先级等,为触发中断作好准备。
例如,要求外部中断1为电平触发方式,允许中断,优先级最高,则初始化如下:
TCON=0X00;
IE=0X84;
IP=0X04;
中断服务程序主要完成中断请求需做的事情,外部中断服务函数的格式如下:
函数类型 函数名(形式参数表)[interrupt 中断号(0或2)] [using n]
{
……; //关中断,防止重复中断
……; //中断请求
……; //开中断
}
例如,假设外部中断1请求P1.0外接的LED点亮 ,中断服务函数如下:
void LED_on( )interrupt 2 using 1
{
EX1=0;
LED=0;
EX1=1;
}
5.案例:编程外部中断0控制LED亮灭
1)程序要求
当外部中断0遇到下降沿时,P1.0外接的LED(负端接I/O)亮灭翻转。
2)编程思路
首先对外部中断0进行初始化:设置为边沿触发方式,开中断,然后在中断服务程序控制LED的亮灭变化。其主程序流程图如图2-14所示。中断服务程序流程图如图2-15所示。

图2-14 中断0控制LED亮灭主程序流程图

图2-15 中断服务程序流程图
3)设计程序
根据流程图设计程序,参考程序如下:
#include<reg51.h>
sbit LED=P1^0;
/ **************中断0初始化函数***************** /
void Int0_ init( )
{
TCON=0X01;
IE=0X81;
IP=0X01;
}
/ **************主函数************************ /
main( )
{
Int0_ init( );
while(1);
}
/ **********外部中断0中断服务函数************ /
void LED_on_off( )interrupt 0 using 1
{
EX0=0;
LED=! LED;
EX0=1;
}