嵌入式51单片机03-数码管系列

数码管

一、数码管基础知识

  • 数码管的工作原理:数码管内部其实就是LED灯拼接而成的,只需要在一端给高电平,而另一端给低电平就可以让数码管显示。它们分别称为数码管的位选端段选端

  • 静态显示:只需要通过位选确定显示哪一位,再通过段选控制显示的数字即可。

  • 动态显示:动态显示的特点就是将所有数码管的段选线并联在一起,由位选线控制是哪一位数码管有效。选亮数码管采用动态扫描的方式。所谓动态扫描,就是轮流向各位数码管送出字形码和相应的位选,利用人眼视觉暂留效应,使人的感觉就是各位数码管同时都在显示。动态显示的亮度比静态显示要差一些,所以在选择限流电阻时应略小于静态显示电路中的。

  • 原理图
    在这里插入图片描述

    段选:数码管上方的LED1~LED8,静态显示时只需要给赋低电平即可,动态显示时使用动态扫描的方式实现。段选通过74HC138译码器实现。

    位选:数码管下方的abcdefgdp,分别对应LCD0~LCD7,使用74HC245驱动。

  • 74HC245:双向数据缓冲器,由于单片机或CPU的数据、地址、控制总线端口都有一定的负载能力,如果负载超过负载能力,就达不到要显示的效果,因此需要驱动芯片。74HC245就是可以提高驱动能力的芯片,作用就是只需要提供一个信号,通过芯片内部的电源把驱动信号拉高,让其变为高电平,驱动数码管显示。

  • 74HC138:起到译码的功能,就是用少的引脚控制多的引脚,来满足单片机引脚不足的一种方式,138是用三位输入控制8位输出。

二、数码管系列代码

1. 数码管操作(单个数码管静态显示)

(1)仿真电路图

在这里插入图片描述

(2)源代码
#include "reg52.h"			


sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

