当前位置: 首页 > news >正文

【51单片机】3. 数码管大师

1. 单个数码管基本定义

数码管连接方式:

分为共阳极和共阴极连接,如下图所示,上面为共阴极连接,下面为共阳极连接。

在这里插入图片描述

数码管引脚定义:

右侧从1开始逆时针到10,依次为1,2,3,…,8,9,10。上面数码管连接方式图中的标号就对应到具体的引脚。数码管定义的ABCDEFG&DP如左图所示,结合这些LED灯的编号和引脚编号可以得出连线图。

在这里插入图片描述

连线方式如下图所示:

在这里插入图片描述

2. 多个数码管定义

连接方式如下图所示,一共有12个引脚(上下的连接方式只是共阴极连接和共阳极连接的区别)。

则12,9,8,6控制具体亮哪一个LED灯,而其他控制显示的具体数字

在这里插入图片描述

每一个独立数码管显示(下方)都连接到了相同的接口。如果我们上方将12,9,8,6全部点亮(即所有数码管都显示数字),则每个数码管显示的都是具体ABCDEFG&DP连接的单片机的8个端口对应的结果。

这样的好处是,原本需要4*8=32个引脚控制的多个数码管,只用12个引脚就简单替代了

3. 动态数码管模块电路图分析

动态数码管模块电路图如下:

在这里插入图片描述

图中的COM通常接地或电源负极,这里可以看作这些LED管是共阴极连接,所以具体abcdefg&dp点亮哪一个,就要给哪一个置1。

0-9对应16进制如下(P07→P00):

int LEDNum[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};

下边的74HC245是一个双向数据缓冲器。使用这个是因为:

  • 高电平点亮灯与低电平点亮灯比起来,低电平会更亮一些(需要具体自己动手实验看)

  • 这里的双向数据缓冲器,就是拿单片机的微弱电流作为输入信号,做信号控制,控制右侧B0~B7这部分的结果

  • B0~B7右侧由VCC直流供电,电源更够一些,保证数码管的亮度

  • 综上,双向数据缓冲器就是用来增强驱动能力的

上图中LED连接到74H138译码器如下图所示:

在这里插入图片描述

译码器连接了VCC,所以在输出的LED中,需要通过置0,和VCC行成电压差点亮具体的LED(即给低电压点灯)。138是低电平译码!

通过CBA(P24,P23,P22)三个口来控制输出,具体如下:

  • C B A Output

  • 0 0 0 0(右4)

  • 0 0 1 1(右3)

  • 0 1 0 2(右2)

  • 0 1 1 3(右1)

  • 1 0 0 4(左4)

  • 1 0 1 5(左3)

  • 1 1 0 6(左2)

  • 1 1 1 7(左1)

好处就是仅需单片机3个接口控制8个灯具体亮哪个

还需要注意的是,无论是控制哪个单片机亮、还是控制显示什么数字,例如给P0端口输入,输入的顺序是从P07-P00,而译码器也是从P24-P22输入来控制对应的结果

4. 静态输入位置和数字

代码如下:

#include <REGX52.H>
#include <INTRINS.H>void Delay500ms()        //@11.0592MHz
{unsigned char i, j, k;_nop_();i = 4;j = 129;k = 119;do{do{while (--k);} while (--j);} while (--i);
}int LEDNum[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};void LEDShow(unsigned int LEDLocation,Number)
{switch(LEDLocation){case 1: P2_4 = 1; P2_3 = 1; P2_2 = 1; break;case 2: P2_4 = 1; P2_3 = 1; P2_2 = 0; break;case 3: P2_4 = 1; P2_3 = 0; P2_2 = 1; break;case 4: P2_4 = 1; P2_3 = 0; P2_2 = 0; break;case 5: P2_4 = 0; P2_3 = 1; P2_2 = 1; break;case 6: P2_4 = 0; P2_3 = 1; P2_2 = 0; break;case 7: P2_4 = 0; P2_3 = 0; P2_2 = 1; break;case 8: P2_4 = 0; P2_3 = 0; P2_2 = 0; break;}P0 = LEDNum[Number];
}int main(void)
{while (1){// 检测所有位置显示是否正确LEDShow(1,8);Delay500ms();LEDShow(2,8);Delay500ms();LEDShow(3,8);Delay500ms();LEDShow(4,8);Delay500ms();LEDShow(5,8);Delay500ms();LEDShow(6,8);Delay500ms();LEDShow(7,8);Delay500ms();LEDShow(8,8);Delay500ms();// 检测所有数字显示是否正确LEDShow(3,0);Delay500ms();LEDShow(3,1);Delay500ms();LEDShow(3,2);Delay500ms();LEDShow(3,3);Delay500ms();LEDShow(3,4);Delay500ms();LEDShow(3,5);Delay500ms();LEDShow(3,6);Delay500ms();LEDShow(3,7);Delay500ms();LEDShow(3,8);Delay500ms();LEDShow(3,9);Delay500ms();}
}

给LEDShow函数传入具体显示的LED位置(板子上从左至右是第1-8个位置)以及要显示的具体数字,就能够得到对应的结果。

以上的代码有点长,简单展示在第5位显示8的结果如下:

在这里插入图片描述

5. 动态数码管显示

小节的要求是在多个位置上显示不同的数字。

动态数码管显示实际上是轮流点亮数码管(一个时刻内只有一个数码管是亮的),利用人眼的视觉暂留现象(余晖效应),看起来是所有数码管在同时显示。

基于第四小节的结果,我们可以设计本小节的代码如下(第一版):

#include <REGX52.H>
#include <INTRINS.H>void Delay(unsigned int ms)        //@11.0592MHz
{unsigned char i, j;while (ms){_nop_();i = 2;j = 199;do{while (--j);} while (--i);ms--;}
}int LEDNum[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};void LEDShow(unsigned int LEDLocation,Number)
{switch(LEDLocation){case 1: P2_4 = 1; P2_3 = 1; P2_2 = 1; break;case 2: P2_4 = 1; P2_3 = 1; P2_2 = 0; break;case 3: P2_4 = 1; P2_3 = 0; P2_2 = 1; break;case 4: P2_4 = 1; P2_3 = 0; P2_2 = 0; break;case 5: P2_4 = 0; P2_3 = 1; P2_2 = 1; break;case 6: P2_4 = 0; P2_3 = 1; P2_2 = 0; break;case 7: P2_4 = 0; P2_3 = 0; P2_2 = 1; break;case 8: P2_4 = 0; P2_3 = 0; P2_2 = 0; break;}P0 = LEDNum[Number];
}int main(void)
{while (1){LEDShow(1,2);LEDShow(2,0);LEDShow(3,0);LEDShow(4,1);LEDShow(5,0);LEDShow(6,6);LEDShow(7,0);LEDShow(8,6);}
}

结果如下:

在这里插入图片描述

看起来很花,我认为是闪烁过快没有延时导致的,于是我在LEDShow函数后面加了一个延时1ms,对应函数修改如下:

void LEDShow(unsigned int LEDLocation,Number)
{switch(LEDLocation){case 1: P2_4 = 1; P2_3 = 1; P2_2 = 1; break;case 2: P2_4 = 1; P2_3 = 1; P2_2 = 0; break;case 3: P2_4 = 1; P2_3 = 0; P2_2 = 1; break;case 4: P2_4 = 1; P2_3 = 0; P2_2 = 0; break;case 5: P2_4 = 0; P2_3 = 1; P2_2 = 1; break;case 6: P2_4 = 0; P2_3 = 1; P2_2 = 0; break;case 7: P2_4 = 0; P2_3 = 0; P2_2 = 1; break;case 8: P2_4 = 0; P2_3 = 0; P2_2 = 0; break;}P0 = LEDNum[Number];Delay(1);
}

效果如下:

在这里插入图片描述

上面的现象减轻了一些,但依然存在,这是因为数码管需要消影。数码管的显示过程实际上是:

位选→段选→位选→段选→位选→段选→位选→段选......

但在段选和位选中间就会出现问题,导致把上一个段选的结果带入到下一个位选中,从而导致重影现象,所以在每一个位选→段选过后将数码管置0。Delay仍然需要保留,因为去掉Delay的话会什么都不显示,因为单片机的执行速度很快,我们要让数字留下来,就要保留Delay

修改对应函数如下:

void LEDShow(unsigned int LEDLocation,Number)
{switch(LEDLocation){case 1: P2_4 = 1; P2_3 = 1; P2_2 = 1; break;case 2: P2_4 = 1; P2_3 = 1; P2_2 = 0; break;case 3: P2_4 = 1; P2_3 = 0; P2_2 = 1; break;case 4: P2_4 = 1; P2_3 = 0; P2_2 = 0; break;case 5: P2_4 = 0; P2_3 = 1; P2_2 = 1; break;case 6: P2_4 = 0; P2_3 = 1; P2_2 = 0; break;case 7: P2_4 = 0; P2_3 = 0; P2_2 = 1; break;case 8: P2_4 = 0; P2_3 = 0; P2_2 = 0; break;}P0 = LEDNum[Number];Delay(1);P0 = 0x00;
}

最终效果如下:

在这里插入图片描述

完整代码:

#include <REGX52.H>
#include <INTRINS.H>void Delay(unsigned int ms)        //@11.0592MHz
{unsigned char i, j;while (ms){_nop_();i = 2;j = 199;do{while (--j);} while (--i);ms--;}
}int LEDNum[] = {0x3F, 0x06, 0x5B, 0x4F, 0x66, 0x6D, 0x7D, 0x07, 0x7F, 0x6F};void LEDShow(unsigned int LEDLocation,Number)
{switch(LEDLocation){case 1: P2_4 = 1; P2_3 = 1; P2_2 = 1; break;case 2: P2_4 = 1; P2_3 = 1; P2_2 = 0; break;case 3: P2_4 = 1; P2_3 = 0; P2_2 = 1; break;case 4: P2_4 = 1; P2_3 = 0; P2_2 = 0; break;case 5: P2_4 = 0; P2_3 = 1; P2_2 = 1; break;case 6: P2_4 = 0; P2_3 = 1; P2_2 = 0; break;case 7: P2_4 = 0; P2_3 = 0; P2_2 = 1; break;case 8: P2_4 = 0; P2_3 = 0; P2_2 = 0; break;}P0 = LEDNum[Number];Delay(1);P0 = 0x00;
}int main(void)
{while (1){LEDShow(1,2);LEDShow(2,0);LEDShow(3,0);LEDShow(4,1);LEDShow(5,0);LEDShow(6,6);LEDShow(7,0);LEDShow(8,6);}
}
http://www.xdnf.cn/news/940879.html

相关文章:

  • windows安装Nexus3.6
  • Vue3 + TypeSrcipt 防抖、防止重复点击实例
  • ES8 向量功能窥探系列(二):向量数据的存储与优化
  • Redis 知识点一
  • c# 完成恩尼格玛加密扩展
  • Java线程工厂:定制线程的利器
  • Java线程同步技术深度解析与实践
  • 使用自定义模板的方式批量切割图片。
  • 227.2018年蓝桥杯国赛 - 交换次数(中等)- 贪心
  • 百度首页布局:固定右侧盒子不随界面缩小掉下去
  • 深入解析 Qwen3-Embedding 的模型融合技术:球面线性插值(Slerp)的应用
  • 结合三维基因建模与智能体技术打造工业软件无码平台
  • Python 接口:从协议到抽象基 类(Tombola子类的测试方法)
  • C++核心编程_继承同名静态成员处理方式
  • Java常见异常处理指南:IndexOutOfBoundsException与ClassCastException深度解析
  • C++_核心编程_继承中构造和析构顺序
  • LLMs 系列科普文(6)
  • 第二十七章 位置参数
  • 算数运算符
  • 【阿里巴巴 x 浙江大学】信息与交互设计 - 交互设计概述
  • HNSW - 分层可导航小世界
  • Secs/Gem第十二讲(基于secs4net项目的ChatGpt介绍)
  • ServerTrust 并非唯一
  • Linux操作系统Shell脚本企业级综合练习
  • 2.1.3_2 编码和调制(下)
  • 面壁智能推出 MiniCPM 4.0 端侧大模型,引领端侧智能新变革
  • Python Day45 学习(日志Day13-14复习)
  • JLINK脚本初始化外部SDRAM STM32H7
  • 基于51单片机的红外防盗及万年历仿真
  • 2025-04-23-基于上下位机结构的系统实例分析