有了《51单片机编程学习笔记——74HC138译码器》和《51单片机编程学习笔记——74HC245八路三态输出双向收发器》的基础,我们就可以开始学习动态数码管的编程方法。
我们首先要看下动态数码管的电路图
选位置
可以看到该开发板上的动态数码管使用了两个元器件:74HC138译码器和74HC245八路三态输出双向收发器。
在《51单片机编程学习笔记——74HC138译码器》一文中,我们知道该译码器将3位二进制数转换成8个管脚的输出,并且只有一个管脚是低电平,其他都是高电平。这样我们就可以使用该原理选择出动态数码管中的一位。比如我们希望左起第1个数字区域点亮,则可以让LED8端口为低电平,其他位高电平(只要让P24 P23 P22 都处于高电平即可,即0x111)。
这是因为动态数码管的每个数字区域是8个LED组成,它们分别是a、b、c、d、e、f、g和dp。这些LED的阳极可以连在一起,形成共阳极结构。这样我们可以通过控制每个LED的阴极电压来控制其是否点亮;对应的,有些数码管将这8个LED的阴极连在一起,形成共阴极结构。这个时候我们就可以通过控制每个LED的阳极电压来控制其是否点亮。我们开发板上的数码管就是共阴极方案。
由于这些LED的一端接的是P0系列管脚,提供了高电平。这样另外一端(共极)要提供低电平,才能让LED点亮。而74HC138译码器
正好将选择的管脚设置为低电平。其他另外一端(共极)提供高电平的LED区域,因为形成不了电压差,所以不会点亮这8个LED等,从而不会显示任何数字。
显数字
然后我们需要分析下组成我们认识的数字需要点亮哪些LED灯。比如我们需要形成数字“0”,则除了dp和g不用点亮外,其他都要点亮;在比如数字8,除了dp不用点亮外,其他都要点亮。
下面给出了数字和需要点亮的LED灯之间的关系,区分了共阴极和共阳极两种动态数码管:
- 共阴极方案
显示数字 | 需点亮的 LED 段 | 二进制编码(abcdefgdp) | 十六进制编码 |
---|---|---|---|
0 | a、b、c、d、e、f | 0011 1111 | 0x3F |
1 | b、c | 0000 0110 | 0x06 |
2 | a、b、d、e、g | 0101 1011 | 0x5B |
3 | a、b、c、d、g | 0100 1111 | 0x4F |
4 | b、c、f、g | 0110 0110 | 0x66 |
5 | a、c、d、f、g | 0110 1101 | 0x6D |
6 | a、c、d、e、f、g | 0111 1101 | 0x7D |
7 | a、b、c | 0000 0111 | 0x07 |
8 | a、b、c、d、e、f、g | 0111 1111 | 0x7F |
9 | a、b、c、d、f、g | 0110 1111 | 0x6F |
- 共阳极方案
显示数字 | 需点亮的 LED 段 | 二进制编码(abcdefgdp) | 十六进制编码 |
---|---|---|---|
0 | a、b、c、d、e、f | 1100 0000 | 0xC0 |
1 | b、c | 1111 1001 | 0xF9 |
2 | a、b、d、e、g | 1010 0100 | 0xA4 |
3 | a、b、c、d、g | 1011 0000 | 0xB0 |
4 | b、c、f、g | 1001 1001 | 0x99 |
5 | a、c、d、f、g | 1001 0010 | 0x92 |
6 | a、c、d、e、f、g | 1000 0010 | 0x82 |
7 | a、b、c | 1111 1000 | 0xF8 |
8 | a、b、c、d、e、f、g | 1000 0000 | 0x80 |
9 | a、b、c、d、f、g | 1001 0000 | 0x90 |
这儿需要提醒下,二进制的顺序要从高位向低位,即从P07到P00。
实验
在有了上面的铺垫后,我们通过代码实现如下功能:从坐起第一个位置开始,逐位显示0~7。
首先我们需要选择在哪个位置上显示数字
void select_led_index(unsigned char index) {
// 如果index=0,则P22=1,P23=1,P24=1
// 如果index=1,则P22=0,P23=1,P24=1
// 如果index=2,则P22=1,P23=0,P24=1
// 如果index=3,则P22=0,P23=0,P24=1
// 如果index=4,则P22=1,P23=1,P24=0
// 如果index=5,则P22=0,P23=1,P24=0
// 如果index=6,则P22=1,P23=0,P24=0
// 如果index=7,则P22=0,P23=0,P24=0
P22 = (index & 0x01) ? 0 : 1;
P23 = (index & 0x02) ? 0 : 1;
P24 = (index & 0x04) ? 0 : 1;
}
然后在选择位置上显示各个数字
unsigned char digit[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
……
void display(unsigned char index, unsigned char digit)
{
select_led_index(index);
P0 = digit;
}
……
for(i=0;i<8;i++) {
display(i, digit[i]);
Delay(200);
}
完整代码如下
#include <REG52.H>
#include <intrins.h>
void Delay1ms() //@11.0592MHz
{
unsigned char i, j;
_nop_();
i = 2;
j = 199;
do
{
while (--j);
} while (--i);
}
void Delay(unsigned int millisecond) {
unsigned int i = 0;
for (i = 0; i < millisecond; i++) {
Delay1ms();
}
}
sbit P22 = P2^2;
sbit P23 = P2^3;
sbit P24 = P2^4;
void select_led_index(unsigned char index) {
// 如果index=0,则P22=1,P23=1,P24=1
// 如果index=1,则P22=0,P23=1,P24=1
// 如果index=2,则P22=1,P23=0,P24=1
// 如果index=3,则P22=0,P23=0,P24=1
// 如果index=4,则P22=1,P23=1,P24=0
// 如果index=5,则P22=0,P23=1,P24=0
// 如果index=6,则P22=1,P23=0,P24=0
// 如果index=7,则P22=0,P23=0,P24=0
P22 = (index & 0x01) ? 0 : 1;
P23 = (index & 0x02) ? 0 : 1;
P24 = (index & 0x04) ? 0 : 1;
}
void display(unsigned char index, unsigned char digit)
{
select_led_index(index);
P0 = digit;
}
void main() {
unsigned char i;
unsigned char digit[10] = {0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f};
while(1) {
for(i=0;i<8;i++) {
display(i, digit[i]);
Delay(200);
}
}
}