【制作】基于金沙滩51单片机的电子跑表

基于金沙滩51单片机的电子跑表

很久之前学51单片机的时候做的了,现在分享一下。
基于金沙滩51单片机,很推荐这款单片机开发板,教程很好。

零、完成功能

本项目完成以下功能:
时钟模式:

  1. 在数码管上显示分、秒

跑表模式:

  1. 跑表显示范围:0-999.0秒
  2. 按下启动键开始计时
  3. 按下暂停键暂停计时
  4. 按下继续键继续计时
  5. 按下复位键计时归零

壹、硬件电路图

下面是项目用到的硬件电路图,完整原理图请点击:金沙滩51单片机原理图
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

数码管电路
在这里插入图片描述

贰、程序源码

注释挺多的,程序挺简单的,就不多介绍了,有问题可以在下面讨论

#include<reg52.h>
#define MAX_NUMBER 9999	  //最大值(单位:0.1)
#define INIT_NUMBER 0		 //初始值

sbit ADDR0 = P1^0;
sbit ADDR1 = P1^1;
sbit ADDR2 = P1^2;
sbit ADDR3 = P1^3;
sbit ENLED = P1^4;
sbit keyout = P2^0;
sbit key16 = P2^7; 
sbit key13 = P2^4;
sbit key14 = P2^5;
sbit key15 = P2^6;

unsigned char code smg[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};/*数码管真值表*/

unsigned char smgbuff[] = {0xff,0xff,0xff,0xff,0xff,0xff};/*数码管显示缓存*/

unsigned int n = 0;

unsigned char add = 1;

bit keysta1 = 1;	//按键1的当前状态
bit keysta2 = 1;	//按键2的当前状态
bit keysta3 = 1;	//按键3的当前状态
bit keysta4 = 1;	//按键4的当前状态

bit p = 0;		//计时状态,是否在计时,0否,1是,2暂停

char mode = 1; //时钟模式

unsigned char time[2] = {0,0};//分,秒
unsigned char timeb[2] = {1,1};//分,秒

bit keybackup1 = 1;	//按键1备份
bit keybackup2 = 1;	//按键2备份	
bit keybackup3 = 1;	//按键3备份
bit keybackup4 = 1;	//按键4备份	

unsigned int nb = 1; //第一次显示

