【Proteus】数码管简易计时器

您所在的位置:网站首页 简易计时器制作研究的目的 【Proteus】数码管简易计时器

【Proteus】数码管简易计时器

2024-04-05 15:35| 来源: 网络整理| 查看: 265

前言

本章介绍使用定时器与数码管来做一个简易的计数器,使用3个2位一体数码管来分别代表时,分,秒。使用锁存器来控制数码管的段选与位选。

先放一张完整的仿真图:

锁存器:

锁存器在数码管驱动中是非常常用的一种器件。简单来说,锁存器最主要的作用就是缓存。可以按照下面的简单描述来理解:

当LE给到1的时候,锁存器就会使能打开,然后由单片机给输入数据到D0-D7,然后关闭LE端口,也就是LE端口给0,这时候锁存器的输出端,也就是Q0-Q7就会维持之前单片机输入给D0-D7的数据。

段选与位选:

结合上面的锁存器的东西,经常会看到一些文章中说到段选与位选。简单理解的话,如下图:

段选就是控制数码管显示什么内容,也就是实际写给数码管8个灯的数据,如下:

位选就是控制哪个数码管显示,就是写给数码管控制位的数据,如下:

显示数据:

关于单片机如何控制数码管显示数据,这一点可以参照数码管静态显示的内容,网上的描述很多,我就只简单的说一下。

单个数码管的编号图如下:

这些编号都是通用的,那个小数点,有些是编为H,有些编为DP,你明白是指小数点就可以了。除了编号的确定,之后就是共阴共阳的确定了。其实数码管也就是8个LED灯而已,共阴极就是说,这8个LED是负极接在一起的,那么在控制上就是,位选端口给0,A-H数据端口哪个给1,就哪个亮。

以我们的电路图来说,我们这个是两位一体的,假设我们的是共阴极(实际就是共阴极,略略略):

如果我们需要让左边的数码管显示0,右边的不显示,那么我们就需要把1端口置0,2端口置1,这时候就相当于位选选择了左边的数码管,而A-H需要A-F给1,G与H给0,那么就会显示出0的图案,换算成2进制就是,A-H分别是11111100,这时候就需要注意到一个为题,假如我们用单片机的P1口来直接控制8位数据,那么我的P1口是赋值0x3f(00111111)呢,还是赋值0xfc(11111100)呢,我最开始学习单片机的时候肯定是写0xfc,后面发现是不对的,我以为是十六进制的第一位就对应的单片机端口的第一位,实际刚好是相反的,这个应该是跟芯片设计时的大小端模式有关。有兴趣的话,可以百度大小端模式,了解一下相关内容。

那么由于我们电路中加入了锁存器,那么就要把锁存器的内容给加上:

结合上面锁存器的图,我们可以知道,要想让数码管显示0,我们需要先给段选锁存器写入0需要的数据,然后再让位选锁存器给H1为0。那么测试程序如下:

uint dat; //存储位选数据 uint number; //存储段选数据 WE = 1; P2 = 0xfe; //赋值位选 WE = 0; //关闭位选 DATA = 1; //打开段选 P2 = 0x3f; //段选信号 DATA = 0; //关闭段选

效果如图:

之后我把共阴极的数码管各数据,带小数点,不带小数点的各写入了一个数组,为了以后备用,如下:

//没有小数点的数字数组0~9 uchar code table_nonPos[]= { 0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f }; //有小数点的数字数组0~9 uchar code table_Pos[]= { 0xbf,0x86,0xdb,0xcf,0xe6, 0xed,0xfd,0x87,0xff,0xef };

之后就是定时器计时程序的编写了,关于定时器的配置,我一般就设置定时器0的工作方式为工作方式1,这部分的手册资料也是直接就能查得到,然后使用12M晶振定时50ms:

/************************************************* 功能:定时器0初始化函数 *************************************************/ void time_init() { //晶振采用12M晶振 TMOD=0x01; //设置定时器0的工作方式为工作方式1 TH0=(65525-50000)/256; //赋初值,定时50ms TL0=(65525-50000)%256; EA=1; //开总中断 ET0=1; //开定时器0中断 TR0=1; //启动定时器0 }

之后的定时器中断程序中,就使用三个变量分别代表时,分,秒,然后记录时间即可:

/********************************************* 功能:定时器中断函数 ***********************************************/ void T0_time() interrupt 1 { TH0=(65525-50000)/256; //赋初值,定时50ms TL0=(65525-50000)%256; num++; //50ms if(num==20) //1s时间到 { num=0; //清零 s++; if(s==60) //60s时间到 { s=0; m++; if(m==60) //60分钟时间到 { m=0; h++; if(h==60) //60小时到,全部清零,重新计时 { h=0; m=0; s=0; } } } } }

在定时器中断函数中记录了时,分,秒,那么在mian函数中就驱动数码管显示出来就可以了。这个驱动函数我已经写好,所有完整程序如下:

#include #define uchar unsigned char #define uint unsigned int int num=0; //定时器计数变量 int h=0,m=0,s=0; //分别代表时,分,秒 int hour_1=0; //时第1位 int hour_2=0; //时第2位 int min_1=0; //分第1位 int min_2=0; //分第2位 int s_1=0; //秒第1位 int s_2=0; //秒第2位 sbit WE = P1^2; //锁存器位选 sbit DATA = P1^3; //锁存器段选 //没有小数点的数字数组0~9 uchar code table_nonPos[]= { 0x3f,0x06,0x5b,0x4f,0x66, 0x6d,0x7d,0x07,0x7f,0x6f }; //有小数点的数字数组0~9 uchar code table_Pos[]= { 0xbf,0x86,0xdb,0xcf,0xe6, 0xed,0xfd,0x87,0xff,0xef }; /************************************** 功能:延时函数 **************************************/ void delay(uint num) { int i,j; for(i=0;i


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3