幸运微笑

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

2018年10月16日

LUCKY>

【金沙滩51单片机】时钟整点提醒程序

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

修改电子时钟程序,实现整点提醒功能(整点的时候用8个LED闪烁10s来提示)。

原来书上的代码:

#include<reg52.h>
#define uchar unsigned char		//不推荐这种写法
sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;
uchar cnt = 0;  					//定义一个计数变量,记录TO溢出次数
uchar sec = 0,min = 0,hour = 0;		//定义3个变量分别存储时、分、秒等信息
unsigned char code LedChar[]= {		//共阳数码管真值表
	0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
	0x80,0x90,0x88,0x83,0xc6,0xal,0x86,0x8e,0xff};
void delay_ms(unsigned int cnt);	//延时函数声明
void main()
{
	uchar temp;		//不推荐这种写法
	ENLED = 0;
	ADDR3 = 1;
	TMOD = 0x01;  	//设置TO为模式1
	TH0 = 0x4C;
	TL0 = 0x00;  	//50ms定时
	IE =0x82;  		//允许TO中断
	TR0= 1;  		//启动TO
	while(1)
	{
		ADDR2 = 0;
		ADDR1 = 0;
		ADDR0 = 0;		//显示秒的个位
		temp = sec%10;
		P0 = LedChar[temp];
		delay_ms(2);  	//延时2ms
		ADDR2 = 0;
		ADDR1 = 0;
		ADDR0 = 1;  	//显示秒的十位
		temp = sec/10;
		P0 = LedChar[temp];
		delay_ms(2);  	//延时2ms
		ADDR2 = 0;
		ADDR1 = 1;
		ADDR0 = 0;  	//显示分钟的个位
		temp = min%10;
		P0 = LedChar[temp];
		delay_ms(2);	//延时2ms
		ADDR2 = 0;
		ADDR1 = 1;
		ADDR0 = 1;		//显示分钟的十位
		temp = min/10;
		P0 = LedChar[temp];
		delay_ms(2);  	//延时2ms
		ADDR2 = 1;
		ADDR1 = 0;
		ADDR0 = 0;		//显示时钟的个位
		temp = hour%10;
		P0 = LedChar[temp];
		delay_ms(2);  	//延时2ms
		ADDR2 = 1;
		ADDR1 = 0;
		ADDR0 = 1;  	//显示时钟的十位
		temp = hour/10;
		P0 = LedChar[temp];
		delay_ms(2);  //延时2ms
	}
}


void clock() interrupt 1	//定时中断函数
{
	cnt++;
	TH0 = 0x4C;
	TL0 = 0x00;
	if(cnt == 20)
	{
		cnt = 0;
		sec++;				//cnt = 20表示1s 时间到了,秒钟加1
		if(sec == 60)		//当秒钟等于60,分钟加1,并且将秒钟清零
		{
			sec = 0;
			min++;
			if(min == 60)	//当分钟等于60,时钟加1,并且将分钟清零
			{
				min = 0;
				hour++;
				if(hour == 24) //当时钟等于24,将时钟清零
					hour = 0;
			}
		}
	}
}

void delay_ms(unsigned int cnt)		//延时cnt毫秒,延时函数定义
{
	unsigned char i;
	while(cnt--)
	{
		for(i = 0;i<=110;i++);
	}
}

修改后新的代码:

#include<reg52.h>
sbit ADDR0=P1^0;
sbit ADDR1=P1^1;
sbit ADDR2=P1^2;
sbit ADDR3=P1^3;
sbit ENLED=P1^4;

bit IntHour = 1;		//整点标志
bit FHour = 0;			//是否点亮LED
unsigned char sec = 57,min = 59,hour = 0;		//定义3个变量分别存储时、分、秒等信息
unsigned char code LedChar[]= {		//共阳数码管真值表
	0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
	0x80,0x90,0x88,0x83,0xc6,0xal,0x86,0x8e,0xff};
unsigned char smgbuff[] = {
	0xff,0xff,0xff,0xff,0xff,0xff};		//数码管显示缓存(类似于显卡内存)	
	