void main()
{

	unsigned char th = 0,tl = 0;
	
	
	
	ENLED=0;
	ADDR3=1;

	TMOD = 0x11;	/*让定时器1,0工作在模式1*/
	TH0 = 0x0DC;	/*10ms,计时用*/
	TL0 = 0x00;
	TH1 = 0x0F5;	/*3ms,刷新用*/
	TL1 = 0x33;

	ET0 = 1;	/*开定时器1,0的中断*/
	ET1 = 1;
	EA = 1;		/*开总中断*/
	TR0 = 0;	/*打开定时器*/
	TR1 = 1;

	TR0 = 1;

	keyout = 0;		//按键初始化

	while(1)
	{

		switch(mode)
		{
			case 0:

			if(nb != n)		//如果备份值不等于n,那么n变了,于是重载缓存
			{
				nb = n;
				if((n/100000) == 0)smgbuff[0] = 0xff;else smgbuff[0] = smg[n/100000];
				if((n/10000) == 0)smgbuff[1] = smg[0];else smgbuff[1] = smg[(n/10000)%10];
				if((n/1000) == 0)smgbuff[2] = smg[0];else smgbuff[2] = smg[(n/1000)%10];
				if((n/100) == 0)smgbuff[3] = smg[0];else smgbuff[3] = smg[(n/100)%10];
				if((n/10) == 0)smgbuff[4] = smg[0];else smgbuff[4] = smg[(n/10)%10];
				if((n) == 0)smgbuff[5] = smg[0];else smgbuff[5] = smg[n%10];
				if(n == 0)smgbuff[4] = smg[0];
				
				smgbuff[4] = smgbuff[4]&0x7f;	//加小数点
				/*以上是 载数码管缓存代码,大家自己研究这里不多解释*/
			}
			
			if(keysta2 != keybackup2)		//按键状态发生了变化
			{
				//if(keybackup1 == 0)			//上次是0,这次变化了,说明是抬起按键
				{
				//这里写抬起按键事件	
					
				}
				
				if(keybackup2 == 1)
				{
				//同理,这里写按下事件
					if(p == 0)	//如果没有计时则开始计时
					{
						p = 1;
					}
					else		//否则在计时了就暂停计时
					{
						//TR0 = 0;
						p = 0;
					}
				}
				keybackup2 = keysta2;//备份按键	
			}
			
			if(keysta1 != keybackup1)		//按键2状态发生了变化
			{
				//if(keybackup2 == 0)			//上次是0,这次变化了,说明是抬起按键
				{
				//这里写抬起按键事件	
					
				}
				
				if(keybackup1 == 1)
				{
				//同理,这里写按下事件
					//TR0 = 0;	//停止计时
					//TH0 = 0x4C;	/*重置50ms,计时初值,这里避免到一半继续计时,导致有50ms内误差*/
					//TL0 = 0x00;
					p = 0;	//改状态为停止计时
					n = INIT_NUMBER;	//n置初值,为什么放到这?考虑没停止定时器置初值后进n-1中断导致n的值为998
				}
				keybackup1 = keysta1;//备份按键	
			}
	
			if(keysta4 != keybackup4)		//按键3状态发生了变化
			{
				static char ok = 1;
				if(keybackup4 == 1)
				{
					if(ok){
	
						add = 27;	//n置初值,为什么放到这?考虑没停止定时器置初值后进n-1中断导致n的值为998
						ok = 0;
					}
					else
					{
						add = 1;
						ok = 1;
					}
				}
				keybackup4 = keysta4;//备份按键	
			}

			break;
			case 1:

			smgbuff[1] = 0xff;

			//分
			if(time[0]!=timeb[0])
			{
				timeb[0]=time[0];
				smgbuff[2] = smg[timeb[0]/10];
				smgbuff[3] = smg[timeb[0]%10];
				smgbuff[3] = smgbuff[3]&0x7f;	//加小数点
			}

			//秒
			if(time[1]!=timeb[1])
			{
				timeb[1]=time[1];
				smgbuff[4] = smg[timeb[1]/10];
				smgbuff[5] = smg[timeb[1]%10];
			}
			break;
		}
	}
}

void timer() interrupt 1
{
	static unsigned char cnt = 0,tim = 0;
	TH0 = 0x4C;	/*50ms,计时*/
    TL0 = 0x00;
	cnt++;
	if(cnt>=2)		//到100ms时,
	{
		cnt = 0;	//清计数
		tim++;

		if(tim == 10)
		{
			time[1]++;
			tim = 0;
			if(time[1]==60)
			{
				time[0]++;
				time[1]=0;
				if(time[0]>99)
				{
					time[0] = 99;
				}
			}
		}

		if(p){
			n+=add;		//n+1
			if(n <= 0)	//考虑到倒计时结束
			{
				n = 0;	//可不加,严谨考虑
				//ET0 = 0;//这个可有可无
				//TR0 = 0;	//关闭定时器
				p = 0;		//把状态设置为停止计时
			}
	
			if(n>MAX_NUMBER) //最大限度
			{
				n = MAX_NUMBER;
				//TR0 = 0;	//关闭定时器
				p = 0;		//把状态设置为停止计时
			}
		}
	}
}

