51单片机编程应用(C语言):数码管

目录

1.数码管原理

一位数码管引脚定义:

四位一体数码管:

多个数码管同时显示不同数字 

51单片机的数码管的原理图

51单片机实现静态显示和动态显示

静态显示:

 动态显示:


1.数码管原理

一位数码管引脚定义:

数码管是由8个LED组成的,其中共阴极数码管是8个LED共用一个阴极;共阳极数码管是8个LED共用一个阳极;每个数码管灯由图中左下角的8段LED构成,分别是ABCDEFG以及DP;正好和1个字节的8位相对应;从图中也可以看出,8段LED中,每段LED对应的引脚图,即每段LED和引脚之间的连接关系,基本是按照就近原则来连接的,比如A段,A段的正极连接3和8引脚(在共阳极数码管的情况下),A段的负极连接7号引脚;以此类推,其他引脚关系都可从图中看出来。

值得注意的是,我们开发板上的连接方式是共阴极连接。
如果想要使这个数码管显示数字“6”,该怎么操作呢?需要让A、F、E、D、C、G都亮起来即可。那么如何使A、F、E、D、C、G都点亮,其他的熄灭呢?参照上面的图可知,对于共阴极连接方式,首先3和8引脚都是要接地的(即负极、低电平、0);然后A、F、E、D、C、G都接正极(高电平,1),B和DP接负极,这样就能得到一个数字“6”,即A、B、C、D、E、F、G、DP设置为1011 1110;

下面为proteus仿真视频

proteus单个数码管仿真

实现9到0依次循环,代码如下 :

#include <REGX52.H>
void Delay(unsigned int xms)
{unsigned char i, j;while(xms--){i = 2;j = 239;do{while (--j);} while (--i);}
}
void main()	
{while(1){P2=0x6F;Delay(500);P2=0x7F;Delay(500);P2=0x07;Delay(500);P2=0x7D;Delay(500);P2=0x6D;Delay(500);P2=0x66;Delay(500);P2=0x4F;Delay(500);P2=0x5B;Delay(500);P2=0x06;Delay(500);P2=0x3F;Delay(500);}
}

因为我是P2-7接的是G,P2-6接的是F..........反过来的,所以根据上面的引脚图要反着来计算二进制的值。

四位一体数码管:

可以看到,以共阴极数码管为例,每个数码管共用阴极,但是四个数码管阳极所有的对应引脚都是连接同一个引脚;例如这四个数码管的A段LED都是连接在一起的,和11引脚相连;这四个数码管的B段LED都是连接在一起的,和7引脚相连。这样做的好处是节省单片机的引脚,如图中有4*8=32个LED段,但是只用12个引脚就可以了。
对于这种数码管,如果想让第三位数码管显示一个数字1,怎么操作?

因为是共阴极,所以12、9、8、6正常来讲都是负极才能点量对应的数码管。要想达到只第三个数码管显示1的目的:其中引脚12、9、6这三个阴极都置为1(高电平),这样第一、二、四个数码管就都不会亮;将引脚8设置为0(低电平),这样第三个数码管就有了电路连通的条件;然后再将B断和C段对应的引脚置为高电平,即7和4引脚置为1(高电平),此时就能第三个数码管中的B和C段对应的LED灯就亮了,其他段的灯不亮,即达到了只第三个数码管显示1的目的。

proteus仿真如下:

代码是P2=0x60;我这里P2.7接的是A,根据这两个例子,P2的值赋值是不是要看数码管的A,B,C,D.....与P2的8个引脚怎么接才行,这里P2.7接A,依次下去,亮一,就赋值P2=0x60。

比如P2.0接A,亮1就赋值0x06,所以一定要看自己的单片机原理图是如何接的,还要看是共阴极还是共阳极,

下面我就给出两种情况显示各个数字的值(小数点dp都不点亮)(共阴极数码管)

第一种:P2.0接A,依次接下去,(例如视频所示)

第二种:P2.7接A,依次接下去:(例如上面图所示) 

0  :  0xFE     1:     0x60         2:      0xDA       3:       0xF2        4: 0x66       5:         0xB6  

6   :   0xBE     7  :     0xD0       8:      0xFE       9:        

多个数码管同时显示不同数字 

 

