• 【制作】基于金沙滩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

    成功完成以上功能。
    喜欢的小伙伴支持一下呗~

  • 相关阅读:
    LightOj 1016
    uva 127 "Accordian" Patience 简单模拟
    hdu 1180 诡异的楼梯 BFS + 优先队列
    UVALive 3907 Puzzle AC自动机+DP
    HDU 4001 To Miss Our Children Time DP
    HDU 4000 Fruit Ninja 树状数组
    hdu_1021_Fibonacci Again_201310232237
    hdu_1005_Number Sequence_201310222120
    hdu_1029-Ignatius and the Princess IV_201310180916
    hdu_1020_Encoding_201310172120
  • 原文地址:https://www.cnblogs.com/minuy/p/14494078.html
Copyright © 2020-2023  润新知