> 技术文档 > 【Protues仿真】基于AT89C52单片机的数码管驱动事例

【Protues仿真】基于AT89C52单片机的数码管驱动事例

目录

1 AT89C52单片机驱动单个数码管

1.1 数码管基础知识

1.1.1外观与引脚

1.1.2 共阴(CC) vs 共阳(CA)

1.1.3段码表(以数字1为例)

1.1.4驱动方式A. 直连IO(最简单,占用IO多)一个段一根线,共阴或共阳公共端固定接GND/VCC。适合单个数码管、教学实验。

1.1.6 快速排查清单

1.2 完整例子1——AT89C52单片机驱动单个数码管0~9循环计数

1.2.1 电路原理图

1.2.2 控制程序

1.3 完整例子2——AT89C52单片机实现比分计数器

1.3.1 74HC573透明锁存器

1.3.2 引脚与封装

1.3.3 真值表(简化)

1.3.4 典型应用:51 单片机驱动 4 位共阴七段数码管

1.3.5 最小示例(Keil C,12 MHz 晶振)

1.3.6 常见问题速查

1.4 AT89C52单片机实现比分计数器电路原理图

1.5 控制程序


摘要:本文介绍了AT89C52单片机驱动数码管的基础知识及实现方法。主要内容包括:1.数码管工作原理,包括共阴/共阳结构、段码表、驱动方式;2.两个具体应用实例:单个数码管0-9循环计数和比分计数器;3.详细硬件电路设计(含74HC573锁存器应用)和配套C语言程序实现;4.常见问题排查指南。通过定时器中断实现精确控制,采用动态扫描技术实现多位显示,并提供了完整的代码示例和电路原理图。

1 AT89C52单片机驱动单个数码管

1.1 数码管基础知识

7段数码管(7-segment display)是最常见的数字显示器件之一,广泛用于仪表、时钟、计数器等场合。

1.1.1外观与引脚

如上图所示,7个发光段分别命名为 a、b、c、d、e、f、g(顺时针方向排列),再加一个小数点 dp。

单个数码管常见封装:
直插 DIP-10(2.54 mm)
贴片 SMD-10

引脚排列没有统一标准,务必看数据手册或用万用表「二极管档」量:红笔固定接公共端,黑笔依次碰其它脚,某一段亮就说明该脚对应段。

1.1.2 共阴(CC) vs 共阳(CA)

共阴:所有 LED 阴极并在一起 → 公共脚接 GND,要点亮某段就给该段阳极送高电平(+V)。

共阳:所有 LED 阳极并在一起 → 公共脚接 +V,要点亮某段就给该段阴极送低电平(GND)。

记忆口诀:
共阴 = “给1亮”
共阳 = “给0亮”

1.1.3段码表(以数字1为例)

数字1需要点亮 b、c 两段。

类型

a b c d e f g dp

十六进制

说明

共阴

0 1 1 0 0 0 0 0

0x06

b、c=1,其余=0

共阳

1 0 0 1 1 1 1 1

0xF9

b、c=0,其余=1

完整段码速查:
0 1 2 3 4 5 6 7 8 9
共阴:0x3F 0x06 0x5B 0x4F 0x66 0x6D 0x7D 0x07 0x7F 0x6F
共阳:取反即可(~共阴 & 0xFF)

1.1.4驱动方式
A. 直连IO(最简单,占用IO多)
一个段一根线,共阴或共阳公共端固定接GND/VCC。
适合单个数码管、教学实验。

B. 译码/驱动芯片
74HC47(BCD→7段,共阳)
CD4511(BCD→7段,带锁存,共阴)
TM1637、MAX7219(集成扫描与亮度调节)

C. MCU+三极管/MOS(动态扫描多个位)
节省IO:段线共用,位选线轮流导通。
需要定时刷新(>100 Hz 无闪烁)。
1.1.5 多连排数码管动态扫描
以4位共阴为例:

12个IO:8段+4位选

流程:

关所有位(位选高)

送第N位段码

打开第N位(位选低)

延时1~2 ms

回到1,循环

伪代码:

const uint8_t seg_cc[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};void display_4digit(uint16_t val){ for(uint8_t pos=0; pos<4; pos++){ set_digit_OFF(); output_SEG(seg_cc[val%10]); // 输出段码 set_digit_ON(pos); // 打开位 delay_ms(2); val /= 10; }}

1.1.6 快速排查清单

不亮:检查公共端电压、限流电阻(每段330 Ω~1 kΩ)。

乱亮:段码高低反了(把共阴/共阳搞反)。

闪烁:动态扫描频率太低,提高刷新或加定时器中断。

1.2 完整例子1——AT89C52单片机驱动单个数码管0~9循环计数

1.2.1 电路原理图

如上图所示,AT89C52单片机驱动单个数码管0~9循环计数电路原理图由AT89C52单片机、上拉排阻、数码管、晶振和复位电路组成,通过AT89C52单片机控制P0的输出电平实现数码管数字显示的控制。

1.2.2 控制程序

//头文件与位定义# include # include //数码管对应数字// 0:10000000 1:11110010 2:010010003:01100000 4:00110010 5:00100100 6:00000100 7:11110000 8:00000000 9:00100000unsigned char display_table[] ={ 0x80, 0xf2, 0x48, 0x60, 0x32, 0x24, 0x04, 0xf0, 0x00, 0x20 }; // 共阳极数码管显示编码16进制unsigned int i=0;//定时器T0初始化void inittimer(){ TMOD = 0x01; // T0 方式 1 TH0 = 0xFC; // 1 ms TL0 = 0x18; TR0 = 1; ET0 = 1; EA = 1;//中断设置值}//定时器延时函数void Delay(unsigned int ms){ unsigned int i; for (i = 0; i < ms; i++) { while (!TF0); // 等待定时器T0溢出 TF0 = 0; // 清除溢出标志 }}//定时器T0模式1中断服务函数void Timer0_ISR() interrupt 1{ TH0 = 0xFC; TL0 = 0x18;}void main() // 主程序{inittimer();while(1){P0 = 0x00;for(i = 0; i < 10; i++){if (i == 10) // 当i=10时,将0清零。就是当数码管显示9后,再从0开始{i = 0;}P0 = display_table[i];Delay(1000);}}}

如上程序所示,程序使用定时器T0的T1模式实现精确延时控制,从而实现控制数码管的显数显示。

1.3 完整例子2——AT89C52单片机实现比分计数器

1.3.1 74HC573透明锁存器

74HC573是一块“8 位透明锁存器(Octal D-Type Transparent Latch)”,带三态输出,最常被拿来做“IO口扩展+数据保持”,比如用3片74HC573 就能让 8 位单片机口线分时输出 24 位数据,正好驱动 8×16 LED 点阵或多位七段数码管

1.3.2 引脚与封装

封装:DIP-20、SOP-20、TSSOP-20 等

关键脚位(俯视图左下角圆点逆时针数):
1 OE̅ 输出使能(低电平有效,拉高则 Q0~Q7 高阻)
11 LE 锁存使能(高=透明,低=锁存)
2~9 D0~D7 数据输入
19~12 Q0~Q7 三态输出
20 VCC,10 GND

1.3.3 真值表(简化)

OE̅

LE

D

Q

0

1

X

随D(透明)

0

0

X

保持上次数据

1

X

X

高阻态

1.3.4 典型应用:51 单片机驱动 4 位共阴七段数码管

接线示意
MCU-P0 → 74HC573(段码) → 330 Ω 电阻 → a~g,dp
MCU-P2.0~P2.3 → 三极管 → 位选线(共阴端)
锁存器:
OE̅ 接地(一直使能)
LE → 单片机 P3.6(段锁存)

时序

1把段码送 P0

2给 LE 一个高脉冲(锁存段码)

3打开对应位选线,延时 2 ms

4关位选、重复扫描

1.3.5 最小示例(Keil C,12 MHz 晶振)

#include sbit HC573_LE = P3^6; // 段锁存unsigned char code seg7[] = {0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};void delay_ms(unsigned char t){ unsigned int i; while(t--) for(i=0;i<123;i++);}void main(){ unsigned char i=0; while(1) { P0 = seg7[i]; // 送段码 HC573_LE = 1; // 锁存 HC573_LE = 0; P2 = ~(1<9) i=0; }}

1.3.6 常见问题速查

输出全高阻:OE̅ 被拉高,请接地。

数据写不进去:LE 没有拉到高电平或脉冲宽度不足(>10 ns 即可)。

电流不够:段码端只能提供 ±4 mA,驱动大电流 LED 请加三极管或 ULN2803。

1.4 AT89C52单片机实现比分计数器电路原理图

如上图所示,电路原理图由AT89C52单片机、上拉排阻、控制按键、晶振和复位电路、锁存器和6个数码管组成。通过五个独立按键控制高低电平,可以实现数值增加、减少或清零,并通过数码管显示数值。

1.5 控制程序

//头文件与位定义#include #define uint unsigned int#define uchar unsigned charsbit AJJ= P2^1;//A-sbit BJJ= P2^2;//B-sbit CLC= P2^3;//A+sbit AJ= P2^4;//A+sbit BJ= P2^5;//B+sbit LE_D = P2^6;//段选sbit LE_W = P2^7;//位选uchar code table_D[] = {0xC0,0xF9,0xA4,0XB0,0x99,0x92,0x82,0xF8,0x80,0x98};//段值0-9uchar code table_W[] = {0x01,0x02,0x04,0x08,0x10,0x20};//位值1-6uint time = 0;uint Num_D = 0;uint Num_W = 0;uchar ge,shi,bai;//个 十 百位uint num = 0;uint num1 = 0;void init();//定时器T0初始化void delay(uint dtime);//延时函数void display1(uint num);//显示函数void display2(uint num);//显示函数//定时器T0段选位选初始化void init(){LE_D = 0;LE_W = 0;AJ=1;BJ=1;TMOD = 0x01;//0000 0001TH0 = 0xFC;//1msTL0 = 0x17;EA = 1;ET0 = 1;TR0 = 1;}//定时器T0延时函数void delay(unsigned int dtime){ unsigned int i; for (i = 0; i = 300)&&(AJ==0)){time=0;num1++;}else if((time >= 300)&&(BJ==0)){time=0;num++;}else if((time >= 300)&&(AJJ==0)&&(num>0)){time=0;num1--;}else if((time >= 300)&&(BJJ==0)&&(num>0)){time=0;num--;}else if((time >= 300)&&(CLC==0)){time=0;num=0;num1=0;}display1(num1);display2(num);}}//后三个数码管显示数字的函数void display1(uint num){bai = num / 100;//百位应显示的数字shi = num % 100 /10;//十位应显示的数字ge = num % 10;//个位应显示的数字//数码管显示个位数字LE_D = 1;P0 = table_D[ge];//段——>位 会在段所指的位置上显示段LE_D = 0;//位——>段 新的数字会显示到之前的位置上LE_W = 1;P0 = 0x20;//0010 0000LE_W = 0;delay(1);LE_W = 1;//消隐P0 = 0;LE_W = 0;//数码管显示十位数字LE_D = 1;P0 = table_D[shi];LE_D = 0;LE_W = 1;P0 = 0x10;//0001 0000LE_W = 0;delay(1);LE_W = 1;//消隐 P0 = 0;LE_W = 0;//数码管显示百位数字LE_D = 1;P0 = table_D[bai];LE_D = 0;LE_W = 1;P0 = 0x08;//0000 1000LE_W = 0;delay(1);LE_W = 1;//消隐P0 = 0;LE_W = 0;}//前三个数码管显示数字的函数void display2(uint num){bai = num / 100;//百位应显示的数字shi = num % 100 /10;//十位应显示的数字ge = num % 10;//个位应显示的数字//数码管显示个位数字LE_D = 1;P0 = table_D[ge];//段——>位 会在段所指的位置上显示段LE_D = 0;//位——>段 新的数字会显示到之前的位置上LE_W = 1;P0 = 0x04;//0000 0100LE_W = 0;delay(1);LE_W = 1;//消隐P0 = 0;LE_W = 0;//数码管显示十位数字LE_D = 1;P0 = table_D[shi];LE_D = 0;LE_W = 1;P0 = 0x02;//0000 0010LE_W = 0;delay(1);LE_W = 1;//消隐 P0 = 0;LE_W = 0;//数码管显示百位数字LE_D = 1;P0 = table_D[bai];LE_D = 0;LE_W = 1;P0 = 0x01;//0000 0001LE_W = 0;delay(1);LE_W = 1;//消隐P0 = 0;LE_W = 0;}