【51单片机实验笔记】LED篇(三) 数码管的基本控制


前言

本节内容我们学习如何控制数码管,先尝试点亮一个数码管,并实现倒计时效果。

本节涉及到的封装源文件可在《模块功能封装汇总》中找到。

本节完整工程文件已上传GitHub仓库地址,欢迎下载交流!


硬件介绍

数码管的英文为Nixie Tube,又称辉光管LED数码管。其基本单元由LED组成,单个数码管的概念图如左图所示,一般可以分为七段数码管八段数码管两种。八段七段多一个小数点,应用更为广泛。

除此之外,单个数码管只能显示一个数字(字母),功能受限。所以常常将多个数码管封装起来,如右图所示,常用的为4位数码管

图1 八段数码管
图2 多位数码管

数码管发光颜色由管中充的低压气体决定,加上一些汞或氩,一般为橙色绿色


原理图分析

数码管的电路原理图如下:
在这里插入图片描述
LED的连接方式可以分为共阴极数码管和共阳极数码管。

  • 共阴极:将LED的阴极连在一起称为公共阴极COM
  • 共阳极:将LED的阳极连在一起称为公共阳极COM

共阴极需要单片机 IO高电平,对应的LED)才能点亮,而单片机的 IO 引脚电流输出能力不足,往往需要借助驱动芯片(如74HC245芯片)才可以点亮数码管。而共阳极只需要单片机 IO低电平,单片机的灌电流大于拉电流,故共阳极数码管应用更加广泛。

:由于每段都是由LED组成,故实际电路中应该串联限流电阻,一般接一个8P排阻


段选和位选

数码管中有段选位选两个概念,现阐释如下:

  • 段选:针对单个数码管而言。选择要点亮数码管a、b、c、d、e、f、g、dp 哪些段。一般通过给 IO 引脚赋值实现。
  • 位选:针对多位数码管而言。选择点亮哪个数码管。即控制COM端的高低电平。

仔细观察数码管段选顺序按 a、b、c、d、e、f、g、h 逆时针排列,依次对应字节的低位至高位。因此,我们可以给出共阴极数码管字形码编码表。(有些字母不易表示,缺省)

字形码dp g f e d c b a十六进制
00011 11110x3f
10000 01100x06
20101 10110x5b
30100 11110x4f
40110 01100x66
50110 11010x6d
60111 11010x7d
70000 01110x07
80111 11110x7f
90110 11110x6f
A0111 01110x77
b0111 11000x7c
c0101 10000x58
d0101 11100x5e
E0111 10010x79
F0111 00010x71
G--
H0111 01100x76
I0011 00000x30
J0000 11100x0e
K--
L0011 10000x38
M--
n0101 01000x54
o0101 11000x5c
p0111 00110x73
q0110 01110x67
r0101 00000x50
s0110 11010x6d
t--
U0011 11100x3e
v0001 11000x1c
w--
x--
y0110 11100x6e
z--

如果是共阳极,其编码表刚好是共阴极按位取反(~)

其实可以看出,数码管显示字母不友好,一般用于显示数字,在电梯楼层显示计算器显示中应用广泛。

从上述一系列分析中我们得到,数码管相当于LED堆叠,它对 IO 口资源的消耗是巨大的。如果要同时显示多个数字,除了采用芯片(如38译码器)来节约 IO 口,还可以采用不同的显示方式实现。数码管两种驱动显示方式静态显示动态显示

  • 静态显示:即每个数码管每一个段码都由一个单片机的I/O端口进行驱动。优点编程简单显示亮度高缺点占用I/O端口过多,这显然是致命的。
  • 动态显示:利用人眼暂留效应分时轮流控制 COM端位选),每个数码管点亮时间为1ms~2ms,因为频率很快,仿佛所有数码管都是同时点亮的,这即是动态的含义。优点节省大量IO口功耗低缺点亮度不及静态显示方式,但可以通过降低限流电阻的阻值来提高亮度。

驱动芯片

我们需要清楚一点,单片机适合用于控制,它可以输入输出电平,但电流是很小的。或许单片机驱动单独一个LED是足够的,但当LED数量多起来时,它便无能为力了,更别提驱动大功率灯泡或是电机了。

这些功率比较大的外设往往需要外接电源,通过驱动芯片来提供电流能量,单片机提供信号指令


74HC138芯片

2个4位共阴极数码管74HC138芯片38译码器)原理图如下:

2个4位共阴极数码管
38译码器

将各数码管相同的段选连在一起,由 P0 统一控制,这样每个数码管显示的字符都是一样的。如何使不同数码管显示不同的字符?只需要给出位选信号指定不同的数码管点亮即可。

