重生之我是八位数码管糕手
雪底犹存三尺绿,人间自有不凋春
- 前情提要
- 引入
- 一、基础知识
- 二、位选
- 三、段选
- 段落小结
- 实验设计
- 1. 理想实验
- 2.二转十六小技巧
- 3.问题以及辅助芯片
- 问题
- 74LS138/74HC138
- 74HC245
- ~~74HC595~~
- 4. 静态显示
- 5.动态显示
- 参考资料以及推荐学习
- 总结
前情提要
接上回,咱们深入了解了GPIO管脚的使用,并且根据其输出功能设计实现了一系列的实验,但是宁肯定会嫌弃说:“主播主播你的显示器件led和蜂鸣器太简单了,有没有更吃操作的显示器件?”有的,有的兄弟,咱们今天介绍------八位晶体数码管。
引入
要想使用数码管,比起led和蜂鸣器,咱们还得知道一些其相关的知识:
一、基础知识
- 首先,数码管是由多个led封装在一起的一种显示器件,常用于简单的数字/时间的显示,优点是成本低廉、应用场景广泛(比如家中的微波炉或者电饭煲按键后的红色字体显示其实就是数码管的应用);缺点嘛,就是显示精度不够,在一些工业级别的显示操作就不会选择这种”低端的low货“哩。
二、位选
- 其次,也是比较重要的一点,数码管分为共阴数码管和共阳数码管,简单的说明它们的结构及其不同:假设是八位共阴数码管,那么就有八个可单独静态显示的数码管,而其八个单独的数码管的非连接单片机管脚的另一端com(也就是端口)分别经过─►|─连接在同一个GND(地端)上;而共阳数码管则是这八个com经过─|◄─连接在同一个VCC(阳极)上;这是咱用markdown画的草图:
八位共阴数码管:
VCC
│
段选引脚(a/b/c/d/e/f/g/dp)──LED阳极(这里及前面可先忽略)
│
▼
│
COM0- COM1- COM2- COM3- COM4- COM5- COM6- COM7- (8个独立阴极)
││ ││ ││ ││ ││ ││ ││ ││ (类似于等号,仅有位选信号为0时被位选中)
SEG_0 SEG_1 SEG_2 SEG_3 SEG_4 SEG_5 SEG_6 SEG_7 (位选信号,由GPIO控制)
八位共阳数码管:
GND
│
段选引脚(a/b/c/d/e/f/g/dp) ──LED阴极(这里及前面可先忽略)
│
▼
│
COM0+ COM1+ COM2+ COM3+ COM4+ COM5+ COM6+ COM7+ (8个独立阳极)
││ ││ ││ ││ ││ ││ ││ ││ (类似于等号,仅有位选信号为1时被选中)
SEG_0 SEG_1 SEG_2 SEG_3 SEG_4 SEG_5 SEG_6 SEG_7 (位选信号,由GPIO控制)
通过结构图,咱们可以直观认识到共阴和共阳的位选区别就是想要显示的数码管对应的管脚输入0还是1让其显示,这就是数码管的位选(哪一位数码管亮)。(共阴:SEG_x拉到GND,即管脚输出0选位中;共阳:SEG_x拉到VCC,即管脚输出1位选中)
三、段选
- 说完了位选这个概念,咱们就可以引入段选(哪个段亮)这个概念:宁看着一个数码管,咱们之前也提到过它是由多个led组成的,所以一个数码管一般被分成八个段(每段就是一个笔画),结构图抽象如下 :
a
──
f │ │ b
── g
e │ │ c
── ○ dp
d
怎么记住呢?其实就是从最上面的一横开始顺时针a、b……f,中间那一横是g,小数点是dp
假如咱们想显示一个H,那么就要让b,c,e,f,g段被选中;而如何段选呢?先看结构图:
共阴数码管:
VCC
│
段选引脚(a/b/c/d/e/f/g/dp)
││ (段选信号有效则被段选中)
SEG_A SEG_B ... SEG_DP (段选信号,高电平有效)
│
│
LED阳极
│
位选(位选信号,低电平有效)
共阳数码管:
GND
│
段选引脚(a/b/c/d/e/f/g/dp)
││ (段选信号有效则被段选中)
SEG_A SEG_B ... SEG_DP (段选信号,低电平有效)
│
│
LED阳极
│
位选(位选信号,高电平有效)
由此咱们同样可以看出共阴和共阳的段选区别就是对应管脚输出1还是0让其显示。(共阴:SEG_y拉到VCC,段被选中;共阳:SEG_y拉到GND,段被选中)
段落小结
数码管是多led封装的显示设备,想要点亮想要的数字或字母要进行位选和段选,前者控制第几个数码管亮,后者控制数码管的哪些笔画亮;数码管分成共阳和共阴,共阴的位选是阴(0)为亮、段选是阳(1)为亮
,共阳则相反,位选是阳(1)为亮,段选是阴(0)为亮
实验设计
1. 理想实验
了解完数码管的显示原理之后,咱们终于可以开始数码管显示的实验了,吗?答案是否定的,但是咱们可以模拟一下理想情况中的实验,假设咱们一点都不用吝惜单片机的接口资源且单片机的GPIO引脚驱动能力十分的强大(这也就是实际咱们会遇到的问题,接口资源有限且驱动能力对于数码管的段选来说还是捉襟见肘),咱们假定咱们的八个位选SEG
(哦,这里提一嘴,不用在意SEG是什么,约定俗成的一种表示罢了) 信号是由P2的八个管脚提供(即是位选由P2决定),八个段选SEG信号由P0的八个管脚提供(即是段选由P0决定)
,那咱们着手来写一段理想情况的数码管静态显示(显示单个数码管的意思,此概念后面会提及)的代码
首先咱们确定一下,就八位共阴数码管的T0显示一个字母H吧,那么咱们思考一下应该怎么位选和段选:先是位选,就只有0数码管被选中,共阴是0位选为亮,所以对应的八位二进制数为:1111 1110(通常标准下的数码管遵循高位在前的设计),那么对应的代码片为:P2=0xFE;
(标准十六进制下表示的1111 1110);接下来是段选,依旧是高位在前的封装设计,对应的位置是:dp g f e d c b a
,再一次搬出这个结构图
a
──
f │ │ b
── g
e │ │ c
── ○ dp
d
咱们需要显示出H,那么需要点亮的段就是b、c、e、f、g且共阴数码管的段选是1点亮,那么对应的八位二进制数是:0111 0110,于是有对应的代码片P0=0x76;
至此,咱们如同爱因斯坦模拟光速变短般的思维理想实验结束了,获得的理想代码是这样的:
!!!别烧录,此代码跑不通
#include<regx52.h>
int main()
{
P2=0xFE;//位选第0位
P0=0x76;//段选显示H
while(1);
}
2.二转十六小技巧
假设咱们开发板上的是常见的八位数码管,在总线操作法
中,我们总需要把八位二进制数转成十六进制数的标准表示,其实呢,采用分割法
(自己取的名字)是比较快捷的。
所谓分割,就是把八位二进制数先分成两个四位二进制数,再把四位二进制数分别转成十六进制,就十分简单哩。
看起来这个方法还是很麻烦?看个例子先:
对于 1111 1110,分成1111和1110,1111根据位权展开就是8+4+2+1=15,1110根据位权展开是8+4+2=14;而15转成十六进制则是F,14就是E;所以1111 1110转成十六进制为FE,即0xFE
再来一个例子防止偶然性:
0001 0110:先分成0001和0110,位权展开分别是1和4+2=6,于是有十六进制16,即0x16
如果宁是刚入门嵌入式,以前没有接触过二进制,不会位权展开,这里有四位二进制转十六进制映射表:
二进制 | 十六进制 | 二进制 | 十六进制 |
---|---|---|---|
0000 | 0 | 1000 | 8 |
0001 | 1 | 1001 | 9 |
0010 | 2 | 1010 | A |
0011 | 3 | 1011 | B |
0100 | 4 | 1100 | C |
0101 | 5 | 1101 | D |
0110 | 6 | 1110 | E |
0111 | 7 | 1111 | F |
这个方法无需中间十进制转换,适合心算和快速运算。
3.问题以及辅助芯片
问题
咱们之前在理想情况的时候已经提及,咱们有两个亟待解决的问题,分别是:
1.单片机的接口资源十分有限,因为一个数码管显示器件就占用16个管脚,资源利用率怎么看怎么低
2.单片机的管脚驱动驱动单个LED或者有源蜂鸣器能力还行,对于内部结构是多线路连接的多LED组成的数码管,其输出的电流与段选需要的电流是小巫见大巫
且正好这两个问题的解决一个属于位选板块,一个属于段选板块;而解决方法就是引入辅助芯片
74LS138/74HC138
这是两种不同型号但是功能一样的138译码器,宁是不是以为咱要开始长篇大论了?咱不想给我的观众填鸭诸如模电啊原理图分析啊的知识,咱们现在只需要点亮数码管就可以了,所以原理我不讲。
直白的说,138译码器就是用单片机三个管脚控制输出八个位选信号
宁会问,哪三个?在宁的开发板对应的使用的芯片的数据手册中找到类似下图的表格(在wps同时按ctrl+f搜索“表”,可以找的更快)
ENABLE不用管,SELECT的三个引脚代表这三个引脚怎么定义才能使得八个Y引脚输出,且前三行XXX的根本也不用看,就以第四行来进行简单说明:CBA对应的输入由表可知为LLL,也就是000,也就是CBA对应的三个单片机管脚输出000,则这个芯片给的连接晶体管的八个引脚输出位选信号为HHHHHHHL(图中是低位在前,我把其改成单片机设计中默认的高位在前表示),也就是1111 1110,对应的八位共阴数码管就是位选第0位,以此类推
宁肯定还有问题:那这三个引脚在哪呢?
这是SN74HC138的简单引脚图,(3 线路至 8 线路解码器/多路信号分离器),咱们需要找ABC这三个引脚,这也算是比较通用的,Y引脚就是输出引脚,但是咱们不深究原理图就先不讲
现在咱们要找到如上图的图, 步骤:
1. 找到宁开发板的原理图(一般买的时候商家会提供,宁如果没有或找不到可以先去问商家要,商家没法提供的话,如果宁的开发板比较热门,可以去社区搜索,大概率能找到原理图PDF)
2. 使用WPS打开后同时按下ctrl+F快捷键打开搜索框,输入“SEG”,并回车
3. 找到如上的原理图部分电路
咱这里的CBA(顺序对应表的顺序)话就是P2_2,P2_3,P2_4,宁也快去找找宁的吧
74HC245
这个芯片没什么好说的,在不讨论其模电实现的话,就基本没东西可聊了,就是放大驱动能力,让单片机能有足够点亮数码管段选的能力
咱们如刚刚译码器板块一样找一找咱们这个芯片(八对八)的八个输入引脚对应单片机的哪些管脚吧:
WPS打开原理图,ctrl+F搜索“SEG”,找到类似如下的部分电路图:
发现段选对应引脚为P0的八个引脚0-7对应A-DP八个段
,提示使用P0的总线操作法比位操作法(使用位操作法可能导致“鬼影”问题)方便,总线操作法的P0写入的十六进制数得是满足高位在前的八位二进制数转换而来
小tips:宁可以搜一下原理图中SEG_EN#对应的地方,可能会是一个拨码开关
74HC595
假如宁这个芯片的话,宁看过博客后可以去看看宁买的板子的视频资料,咱要下一篇才讲这个芯片的使用,且其需要用到其他的特殊功能引脚
4. 静态显示
什么是数码管的静态显示?就是只显示一个单独的晶体管,这个概念是相对于动态显示的显示多个数码管而来的
以下是一段静态显示的实例代码(相对于咱的开发板,宁的需要根据宁开发板对应的位选和段选以及共阴还是共阳有所调整):
#include <REGX52.H>
void main()
{
P2_2 = 0;
P2_3 = 0;
P2_4 = 0;
P0 = 0x76;
while (1);
}
静态显示就跟点亮LED一样简单对吧?
5.动态显示
想要动态显示,也就是同时显示多个数码管,需要什么思路咱先暂时不表,宁思考一下呢?假如咱们要用最后三个数码管(于我而言对应2、1、0三位被位选)显示985三个数字,应该怎么做?
想到了吗?按照行话来说,也就是专业的说法:“通过快速轮询、动态扫描并点亮各数码管,利用人眼视觉暂留效应实现同时显示”,白话一点:“把需要的位选和段选放进while(1)中,并增加延时”
那么咱们可以简单来写一段:
#include<REGX52.h>
void delay_ms(unsigned int n)
{
unsigned int i;
while(n--)
{
for(i=0;i<280;++i);
}
}
int main()
{
while (1)
{
//如果你的代码编译报错,删除注释试试
//位选0,段选出5
P2_4 = 0;
P2_3 = 0;
P2_2 = 0;
P0 = 0x6D;
delay_ms(1);
//位选1,段选出8
P2_4 = 0;
P2_3 = 0;
P2_2 = 1;
P0 = 0x7F;
delay_ms(1);
//位选2,段选出9
P2_4 = 0;
P2_3 = 1;
P2_2 = 0;
P0 = 0x6F;
delay_ms(1);
}
}
把这段代码烧录通过STC-ISP烧录进板子里宁会发现,这并不是咱们想要的985,还会有淡淡的“鬼影”
,这是因为切换数码管的时候,如果没关掉上一个段选,就会在视网膜留下下一个位选的上一个段选的残影,并不断加剧
解决方法就是每次要进入下一次为位选时,清除上一个段选:
#include<REGX52.h>
void delay_ms(unsigned int n)
{
unsigned int i;
while(n--)
{
for(i=0;i<280;++i);
}
}
int main()
{
while (1)
{
P2_4 = 0;
P2_3 = 0;
P2_2 = 0;
P0 = 0x6D;
delay_ms(1);
P0 = 0x00;
P2_4 = 0;
P2_3 = 0;
P2_2 = 1;
P0 = 0x7F;
delay_ms(1);
P0 = 0x00;
P2_4 = 0;
P2_3 = 1;
P2_2 = 0;
P0 = 0x6F;
delay_ms(1);
P0 = 0x00;
}
}
参考资料以及推荐学习
【接入DeepSeek的51单片机入门教程 Windows Linux Mac通用 持续更新 旧视频每日替换】
江科大—【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】
总结
数码管中藏玄机,位选段选分阴阳;
译码驱动齐相助,段码表里寻真知。
动态扫描消残影,循环延时妙无穷;
实践出真知,巧手定乾坤!