分别用两个开关使用中断操作实现计数和清零。目的就是搞清楚中断是如何工作的。CSDN文本编辑实现首行缩进的方法
/*****************************************************************************
******************************************************************************************
***
* 文件名:main.c
* 说 明:用四位数码管显示外部中断的计数
******************************************************************************
******************************************************************************************
**/
#include "reg51.h"
#include "main.h"
#include "delay.h"
/* 数码显示管 */
uchar code DIS_CODE[12] = {0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90,0xFF,0x0C};
uint g_unDisNum; //保存计数值,用数码管来显示
/*****************************************************************************
******************************************************************************************
***
* 函数名:显示数字的函数,显示4位数字
* 参 数:num,要显示的数字
* 返回值:无
******************************************************************************
******************************************************************************************
***/
void disp_num(uchar num)
{
uchar sep_num; //要显示数字的个位
uchar ten_num; //要显示数字的十位
uchar hund_num; //要显示数字的百位
uchar thou_num; //要显示数字的千位
sep_num = num%10;
ten_num = (num%100)/10;
hund_num = (num%1000)/100;
thou_num = (num%10000)/1000; //相当于num/1000(原因是四位数的num%10000的值还是
// num本身)
P2 = 0x01; //
P0 = DIS_CODE[thou_num];
delay_ms(5);
P2 = 0x02;
P0 = DIS_CODE[hund_num];
delay_ms(5);
P2 = 0x04;
P0 = DIS_CODE[ten_num];
delay_ms(5);
P2 = 0x08;
P0 = DIS_CODE[sep_num];
}
/*****************************************************************************
******************************************************************************************
***
* 函数名:Int0中断函数,0是Int0的中断号
* 参 数:空
* 返回值:无
******************************************************************************
******************************************************************************************
***/
void int0_inter() interrupt 0
{
g_unDisNum++;
}
/*****************************************************************************
******************************************************************************************
***
* 函数名:Int1中断函数,2是Int1的中断号
* 参 数:无
* 返回值:无
******************************************************************************
******************************************************************************************
***/
void int1_inter() interrupt 2
{
g_unDisNum = 0;
}
/*****************************************************************************
******************************************************************************************
***
* 函数名:主函数,初始化中断设定,显示数据计数
* 参 数:无
* 返回值:无
******************************************************************************
******************************************************************************************
***/
void main (void)
{
g_unDisNum = 0; //要显示的变量初始化
P0 = 0xFF;
P2 = 0xFF;
P3 = 0xFF;
IT0 = 1; //下降沿触发模式 或可以写成 TCON |= 0x05;
IT1 = 1;
EX0 = 1; //打开Int0中断
EX1 = 1; //
EA = 1; //打开全局中断
while(1)
{
disp_num(g_unDisNum);
}
}
设定触发方式时可以写为TCON= 0x05或TCON |= 0x05,这是因为根据表6-2知道,IT0和IT1就是寄存器TCON的Bit0和Bit2位。0x05就是0000 0101。
void int0_inter() interrupt 0,这里的函数返回值是空的,无参数,int0_inter是函数的名字,可以根据自己的需要定义,interrupt是关键字,后面紧跟的数字0是中断号,编译器就是靠这个中断号来识别该中断函数是什么中断的(有关中断号更详细的解释我们稍后介绍,这里先说完中断函数的定义)。这还不是中断函数的全部,其实后面还可以跟工作寄存器组的内容,由于编译器会自动分配工作寄存器组,因而通常不写工作组的内容。一个完整的中断函数格式如下:
通常不写using的内容。
最后介绍一下中断号的内容,我们看一看表6-3中51单片机的中断和中断号的对应关系。
上面给出了几种中断的中断号,我们的代码也是根据这个中断号来写的中断优先级的问题,根据默认的优先级int0的优先级最高,其实它们的优先级是可以根据需要定义的。
P3口是一个带内部上拉电阻的8位双向I/O口。P3口的输出缓冲器可以驱动4个TTL门电路。对P3口写“1”,通过内部的上拉电阻把端口拉为高电平,此时P3口可以作为输入口使用。作输入口使用时,P3口被外部拉低的引脚会因为内部上拉电阻的存在而输出电流(IIL)。
AT89C51的P3口也提供一些特殊功能,如下所示:
首先了解两个寄存器,IE和TCON
IE寄存器的全称是Interrupt Enable Register,译为中文就是中断允许寄存器。打开reg51.h可以找到该寄存器。
对于sfr以及sbit的关键字解释参考51单片机bit、sbin、sfr、sfr_16有什么区别。
EX0:外部中断0中断允许位。该位设定为1,外部中断0打开;设定为0,外部中断0关闭。
EX1:外部中断1中断允许位。该位设定为1,外部中断1打开;设定为0,外部中断1关闭。
ET0:定时/计数器0溢出中断允许位。该位设定为1,打开T/C0溢出中断;设定为0,关闭T/C0溢出中断。
ET1:定时/计数器1溢出中断允许位。该位设定为1,打开T/C1溢出中断;设定为0,关闭T/C1溢出中断。
ES:串口中断运行位。该位设定为1,打开串口中断;设定为0,关闭串口中断。
EA:全局控制位。该位设定为1,打开全局中断;设定为0,关闭全局中断。
这里EX0、EX1、EA三个控制位要重点理解,其他三个控制位用到时再讲解。EA是全局控制位,因而要使用中断就要设定该位为1,否则所有中断都将被关闭。EX1和EX0是外部中断1和外部中断0对应的控制位,因而要使用外部中断,就要设定对应的控制位为1。
该寄存器默认值是0,所以要使用中断,一定要设定该寄存器中对应的位,特别是EA的设置。只要使用中断,都要设定EA=1(或IE =IE|0x80),否则不能进入任何中断。
该寄存器的全称是Timer/CounterControl Register,译为中文就是定时/计数器控制寄存器。reg51.h中找到其定义:
首地址为0x88,
IT0:外部中断0触发方式选择位。该位设定为1,外部中断0下降沿触发;设定为0,外部中断0低电平触发。
IT1:外部中断1触发方式选择位。该位设定为1,外部中断1,下降沿触发;设定为0,外部中断1低电平触发。
IE0:外部中断0请求标志位。当外部中断0触发时,硬件会自动将该位置1;响应中断后,硬件自动将该位置0。
IE1:外部中断1请求标志位。当外部中断1触发时,硬件会自动将该位置1;响应中断后,硬件自动将该位置0。
TR0:定时器0运行控制位。
TR1:定时器1运行控制位。
TF0:定时器0溢出标志位。定时器0溢出时,硬件会自动将该位置1;响应中断后,硬件自动将该位置0。
TF1:定时器1溢出标志位。定时器1溢出时,硬件会自动将该位置1;响应中断后,硬件自动将该位置0。
这里要关注的是IT0、IT1,要使用外部中断,就要设定该位选择触发方式。
该寄存器默认值是0,也就是说外部中断、全局中断都打开的情况下,外中断0、外中断1的默认触发方式是低电平触发,如果想使用下降沿触发方式就要设定IT0=1、IT1=1。