虽然位选端共有8个引脚,但实际上我们只需要每次点亮一个数码管,即只有8种情况,那么完全可以用3个引脚来控制这8种输出,这就是38译码器实现机理

观察38译码器原理图。其中, G 1 G1 G1 G 2 ‾ \overline{G2} G2 G 3 ‾ \overline{G3} G3 为使能端,其中G1高电平有效,G2、G3低电平有效(即上横线的含义)。38译码器真值表

A0A1A2Y0Y1Y2Y3Y4Y5Y6Y7
00001111111
00110111111
01011011111
01111101111
10011110111
10111111011
11011111101
11111111110

因为是共阴极数码管,所以Y端口低电平时该数码管被点亮。


74HC245芯片

在这里插入图片描述
主要用于提升单片机 IO 口驱动电流。一般 IO 口输出电流20mA,这个电流大小仅仅点亮一颗LED是没有问题的,但对于驱动数码管点阵多负载模块就力不从心了。

74HC245芯片可以将输出电流提升至70-80mA左右,具有8路输入8路输出,可输出低电平、高电平、高阻态三态。其中DIR引脚用于控制输入输出方向,高电平(A => B)、低电平(B => A)。 O E ‾ \overline{OE} OE使能引脚低电平输出有效。


软件实现

点亮一只数码管

#include "REGX52.H"

#define SMG_PORT P0

//重定义数据类型
typedef unsigned char u8;
typedef unsigned int u16;

//共阴极数码管字形码编码
u8 code smgduan[] = {0x3f,0x06,0x5b,0x4f,0x66, //0 1 2 3 4
					 0x6d,0x7d,0x07,0x7f,0x6f, //5 6 7 8 9
					 0x77,0x7c,0x58,0x5e,0x79, //A b c d E
					 0x71,0x76,0x30,0x0e,0x38, //F H I J L
					 0x54,0x5c,0x73,0x67,0x50, //n o p q r
					 0x6d,0x3e,0x1c,0x6e};     //s U v y  

void main()
{
	//P0口控制数码管显示字符
	SMG_PORT = smgduan[14]; //E
	while(1);
}

定义共阴极数码管字形码编码,注意这里的定义中使用了code关键字,这是C51拓展存储器类型。在标准C中,变量的定义格式

[存储类别] 数据类型 变量名 = 初值;

