数码管程序Word文件下载.docx
- 文档编号:20420905
- 上传时间:2023-01-22
- 格式:DOCX
- 页数:9
- 大小:112.65KB
数码管程序Word文件下载.docx
《数码管程序Word文件下载.docx》由会员分享,可在线阅读,更多相关《数码管程序Word文件下载.docx(9页珍藏版)》请在冰豆网上搜索。
for(num=0;
num<
9;
num++)
{
P0=table[num];
P2=code[num];
delayms
(2);
}
}
看出什么问题来了没有,如果没有看出来请仔细想一下,如果还没有想出来,请回过头去,认真再看一遍“学会释放CPU”这一章的内容。
这个程序作为演示程序是没有什么问题的,但是实际应用的时候,数码管显示的内容经常变化,而且还有很多其它任务需要执行,因此这样的程序在实际中是根本就无法用的,更何况,它这里也调用了delayms
(2)这个函数来延时2ms这更是令我们深恶痛绝
本章的内容正是探讨如何解决多任务环境下(不带OS)的数码管程序设计的编写问题。
理解了其中的思想,无论要求我们显示的形式怎么变化(如数码管闪烁,移位等),我们都可以很方便的解决问题。
数码管的显示分为动态显示和静态显示两种。
静态显示是每一位数码管都用一片独立的驱动芯片进行驱动。
比较常见的有74LS164,74HC595等。
利用这类芯片的好处就是可以级联,留给单片机的接口只需要时钟线,数据线,因此比较节省I/O口。
如下图所示:
图片:
74hc164级联数码管.jpg
利用74LS164级联驱动8个单独的数码管
静态显示的优点是程序编写简单。
但是由于涉及到的驱动芯片数量比较多,同时考虑到PCB的布线等等因素,在低成本要求的开发环境下,单纯的静态驱动并不合适。
这个时候就可以考虑到动态驱动了。
动态驱动的图如下所示(以EE21开发板为例)
动态驱动数码管硬件图.jpg
由上图可以看出。
8个数码管的段码由一个单独的74HC573驱动。
同时每一个数码管的公共端连接在另外一个74HC573的输出上。
当送出第一位数码管的段码内容时候,同时选通第一位数码管的位选,此时,第一位数码管就显示出相应的内容了。
一段时间之后,送出第二位数码管段码的内容,选通第二位数码管的位选,这时显示的内容就变成第二位数码管的内容了……依次循环下去,就可以看到了所有数码管同时显示了。
事实上,任意时刻,只有一位数码管是被点亮的。
由于人眼的视觉暂留效应以及数码管的余辉效应,当数码管扫描的频率非常快的时候,人眼已经无法分辨出数码管的变化了,看起来就是同时点亮的。
我们假设数码管的扫描频率为50Hz,则完成一轮扫描的时间就是1/50=20ms。
我们的系统共有8位数码管,则每一位数码管在一轮扫描周期中点亮的时间为20/8=2.5ms。
动态扫描对时间要求有一点点严格,否则,就会有明显的闪烁。
假设我们程序中所有任务如下:
while
(1)
{
LedDisplay();
//数码管动态扫描
ADProcess();
//AD采集处理
TimerProcess();
//时间相关处理
DataProcess();
//数据处理
LedDisplay()这个任务的执行时间,如同我们刚才计算的那样,50Hz频率扫描,则该函数执行的时间为20ms。
假设ADProcess()这个任务执行的的时间为2ms,TimerProcess()这个函数执行的时间为1ms,DataProcess()这个函数执行的时间为10ms。
那么整个主函数执行一遍的总时间为20+2+1+10=33ms。
即LedDisplay()这个函数的扫描频率已经不为50Hz了,而是1/33=30.3Hz。
这个频率数码管已经可以感觉到闪烁了,因此不符合我们的要求。
为什么会出现这种情况呢?
我们刚才计算的50Hz是系统只有LedDisplay()这一个任务的时候得出来的结果。
当系统添加了其它任务后,当然系统循环执行一次的总时间就增加了。
如何解决这种现象了,还是离不开我们第二章所讲的那个思想。
系统产生一个2.5ms的时标消息。
LedDisplay(),每次接收到这个消息的时候,扫描一位数码管。
这样8个时标消息过后,所有的数码管就都被扫描一遍了。
可能有朋友会有这样的疑问:
ADProcess()以及DataProcess()等函数执行的时间还是需要十几ms啊,在这十几ms的时间里,已经产生好几个2.5ms的时标消息了,这样岂不是漏掉了扫描,显示起来还是会闪烁。
能够想到这一点,很不错,这也就是为什么我们要学会释放CPU的原因。
对于ADProcess(),TimerProcess(),DataProcess(),等任务我们依旧要采取此方法对CPU进行释放,使其执行的时间尽可能短暂,关于如何做到这一点,在以后的讲解如何设计多任务程序设计的时候会讲解到。
下面我们基于此思路开始编写具体的程序。
首先编写Timer.c文件。
该文件中主要为系统提供时间相关的服务。
必要的头文件包含。
#include<
reg52.h>
#include"
MacroAndConst.h"
为了方便计算,我们取数码管扫描一位的时间为2ms。
设置定时器0为2ms中断一次。
同时声明一个位变量,作为2ms时标消息的标志
bitg_bSystemTime2Ms=0;
//2msLED动态扫描时标消息
初始化定时器0
voidTimer0Init(void)
TMOD&
=0xf0;
TMOD|=0x01;
//定时器0工作方式1
TH0
=
0xf8;
//定时器初始值
TL0
0xcc;
TR0
=1;
ET0
在定时器0中断处理程序中,设置时标消息。
voidTime0Isr(void)interrupt1
//定时器重新赋初值
g_bSystemTime2Ms=1;
//2MS时标标志位置位
然后我们开始编写数码管的动态扫描函数。
新建一个C源文件,并包含相应的头文件。
Timer.h"
先开辟一个数码管显示的缓冲区。
动态扫描函数负责从这个缓冲区中取出数据,并扫描显示。
而其它函数则可以修改该缓冲区,从而改变显示的内容。
uint8g_u8LedDisplayBuffer[8]={0};
//显示缓冲区
然后定义共阳数码管的段码表以及相应的硬件端口连接。
codeuint8g_u8LedDisplayCode[]=
0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,
0x80,0x90,0x88,0x83,0xC6,0xA1,0x86,0x8E,
0xbf,//'
-'
号代码
};
sbitio_led_seg_cs=P1^4;
sbitio_led_bit_cs=P1^5;
#defineLED_PORTP0
再分别编写送数码管段码函数,以及位选通函数。
staticvoidSendLedSegData(uint8dat)
LED_PORT
=dat;
io_led_seg_cs=1;
//开段码锁存,送段码数据
io_led_seg_cs=0;
staticvoidSendLedBitData(uint8dat)
uint8temp;
temp=(0x01<
<
dat);
//根据要选通的位计算出位码
=temp;
io_led_bit_cs=1;
//开位码锁存,送位码数据
io_led_bit_cs=0;
下面的核心就是如何编写动态扫描函数了。
如下所示:
voidLedDisplay(uint8*pBuffer)
staticuint8s_LedDisPos=0;
if(g_bSystemTime2Ms)
{
g_bSystemTime2Ms=0;
SendLedBitData(8);
//消隐,只需要设置位选不为0~7即可
if(pBuffer[s_LedDisPos]=='
)
//显示'
号
SendLedSegData(g_u8LedDisplayCode[16]);
}
else
SendLedSegData(g_u8LedDisplayCode[pBuffer[s_LedDisPos]]);
SendLedBitData(s_LedDisPos);
if(++s_LedDisPos>
7)
s_LedDisPos=0;
}
函数内部定义一个静态的变量s_LedDisPos,用来表示扫描数码管的位置。
每当我们执行该函数一次的时候,s_LedDisPos的值会自加1,表示下次扫描下一个数码管。
然后判断g_bSystemTime2Ms时标消息是否到了。
如果到了,就开始执行相关扫描,否则就直接跳出函数。
SendLedBitData(8);
的作用是消隐。
因为我们的系统的段选和位选是共用P0口的。
在送段码之前,必须先关掉位选,否则,因为上次位选是选通的,在送段码的时候会造成相应数码管的点亮,尽管这个时间很短暂。
但是因为我们的数码管是不断扫描的,所以看起来还是会有些微微亮。
为了消除这种影响,就有必要再送段码数据之前关掉位选。
if(pBuffer[s_LedDisPos]=='
号这行语句是为了显示’-’符号特意加上去的,大家可以看到在定义数码管的段码表的时候,我多加了一个字节的代码0xbf:
通过SendLedSegData(g_u8LedDisplayCode[pBuffer[s_LedDisPos]]);
送出相应的段码数据后,然后通过SendLedBitData(s_LedDisPos);
打开相应的位选。
这样对应的数码管就被点亮了。
if(++s_LedDisPos>
然后s_LedDisPos自加1,以便下次执行本函数时,扫描下一个数码管。
因为我们的系统共有8个数码管,所以当s_LedDisPos>
7后,要对其进行清0。
否则,没有任何一个数码管被选中。
这也是为什么我们可以用
对数码管进行消隐操作的原因。
下面我们来编写相应的主函数,并实现数码管上面类似时钟的效果,如显示10-20-30
即10点20分30秒。
Main.c
Led7Seg.h"
sbitio_led=P1^6;
voidmain(void)
io_led=0;
//发光二极管与数码管共用P0口,这里禁止掉发光二极管的锁存输出
Timer0Init();
g_u8LedDisplayBuffer[0]=1;
g_u8LedDisplayBuffer[1]=0;
g_u8LedDisplayBuffer[2]='
;
g_u8LedDisplayBuffer[3]=2;
g_u8LedDisplayBuffer[4]=0;
g_u8LedDisplayBuffer[5]='
g_u8LedDisplayBuffer[6]=3;
g_u8LedDisplayBuffer[7]=0;
EA=1;
while
(1)
LedDisplay(g_u8LedDisplayBuffer);
将整个工程进行编译,看看效果如何
显示.jpg
动起来
既然我们想要模拟一个时钟,那么时钟肯定是要走动的,不然还称为什么时钟撒。
下面我们在前面的基础之上,添加一点相应的代码,让我们这个时钟走动起来。
我们知道,之前我们以及设置了一个扫描数码管用到的2ms时标。
如果我们再对这个时标进行计数,当计数值达到500,即500*2=1000ms时候,即表示已经逝去了1S的时间。
我们再根据这个1S的时间更新显示缓冲区即可。
听起来很简单,让我们实现它吧。
首先在Timer.c中声明如下两个变量:
bitg_bTime1S=0;
//时钟1S时标消息
staticuint16s_u16ClockTickCount=0;
//对2ms时标进行计数
再在定时器中断函数中添加如下代码:
if(++s_u16ClockTickCount==500)
s_u16ClockTickCount=0;
g_bTime1S=1;
从上面可以看出,s_u16ClockTickCount计数值达到500的时候,g_bTime1S时标消息产生。
然后我们根据这个时标消息刷新数码管显示缓冲区:
voidRunClock(void)
if(g_bTime1S)
g_bTime1S=0;
if(++g_u8LedDisplayBuffer[7]==10)
if(++g_u8LedDisplayBuffer[6]==6)
g_u8LedDisplayBuffer[6]=0;
if(++g_u8LedDisplayBuffer[4]==10)
g_u8LedDisplayBuffer[4]
=0;
if(++g_u8LedDisplayBuffer[3]==6)
g_u8LedDisplayBuffer[3]=0;
if(
g_u8LedDisplayBuffer[0]<
2)
if(++g_u8LedDisplayBuffer[1]==10)
{
g_u8LedDisplayBuffer[0]++;
else
if(++g_u8LedDisplayBuffer[1]==4)
g_u8LedDisplayBuffer[0]=0;
这个函数的作用就是对每个数码管缓冲位的值进行判断,判断的标准就是我们熟知的24小时制。
如秒的个位到了10就清0,同时秒的十位加1….诸如此类,我就不一一详述了。
同时,我们再编写一个时钟初始值设置函数,这样,可以很方便的在主程序开始的时候修改时钟初始值。
voidSetClock(uint8nHour,uint8nMinute,uint8nSecond)
g_u8LedDisplayBuffer[0]=nHour/10;
g_u8LedDisplayBuffer[1]=nHour%10;
g_u8LedDisplayBuffer[3]=nMinute/10;
g_u8LedDisplayBuffer[4]=nMinute%10;
g_u8LedDisplayBuffer[6]=nSecond/10;
g_u8LedDisplayBuffer[7]=nSecond%10;
然后修改下我们的主函数如下:
SetClock(10,20,30);
//设置初始时间为10点20分30秒
RunClock();
编译好之后,下载到我们的实验板上,怎么样,一个简单的时钟就这样诞生了。
动起来.jpg
至此,本章所诉就告一段落了。
至于如何完成数码管的闪烁显示,就像本章开头所说的那个数码管时钟的功能,就作为一个思考的问题留给大家思考吧。
同时整个LED篇就到此结束了,在以后的文章中,我们将开始学习如何编写实用的按键扫描程序。
[/post
本章所附例程在EE21学习板上调试通过,拥有板子的朋友可以直接下载附件对照学习。
- 配套讲稿:
如PPT文件的首页显示word图标,表示该PPT已包含配套word讲稿。双击word图标可打开word文档。
- 特殊限制:
部分文档作品中含有的国旗、国徽等图片,仅作为作品整体效果示例展示,禁止商用。设计者仅对作品中独创性部分享有著作权。
- 关 键 词:
- 数码管 程序
![提示](https://static.bdocx.com/images/bang_tan.gif)