【四】数码管和中断(KST-51)

中断系统非常重要,学过STM32的我深刻体会到,在STM32没有中断的代码都不是完整的,在51单片机中同样重要

文章目录


一、数码管 

1、认识数码管

数码管其实就是8个LED小灯组合起来的,是由a,b,c,d,e,f,g,dp八段组合而成,八个LED小灯可以通过三八译码器来进行控制来显示数字和字符。它还多出两个com口这是数码管的公共段主要作用是来分流的,减小单条电路所受的电流(串联分压,并联分流),其原理图如下显示

 在KST-51上面有六个数码管,且是共阳数码管(共阳数码管就是8个LED小灯的阳极连在一起,共阴数码管就是阴极连在一起)

2、如何使用数码管 

我们要结合三八译码器来学习如何使用数码管

第一步就是学习开启数码管,根据上图可以看出,数码管的激活是靠它上方的三极管控制的,而这六个三极管分别游LEDS0~LEDS5控制,由图可见这些三极管全是PNP型三极管,只有基级为低电平时三极管才能导通,数码管才能被开启

 数码管显示字符A

#include<reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

void main()
{
	ENLED = 0;
	ADDR3 = 1;
	ADDR2 = 0;
	ADDR1 = 0;
	ADDR0 = 0;   //开启第一个数码管
	
	P0 = 0x88;   //显示字母A
	
	while(1);
}

 3、数码管真值表

我们先看真值表,不知道你是否疑惑这个表是怎么来的,来让我分析第一个0开始

 要想让数码管显示0,我们就要让abcdef亮,即开启abcdef这六个LED灯,这里就不得不提我们在第一课中学习的51单片机的245应用电路了,我们可以看到数码管的a,b,c,d,e,f,g,dp对应的口分别为DB0,DB1,DB2,DB3,DB4,DB5,​​​​​​​DB6,​​​​​​​DB7。这八个口来决定数码管LED小灯的熄灭情况,所以我们可以控制这八个IO口​来进行数码管控制,好巧不巧这八个口都归P0口管理当我们对P0输入0xC0时,对应的二进制就是11000000(对应DB是倒着来读的,前面是DB7,后面是DB0),自然除了g,dp口是高电平(1),其他都是低电平(0),自然1也是同理(0xF9)转换成二进制就是11111001,说明b,c是低电平在数码管上显示的就是1),其他都是一样​​

 

 数码管静态显示

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char code LedChar[]={
		0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};   //数码管真值表通过数组进行封装

void main()
{
   unsigned char cnt = 0;
	 unsigned char sec = 0;
	 
     ENLED = 0;
	 ADDR3 = 1;
	 ADDR2 = 0;
	 ADDR1 = 0;
	 ADDR0 = 0;   //开启第一个数码管
	 
	 TMOD = 0x01;   //定时器模式1
	 TH0 = 0xB8;
	 TL0 = 0x00;    //定时20ms
	 TR0 = 1;     开启定时器0
	 
	 while(1)
	 {
	    if(TF0 == 1)     //判断定时器是否溢出,溢出标志就是TF0  == 1
			{
			   TF0 = 0;    //清0
				 TH0 = 0xB8;
				 TL0 = 0x00;
				 cnt++;
				 if(cnt >= 50)   //定时1s
				 {
				   cnt = 0;
					 P0 = LedChar[sec];   //将真值表的值在P0刷新
					 sec++;
					 if(sec >=16)   //当秒数大于0x0F(15)时
					 {
					    sec = 0;   //归0
					 }
				 }
			}
	 }
}

4、数码管动态显示 

74HC138 只能在同一时刻导通一个三极管,而我们的数码管是靠了 6 个三极管来控制,那我们在怎么操作才能一次开启六个数码管呢?

其实多个数码管显示数字的时候,我们实际上是轮流点亮数码管(一个时刻内只有一个数码 管是亮的),利用人眼的视觉暂留现象(也叫余辉效应),就可以做到看起来是所有数码管都 同时亮了,这就是动态显示,也叫做动态扫描。

实际只要刷新率超过100HZ(即刷新时间小于 10ms)就没有闪烁了

数码管动态刷新

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char code LedChar[]={
    0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};   //数码管真值表

unsigned char LedBuff[6]={
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
};   //数码管显示缓冲区
		