关于上面讲到的,这四个数码管四个数码管阳极所有的对应引脚都是连接同一个引脚,这样导致的结果是,如果我们想让第二个数码管和第三个数码管同时点亮,且第二个和是第三个数码管显示不同的数字,是无法做到的,因为即使为了让第二个数码管亮而将9号引脚置为0,那么此时9和8引脚都为0,7和4引脚都为1,结果是第二个二极管和第三个二极管都显示数字1,无法达到显示不同数字的目的;所以因为四个二极管对应段LED都共用同一个引脚,导致的结果是只能显示同样的数字。

那么如何使不同的数码管显示不同的数字呢?这就是我们的目标2要实现的了,即动态数码管显示;利用的原理是人眼的视觉暂留和数码管显示的余晖原理;比如我们想达到让前三个数码管分别显示“1”“2”“3”的目的,经过上面的理论我们可以知道让三个数码管同时显示三个不同的数字是不可能的,但是我们可以让第一个数码管显示数字1,然后迅速的让第二个数码管显示数字2,然后迅速的让第三个数码管显示数字3,这要他们的间隔足够短,在我们视觉上看起来就像是同时在显示1、2、3一样。

#include <REGX52.H>//数码管段码表
unsigned char NixieTable[]={0xFC,0x60,0xDA,0xF2,0x66,0xB6,0xBE,0xD0,0xFE,0xF6};//延时子函数
void Delay(unsigned int xms)
{unsigned char i, j;while(xms--){i = 2;j = 239;do{while (--j);} while (--i);}
}//数码管显示子函数
void Nixie(unsigned char Location,Number)
{switch(Location)		//位码输出{case 1:P0_0=1;P0_1=1;P0_2=1;P0_3=1;break;//4个数码管都不选case 2:P0_0=1;P0_1=1;P0_2=1;P0_3=0;break;//选择第四个数码管case 3:P0_0=1;P0_1=1;P0_2=0;P0_3=1;break;//选择第三个数码管case 4:P0_0=1;P0_1=1;P0_2=0;P0_3=0;break;//选择第3和第4个数码管case 5:P0_0=1;P0_1=0;P0_2=1;P0_3=1;break;//选择第二个数码管case 6:P0_0=1;P0_1=0;P0_2=1;P0_3=0;break;//选择第2和第4个数码管case 7:P0_0=1;P0_1=0;P0_2=0;P0_3=1;break;//选择第2和第3个数码管case 8:P0_0=1;P0_1=0;P0_2=0;P0_3=0;break;//选择第2和第3和第4个数码管case 9:P0_0=0;P0_1=1;P0_2=1;P0_3=1;break;//选择第一个数码管case 10:P0_0=0;P0_1=1;P0_2=1;P0_3=0;break;//选择第1和第4个数码管case 11:P0_0=0;P0_1=1;P0_2=0;P0_3=1;break;//选择第1和第3个数码管case 12:P0_0=0;P0_1=1;P0_2=0;P0_3=0;break;//选择第1和第3和第4个数码管case 13:P0_0=0;P0_1=0;P0_2=1;P0_3=1;break;//选择 1 2 号数码管case 14:P0_0=0;P0_1=0;P0_2=1;P0_3=0;break;//选择1 2 4  号数码管case 15:P0_0=0;P0_1=0;P0_2=0;P0_3=1;break;//选择1 2 3 号数码管case 16:P0_0=0;P0_1=0;P0_2=0;P0_3=0;break;//四个数码管全选}P2=NixieTable[Number];	//段码输出Delay(1);				//显示一段时间P2=0x00;				//段码清0,消影
}void main()
{while(1){Nixie(9,1);		//在数码管的第1位置显示1
//		Delay(20);Nixie(5,2);		//在数码管的第2位置显示2
//		Delay(20);Nixie(3,3);		//在数码管的第3位置显示3
//		Delay(20);Nixie(2,0);	}
}

注意: 虽然我switch case 把所有的情况都列出来了,也就是位选的所有情况,但是,动态扫描时,一个数码管是显示一位数字,所以尽量要选择单个数码管,代码中的case9 5 3 2。如果你选中的是多个数码管,那么他只会显示相同的数字,而且,你选中多个数码管时,main语句时要注意不要重复选中相同的数码管,比如不能同时选择case7 8,否则会出错,下图所示是选择4个数码管一起亮,显示5:

 代码是:Nixie(16,5);

上面是用了C语言的数组,和switch case语句,调用函数,我们讲一下数组就OK了,switch case 还是很好理解的

 有了这些基础,我们看看51单片机的数码管的相关原理图

51单片机的数码管的原理图

 

显然,8个数码管的位选(选择哪一个数码管亮)由单片机3个引脚控制,这样的好处大大缩小了引脚的数量,不用每一个LED对应一个引脚。下面我们讲一讲38译码器电路。

38译码器是三个线到八个线的译码器;其实就是负责将三个输入A、B、C(P22-P24)转成八个输出Y0-Y7(也对应LED1-8);A、B、C三个输入值分别表示为三个二进制的数(C为高位,B为中位,A为低位,即数字组成为CBA),这三个输入值,转换成十进制,就对应他们的输出。

例如输入A为0,B为0,C为0,则输入为000,其对应的十进制值是0,即Y0有效,其他无效(低电平为有效,高电平位无效),所以Y0是0,Y1-Y7为1;

再例如,如果输入A为1,B为0,C为0,则输入为001(CBA,前面说了,C为高位,B为中位,A为低位),其对应的十进制为1,即Y1有效,其他无效(低电平为有效,高电平位无效),所以Y1是0,Y0和Y2-Y7为1;刚好对应我们的8个数码管,
以此类推。。。。

其真值表如下所示

有了这些知识,比如我们要选中第三个数码管亮,LED(1~8)的值是 

对应38译码器是不是 101  P2_4=1,P2_3=0,P2_2=1,即可

下面我们再来看数74HC245(双向据缓冲器)

根据原理图我们是不是知道,数码管的段选都与这个芯片连接,即晶体管的正极是接在74HC245(双向数据缓冲器)上的。为什么不直接接在CPU上呢?还要多此一举呢?

因为单片机的高电平驱动能力太弱,这个缓存器提高驱动能力。这样单片机的I/O口就变成了控制信号,不需要很高的电流驱动,把数据给了这个芯片之后,这个芯片有VCC给他供电,就很好的驱动数码管,亮度得到了保证。

DIR的高低电平决定了数据的流向;在74HC245中,如果将DIR,也就是LE(1引脚)设置为高电平,则表示数据流向为从左边到右边。由下图可知,A0对应B0,A1对应B1,以此类推;而B0-B7对应LCD0-7;

总结一下说就是,输入给P00-P07什么数据,该数据就原封不动的送给LCD0-LCD7。 

电容的作用:给VCC滤波,稳定电源,确保电路稳定性。提高电路工作性能。

电阻:限流

  74HC245作用:双向的数据缓冲 

51单片机实现静态显示和动态显示

静态显示:

第二个数码管显示5

第一步是选择使哪个晶体管点亮:即要让目标点亮的等负极有效,而负极是接在138译码器上的,138译码器的8输出连接着静态数码管的负极,138译码器的3个输入连接着MCU的引脚(P22-P24口);所以我们要通过对P22-P24口的设置,来控制目标晶体管负极有效。

第二步是设置该目标点亮的晶体管具体显示什么数字;即通过对正极引脚的设置,控制具体LED的8段LED哪几段点亮,用以生成目标数字。晶体管的正极是由74HC245的P00-P07等8个引脚来输入的;

总结:

  • 第一步,选择哪个晶体管点亮,控制引脚为P22-P24;
  • 第二步,选择具体点亮的数字,控制引脚为P00-P07;
#include <REGX52.H>void main()	
{while(1){P2_2=0;P2_3=1;P2_4=0;P0_0=1;P0_1=0;P0_2=1;P0_3=1;P0_4=1;P0_5=1;P0_6=1;P0_7=0;}
}

最后,我们可以对代码进行完善,写一个函数,两个入参分别为:第一个参数为第几个等亮,第二个参数为显示什么数字,这样就能通过调用该函数时,传入参数的不同,控制不同的灯显示不同的数字,代码如下: 

#include <REGX52.H>//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//数码管显示子函数
//Location表示第几个数码管点亮;Number表示该数码管显示什么数字
void Nixie(unsigned char Location,Number)
{switch(Location)		//位码输出{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=NixieTable[Number];	//段码输出
}void main()
{Nixie(2,5);	//在数码管的第3位置显示数字6while(1){}
}

 动态显示:

实现动态数码管的方法和代码,即如果想让第一个数码管显示1,第二个数码管显示2,第三个数码管显示3,且让他们同时显示;方法就是先让第一个显示1,然后立马让第二个显示2,再立马让第三个显示3;只要他们之间的间隔足够短,在我们视觉效果上看来就是在同时显示。

代码如下

#include <REGX52.H>//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};//延时子函数
void Delay(unsigned int xms)
{unsigned char i, j;while(xms--){i = 2;j = 239;do{while (--j);} while (--i);}
}//数码管显示子函数
void Nixie(unsigned char Location,Number)
{switch(Location)		//位码输出{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=NixieTable[Number];	//段码输出Delay(1);				//显示一段时间P0=0x00;				//段码清0,消影
}void main()
{while(1){Nixie(1,1);		//在数码管的第1位置显示1
//		Delay(20);Nixie(2,2);		//在数码管的第2位置显示2
//		Delay(20);Nixie(3,3);		//在数码管的第3位置显示3
//		Delay(20);}
}

其中的P0=0x00;表示每次循环结束时都将所有的数码管进行清零,即全部熄灭,免得留下灯的残影。

 

 

 

 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/661249.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

外包干了10个月,技术退步明显...

先说一下自己的情况&#xff0c;大专生&#xff0c;18年通过校招进入武汉某软件公司&#xff0c;干了接近4年的功能测试&#xff0c;今年年初&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落! 而我已经在一个企业干了四年的功能测…

【代码随想录】LC 349. 两个数组的交集

文章目录 前言一、题目1、原题链接2、题目描述 二、解题报告1、思路分析2、时间复杂度3、代码详解 前言 本专栏文章为《代码随想录》书籍的刷题题解以及读书笔记&#xff0c;如有侵权&#xff0c;立即删除。 一、题目 1、原题链接 349. 两个数组的交集 2、题目描述 二、解题报…

C语言实战项目<贪吃蛇>

我们这篇会使用C语言在Windows环境的控制台中模拟实现经典小游戏贪吃蛇 实现基本的功能&#xff1a; 结果如下: 1.一些Win32 API知识 本次实现呢我们会用到一些Win32 API的知识(WIN32 API也就是Microsoft Windows 32位平台的应用程序编程接口): 1)控制窗口大小 我们可以使用…

【Qt学习笔记】(二)信号和槽

信号和槽 1 信号和槽概述2 信号和槽的使用3 可视化生成槽函数4 自定义信号和槽5 带参数的信号和槽6 信号与槽的连接方式7 信号与槽的断开8 使用 Lambda 表达式来定义槽函数 1 信号和槽概述 在Qt中&#xff0c;用户和控件的每次交互过程称为一个事件。比如"用户点击按钮&q…

实时时钟芯片DS1307单片机C语言驱动程序

实时时钟RTC相关索引 1.单片机RTC及时钟芯片的时间到底从哪一年起始&#xff1f; 2.STM32F103单片机内部RTC实时时钟驱动程序 3.实时时钟芯片DS1302单片机C语言驱动程序 4.实时时钟芯片DS1307单片机C语言驱动程序 一、DS1307简介 DS1307是一款非易失性实时时钟&#xff08;R…

【Java程序设计】【C00209】基于SSM个人求职管理系统(论文+PPT)

基于SSM个人求职管理系统&#xff08;论文PPT&#xff09; 项目简介项目获取开发环境项目技术运行截图 项目简介 这个一个基于SSM的个人求职管理系统&#xff0c;本系统共分为三种权限&#xff1a;管理员、普通管理员、用户 管理员&#xff1a;首页、个人中心、用户管理、管理…

go并发编程-介绍与Goroutine使用

1. 并发介绍 进程和线程 A. 进程是程序在操作系统中的一次执行过程&#xff0c;系统进行资源分配和调度的一个独立单位。B. 线程是进程的一个执行实体,是CPU调度和分派的基本单位,它是比进程更小的能独立运行的基本单位。C.一个进程可以创建和撤销多个线程;同一个进程中的多个…

Go语言的100个错误使用场景(11-20)|项目组织和数据类型

前言 大家好&#xff0c;这里是白泽。 《Go语言的100个错误以及如何避免》 是最近朋友推荐我阅读的书籍&#xff0c;我初步浏览之后&#xff0c;大为惊喜。就像这书中第一章的标题说到的&#xff1a;“Go: Simple to learn but hard to master”&#xff0c;整本书通过分析100…

DevSecOps 参考模型介绍

目录 一、参考模型概述 1.1 概述 二、参考模型分类 2.1 DevOps 组织型模型 2.1.1 DevOps 关键特性 2.1.1.1 模型特性图 2.1.1.2 特性讲解 2.1.1.2.1 自动化 2.1.1.2.2 多边协作 2.1.1.2.3 持续集成 2.1.1.2.4 配置管理 2.1.2 DevOps 生命周期 2.1.2.1 研发过程划分…

leetcode刷题(剑指offer)54.螺旋矩阵

54.螺旋矩阵 给你一个 m 行 n 列的矩阵 matrix &#xff0c;请按照 顺时针螺旋顺序 &#xff0c;返回矩阵中的所有元素。 示例 1&#xff1a; 输入&#xff1a;matrix [[1,2,3],[4,5,6],[7,8,9]] 输出&#xff1a;[1,2,3,6,9,8,7,4,5]示例 2&#xff1a; 输入&#xff1a;ma…

Java基础-集合框架

集合框架&#xff1a; 内存层面可考虑的数据存储容器&#xff1a;数组&#xff0c;集合 数组的特点&#xff1a;长度&#xff0c;存储元素类型确定&#xff0c;既可以放基本数据类型&#xff0c;也可以放引用数据类型 缺点&#xff1a;长度不可变&#xff0c;存储元素特点单…

从零开始 Linux(一):基础介绍与常用指令总结

从零开始 Linux 01. 概念理解 1.1 什么是 Linux&#xff1f; Linux 是一个开源免费的 操作系统&#xff0c;具有很好的稳定性、安全性&#xff0c;且有很强的处理高并发的能力 Linux 的应用场景&#xff1a; 可以在 Linux 下开发项目&#xff0c;比如 JavaEE、大数据、Python…

3D词云图

工具库 tagcanvas.min.js vue3&#xff08;框架其实无所谓&#xff0c;都可以&#xff09; 实现 <script setup> import { onMounted, ref } from vue; import ./tagcanvas.min.js;const updateFlag ref(false);// 词云图初始化 const initWordCloud () > {let …

RabbitMQ快速实战

目录 什么是消息队列&#xff1f; 消息队列的优势 应用解耦 异步提速 削峰填谷 总结 主流MQ产品特点比较 Rabbitmq快速上手 创建用户admin Exchange和Queue Connection和Channel RabbitMQ中的核心概念总结 什么是消息队列&#xff1f; MQ全称Message Queue&#xf…

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入)

Spring5深入浅出篇:Spring中ioc(控制反转)与DI(依赖注入) 反转(转移)控制(IOC Inverse of Control) 控制&#xff1a;对于成员变量赋值的控制权 反转控制&#xff1a;把对于成员变量赋值的控制权&#xff0c;从代码中反转(转移)到Spring⼯⼚和配置⽂件中完成好处&#xff1a;…

七、并发工具(上)

一、自定义线程池 1&#xff09;背景&#xff1a; 在 QPS 量比较高的情况下&#xff0c;我们不可能说所有的访问都创建一个线程执行&#xff0c;这会导致内存占用过高&#xff0c;甚至有可能出现 out of memory另外也要考虑 cpu 核数&#xff0c;如果请求超过了cpu核数&#…

【bitonicSort学习】

bitonicSort学习 什么是Bitonic Sort核心 什么是Bitonic Sort https://zhuanlan.zhihu.com/p/53963918 这个是用来并行排序的一个操作 之前学过一些CPU排序&#xff0c;快排 冒泡 归并啥的&#xff0c;有一些能转成并行&#xff0c;有一些不适合 像快排这种二分策略就可以考虑…

Vue3的自定义指令怎么迁移到nuxt3

一、找到Vue3中指令的源码 const DISTANCE 100; // 距离 const ANIMATIONTIME 500; // 500毫秒 let distance: number | null null,animationtime: number | null null; const map new WeakMap(); const ob new IntersectionObserver((entries) > {for (const entrie…

草图导入3d后模型贴材质的步骤?---模大狮模型网

3D模型在导入草图大师后出现混乱可能有多种原因&#xff0c;以下是一些可能的原因和解决方法&#xff1a; 模型尺寸问题&#xff1a;如果3D模型的尺寸在导入草图大师时与画布尺寸不匹配&#xff0c;可能导致模型混乱。解决方法是在3D建模软件中调整模型的尺寸&#xff0c;使其适…

FreeRTOS使用计数信号量进行任务同步与资源管理

FreeRTOS使用计数信号量进行任务同步与资源管理 介绍 在多任务系统中&#xff0c;任务之间的同步和对共享资源的管理是非常重要的。FreeRTOS 提供了丰富的同步机制&#xff0c;其中计数信号量是一种强大的工具&#xff0c;用于实现任务之间的同步和对资源的访问控制。 什么是…