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

目录

[1 AT89C52单片机驱动单个数码管](#1 AT89C52单片机驱动单个数码管)

[1.1 数码管基础知识](#1.1 数码管基础知识)

1.1.1外观与引脚

[1.1.2 共阴(CC) vs 共阳(CA)](#1.1.2 共阴(CC) vs 共阳(CA))

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

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

[1.1.6 快速排查清单](#1.1.6 快速排查清单)

[1.2 完整例子1------AT89C52单片机驱动单个数码管0~9循环计数](#1.2 完整例子1——AT89C52单片机驱动单个数码管0~9循环计数)

[1.2.1 电路原理图](#1.2.1 电路原理图)

[1.2.2 控制程序](#1.2.2 控制程序)

[1.3 完整例子2------AT89C52单片机实现比分计数器](#1.3 完整例子2——AT89C52单片机实现比分计数器)

[1.3.1 74HC573透明锁存器](#1.3.1 74HC573透明锁存器)

[1.3.2 引脚与封装](#1.3.2 引脚与封装)

[1.3.3 真值表(简化)](#1.3.3 真值表(简化))

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

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

[1.3.6 常见问题速查](#1.3.6 常见问题速查)

[1.4 AT89C52单片机实现比分计数器电路原理图](#1.4 AT89C52单片机实现比分计数器电路原理图)

[1.5 控制程序](#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,循环

伪代码:

objectivec 复制代码
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 控制程序

objectivec 复制代码
//头文件与位定义
# include <reg51.h>
# include <intrins.h>
//数码管对应数字
// 0:10000000 1:11110010 2:01001000	3:01100000 4:00110010 5:00100100 6:00000100 7:11110000 8:00000000 9:00100000
unsigned 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 晶振)

objectivec 复制代码
#include <reg52.h>
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<<0);          // 点亮第 1 位
        delay_ms(2);
        P2 = 0xFF;             // 关闭所有位
        if(++i>9) i=0;
    }
}

1.3.6 常见问题速查

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

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

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

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

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

1.5 控制程序

objectivec 复制代码
//头文件与位定义
#include <reg52.h>
#define uint unsigned int
#define uchar unsigned char
sbit 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-9
uchar code table_W[] = {0x01,0x02,0x04,0x08,0x10,0x20};	//位值1-6	

uint 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 0001
	TH0 = 0xFC;				//1ms
	TL0 = 0x17;
	EA = 1;
	ET0 = 1;
	TR0 = 1;
}

//定时器T0延时函数
void delay(unsigned int dtime)
{
    unsigned int i;
    for (i = 0; i <dtime; i++)
    {
        while (!TF0);  // 等待定时器T0溢出
        TF0 = 0;       // 清除溢出标志
    }
}
//定时器T0模式1中断服务函数
void Timer0_ISR() interrupt 1
{
    TH0 = 0xFC; 
	  TL0 = 0x17;
    time++;
}


void main(){
	init();
	num1 = 0;
	num1 = 0;
	while(1)
		{
		if((time >= 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 0000
		LE_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 0000
		LE_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 1000
		LE_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 0100
		LE_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 0010
		LE_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 0001
		LE_W = 0;
		delay(1);
		LE_W = 1;						//消隐
		P0 = 0;
		LE_W = 0;
}
相关推荐
国科安芯1 小时前
高速CANFD收发器ASM1042在割草机器人轮毂电机通信系统中的适配性研究
网络·单片机·嵌入式硬件·性能优化·机器人·硬件工程
CC呢1 小时前
基于单片机智能路灯控制
单片机·嵌入式硬件·智能路灯
DDUU__2 小时前
STM32低功耗模式
stm32·单片机·嵌入式硬件
小莞尔3 小时前
【51单片机】【protues仿真】基于51单片机宠物投食器系统
c语言·stm32·单片机·嵌入式硬件·51单片机·proteus
風清掦3 小时前
零基础玩转STM32:深入理解ARM Cortex-M内核与寄存器编程
stm32·单片机·嵌入式硬件·mcu·物联网
芯岭技术8 小时前
PY32F003国产单片机、外设丰富、高性价比的国产替代方案
单片机·嵌入式硬件
QQ52862112410 小时前
单片机GD32F230芯片解密解析及专业操作建议
单片机·嵌入式硬件
一枚小小程序员哈10 小时前
基于stm32的智能建筑能源管理系统/基于单片机的能源管理系统
stm32·单片机·能源
物联网牛七七10 小时前
51和stm32的点灯区别
stm32·单片机·51单片机