第一次看到数码管时,你可能觉得它就是个会发光的塑料块。但当你拆开一个老式电子钟或者老款计算器,就会发现这些红色或绿色的数字显示器件无处不在。数码管本质上是由多个发光二极管(LED)组成的显示器件,通过控制不同LED的亮灭来组合出数字0-9。
我手头正好有个四位共阳数码管,拿起来仔细观察可以看到,每个数字其实是由7个LED段组成(加上小数点就是8段)。这些LED的排列很有意思 - 横着的是a、f、b、e段,竖着的是g、c、d段,小数点标记为dp。当给特定段通电时,就能组合出不同的数字形状。比如要显示数字"7",只需要点亮a、b、c三段即可。
数码管分为共阴和共阳两种类型,这个"共"指的是所有LED的公共端连接方式。共阴就是把所有LED的阴极连在一起,共阳则是阳极相连。这个区别很重要,直接决定了我们后续的驱动电路设计。我建议新手可以准备一个万用表,用二极管测试档快速判断手头的数码管类型 - 红表笔接公共端,黑表笔依次碰其他引脚,能点亮的就是共阳,反之则是共阴。
拆开一个单位数码管,你会发现它通常有10个引脚。其中8个分别对应a-g段和小数点dp,剩下2个是公共端(实际内部相连,相当于1个)。多位数码管的引脚会更多,比如四位一体数码管常见12个引脚 - 4个位选端加8个段选端。
我在面包板上做过一个有趣的实验:用杜邦线直接把数码管接到单片机IO口。结果发现亮度很不均匀,而且单片机很快就发热了。这是因为数码管每个LED需要5-20mA驱动电流,而单片机IO口的驱动能力通常只有几mA。这就是为什么实际电路中必须加上驱动电路,最常见的就是使用锁存器配合限流电阻。
共阴数码管的电路设计相对简单:公共端接地,需要点亮的段给高电平。比如要显示数字"1",就给b、c段接VCC。但实际使用时要注意,单片机IO口输出高电平时的驱动能力较弱,所以更常见的做法是用三极管或专用驱动芯片来增强电流。
共阳数码管则相反:公共端接VCC,要点亮的段给低电平。这种接法有个好处是可以直接利用单片机的灌电流能力(通常比拉电流强)。我在一个温控器项目中使用74HC595驱动四位共阳数码管,实测显示效果非常稳定。
静态显示是指所有数码管同时显示相同内容。听起来简单,但实现起来需要解决一个关键问题:如何避免单片机在更新显示内容时的闪烁现象?这就需要用到锁存器了。
以常用的74HC573为例,这个8位锁存器有三大关键引脚:
我画了个简单的控制时序:
这个过程看似复杂,但用代码实现其实很简单。下面是个51单片机的示例:
c复制sbit LE1 = P2^6; // 位选锁存
sbit LE2 = P2^7; // 段选锁存
void display(unsigned char num) {
LE1 = 1; // 打开位选锁存
P0 = 0x01; // 选中第一个数码管
LE1 = 0; // 锁存位选
LE2 = 1; // 打开段选锁存
P0 = segCode[num]; // 输出段选码
LE2 = 0; // 锁存段选
}
在TX-1C开发板上,数码管电路设计得很典型:段选通过U1锁存器接到P0口,位选通过U2锁存器也接到P0口。这种设计巧妙地解决了IO口复用问题。我在面包板上复现这个电路时,总结了几点经验:
要让数码管显示数字,需要先将数字转换为对应的段选码。我习惯用以下方法生成共阳段码表:
c复制unsigned char code segCode[] = {
0xC0, // 0
0xF9, // 1
0xA4, // 2
0xB0, // 3
0x99, // 4
0x92, // 5
0x82, // 6
0xF8, // 7
0x80, // 8
0x90 // 9
};
这个数组每个元素对应一个数字的段码,顺序是dp-g-f-e-d-c-b-a。比如数字"0"的段码0xC0(二进制11000000)表示要点亮a-g段(对应位为0)。
虽然我们讲的是静态显示,但实际应用中经常需要显示不同内容。这时可以采用"伪静态"的方法 - 快速轮流显示不同数字,利用人眼视觉暂留效应。下面是个简单的多位数显示函数:
c复制void showNumber(unsigned int num) {
static unsigned char pos = 0;
unsigned char digit;
LE1 = 1;
P0 = 1 << pos; // 位选
LE1 = 0;
digit = num % 10;
LE2 = 1;
P0 = segCode[digit];
LE2 = 0;
pos = (pos + 1) % 4;
num /= 10;
}
这个函数每次调用显示一位数字,通过定时器中断定期调用就能实现稳定显示。我在一个计时器项目中用这种方法,显示效果非常流畅。