void main()
{
    unsigned int cnt = 0;
    unsigned long sec = 0;
	unsigned char i = 0;
    ENLED = 0;
	ADDR3 = 1;
	TMOD = 0x01;   //定时器模式1
	TH0 = 0xFC;
	TL0 = 0x67;   //定时1ms
	TR0 = 1;
		
		while(1)
		{
		    if(TF0 ==1)
				{
				    TF0 = 0;
					TH0 = 0xFC;
					TL0 = 0x67;
					cnt++;
					if(cnt >=1000)   //定时1s
					   {
					    cnt = 0;
						sec++;
                       //一下代码实现十进制位从高到低提取转化为数码管字符
						LedBuff[0] = LedChar[sec%10];
						LedBuff[1] = LedChar[sec/10%10];
						LedBuff[2] = LedChar[sec/100%10];
						LedBuff[3] = LedChar[sec/1000%10];
						LedBuff[4] = LedChar[sec/10000%10];
						LedBuff[5] = LedChar[sec/100000%10];
 					    }
                       //以下代码实现数码管动态刷新
						if(i == 0)
						{
						    ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=LedBuff[0];
						}
						else if(i == 1)
						{
						    ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=LedBuff[1];
						}
						else if(i == 2)
						{
						    ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=LedBuff[2];
						}
						else if(i == 3)
						{
						    ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=LedBuff[3];
						}
						else if(i == 4)
						{
						    ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=LedBuff[4];
						}
						else if(i == 5)
						{
						    ADDR2=1;ADDR1=0;ADDR0=1;i=0;P0=LedBuff[5];
						}
				}
		}
}

让我分析一下这个难理解的几个点 

1.提取数字,根据定时器每1s后cnt清0且sec++,sec从0开始加,分析第一句LedBuff[0] = LedChar[sec%10];LedBuff[0]=sec对10取余,按照c语言逻辑,LedBuff[0]=sec对10取余还是等于LedChar[sec](sec<=10),动态刷新数码管真值表中的0~9

当sec>10后执行LedBuff[1] = LedChar[sec/10%10];sec/10%10等于其个位数,其他同理
                    TF0 = 0;
                        TH0 = 0xFC;
                        TL0 = 0x67;
                        cnt++;
                        if(cnt >=1000)
                        {
                              cnt = 0;
                                sec++;
                                LedBuff[0] = LedChar[sec%10];
                                LedBuff[1] = LedChar[sec/10%10];
                                LedBuff[2] = LedChar[sec/100%10];
                                LedBuff[3] = LedChar[sec/1000%10];
                                LedBuff[4] = LedChar[sec/10000%10];
                                LedBuff[5] = LedChar[sec/100000%10];
                         }

2.动态刷新i ==0时,if的内容是ADDR2=0;ADDR1=0;ADDR0=0这就是是三八编码器的控制此时开启的是LEDS0,之后i++,i==1,将上个代码的LedBuff[0]代入P0,LedBuff[0]中的数随1s加1

i==1,内容为ADDR2=0;ADDR1=1;ADDR0=0开启LEDS1(第二个数码管);i++;P0=LedBuff[2],后面依次循环,知道执行到i==5执行完  ADDR2=1;ADDR1=0;ADDR0=1;i=0;P0=LedBuff[5]后i=0回到开始,所以每一次都会把下面所有代码遍历,在代码证存在缓冲区保证没执行到时其他数码管,保持全是0xFF
                        if(i == 0)
                        {
                            ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=LedBuff[0];
                        }
                        else if(i == 1)
                        {
                            ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=LedBuff[1];
                        }
                        else if(i == 2)
                        {
                            ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=LedBuff[2];
                        }
                        else if(i == 3)
                        {
                            ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=LedBuff[3];
                        }
                        else if(i == 4)
                        {
                            ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=LedBuff[4];
                        }
                        else if(i == 5)
                        {
                            ADDR2=1;ADDR1=0;ADDR0=1;i=0;P0=LedBuff[5];
                        }
                }
        }

二、中断

在51单片机中,中断就CPU正在处理A程序,出现了B程序,请求CPU马上去处理(中断发生);CPU暂时停止当前的工作(中断响应),转去执行B程序;待CPU处理B程序完成后,再回到原来的A程序中(断点)继续执行,这样的行为我们称为中断。