void main()
{
	unsigned char secb = 1,minb = 1,hourb = 1;
	
	ENLED = 0;
	ADDR3 = 1;
	
	TMOD = 0x11;  	//设置TO和T1都为模式1
	TH0 = 0x4C;		//50ms定时
	TL0 = 0x00;  	
	
	TH1 = 0xFA;		//1.5ms定时
	TL1 = 0x9A;
	
	EA = 1;  		//允许总中断
	ET1 = 1;
	ET0 = 1;		//允许定时器0中断
	TR0 = 1;  		//启动TO
	TR1 = 1;		//启动T1
	
	while(1)
	{
		if(secb != sec)		//如果变了再刷新缓存,以减少对其他程序的影响
		{
			smgbuff[5] = LedChar[sec%10];
			smgbuff[4] = LedChar[sec/10];
			secb = sec;		//备份当前值
			
			if(IntHour)		//整点的时候
			{
				if(sec <= 10)		//前10秒的时候
				{
					if(sec%2 == 0)
					{
						FHour = 1;
					}
					else
					{
						FHour = 0;
					}
				}
				else				//秒大于10,停止闪烁
				{
					IntHour = 0;
					FHour = 0;
				}
			}	
		}
		if(minb != min)		//如果变了再刷新缓存,以减少对其他程序的影响
		{
			smgbuff[3] = LedChar[min%10]&0x7f;		//分钟个位
			smgbuff[2] = LedChar[min/10];
			minb = min;		//备份当前值
		}
		if(hourb != hour)	//如果变了再刷新缓存,以减少对其他程序的影响
		{
			smgbuff[1] = LedChar[hour%10]&0x7f;		//小时个位
			smgbuff[0] = LedChar[hour/10];
			hourb = hour;		//备份当前值
		}
	}
}

void refresh() interrupt 3	//1定时中断函数
{
	static unsigned char i = 1;
	TH1 = 0xFA;		//50ms定时
	TL1 = 0x9A;
	
	P0=0XFF;		//消影
	switch(i)
	{
		case 0:i++;if(FHour){ADDR2=1;ADDR1=1;ADDR0=0;P0=0x00;}break;//配合主函数点亮LED
		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=0;P0=smgbuff[0];break;
		default:i = 0;
	}
}

void clock() interrupt 1	//0定时中断函数
{
	static char cnt = 0;		//定义一个计数变量,记录TO溢出次数
	cnt++;
	TH0 = 0x4C;
	TL0 = 0x00;
	if(cnt >= 20)
	{
		cnt = 0;
		sec++;				//cnt = 20表示1s 时间到了,秒钟加1
		if(sec >= 60)		//当秒钟等于60,分钟加1,并且将秒钟清零
		{
			sec = 0;
			min++;
			if(min >= 60)	//当分钟等于60,时钟加1,并且将分钟清零
			{
				static unsigned char hour12 = 0;
				min = 0;
				hour++;
				IntHour = 1;

				if(hour >= 24) //当时钟等于24,将时钟清零
					hour = 0;
				/*下面是12时制转换,使用12时制时请使用hour12更新数码管*/
				if(hour > 0 && hour < 13)	//如果是早上,且不是00(晚上12)点
					hour12 = hour;		//时制数字相等
				else				//如果是下午
					if(hour == 0)		//如果是下午(晚上)12点
						hour12 = 12;	//12时制为12
					else			//否则
						hour12 = hour - 12;	//24转12
			}
		}
	}
}

大家可以对比一下那个程序效率更高……..哈哈,还有一些细节之处,大家可以说说看自己的意见并上传到下方评论区哦。

至于第说时、分、秒采用两位计数,就定义6个变量,分别存时、分、秒的十位和个位,个位到十位的变化用十进制,其他位还是用时钟进制

简单代码如下:

unsigned char h = 0,hg = 0,m = 0,mg = 0,s = 0,sg = 0;
if(cnt>=20)
{
    cnt = 0;
    sg++;
	if(sg>=10)
	{
		sg = 0;
		s++;
		if(s>=6)
		{
			s = 0;
			mg++;
			if(mg>=10)
			{
				mg = 0;
				m++;
				if(m>=6)
				{
					m = 0;
					hg++;
					if(hg>=10)
					{
						hg = 0;
						h++
						if((h == 2)&&(hg == 4))
						{
							h = 0;
							hg = 0;
						}
					}
				}
			}
		}
	}
    
}

大家还是要多实践啊,emmm……..

加油ヾ(◍°∇°◍)ノ゙

来一发吐槽