基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)

用四位数码管显示外部中断的计数

  • 设计要求
  • 程序设计
  • 硬件设计
  • 知识补充
    • P3端口
    • 中断
    • IE
    • TCON

设计要求

  分别用两个开关使用中断操作实现计数和清零。目的就是搞清楚中断是如何工作的。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是中断号,编译器就是靠这个中断号来识别该中断函数是什么中断的(有关中断号更详细的解释我们稍后介绍,这里先说完中断函数的定义)。这还不是中断函数的全部,其实后面还可以跟工作寄存器组的内容,由于编译器会自动分配工作寄存器组,因而通常不写工作组的内容。一个完整的中断函数格式如下:
基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)_第1张图片
  通常不写using的内容。
  最后介绍一下中断号的内容,我们看一看表6-3中51单片机的中断和中断号的对应关系。
基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)_第2张图片
  上面给出了几种中断的中断号,我们的代码也是根据这个中断号来写的中断优先级的问题,根据默认的优先级int0的优先级最高,其实它们的优先级是可以根据需要定义的。

硬件设计

基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)_第3张图片

知识补充

P3端口

P3口是一个带内部上拉电阻的8位双向I/O口。P3口的输出缓冲器可以驱动4个TTL门电路。对P3口写“1”,通过内部的上拉电阻把端口拉为高电平,此时P3口可以作为输入口使用。作输入口使用时,P3口被外部拉低的引脚会因为内部上拉电阻的存在而输出电流(IIL)。

AT89C51的P3口也提供一些特殊功能,如下所示:

基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)_第4张图片
与P1、P2口比较会发现,P3口多了第二功能。
如中断。

中断

首先了解两个寄存器,IE和TCON

IE

IE寄存器的全称是Interrupt Enable Register,译为中文就是中断允许寄存器。打开reg51.h可以找到该寄存器。
基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)_第5张图片
对于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),否则不能进入任何中断。

TCON

该寄存器的全称是Timer/CounterControl Register,译为中文就是定时/计数器控制寄存器。reg51.h中找到其定义:
基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)_第6张图片
首地址为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。
基于Proteus与keil联合仿真的51单片机学习记录(四)(用四位数码管显示外部中断的计数)_第7张图片

你可能感兴趣的:(单片机,控制,51单片机)