利用51单片机制作一个秒表的详细过程

前面的话:

和很多朋友一样,在学51单片机的过程中我们肯定会涉及到制作一个秒表,牵涉到把单片机的多个部分组合起来使用,这对于我们初学者来说可能显得有些困难,我同大家一样,百思不得其解,最后头都弄大了才把这个秒表制作出来,为了给以后的朋友们一些思路,一些参考,所以在这里我把自己制作的整个详细过程整理出来供大家参考。我调试出来是没有问题的,各方面都稳定运行,由于我水平有限,中间可能会有不对的地方,欢迎大家指正,我们一起学习,一起进步!

我将分为三个部分来介绍:1.整体思路,2.硬件电路方面,3.软件编程方面。


1.整体思路

利用51单片机制作秒表时,我介绍精确到十分位(即0.1s)的制作,并让其拥有启动,暂停,复位三个功能。
用到的单片机部分:定时器部分,独立按键的检测与应用,数码管的显示,并结合一些简单的程序即可实现。
用5位数码管来进行显示,分别显示秒的十分位,秒的个位,秒的十位,分的个位,分的十位。用定时器定时50ms,2个定时器中断即是0.1s,即秒的十分位,20个定时器中断即是1s,60个1s即是1分钟,通过程序将5位数码管的值分离出来,并进行显示。这就是我在数码管显示方面的思路,如果不是太清楚,结合我下面软件编程方面的程序来看你可能就会明白,我会在那部分做详细介绍,看完了可能你就懂了。
利用独立按键设置启动/暂停键和清零键,利用独立按键的检测,若启动/暂停按键按下,秒表则启动或者暂停,按下复位键,秒表清零复位。我在程序后面全都有注释,不用担心。看完你就会明白了。
这是我制作的的流程图:




“ms100”表示秒的十分位,"s"表示秒的个位,“s1”表示秒的十位,“min”表示分的个位,“min1”表示分的十位。
“cnt”表示秒的计数位,即多少个一秒,定时满一秒加1,“minu”表示分的计数位,即多少个一分钟,一分钟加1,
这个流程图提供了大致思路,要结合下面的程序部分一起看。可能有些简陋,请多多包涵!


看起来是不是好简单?有木有?请继续往下看。

2.硬件电路方面

每个人的硬件可能都不一样,(哪些控制数码管的位选,哪些控制数码管的段选,哪些控制独立按键等等),大家在自己制作过程中都要仔细考虑,我在这里就用我自己的硬件进行介绍。

这是我的数码管的电路图:(将J12用杜邦线接到对应的P0口,将J16用杜邦线接到对应的P1口)


位选端我用P1口控制,段选端我用P0口控制。在图中我已标明秒的个位s,秒的十位s1,分的个位min,分的十位min1所对应的数码管。该数码管是共阴极。
秒的十分位我用的是另一个共阳数码管。我用P3口控制该数码管的段选,其图如下:



而独立按键我用的P2^7控制“启动/暂停键”,P2^6控制复位键:电路图如下:(将JP5通过杜邦线接到P3口)

硬件电路基本上就是这些,由于分和秒之间要用小数点分隔开,所以分的个位对应的数码管的段码要用带小数点的段码,其余的数码管则不用。

硬件方面是为看懂软件程序做准备,下面我们就开始我们的软件程序方面吧!  

3.软件程序方面


#include <REGX51.H>
#define uchar unsigned char
#define uint unsigned int

#define PIN0 P0  //数码管段选端
#define PIN1 P1  //数码管位选端
#define PIN3 P3	 //十分位数码管的段码端

sbit start=P2^7;  //启动/暂停按钮
sbit reset=P2^6;  //复位按钮

uint cnt=0;   //1s的次数的计数值
uint num=0;     //进入中断次数的计数值(一次50ms)
uint num1=0;		//0.1s的次数的计数值

uchar code table[]={0x3f,0x06,0x5b,
0x4f,0x66,0x6d,0x7d,0x07, 0x7f,0x6f};
//不带小数点的共阴极数码管段码0-9

uchar code table1[]={0xbf,0x86,
0xdb,0xcf,0xe6,0xed,0xfd,0x87,0xff,0xef};
//带小数点的共阴极数码管段码0-9

