【16】数码管动态扫描
本课资源下载
共 3 个资源课程笔记
本节目标概括
创建main.c > 编写点灯代码 > 编译HEX文件 > 下载到学习板 > 数码管动态显示
一、数码管基础控制原理
1. 共阴极、共阳极区分
数码管内部由 a~g 七段显示笔画 + 小数点 dp 组成,两种供电结构:
- 共阴极:所有发光二极管负极接公共端,公共端接地;段脚输入高电平,对应段点亮。
- 共阳极:所有发光二极管正极接公共端,公共端接高电平;段脚输入低电平,对应段点亮。
二者段码表电平完全相反,写程序时要严格匹配硬件类型。
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 资源,是多位数码管标配驱动芯片。
三、驱动核心:位选、段选
- 段选:控制 a~g、dp8 根引脚,决定单个数码管亮哪几段,对应显示什么数字字符;
- 位选:控制每一个数码管的公共端,决定当前点亮第几个管子;
动态扫描流程:打开位选 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}1011// 显示单个数字12void digit_showSingleNum(unsigned char pos, unsigned char num)13{14 if (pos > 8)15 pos = 8;1617 // 关闭所有位的显示(消隐)18 LATCH_WRITE_DIGIT_SEL();19 DATA_PORT = DIGIT_SEL_NONE;20 LATCH_HOLD_ALL();2122 // 锁存段数据23 LATCH_WRITE_DIGIT_SEG();24 DATA_PORT = char_table[num];25 LATCH_HOLD_ALL();2627 // 选通要显示的位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}3536// 动态扫描显示所有数位37// 显示空位(保持与实显位相同的时间以保证亮度一致)38static void digit_showBlankSlot(unsigned char pos)39{40 if (pos > 8)41 pos = 8;4243 // 关闭所有位的显示(消隐)44 LATCH_WRITE_DIGIT_SEL();45 DATA_PORT = DIGIT_SEL_NONE;46 LATCH_HOLD_ALL();4748 // 锁存空段数据(全部段灭)49 LATCH_WRITE_DIGIT_SEG();50 DATA_PORT = DIGIT_SEG_NONE;51 LATCH_HOLD_ALL();5253 // 选通要(空)显示的位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}6162// 动态扫描显示所有数位,参数 display_count 指定要实际显示的位数(1..8,0或>8视为8)63void digit_scanDisplay(unsigned char display_count)64{65 unsigned char i;6667 if (display_count == 0 || display_count > 8)68 display_count = 8;6970 // 轮流扫描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 else77 digit_showBlankSlot(i + 1);78 }79}8081// 刷新显示并保持指定毫秒数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;8687 if (display_count == 0 || display_count > 8)88 display_count = 8;8990 if (ms_per_scan == 0)91 ms_per_scan = 1;9293 repeats = ms / ms_per_scan;94 if (repeats == 0)95 repeats = 1;9697 while (repeats--)98 {99 digit_scanDisplay(display_count);100 }101}
主函数:
- 现象:动态扫描实现八个数码管同时显示
C语言
1void main(void)2{3 digit_Init();45 while (1)6 {7 // 数码管显示8个88 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}