存储类别含义特点
auto自动变量默认类型。(生存期)属于动态局部变量,调用时临时分配内存,函数调用结束即释放。(初值分配)在调用时赋初值,未赋初值则初值不确定。(作用域)仅在函数体内可调用。
static静态变量生存期) 属于静态局部(全局)变量,调用结束后保留当前值。(初值分配)只在编译时赋初值,默认赋0'\0'。 (作用域静态局部变量仅在函数体内可调用,静态全局变量本文件中可调用。
extern外部变量外部声明数据类型可省略扩展变量作用域,实现跨文件调用。
register寄存器变量将变量存储在CPU的寄存器中,减小内存开销

但在C51中,变量的完整定义格式

[存储类别] 数据类型 [存储器类型] 变量名 = 初值;

存储器类型特点
code变量放在ROM(程序存储器,64KB),不可更改
data变量放在可直接寻址片内RAM(数据存储器,低128B),访问速度快
xdata变量放在间接寻址片外RAM(数据存储器,全64KB)
bdata变量放在可位寻址片内RAM(数据存储器,20H~2FH,16B)
idata变量放在间接寻址片内RAM(数据存储器,全256B)
pdata变量放在间接寻址片外RAM(数据存储器,低128B)

单片机的ROM一般比RAM大很多(STC89C52单片机ROM8KBRAM256个字节),所以一些硬编码数据(比如字形库数据)可以放在ROM区,以节省片内RAM资源


倒计时效果

代码如下:

#include <REGX52.H>
#define SMG_PORT P0

typedef unsigned char u8;
typedef unsigned int u16;


void delay(u16 t){
	while(t--);
}


void main(){
	//定义共阴数码管字形码编码
	u8 smg_array[] = {0x3f,0x06,0x5b,0x4f,0x66, //0 1 2 3 4
					 0x6d,0x7d,0x07,0x7f,0x6f}; //5 6 7 8 9 

	while(1){
		int i;
		for(i=0;i<10;i++){
			SMG_PORT = smg_array[9-i];
			delay(50000);
		}
		delay(60000);
	}
}

效果图如下:
在这里插入图片描述


动态显示字符

下面,我们通过动态驱动显示的原理来显示字符I LOVE YOU

#include <REGX52.H>
#define SMG_SELECT_PORT P2 //位选端口
#define SMG_PORT P0

typedef unsigned char u8;
typedef unsigned int u16;

//共阴数码管码表(I LOVE YOU)
u8 code smg_array[] = {0x30,0x38,0x3f,0x3e,0x79,0x6e,0x3f,0x3e};

sbit A0 = SMG_SELECT_PORT^2;
sbit A1 = SMG_SELECT_PORT^3;
sbit A2 = SMG_SELECT_PORT^4;		


void delay(u16 t){
	while(t--);
}			
		 
//位选码,利用十进制取余
void Dec2Bin(u8 i){
	A0 = i % 2;
	i /= 2;
	A1 = i % 2;
	i /= 2;
	A2 = i % 2;
}


void main(){
	u8 i;
	while(1){
		for(i=0;i<8;i++){
			Dec2Bin(i); //给38译码器赋值
			SMG_PORT = smg_array[7-i];
			delay(100); //1ms,实验测试5ms以上能察觉出闪烁
			SMG_PORT  = 0x00; //消除重影
		}
	}
}

硬件电路中,位选信号P2.2、P2.3、P2.4控制,借助38译码器,控制8位COM端

在程序中,通过取余运算得到位选信号的取值,并依次赋值给各端口。当然,也可以通过switch语句,分别讨论8种取值情况。

比较重要的是,数码管的动态显示存在重影的问题。重影产生的本质是当位选信号发生改变时,上个数码管段选信号这一瞬间还未发生改变,但因为这个时间极短,因此只会留下淡淡的残影。如何消影呢,只要在下个数码管被点亮前,将段选信号清除即可(熄灭)。

最终效果图如下:
在这里插入图片描述


总结

基于延时实现的数码管动态刷新两个重要的时间

  1. 每个位选停留的时间t1
  2. 两次整体动态刷新之间的间隔t2

我们现在总结一下两个时间长短数码管显示的影响。

  • t1比较时,数码管逐位点亮的频率变慢人眼会明显察觉出闪烁。由于每个位停留时间比较,所以数码管比较
  • t1比较时,数码管逐位点亮的频率变快人眼无法察觉出闪烁。由于每个位停留时间比较,所以数码管比较
  • t2比较时,数码管整体刷新点亮的频率变慢人眼会明显察觉出整体闪烁
  • t2比较时,数码管整体刷新点亮的频率变快人眼无法察觉出整体闪烁

t1可以在程序中手动调节合适的值。而t2则由程序其他代码量决定,如果其他程序耗时太长,导致t2变大数码管将发生严重闪烁

当然,t2弱点将在中断篇彻底消除,那时我们将用最佳方式刷新数码管

数码管本质就是发光二极管的封装,所以有了LED基础之后,本节内容并不难理解。继续加油吧!

  • 9
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
51单片机中开关控制LED数码管静态显示的基本原理是:通过设置开关的状态,控制51单片机上的GPIO口的电平状态,从而控制LED数码管的亮灭。 首先,我们需要连接开关和LED数码管51单片机。将开关的一个引脚连接到GND,另一个引脚连接到51单片机上的一个GPIO口(例如P1.0),以输入方式连接。然后,将LED数码管的各个段选引脚分别连接到51单片机上的不同GPIO口,以输出方式连接。通过这样的连接方式,我们可以通过控制51单片机的GPIO口的电平状态来控制LED数码管的亮灭。 接下来,我们需要在51单片机的程序中进行相应的设置。首先,我们需要配置P1为输入口,可以设置P1的相应寄存器(比如P1CON)来将其设置为输入模式。然后,我们可以使用51单片机的输入相关的函数(如P1的输入函数)读取开关的状态,即判断开关是否闭合或打开。 在主程序中,我们可以使用if语句来判断开关的状态。当开关闭合时,我们设置相应的GPIO口输出低电平,以控制LED数码管的亮灭;当开关打开时,我们设置相应的GPIO口输出高电平,以控制LED数码管的熄灭。具体的代码可以如下: ```c #include <reg51.h> #define GPIO_LED_P1 P1 // LED数码管连接到P1口 sbit SW = P1^0; // 开关连接到P1.0引脚 void main() { GPIO_LED_P1 = 0xFF; // 给所有段选引脚置高电平,熄灭数码管 while(1) { if(SW == 0) { // 开关闭合 GPIO_LED_P1 = 0x00; // 给所有段选引脚置低电平,亮起数码管 } else { // 开关打开 GPIO_LED_P1 = 0xFF; // 给所有段选引脚置高电平,熄灭数码管 } } } ``` 以上就是51单片机中开关控制LED数码管静态显示的基本原理和一个简单的代码示例。通过控制开关的状态,可以实现LED数码管的亮灭,从而达到静态显示的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

悬铃木下的青春

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值