幸运微笑

微笑一下,世界就会变得不一样

2018年10月14日

LUCKY>

【金沙滩51单片机】99.9倒计时秒表

这个实验适用于金沙滩51单片机开发板

编程设计一个99.9s~0s的倒计时器

实验效果图:

QQ图片20181014132736.gif

需要用到的原理图:

单片机部分:

QQ截图20181014132923.jpg

按键部分:

QQ截图20181014132859.jpg

数码管部分:QQ截图20181014132825.jpg

74H138部分:

QQ截图20181014132849.jpg

跳线部分:

QQ截图20181014132909.jpg

程序代码和解释:


#include<reg52.h>

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 key14 = P2^5;
sbit key15 = P2^6;

unsigned int code NC = 999;//设定初值

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 = 999;

bit keysta1 = 1;	//按键1的当前状态
bit keysta2 = 1;	//按键1的当前状态

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


void main()
{
	bit keybackup1 = 1;	//按键1备份
	bit keybackup2 = 1;	//按键2备份
	
	
	unsigned int nb = 0;
	
	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;

	keyout = 0;		//按键初始化

	while(1)
	{
		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] = 0xff;else smgbuff[1] = smg[(n/10000)%10];
			if((n/1000) == 0)smgbuff[2] = 0xff;else smgbuff[2] = smg[(n/1000)%10];
			if((n/100) == 0)smgbuff[3] = 0xff;else smgbuff[3] = smg[(n/100)%10];
			if((n/10) == 0)smgbuff[4] = 0xff;else smgbuff[4] = smg[(n/10)%10];
			if((n) == 0)smgbuff[5] = smg[0];else smgbuff[5] = smg[n%10];
			if(n>9)smgbuff[4] = smgbuff[4]&0x7f;
			if((n<=9) && (n>0))smgbuff[4] = smg[0]&0x7f;
			if(n == 0)smgbuff[4] = 0xff;
			/*以上是 载数码管缓存代码,大家自己研究这里不多解释*/
		}
		
		if(keysta2 != keybackup2)		//按键状态发生了变化
		{
			//if(keybackup1 == 0)			//上次是0,这次变化了,说明是抬起按键
			{
			//这里写抬起按键事件	
				
			}
			
			if(keybackup2 == 1)
			{
			//同理,这里写按下事件
				if(p == 0)	//如果没有计时则开始计时
				{
					TR0 = 1;
					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 = NC;	//n置初值,为什么放到这?考虑没停止定时器置初值后进n-1中断导致n的值为998
			}
			keybackup1 = keysta1;//备份按键	
		}
	}
}

void time() interrupt 1
{
	static cnt = 0;
	TH0 = 0x4C;	/*50ms,计时*/
    TL0 = 0x00;
	cnt++;
	if(cnt>=2)		//到100ms时,
	{
		cnt = 0;	//清计数
		n--;		//n-1
		if(n <= 0)	//考虑到倒计时结束
		{
			n = 0;	//可不加,严谨考虑
			//ET0 = 0;//这个可有可无
			TR0 = 0;	//关闭定时器
			p = 0;		//把状态设置为停止计时
		}
		if(n > NC)		//考虑特殊情况
		{
			n = NC;
		}
	}
}

void display() interrupt 3
{
	static char i = 1;
	static keybuff[] = {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;		//同上理
	
	if((keybuff[0]&0x0F) == 0x00)	//连续4个扫描都为0,也就是4*3=12ms的时间内扫描到的都是0,可认为按下了
	{
		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;
	}
	
}

以后带开发板去比赛跑步啦!!

小伙伴们可以设计一个从0开始的计时器,到小数点后面两位的那种。

做好后记得把代码上传到下面评论区哦!

11.jpg

来一发吐槽