波特律动
课程中心/51单片机教程/【16】数码管动态扫描

【16】数码管动态扫描

本课资源下载
共 3 个资源
P16数码管动态显示

本节课的标准源代码工程/可供参考

V1.0压缩包41 KB
下载
SN74HC32DR

或门逻辑芯片

PDF 文档3.2 MB
预览下载
SN74HC04DR

非门逻辑芯片

PDF 文档545 KB
预览下载

课程笔记


本节目标概括

创建main.c > 编写点灯代码 > 编译HEX文件 > 下载到学习板 > 数码管动态显示

一、数码管基础控制原理

1. 共阴极、共阳极区分

数码管内部由 a~g 七段显示笔画 + 小数点 dp 组成,两种供电结构:

  1. 共阴极:所有发光二极管负极接公共端,公共端接地;段脚输入高电平,对应段点亮。
  2. 共阳极:所有发光二极管正极接公共端,公共端接高电平;段脚输入低电平,对应段点亮。
    二者段码表电平完全相反,写程序时要严格匹配硬件类型。

2. 单个数码管

仅一组 a~g、dp 引脚,配合公共端,直接输出对应段码就能显示 0-9、A-F 等字符,驱动逻辑最简单,适合入门测试。

3. 4 位多位数码管

4 个数码管封装一体,段脚 a~g、dp 全部并联共用,各自独立引出位选公共端;采用动态扫描驱动:快速轮流打开每一位位选、输出对应段码,利用人眼视觉暂留,实现多位同时显示效果。

二、配套逻辑芯片作用

1. 74HC04 反相器

实现电平翻转,常搭配锁存器、位选电路使用;可调整电平匹配数码管极性,部分电路中配合锁存引脚实现默认锁存状态,无信号输入时输出保持不变,防止数码管乱跳。

2. 74HC32 或门

或门逻辑:任一输入为高,输出即为高;多用于上电复位、稳定控制电路,上电瞬间强制电路进入稳定初始状态,避免开机杂波导致数码管闪烁、乱码。

3. 74HC573 锁存器

核心作用:IO 口分时复用。一组 IO 先送段码 / 位选数据,拉高锁存引脚存入芯片,之后 MCU 收回 IO 口去做其他任务;锁存器会持续保持输出电平,大幅节约单片机有限 IO 资源,是多位数码管标配驱动芯片。

三、驱动核心:位选、段选

  1. 段选:控制 a~g、dp8 根引脚,决定单个数码管亮哪几段,对应显示什么数字字符;
  2. 位选:控制每一个数码管的公共端,决定当前点亮第几个管子;
    动态扫描流程:打开位选 1→送第一位段码→短暂延时→关闭位选 1;打开位选 2→送第二位段码…… 循环往复。

四、例程讲解


数码管驱动库功能函数介绍:

C语言
1// 设置显示缓存中的数字
2void digit_setNum(unsigned char pos, unsigned char num)
3{
4 if (pos > 8)
5 pos = 8;
6 if (num > 9)
7 num = 9;
8 digit_display_buffer[pos - 1] = num;
9}
10
11// 显示单个数字
12void digit_showSingleNum(unsigned char pos, unsigned char num)
13{
14 if (pos > 8)
15 pos = 8;
16
17 // 关闭所有位的显示(消隐)
18 LATCH_WRITE_DIGIT_SEL();
19 DATA_PORT = DIGIT_SEL_NONE;
20 LATCH_HOLD_ALL();
21
22 // 锁存段数据
23 LATCH_WRITE_DIGIT_SEG();
24 DATA_PORT = char_table[num];
25 LATCH_HOLD_ALL();
26
27 // 选通要显示的位
28 DATA_PORT = digit_select_index[pos - 1];
29 LATCH_WRITE_DIGIT_SEL();
30 _nop_();
31 _nop_();
32 LATCH_HOLD_ALL();
33 delay(DIGIT_HOLD_TIME);
34}
35
36// 动态扫描显示所有数位
37// 显示空位(保持与实显位相同的时间以保证亮度一致)
38static void digit_showBlankSlot(unsigned char pos)
39{
40 if (pos > 8)
41 pos = 8;
42
43 // 关闭所有位的显示(消隐)
44 LATCH_WRITE_DIGIT_SEL();
45 DATA_PORT = DIGIT_SEL_NONE;
46 LATCH_HOLD_ALL();
47
48 // 锁存空段数据(全部段灭)
49 LATCH_WRITE_DIGIT_SEG();
50 DATA_PORT = DIGIT_SEG_NONE;
51 LATCH_HOLD_ALL();
52
53 // 选通要(空)显示的位
54 DATA_PORT = digit_select_index[pos - 1];
55 LATCH_WRITE_DIGIT_SEL();
56 _nop_();
57 _nop_();
58 LATCH_HOLD_ALL();
59 delay(DIGIT_HOLD_TIME);
60}
61
62// 动态扫描显示所有数位,参数 display_count 指定要实际显示的位数(1..8,0或>8视为8)
63void digit_scanDisplay(unsigned char display_count)
64{
65 unsigned char i;
66
67 if (display_count == 0 || display_count > 8)
68 display_count = 8;
69
70 // 轮流扫描8个位:对于小于 display_count 的位显示缓存内容,
71 // 其余位熄灭(熄灭位也扫描,以保持亮度恒定不跳变)
72 for (i = 0; i < 8; i++)
73 {
74 if (i < display_count)
75 digit_showSingleNum(i + 1, digit_display_buffer[i]);
76 else
77 digit_showBlankSlot(i + 1);
78 }
79}
80
81// 刷新显示并保持指定毫秒数
82void digit_refreshMs(unsigned char display_count, unsigned int ms)
83{
84 unsigned int ms_per_scan = 8 * DIGIT_HOLD_TIME;
85 unsigned int repeats;
86
87 if (display_count == 0 || display_count > 8)
88 display_count = 8;
89
90 if (ms_per_scan == 0)
91 ms_per_scan = 1;
92
93 repeats = ms / ms_per_scan;
94 if (repeats == 0)
95 repeats = 1;
96
97 while (repeats--)
98 {
99 digit_scanDisplay(display_count);
100 }
101}


主函数:

  • 现象:动态扫描实现八个数码管同时显示
C语言
1void main(void)
2{
3 digit_Init();
4
5 while (1)
6 {
7 // 数码管显示8个8
8 digit_setNum(1, 8);
9 digit_setNum(2, 8);
10 digit_setNum(3, 8);
11 digit_setNum(4, 8);
12 digit_setNum(5, 8);
13 digit_setNum(6, 8);
14 digit_setNum(7, 8);
15 digit_setNum(8, 8);
16 digit_refreshMs(8, 1000);
17 }
18}