第五节 七段数码管的使用.docx
- 文档编号:4413689
- 上传时间:2022-12-01
- 格式:DOCX
- 页数:22
- 大小:264.26KB
第五节 七段数码管的使用.docx
《第五节 七段数码管的使用.docx》由会员分享,可在线阅读,更多相关《第五节 七段数码管的使用.docx(22页珍藏版)》请在冰豆网上搜索。
第五节七段数码管的使用
第五节数码管的使用
5.1数码管简介
同学们!
相信你的流水灯也做的不错了吧,现在能玩出几种花样了?
但是工程师们设计这么一个单片机,并不是只为了让它做流水灯的,那样也太浪费点了吧...^_^ 。
数码管的一种是半导体发光器件,7段LED数码管是利用7个LED(发光二极管)外加一个小数点的LED组合而成的显示设备,可以显示0~9等10个数字和小数点,使用非常广泛,数码管可以分为一位和多位它的外观如图5-1所示。
图5-1
5.2数码管的显示原理
数码管可以分为共阳极与共阴极两种,共阳极就是把所有LED的阳极连接到共同接点com,使用时com接正5伏电源,而每个LED的阴极分别为a、b、c、d、e、f、g及dp(小数点);共阴极则是把所有LED的阴极连接到共同接点com,使用时com要将其接地。
而每个LED的阳极分别为a、b、c、d、e、f、g及dp(小数点),8个LED的分布方式如图5-2所示。
图中的8个LED分别与上面那个图中的A~DP各段相对应,通过控制各个LED的亮灭来显示数字。
那么,实际的数码管的引脚是怎样排列的呢?
对于单个数码管来说,从它的正面看进去,左下角那个脚为1脚,以逆时针方向依次为1~10脚,左上角那个脚便是10脚了,上面两个图中的数字分别与这10个管脚一一对应。
注意,3脚和8脚是连通的,这两个都是公共脚。
它对应的引脚分布为图5-3所示。
图5-2图5-3
数码管的8段,对应一个字节的8位,a对应最低位,dp(小数点)对应最高位。
所以如果想让数码管显示数字0,那么共阴数码管的字符编码为00111111,即0x3f;共阳数码管的字符编码为11000000,即0xc0。
可以看出两个编码的各位正好相反。
如图5-4所示。
图5-4
那么,一位数码管要显示字符0~F,则对应的编码如表2所示。
一个八段数码管称为一位,多个数码管并列在一起可构成多位数码管,它们的段选线(即a,b,c,d,e,f,g,dp)连在一起,而各自的公共端称为位选线。
显示时,都从段选线送入字符编码,而选中哪个位选线,那个数码管便会被点亮。
5.3一位数码管的显示
请实现:
让一位数码管依次显示字符0~F,每个字符显示1秒,如此反复。
一般情况下,为了计算或取码的方便,我们把a-dp依次接到单片机某个口上的Px.0--Px.7上。
x表示0,1,2,3其中的一个。
这样我们只要给某个口,赋一个值,则相应的LED段就被点亮,但是在硬件连接上要注意了:
单片机可能不能直接驱动LED,所以我们可以通过控制三级管的导通或截止,或者使用共阳极数码管(以灌电流的方式)、或者使用锁存器来驱动。
来控制LED的亮与灭!
5.3.1硬件的选择与仿真电路的设计
1.打开Proteus,选择“File/NewDesign”菜单选项,新建一个“设计项目”。
并将项目保存为“SEG7_1”。
2.选择“P”按钮或菜单“Library/PickDivice/Symbol…P”菜单,从“元件库”中选取元件。
依次添加其他元件。
其名称和位置见下表。
元件名称
Category
Sub-Category
Results
AT89C52
MicroprocessorICs
8051Family
AT89C52
7SEG-MPX1-CA(注1)
Optoelectronics
7-SegmentDisplays
7SEG-MPX1-CA
RX8(注2)
Resistors
ResistorPacks
RX8
RESPACK-8(注3)
Resistors
ResistorPacks
RESPACK-8
注1:
7SEG表示7段数码管(Proteus还提供了14段和16段数码管)
MPX1表示1位(Proteus还提供了2位、4位、6位和8位数码管)
CA表示共阳极(CC表示共阴极)
注2:
RX8表示电阻排,它实际相当于8个电阻并排摆放在一个容器内。
在这里是作为限流电阻来使用的。
注3:
RESPACK-8表示电阻排,它实际相当于8个电阻并排摆放在一个容器内,但是这8个电阻的一段是连接在一起作为公共端的。
在这里是作为P0口的上拉电阻来使用的。
依次从备选元件库中摆放器件,连线,画出仿真电路图,如图5-5所示。
图5-5
注意:
在Proteus中,实际上,51单片机是不需要晶振、复位电路和电源就可以仿真的,因此,为了方便我们教学,以后,我们将不再画上述51的外围电路。
5.3.2程序的设计
1.新建一个keil项目,并命名为“SEG7_1”并添加一个名为“main.c”的源代码文件,然后键入如下代码。
如代码5.1所示。
//代码5.1
#include
#defineSegPortP0//定义数码管连接的端口
#defineucharunsignedchar//宏定义将unsignedchar替换为较为简单的uchar写法
#defineuintunsignedint//宏定义将unsignedint替换为较为简单的uint写法
//用一个数组来定义字符0~f共阳极数码管编码
ucharcodeseg7ca[]={
0xc0,0xf9,0xa4,0xb0,//0~3
0x99,0x92,0x82,0xf8,//4~7
0x80,0x90,0x88,0x83,//8~b
0xc6,0xa1,0x86,0x8e//c~f
};
//延时函数ms毫秒
voidDelayMs(uintms)
{
uinti,j;
for(i=0;i { for(j=0;j<124;j++); } } voidmain() { while (1)//无限大循环 { //这段代码将字符0~F轮流显示一遍,每个字符显示1秒 uchari=0;//从数组第一个元素开始显示 for(i=0;i<16;i++) { SegPort=seg7ca[i];//按次序显示字符0~F DelayMs(1000);//延时1秒 } } ●知识点: 数组seg7ca[]的定义 格式: 数据类型(数组位置)数组名称[]={数组元素1,数组元素2,……}; ●知识点: code关键字 “code”是C51所定义的关键字,他的含义是定义将代码放在ROM中,由于51的RAM很小,因此,为了节约有限的RAM,我们通常会把一些不会变化的数据(比如数码管的编码、参数表等等)放在ROM中,这样,我们就可以多空出一些RAM供程序来使用。 那么怎样把这些常量放在ROM中呢,即给定义语句前添加一个“code”关键字,告诉编译器,这些常量要放在ROM中,如果没有添加“code”,那么这些编码就会放在RAM中。 同学们可以通过删除“code”关键字,重新build程序,然后查看程序占用RAM的大小,来验证“code” 关键字的作用。 ●知识点: 数组元素的访问 数组元素是通过他的序号来访问的。 例如数组 seg7ca[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e}一共有16个元素,其中0xc0的序号为0(请记住,数组中的第一个元素序号为0),0xf9的序号为1,……,0x8e的序号为15,以此类推。 那么当我们想要使用0xc0时,我们可以使用“seg7ca[0]”这种方式。 因此,代码“SegPort=seg7ca[i]”;//按次序显示字符0~F ●程序代码说明 uchari=0;//从数组第一个元素开始显示 for(i=0;i<16;i++) { SegPort=seg7ca[i];//按次序显示字符0~F DelayMs(1000);//延时1秒 } 这段代码将字符0~F轮流显示一遍,每个字符显示1秒 当for循环开始时,i=0,因此,SegPort=seg7ca[0]; 由于SegPort是P0,seg7ca[0]=0xc0,因此,P0=0xc0,即P0口送出0xc0,由于0xc0是共阳极数码管字符“0”的编码,因此,数码管显示字符“0”。 当for第二次循环时,i=1,因此,SegPort=seg7ca[1]; 即,P0=0xf9,即P0口送出0xf9,由于0xf9是共阳极数码管字符“1”的编码,因此,数码管显示字符“1”。 以此类推,随着for循环,P0口送出数组seg7ca所定义的16个元素,从而在数码管上显示对应的十六个字符。 5.4多位数码管的显示 想必大家已经可以把0-F显示出来了吧! 但是如果要你显示两位数,三位数呢? 让我们实现如下功能: 让两位数码管显示数字“15”。 或许,有的朋友会这么想: 在P0口上接一个数码管,再在P1口上接个数码管! 但是,如果要显示4位、5位的数字呢? 那岂不是一块AT8951都接不过来! 难到就不能接4位或5位以上的吗? 肯定不是的! 说到这里,我们来讲讲数码管的显示方式,可分为两种: 动态扫描和静态显示。 上面我们所说的即为静态显示。 但是如果我们采用动态扫描显示,那么就可以解决上面的问题,动态扫描是指每隔一段时间循环点亮每个数码管,每次只有一个数码管被点亮。 细心的朋友会问这样的问题: 是让数码管一个一个亮,那还是不能控制数码管一起亮或灭嘛! 怎么解决? 其实,人的眼睛有视觉暂留效应,黑夜里,拿着一支烟,在你面前快速的晃动,你会发现什么样的现象? 是不是原本不连续的点变成了一条看上去连续的曲线或者直线! 再回过头来,仔细想想我们的数码管! 原理是一样的,只要我们快速的循环显示每个数码管,人的眼睛看起来就好像是它们同时被点亮了,关键是速度。 比如点亮6位数码管,硬件连接可以这样解决: a--dp还是接至P0.0--P0.7上,还有6个COM脚再接至另外口的P2.0--P2.5。 P0口作段选(控制数字字符),P2口作位选(选通哪个数码管被点亮)这样我们控制P0和P2口就可以控制6个数码管了。 5.4.1硬件的选择与仿真电路的设计 1.打开Proteus,选择“File/NewDesign”菜单选项,新建一个“设计项目”。 并将项目保存为“SEG7_2”。 2.选择“P”按钮或菜单“Library/PickDivice/Symbol…P”菜单,从“元件库”中选取元件。 依次添加其他元件。 其名称和位置见下表。 元件名称 Category Sub-Category Results AT89C52 MicroprocessorICs 8051Family AT89C52 7SEG-MPX2-CC(注1) Optoelectronics 7-SegmentDisplays 7SEG-MPX2-CC RX8 Resistors ResistorPacks RX8 RESPACK-8 Resistors ResistorPacks RESPACK-8 74HC573(注2) TTL74HCseries Flip-Flops&latches 74HC573 注1: 7SEG表示7段数码管、MPX2表示2位、CC表示共阴极(CC表示共极) 注2: 74HC573是一个8位锁存器,在这里主要是提供锁存和驱动功能。 依次从备选元件库中摆放器件,连线,画出仿真电路图,如图5-6所示。 图5-6 1.连线的标号连接法: 由于某些连线不太方便直接连接,或者由于美观原因,我们可以采用标号连接。 例如,我们想将51的P1.2引脚和74HC573的“LE”引脚相连,方法如下: (1)先将51的P1.2引脚和74HC573的“LE”引脚各用鼠标延长一段。 (2)点击Proteus侧边工具栏的“LBL(WireLabelMode)”按钮,如图5-7所示。 图5-7图5-8 (3)将鼠标移动到51的P1.2引脚点一下,出现如下“EditWireLabel”窗口,在“EditWireLabel”窗口的“string”编辑框中填入该引脚的名称,比如“P12”,然后点击“OK”。 如果5-8所示。 (4)再将将鼠标移动到74HC573的“LE”引脚点一下,再在“EditWireLabel”窗口的“string”编辑框中填入该相同的名称,比如“P12”,然后点击“OK”。 (5)这样,引脚标号相同的引脚就会被物理的连接在一起了。 2.74HC573的使用 74HC573为8位3态非反转透明锁存器。 数据从D0~D7引脚输入,从Q0~Q7引脚输出。 他的真值表如图5-9所示。 图5-9 OE为输出使能端,低电平有效,当OE为高电平时,D和Q不通,即所谓的输出高阻态。 LE为锁存端,当LE为高电平时,D和Q是直通的,当LE为低电平时,不管D端输入是什么,Q端保持上一次的输出,即开启锁存功能。 3.电路说明 因为我们使用了两位数码管,因此,我们需要轮流点亮数码管的各位和十位。 由于数码管是共阴极的,因此,我们需要在P0口送出数码管共阴极的编码,同时,给要点亮数码管位选线一个低电平,由于51的驱动能力不足以直接驱动数码管,因此,我们通过74HC573这个锁存器来驱动,它的输出电流足够大,能够很好的驱动数码管发光。 5.4.2程序的设计 1.新建一个keil项目,并命名为“SEG7_2”并添加一个名为“main.c”的源代码文件,然后键入如下代码。 如代码5.2所示。 代码5.2 #include #defineSegPortP0//定义数码管连接的端口 #defineucharunsignedchar//宏定义将unsignedchar替换为较为简单的uchar写法 #defineuintunsignedint//宏定义将unsignedint替换为较为简单的uint写法 //用一个数组来定义字符0~f共阴极数码管编码 ucharcodeseg7cc[]= { 0x3f,0x06,0x5b,0x4f,//0~3 0x66,0x6d,0x7d,0x07,//4~7 0x7f,0x6f,0x77,0x7c,//8~b 0x39,0x5e,0x79,0x71//c~f }; sbitGeWei=P1^1;//定义数码管个位的位选线 sbitShiWei=P1^0;//定义数码管十位的位选线 sbitle573=P1^2;//定义573LE引脚的位选线 //延时函数ms毫秒 voidDelayMs(uintms) { uinti,j; for(i=0;i { for(j=0;j<124;j++); } } voidmain() { GeWei=1;//先将数码管个位显示关闭 ShiWei=1;//先将数码管十位显示关闭 while (1)//无限大循环 { le573=1;//将锁存器设置为直通模式 SegPort=seg7cc[5];//将‘5’的编码送出 GeWei=0;//先显示个位,将十位关闭 le573=0;//将锁存器设置为锁存模式 DelayMs (1); GeWei=1; ShiWei=1;//消隐操作,防止数码管闪烁 le573=1;//将锁存器设置为直通模式 SegPort=seg7cc[1];//将‘1’的编码送出 ShiWei=0;//再显示十位,将个位关闭 le573=0;//将锁存器设置为锁存模式 DelayMs (1); GeWei=1; ShiWei=1;//消隐操作,防止数码管闪烁 } } ●程序代码说明 1.初始化 GeWei=1;//先将数码管个位显示关闭 ShiWei=1;//先将数码管十位显示关闭 通过这两行代码将数码管的个位和十位位选线都置为高电平,对于共阴极数码管来讲,那么个位和十位都不能显示了,即先将两位都关闭。 2.我们现在想让个位数码管显示字符“5”,我们需要做的是: (1)LE引脚拉高,使74HC573进入直通模式。 (2)P0口送出字符“5”共阴极编码“0x6d” (3)GeWei(即P1.1)引脚送出低电平,选中数码管个位,此时数码管个位显示字符“5”。 (4)LE引脚拉低,使74HC573进入锁存模式,此时,74HC573的Q端始终保持输出“0x6d”,则数码管个位始终保持显示字符“5” 把上述伪代码翻译为C51代码就是: le573=1;//将锁存器设置为直通模式 SegPort=seg7cc[5];//将‘5’的编码送出 GeWei=0;//先显示个位,将十位关闭 le573=0;//将锁存器设置为锁存模式 3.消隐操作 为了防止数码管闪烁,我们需要消隐操作,即将两位数码管都关闭,代码如下: DelayMs (1); GeWei=1; ShiWei=1;//消隐操作,防止数码管闪烁 4.我们再用相同的方法让十位数码管显示字符“1”。 5.通过循环操作,使两位数码管快速轮流显示字符“1”和“5”,由于视觉暂留效应,我们看到的就是字符“1”和“5”同时显示出来了。 5.5多位数码管显示秒数据 让我们实现如下功能: 让两位数码管依次显示数字“00~59”,每个数字显示1秒,显示完59后,回到00,如此反复。 5.5.1实现原理分析 1.我们使用一个变量second表示当前的秒数,让second从0开始,每隔一秒钟加1,当second增加到59时,让它回到0,重新开始。 这样,second就在0~59之间反复变化。 2.从second中拆分出它的个位和十位呢? 我们可以使用以下方法。 提取个位: tmp=second%10;//例如second=45,second%10=5 提取十位: tmp=second/10;//例如second=45,second/10=4 3.我们让数码管的个位显示second的个位,数码管的十位显示second的十位。 5.5.2硬件电路的设计 不变。 5.5.3程序的设计 1.新建一个keil项目,并命名为“SEG7_3”并添加一个名为“main.c”的源代码文件,然后键入如下代码。 如代码5.3所示。 //代码5.3 #include #include"commmon.h"//包含#defineucharunsignedchar等定义 #include"function.h"//包含DelayMs函数 #defineSegPortP0//定义数码管连接的端口 sbitGeWei=P1^1;//定义数码管个位的位选线 sbitShiWei=P1^0;//定义数码管十位的位选线 sbitle573=P1^2;//定义573LE引脚的位选线 //用一个数组来定义字符0~f共阴极数码管编码 unsignedcharcodeseg7cc[]= { 0x3f,0x06,0x5b,0x4f,//0~3 0x66,0x6d,0x7d,0x07,//4~7 0x7f,0x6f,0x77,0x7c,//8~b 0x39,0x5e,0x79,0x71//c~f }; voidmain() { uchartmp,second;//second为当前的秒数 GeWei=1;//先将数码管个位显示关闭 ShiWei=1;//先将数码管十位显示关闭 second=0;//second将从0开始增加 while (1)//无限大循环 { tmp=second%10;//提取个位数 le573=1;//将锁存器设置为直通模式 SegPort=seg7cc[tmp];//将‘second’个位的编码送出 GeWei=0;//先显示个位,将十位关闭 le573=0;//将锁存器设置为锁存模式 DelayMs(500); GeWei=1; ShiWei=1;//消隐操作,防止数码管闪烁 tmp=second/10;//提取十位数 le573=1;//将锁存器设置为直通模式 SegPort=seg7cc[tmp];//将‘second’十位的编码送出 ShiWei=0;//再显示十位,将个位关闭 le573=0;//将锁存器设置为锁存模式 DelayMs(500);//延时500毫秒,连同前面延时的500毫秒,刚好是1秒 GeWei=1; ShiWei=1;//消隐操作,防止数码管闪烁 if(second<59)//second增加到59后,将重新从0开始增加 second++; else second=0; } } ●程序代码说明 1.让second就在0~59之间反复变化。 代码如下: if(second<59)//second增加到59后,将重新从0开始增加 second++; else second=0; 2.从second中拆分出它的个位和十位。 提取个位: tmp=second%10;//例如second=45,second%10=5 提取十位: tmp=second/10;//例如second=45,second/10=4 3.我们让数码管的个位显示second的个位,数码管的十位显示second的十位。 SegPort=seg7cc[tmp];//将‘second’个位的编码送出 SegPort=seg7cc[tmp];//将‘second’十位的编码送出 4.second每隔一秒钟加1 我们使用两次DelayMs(500),则总的延时时间就是1秒 ●实际代码执行的效果 我们看到,实际代码执行的效果其实不太理想,秒数的显示不是同时显示出来的,问题出在哪里呢? 其实,问题出在second的增加和数码管扫描的速度要求不一致。 second增加的速度要求很慢,1秒钟增加一次,而数码管扫描要求速度很快,几毫秒就要动态显示一遍。 而我们在一个程序序列中是无法同时满足这个快速和慢速两个要求的。 5.6多位数码管显示秒数据改进版(定时器的使用) 5.6.1实现原理分析 1.如果我们能使用一个方法使second值1秒钟增加一次,同时能让数码管很快的动态显示,那么就能解决我们的问题了。 使用什么方法呢,答案就是使用定时器。 定时器可以实现在一定的时间间隔重复执行某个任务。 例如,我们想每隔1秒执行一次second值加1的操作,我们就应该使用定时器。 51单片机内部有两个定时器(52有三个),即T0和T1。 2.我们在主程序循环中做快速的数码管动态扫描,同时在定时器中断中做second每秒加1的操作就可以了。 ●知识点: 定时器中断 什么是中断呢? 讲个比较通俗的例子: 比如你正在家中看电视,突然电话响了,你的第一反应是什么? 是不是先跑过去接电话! 接完电话后,继续看电视。 这就是个中断的例子,电话打断了你看电视这件事(所以叫做中断源),你跑过去就是响应中断,接电话就是中断的处
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 第五节 七段数码管的使用 五节 数码管 使用