数码管作为嵌入式系统中最基础的人机交互设备之一,在各类电子设备中广泛应用。这次我们在普中51-Ai8051开发板上实现的数码管显示实验,看似简单却包含了嵌入式开发的多个核心知识点。
我从事单片机开发已有八年时间,处理过各种数码管驱动问题。在实际项目中,数码管显示往往需要考虑功耗、亮度均匀性、刷新频率等细节。这个实验虽然只实现了基本的数字显示,但已经涵盖了硬件电路设计、驱动芯片选型、软件动态扫描等关键技术点。
开发板采用了两片四位共阴数码管(实际构成8位显示),通过74HC245增强驱动能力,配合74HC138译码器节省IO资源。这种设计方案在工业控制仪表中非常典型,比如我去年参与的温控器项目就采用了几乎相同的硬件架构。
数码管本质上是由多个LED组成的显示器件。我们开发板使用的是共阴型数码管,这意味着所有LED的阴极连接在一起作为公共端,阳极则分别控制各个段。
重要提示:共阴和共阳数码管的驱动逻辑完全相反。使用前务必确认型号,我曾遇到过因型号混淆导致整批样品烧毁的事故。
数码管的段码对应关系如下表所示:
| 段名 | 对应LED位置 | 二进制位 |
|---|---|---|
| a | 顶部水平段 | bit0 |
| b | 右上垂直段 | bit1 |
| c | 右下垂直段 | bit2 |
| d | 底部水平段 | bit3 |
| e | 左下垂直段 | bit4 |
| f | 左上垂直段 | bit5 |
| g | 中间水平段 | bit6 |
| dp | 小数点 | bit7 |
这个8路双向缓冲器在项目中承担着增强IO驱动能力的重要角色。其核心参数值得关注:
配置要点:
这个3-8译码器极大节省了IO资源,其真值表如下:
| A2 | A1 | A0 | 有效输出 |
|---|---|---|---|
| 0 | 0 | 0 | Y0 |
| 0 | 0 | 1 | Y1 |
| 0 | 1 | 0 | Y2 |
| 0 | 1 | 1 | Y3 |
| 1 | 0 | 0 | Y4 |
| 1 | 0 | 1 | Y5 |
| 1 | 1 | 0 | Y6 |
| 1 | 1 | 1 | Y7 |
使能条件:
在Keil开发环境中创建工程时,有几个关键设置需要注意:
GPIO初始化代码中,以下几个配置尤为关键:
c复制P0M1 = 0x00; // P0口推挽输出
P0M0 = 0xFF;
P2M1 = 0x00; // P2.0-P2.2推挽输出
P2M0 = 0x07;
共阴数码管的段码表定义如下:
c复制u8 gsmg_code[17] = {
0x3F, // 0
0x06, // 1
0x5B, // 2
0x4F, // 3
0x66, // 4
0x6D, // 5
0x7D, // 6
0x07, // 7
0x7F, // 8
0x6F, // 9
0x77, // A
0x7C, // b
0x39, // C
0x5E, // d
0x79, // E
0x71, // F
0x00 // 全灭
};
每个数值对应数码管各段的点亮组合。例如数字"0"的段码0x3F,对应二进制00111111,即a-f段点亮,g和dp熄灭。
动态显示的核心函数SMG_Display实现如下:
c复制void SMG_Display(u8 dat[], u8 pos)
{
u8 i = 0;
u8 pos_temp = pos - 1;
for(i = pos_temp; i < 8; i++)
{
switch(i) // 位选控制
{
case 0: LSC=1; LSB=1; LSA=1; break;
case 1: LSC=1; LSB=1; LSA=0; break;
case 2: LSC=1; LSB=0; LSA=1; break;
case 3: LSC=1; LSB=0; LSA=0; break;
case 4: LSC=0; LSB=1; LSA=1; break;
case 5: LSC=0; LSB=1; LSA=0; break;
case 6: LSC=0; LSB=0; LSA=1; break;
case 7: LSC=0; LSB=0; LSA=0; break;
}
SMG_PORT = dat[i-pos_temp]; // 段码输出
delay_ms(1); // 显示稳定时间
SMG_PORT = 0; // 消隐
}
}
这个函数实现了以下关键功能:
主程序中的显示逻辑非常简单:
c复制while(1)
{
for(i=0; i<8; i++)
smgbuf[i] = gsmg_code[i];
SMG_Display(smgbuf, 1);
delay_ms(10);
}
这里有几个优化点值得注意:
现象1:所有数码管显示混乱
现象2:某一位不亮
现象3:显示内容残缺
在工业环境中,数码管显示容易受到干扰,可采取以下措施:
通过按键配合数码管,可以实现简单菜单系统:
c复制enum {DISPLAY_MODE, SETTING_MODE} system_mode;
void handle_key()
{
if(key_pressed)
{
system_mode = (system_mode == DISPLAY_MODE) ? SETTING_MODE : DISPLAY_MODE;
update_display();
}
}
实现文字滚动显示的关键算法:
c复制void scroll_display(u8 *str, u8 len)
{
static u8 pos = 0;
u8 buf[8];
for(u8 i=0; i<8; i++)
{
buf[i] = (pos+i < len) ? get_char_code(str[pos+i]) : 0x00;
}
SMG_Display(buf, 1);
pos = (pos+1) % len;
}
对于电池供电设备,可采取以下措施:
我在实际项目中测试发现,通过优化扫描算法和驱动方式,数码管系统的功耗可以降低60%以上。例如将恒亮改为1/4占空比的扫描,在保证视觉亮度不变的情况下大幅减少能耗。