//段选的数字,从0~f
unsigned char smgduan[17]={
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					 0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

void main()
{
    
    	
    //74HC138控制端,全为0时选择最低位数码管显示
	LSA=0;
	LSB=0;
	LSC=0;	
	
	while(1)
	{
    
    
		P0=smgduan[0];
	}
}
(3)实验结果

在这里插入图片描述

2. 数码管操作(多个数码管静态显示)

(1)仿真电路图

在这里插入图片描述

(2)源代码
#include "reg52.h"			


//数码管段选端位定义
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

//显示0~f
unsigned char smgduan[17]={
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					       0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

						   
//延时函数
void delay(unsigned int i)  
{
    
    
	while(i--);	
}

//数码管显示函数
void DigDisplay()  
{
    
    
	unsigned int i;
	
	for(i = 0;i < 8;i++)
	{
    
    
		switch(i)	 
		{
    
    
			case(0):
				LSA = 0; LSB = 0; LSC = 0; P0 = smgduan[9]; break;
			case(1):
				LSA = 1; LSB = 0; LSC = 0; P0 = smgduan[1]; break;
			case(2):
				LSA = 0; LSB = 1; LSC = 0; P0 = smgduan[4]; break;
			case(3):
				LSA = 1; LSB = 1; LSC = 0; P0 = smgduan[0]; break;
			case(4):
				LSA = 0; LSB = 0; LSC = 1; P0 = smgduan[3]; break;
			case(5):
				LSA = 1; LSB = 0; LSC = 1; P0 = smgduan[2]; break;
			case(6):
				LSA = 0; LSB = 1; LSC = 1; P0 = smgduan[0]; break;
			case(7):
				LSA = 1; LSB = 1; LSC = 1; P0 = smgduan[2]; break;
		}	
		delay(100); 
		P0 = 0x00;
	}
}

//主函数
void main()  
{
    
    	
	while(1)
	{
    
    	
		DigDisplay();  
	}		
}
(3)实验结果

在这里插入图片描述

3. 数码管操作(单只静态数码管循环显示0-9,无开关控制)

(1)仿真电路图

在这里插入图片描述

(2)源代码
//单只静态数码管循环显示0-9
#include "AT89X51.h"


int i,j,k;
int a[17] = {
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
	       0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};


void delay(int n)
{
    
    
	for (j = n;j > 0;j--)
	for (k = 110;k > 0;k--);
}

void main()
{
    
    
	P2_2 = 1;
	P2_3 = 1;
	P2_4 = 1;
    P0 = 0x00;
    
	while (1)
	{
    
    
		for (i = 0;i < 16;i++)
		{
    
    
			P0 = a[i];
			delay(250);
		}
	}		
}
(3)实验结果

4. 数码管操作(单只静态数码管循环显示0-9,k1复位,k2暂停与开始)

(1)仿真电路图

在这里插入图片描述

(2)源代码
#include "reg52.h"	
#include "intrins.h"


//数码管段选端位定义
sbit LSA=P2^2;
sbit LSB=P2^3;
sbit LSC=P2^4;

//按键位定义
sbit k1 = P3^0;
sbit k2 = P3^1;

//显示0~f
unsigned char smgduan[17]={
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,
					       0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};
unsigned char control;						   

						   
//延时函数
void Delay1ms(unsigned int xms)		
{
    
    
	unsigned char i, j;
	
	while(xms--)
	{
    
    
		_nop_();
		i = 2;
		j = 199;
		do
		{
    
    
			while (--j);
		} while (--i);
	}
}

//按键操作函数
void keyboard(void)
{
    
    
	int i;
	
	if(k1 == 0)
	{
    
    
		Delay1ms(20);
		while(k1 == 0);
		Delay1ms(20);
		
		while (1)
		{
    
    
			for (i = 0;i < 10;i++)
			{
    
    
				P0 = smgduan[i];
				Delay1ms(350);
				
				if (k1 == 0)
				{
    
    
					Delay1ms(20);
					while(k1 == 0);
					Delay1ms(20);
					//跳出当前for循环,就会从0开始
					break;
				}
				
				//k2按键按下的第一次进入
				if (k2 == 0)
				{
    
    
					Delay1ms(20);
					while(k2 == 0);
					Delay1ms(20);
					
					//k2按键按下的第二次退出
					do
					{
    
    
						P0 = smgduan[i];
						Delay1ms(350);
					}
					while(k2 != 0);
				}
			}
		}
		P0 = 0x00;
	}
}

//主函数
void main()  
{
    
    
	//控制数码管段选
	LSA = 1;
	LSB = 1;
	LSC = 1;
	//数码管初始化
	P0 = 0x00;
	
	while(1)
	{
    
    	
		keyboard();
	}		
}
(3)实验结果

5. 数码管操作(动态数码管循环移位显示0-9)

(1)仿真电路图

在这里插入图片描述

(2)源代码
#include "AT89X51.h"


int a[17]={
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};


//延时函数
void delay(int n)   
{
    
    
	int i,j;
	for (i=n;i>0;i--)
	for (j=110;j>0;j--);	   
}

//数码管显示函数	
void DigDisplay()	
{
    
    
	int i,t;
	for(i=0;i<8;i++)
	{
    
    
		//位选,选择点亮的数码管
		switch(i)	 
		{
    
    
			case 0:
				P2_2=0;P2_3=0;P2_4=0; break;//显示第0位
			case 1:
				P2_2=1;P2_3=0;P2_4=0; break;//显示第1位
			case 2:
				P2_2=0;P2_3=1;P2_4=0; break;//显示第2位
			case 3:
				P2_2=1;P2_3=1;P2_4=0; break;//显示第3位
			case 4:
				P2_2=0;P2_3=0;P2_4=1; break;//显示第4位
			case 5:
				P2_2=1;P2_3=0;P2_4=1; break;//显示第5位
			case 6:
				P2_2=0;P2_3=1;P2_4=1; break;//显示第6位
			case 7:
				P2_2=1;P2_3=1;P2_4=1; break;//显示第7位	
		}
		//段选
		for (t=0;t<10;t++)
		{
    
    
			P0=a[t];
			delay(150);
		}
		//间隔一段时间扫描	
		delay(50); 
		//消隐
	}
}

void main()
{
    
    	
	while(1)
	{
    
    	
		DigDisplay();  	
	}		
}
(3)实验结果

6. 数码管操作(独立按键控制数码管增加与减少)

(1)仿真电路图

在这里插入图片描述

(2)源代码
#include<reg51.h>
#include "intrins.h"

sbit key1=P3^1;
sbit key2=P3^0;
sbit ad=P2^2;
sbit bd=P2^3;
sbit cd=P2^4;

unsigned int xianshi[]={
    
    0x00,0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71};

void delay(int n)
{
    
    
	unsigned int i,j;
	for (i=n;i>0;i--)
	for (j=110;j>0;j--);
}

void Delay1ms(unsigned int xms)		
{
    
    
	unsigned char i, j;
	
	while(xms--)
	{
    
    
		_nop_();
		i = 2;
		j = 199;
		do
		{
    
    
			while (--j);
		} while (--i);
	}
}

void main()
{
    
    
	unsigned int count=0;
	P0 = 0x00;
	
	while(1)
	{
    
    
		ad=1;bd=1;cd=1;
		
		if (key1 == 0)
		{
    
    
			Delay1ms(20);
			while(key1 == 0);
			Delay1ms(20);
			
			count++;
			if(count==17)
				count=0;
			P0=xianshi[count];
			delay(250);	
		}
		
		if (key2 == 0)
		{
    
    
			Delay1ms(20);
			while(key2 == 0);
			Delay1ms(20);
			
			if (count==0)
				count=15;
			else 
				count--;
			P0=xianshi[count];
			delay(250);	
		}	
	}			
}
(3)实验结果

7. 数码管操作(数码管流水显示"20235218")

(1)仿真电路图

在这里插入图片描述

(2)源代码
#include "AT89X51.h"
#include "intrins.h"


void main()
{
    
    
	//0~9
	int a[10] = {
    
    0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
	//显示的内容
	int b[8] = {
    
    2,0,2,3,5,2,1,8};
	//w: 窗口显示数据的位置,t: 每轮显示的时间长度
	int i, j, w = 0, t = 0;	
	
	while(1)
	{
    
    	
		//位选要有八段,指定一个八位的窗口
		for (i = 0; i < 8; i++)
		{
    
    
			if (i + w < 8) 			
				P0 = 0;				
			else if (i + w > 15) 	
				P0 = 0;
			else
			{
    
    
				//位选
				P0 = a[ b[i + w - 8] ];
				
				//段选
				P2 = (7-i)*4;	
				//延时
				for (j = 0; j < 800; j++);  								
			}
			//清零
			P0 = 0;
		}
		
		//控制显示速度与流水
		if (t++ == 20)		
		{
    
    
			if (w++ == 15) w = 0;
			t = 0;
		}
	}
}
(3)实验结果

(4)结果分析

在这里插入图片描述

如上图所示,我们需要把中间的窗口当做显示窗口,然后两边的窗口作为辅助窗口,当程序运行到最左边的窗口时,我们把位选端置零,不选择任何的位选。当程序运行到中间窗口时,因为中间窗口作为我们的显示窗口,所以要对段选端和位选端同时操作,改变段选的同时要改变位选,程序中巧妙用到嵌套数组的方式实现段选,同时位选端与段选循环同步,达到同步效果。每次操作之后需要延时一段时间,并且对位选端清零。为了更好的控制速度,程序中我们引入变量t来控制,滑动窗口使用变量w来控制。

Guess you like

Origin blog.csdn.net/Lshuangye/article/details/130255311