在51单片机中,有5个基本的中断源,即外部中断0(INT0)、外部中断1(INT1)、定时/计数器0中断(T0)、定时/计数器1(T1)中断以及串口中断(UART),这5个是我们经常见到的5个中断。

标准 51 单片机中控制中断的寄存器有两个,一个是中断使能寄存器,另一个是中断优先级寄存器。

1、中断的寄存器

1.IE中断使能寄存器

 EA是中断的总开关

当写上EA = 1时,单片机就开启了中断

IE的位0~5的控制6个中断使能,根据查询序列的内容进行认识,不必记住,需要使用随时可查。

在这里使能ET0 (定时器0中断使能),即ET0  = 1,

中断的学习是很模糊的,还是搭配程序才能更好认识

 数码管显示程序(中断)

#include <reg52.h>

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;

unsigned char code LedChar[]={    //数码管显示字符的表
       0xC0, 0xF9, 0xA4, 0xB0, 0x99, 0x92, 0x82, 0xF8,
    0x80, 0x90, 0x88, 0x83, 0xC6, 0xA1, 0x86, 0x8E
};
unsigned char LedBuff[6]={    //数码管显示缓冲
    0xFF,0xFF,0xFF,0xFF,0xFF,0xFF
		};

unsigned char cnt  =0;
unsigned char i = 0;      //记录T0中断次数
unsigned char flag1s = 0;   //1s定时器标志位
void main()
{
    unsigned int cnt = 0;
		unsigned long sec = 0;
		unsigned char i = 0;
    ENLED = 0;
		ADDR3 = 1;
		TMOD = 0x01;   //开启定时器模式1
		TH0 = 0xFC;
		TL0 = 0x67;   //1ms定时
		TR0 = 1;
		
		while(1)
		{
		    if(flag1s ==1)
				{
						flag1s =0;
						sec++;
						LedBuff[0] = LedChar[sec%10];
						LedBuff[1] = LedChar[sec/10%10];
						LedBuff[2] = LedChar[sec/100%10];
						LedBuff[3] = LedChar[sec/1000%10];
						LedBuff[4] = LedChar[sec/10000%10];
						LedBuff[5] = LedChar[sec/100000%10];
				}
		}
}

void IniterruptTime0() interrupt 1   //定时器0中断服务函数
{
		TH0 = 0xFC;
		TL0 = ox67;
		cnt++;
		if(cnt>=1000)   //中断1000次即1s
		{
				cnt = 0;  //清0重新计数1s
				flag1s = 1;  //设置1s定时器标志位
		}
		
		P0 = 0xFF;
						switch(i)
						{
						case 0: ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=LedBuff[0];break;
						case 1: ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=LedBuff[1];break;
						case 2: ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=LedBuff[2];break;
						case 3: ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=LedBuff[3];break;
						case 4: ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=LedBuff[4];break;
					    case 5: ADDR2=1;ADDR1=0;ADDR0=1;i=0;P0=LedBuff[5];break;
						default:break; // 动态刷新数码管
						}
}

2.IP中断优先级寄存器

简单了解即可,目前没太多使用。

中断优先级包括抢占优先级和固有优先级

将IP的某一位置1其优先级就高于其他优先级 


总结

文章围绕 51 单片机数码管与中断展开讲解。在数码管部分,先介绍其由 8 个 LED 小灯组成,有共阳、共阴之分,结合三八译码器使用,阐述了开启数码管的方法、真值表原理,给出了显示字符 A、静态显示、动态显示的代码及原理分析,动态显示利用视觉暂留现象,通过轮流点亮数码管实现多管同时亮的效果。在中断部分,解释中断概念为 CPU 暂停当前程序处理其他程序后再返回继续执行,51 单片机有 5 个基本中断源,介绍了中断使能寄存器 IE 和中断优先级寄存器 IP,以数码管显示程序为例展示中断应用,通过定时器 0 中断服务函数实现定时刷新数码管显示 。

最后本文用于个人学习和帮助他人学习解惑,如有不对的地方欢迎给作者建议和学习交流,本文以《手把手教你学51单片机》作为课本教材,本文图片摘自其中,如有侵犯,私下联系,作者会及时更改,感谢。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值