char code table2[]={0xc0,0xf9,0xa4,
0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
//不带小数点的共阳极数码管段码0-9

void Display(uint w,uint a,uint b,uint c,uint d);  //声明显示函数
void InitTimer0();  //声明定时器初始化函数
void Delayms(uint x);  //声明延时函数

void main()
{
	uint ms100=0;	//秒的十分位
	uint s,s1,min,min1,minu=0; 
	//依次是秒的个位,秒的十位,分的个位,分的十位
	InitTimer0();	  //初始化定时器
	while(1)			//进入死循环
{	
	if(start==0)   //检测启动/暂停键是否按下
			Delayms(20); //延时消抖
	{
		if(start==0)  //消抖之后再次检测
		{
			TR0=!TR0;		//定时器的控制位取反
			while(!start);  //等待按键释放
		}
	}
	
if(reset==0)  //检测复位键是否按下
{
	Delayms(20);	//延时消抖
	if(reset==0)  	//消抖之后再次检测
	{
		num=0;		
		num1=0;		//进入中断次数值清0
		ms100=0;	//十分位的计数值清0
		cnt=0;		//秒的计数值清0
		minu=0;		//分的计数值清0
		while(!reset);		 //等待按键释放
	}
}
	if(num1>=2)		//检测是否达到0.1s,(两个50ms)
	{
		num1=0;  		//进入中断次数值清零
		ms100++;		//秒的十分位的计数值加1
		if(ms100>=10)  //若秒的十分位计数值达到10
		{
			ms100=0;  //清零秒的十分位的计数值
			num1=0;	//进入中断次数值置0
		}
	}
	
	if(num>=20)  //判断计时时间是否达到1s(20个50ms)
	{
		num=0;     //进入中断次数值置0
		cnt++;		 //秒的计数值加1
		if(cnt>=60) //判断是否达到60s
	{
		cnt=0;		//若达到60s,将秒的计数值置零
		minu++;			//分的计数值加1
		if(minu>=60)  //判断是否达到60分钟,一般秒表是用不到60分的,这是为了程序的严谨性

		{
			TR0=!TR0;			//达到60分钟则关闭定时器并清零所有的计数值
			num1=0;				
			num=0;
			ms100=0;
			cnt=0;		
			minu=0;
			
		}
	}
	}	
	s=cnt%10;  	//从秒的计数值里面分离秒的个位
	s1=cnt/10; 	//从秒的计数值里面分离秒的十位
	min=minu%10;	//从分的计数值里面分离分的个位
	min1=minu/10;	//从分的计数值里面分离分的十位
	
	Display(ms100,s,s1,min,min1);  //显示这5个数
}	
}

void InitTimer0() //定时器初始化函数
{
	
	TMOD=0x01; //选择定时器0的工作方式1
	TH0=(65536-45872)/256;  //装初值(定时50ms),晶振11.0592MHz
	TL0=(65536-45872)%256;
	EA=1;		//打开总中断
	ET0=1;	//打开定时器中断
	TR0=0;	//先不要启动定时器
	
}

void TIMER0()  interrupt 1  //定时器中断服务函数
{
	TH0=(65536-45872)/256;  //重装初值
	TL0=(65536-45872)%256;
	num++;		//让进入中断次数值加1,用于判断是否达到1s
	num1++;		//让进入中断次数值加1,用于判断是否达到0.1s
}

void Delayms(uint x)   //延时xms
{
	uint i,j;
	for(i=x;i>0;i--)
		for(j=110;j>0;j--);
}

void Display(uint w,uint a,uint b,uint c,uint d) //定义显示函数
{
	PIN3=table2[w];		//秒的十分位的段选
	Delayms(5);
	
	PIN0=table[a]; //秒的个位的段选
	PIN1=0x7f;		 //秒的个位的位选
	Delayms(5);			
	
	PIN0=table[b];  //秒的十位的段选
	PIN1=0xbf;			//秒的十位的位选
	Delayms(5);
	
	PIN0=table1[c];  //分的个位的段选(带小数点)
	PIN1=0xdf;			 //分的个位的位选
	Delayms(5);
		
	PIN0=table[d];		//分的十位的段选
	PIN1=0xef;				//分的十位的位选
	Delayms(5);		
		
}

由于在打字时可能不小心会弄错一丁点程序,我都是一个字母一个字母手打的,所以请大家理解思路即可,根据这个思路自己去写, 这样得到的知识才是属于自己的。毕竟 “读别人的故事,悟自己的人生”。
下面来几张实物图给大家看一下我这个秒表的实际效果。

编译结果:





烧写进单片机的效果:(没有按启动按钮之前)






按了启动按钮之后,秒表将会自动开始计时,由于无法演示动态过程,只能在中间按下暂停键给大家看看效果:











按下复位键后:



由于我用的是一个比较完整的51开发板,所以里面有很多部分,大家只需要注意观察数码管部分就好。
下面再来一个完整的图:





结束语

至此,利用51单片机制作的秒表就已经完成了!若是文章中有什么不懂的地方或者是自己在制作过程中遇到什么问题都可以联系我,或者给我留言,我一定竭尽全力帮助大家!我们一起学习,一起进步!希望大家都能在看完这篇文章后自己动手成功制作出一个秒表,祝愿大家学好单片机!当然,由于自身水平有限,文章中肯定会存在错误或者是考虑不周的的地方,恳请不吝赐教!谢谢大家!

(PS:我写了一整天了,反复的看,反复的改,现在头昏眼花,但是只要能对大家有所帮助,一切都是值得的。)




Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