void display() interrupt 3
{
	static unsigned char i = 1;
	static keybuff[] = {0xff,0xff,0xff};		//默认按键抬起
    TH1 = 0x0F5;	/*3ms,刷新数码管,按键扫描*/
    TL1 = 0x33;
	
	keybuff[0] = (keybuff[0]<<1)|key14;		//按键缓冲右移一位,再把新状态加进来
	/*这里实现的是:
	按键时序状态:
	11111111111111111111111111100101100000000000000000001100101111111111111111111
	第一次按键buff:(11111111)抬起
	1111111111111111111(11111111)00101100000000000000000001100101111111111111111111
	第二次按键buff:(11111110)抬起
	11111111111111111111(11111110)0101100000000000000000001100101111111111111111111
	第三次按键buff:(11111100)抬起
	111111111111111111111(11111100)101100000000000000000001100101111111111111111111
	第七次按键buff:(11001011)抬起  这里就是已经消抖了
	1111111111111111111111111(11001011)00000000000000000001100101111111111111111111
	第十五次按键buff:(00000000)按下  
	111111111111111111111111111001011(00000000)000000000001100101111111111111111111
	具体过程大家可以在草稿纸上演示,还有不懂的可以问
	*/
	keybuff[1] = (keybuff[1]<<1)|key15;		//同上理
	keybuff[2] = (keybuff[2]<<1)|key16;	  
	keybuff[3] = (keybuff[3]<<1)|key13;
	
	if((keybuff[2]&0x0F) == 0x00)	//连续4个扫描都为0,也就是4*3=12ms的时间内扫描到的都是0,可认为按下了
	{
		keysta3 = 0;//0按下
	}

	if((keybuff[2]|0xF0) == 0xFF)	//同上理,可认为抬起了
	{
		keysta3 = 1;//1抬起
	}

	if((keybuff[3]&0x0F) == 0x00)	//连续4个扫描都为0,也就是4*3=12ms的时间内扫描到的都是0,可认为按下了
	{
		keysta4 = 0;//0按下
	}

	if((keybuff[3]|0xF0) == 0xFF)	//同上理,可认为抬起了
	{
		keysta4 = 1;//1抬起
	}

	if((keybuff[0]&0x0F) == 0x00)
	{
		keysta1 = 0;//0按下
	}
	/*这里为什么要keybuff[0]&0x0F?
	比如按键缓冲是11110000
	按位与0x0f(00001111)后是0000000,而11110000是可以认为按下的
	再比如缓冲11111000,按位与后是00001000,不是0x00,所以可行
	*/
	
	if((keybuff[0]|0xF0) == 0xFF)	//同上理,可认为抬起了
	{
		keysta1 = 1;//1抬起
	}
	/*-----------------------下面同理对第二个按键处理----------------------*/
	if((keybuff[1]&0x0F) == 0x00)	
	{
		keysta2 = 0;//0按下
	}
	
	if((keybuff[1]|0xF0) == 0xFF)	
	{
		keysta2 = 1;//1抬起
	}
	
	P0=0XFF;
	switch(i)
	{
	case 1:ADDR2=0;ADDR1=0;ADDR0=0;i++;P0=smgbuff[5];break;
	case 2:ADDR2=0;ADDR1=0;ADDR0=1;i++;P0=smgbuff[4];break;
	case 3:ADDR2=0;ADDR1=1;ADDR0=0;i++;P0=smgbuff[3];break;
	case 4:ADDR2=0;ADDR1=1;ADDR0=1;i++;P0=smgbuff[2];break;
	case 5:ADDR2=1;ADDR1=0;ADDR0=0;i++;P0=smgbuff[1];break;
	case 6:ADDR2=1;ADDR1=0;ADDR0=1;i=1;P0=smgbuff[0];break;
	default:i = 1;
	}

		if(keysta3 != keybackup3)		//按键状态发生了变化
		{

			if(keybackup3 == 1)
			{
				if(mode == 1)
				{
					mode = 0;
				}			 else
				{
					mode = 1;
				}
				//mode = ~mode; //改变模式
				timeb[0] = 255;
				timeb[1] = 255;
				nb = 65535;
			}
			keybackup3 = keysta3;//备份按键	
		}
	
}

叁、项目效果

视频演示:https://www.bilibili.com/video/BV1sv41117ZX
在这里插入图片描述
成功完成以上功能。
喜欢的小伙伴支持一下呗~

  • 5
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考
单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考 单片机 学习资料 项目资料 供学习参考
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

玉米子禾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值