【制作】基於金沙灘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

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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM