资讯详情

【Proteus】数码管简易计时器

前言

本章介绍了使用定时器和数字管作为一个简单的计数器,使用3个2位数字管分别代表时间、分、秒。使用定器来控制数字管的段选和位选。

先放一张完整的仿真图:

锁存器:

锁定器是数字管驱动中非常常用的设备。简单来说,锁定器的主要功能是缓存。可以根据以下简单描述来理解:

当LE当给出1时,锁定器将打开,然后单片机将数据输入到D0-D7,然后关闭LE端口,也就是LE此时0,此时锁定器的输出端,即Q0-Q7.之前的单片机输入将保持不变D0-D7的数据。

段选与位选:

结合上面的锁存器,我们经常在一些文章中看到段选和位选。如下图所示:

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

选择是控制数个数字管显示,是写给数字管控制位的数据,如下:

显示数据:

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

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

这些数字都是通用的,小数点,有的编成H,有些编为DP,你知道这意味着一个小数点。除了确定编号外,还确定了共阴共阳。事实上,数字管是8个LED只是灯,共阴极意味着这八个LED负极接在一起,所以在控制上,位选端口给0,A-H哪个数据端口给1,哪个亮。

假设我们的电路图是两位一体的,假设我们的共阴极(实际上是共阴极,

如果我们需要让左边的数码管显示0,右边的不显示,那么我们就需要把1端口置0,2端口置1,这时候就相当于位选选择了左边的数码管,而A-H需要A-F给1,G用H给0,然后就会显示0的图案,换算成2进制,A-H分别是11111100,此时需要注意一个题目,假如我们用单片机P一口直接控制8位数据,所以我P1口是赋值0x3f(00111111)xfc(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() {     //采用12晶振M晶振  TMOD=0x01;    ///设置定时器0的工作模式为工作模式1  TH0=(65525-50000)/256; ///赋初值,定时50ms  TL0=(65525-50000)%6;  EA=1;    ///开总中断  ET0=1;    ///开定时器0中断  TR0=1;    ///启动定时器0 }

在后续的定时器中断程序中,使用三个变量分别代表时间、分、秒,然后记录时间:

/********************************************* 功能:定时器中断函数 ***********************************************/ void T0_time() interrupt 1 {     TH0=(65525-50000)/256; ///赋初值,定时50ms  TL0=(65525-50000)%6;  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 <reg52.h> #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<num;i  )      for(j=0;j<5;j  ); }    /************************************** 功能:二位一体数码管驱动函数,       number数码管段选    x数码管位选 1位H1 2为H2 3为M1 4为M2 5为S1 6为S2 **************************************/ void two_display(uchar number,uint x) {  ///注意端口赋值的倒序  uint dat;  //存储位选数据   if(x == 1)    ///    dat = 0xfe;  else if(x == 2)    dat = 0xfd;  else if(x == 3)    dat = 0xfb;  else if(x == 4)    dat = 0xf7;  else if(x == 5)    dat = 0xef;  else if(x == 6)    dat = 0xdf;   WE = 1;  P2 = dat;  ///赋值位选  WE = 0;  //关闭位选   DATA = 1;  ///打开段选  P2 = number; ///段选信号  DATA = 0;  //关闭段选 } /************************************************* 功能:定时器0初始化函数 *************************************************/ void time_init() {     //采用12晶振M晶振  TMOD=0x01;    ///设置定时器0的工作模式为工作模式1  TH0=(65525-50000)/256; ///赋初值,定时50ms  TL0=(65525-50000)%6;  EA=1;    ///开总中断  ET0=1;    ///开定时器0中断  TR0=1;    ///启动定时器0 }  /************************************************* 功能:数字管显示函数 *************************************************/ void display() {      //秒     s_1=s/10;   //位
	   two_display(table_nonPos[s_1],5);
	   delay(1);
	   P2=0xff;   //全部清除,防止数据混乱
	   s_2=s%10;   //个位 下同
	   two_display(table_nonPos[s_2],6);
	   delay(1);
	   P2=0xff;   //全部清除,防止数据混乱
	   		//分
	   min_1=m/10;
	   two_display(table_nonPos[min_1],3);
	   delay(1);
	   P2=0xff;   //全部清除,防止数据混乱
	   min_2=m%10;
	   two_display(table_nonPos[min_2],4);
	   delay(1);
	   P2=0xff;   //全部清除,防止数据混乱
	   		//时
	   hour_1=h/10;
	   two_display(table_nonPos[hour_1],1);
	   delay(1);
	   P2=0xff;   //全部清除,防止数据混乱
	   hour_2=h%10;
	   two_display(table_nonPos[hour_2],2);
	   delay(1);
	   P2=0xff;   //全部清除,防止数据混乱	
}

void main()
{
    time_init();
	while(1)
	{
		display();  //数码管显示函数
	}
}

/*********************************************
功能:定时器中断函数
***********************************************/
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;
			  }
		   }
	   }
	}
}

点个赞喽!

标签: 6f24连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台