利用51单片机的定时器设计一个时钟

利用51单片机的定时器设计一个时钟
一、功能要求

  1. 1602液晶显示时间,且每秒更新,自动计时。
  2. 用3个按键实现调节时、分、秒更能,可以定义为功能键、增加键、减小键。
  3. 当按键被按下时,蜂鸣器响一声提示。
  4. 利用AT24C02实现掉电记忆功能。
    二、 原理图设计
    在这里插入图片描述
    在这里插入图片描述
    三、源程序
  5. 在Keil中的同一个文件夹下新建一个AT24C02.h文件和Clock.c文件
//*********************** AT24C02.h源程序***************************//
 bit write=0;		//写AT24C02的标志
sbit SDA=P2^0;		//定义数据串行口,用于单片机通信
sbit SCL=P2^1;	//定义时钟串行口,用于单片机通信

void delayus()		//定义us级延时函数
{;;}

void start()	//起始信号
{
	SDA=1;
	delayus();
	SCL=1;
	delayus();
	SDA=0;
	delayus();
}

void stop()//终止信号
{
	SDA=0;
	delayus();
	SCL=1;
	delayus();
	SDA=1;
	delayus();
}

void ack()//应答信号
{
	uchar i;
	SCL=1;
	delayus();
	while((SDA=1)&&i<250)i++;																	
	SCL=0;
	delayus();
}


void init_AT24C02()	//初始化
{
	SDA=1;
	delayus();
	SCL=1;
	delayus();	
}

void write_byte(uchar dat)	//定义写1个字节程序
{
	uchar i,temp;
	temp=dat;				//将数据赋值给temp。例如:dat为0x01,则temp=0x01=0000 0001。方便后续移位操作用。
	for(i=0;i<8;i++)		//1个字节包括8位二进制数
	{
		temp=temp<<1;		//将temp左移1位,最低位补0
		SCL=0;					//将SCL置0允许SDA数据变化
		delayus();
		SDA=CY;				//将最高位移出的CY位赋给SDA
		delayus();
		SCL=1;					//置1将数据写入
		delayus();
	}
	SCL=0;					//置0允许数据变化,用于SDA置1释放总线。
	delayus();
	SDA=1;					//释放总线
	delayus();			
}

uchar read_byte()	//读1个带返回值的字节
{
	uchar i,k;
	SCL=0;				//置0允许数据变化
	delayus();
	SDA=1;				//假设SDA为1,也可以SDA=0。当SDA=0时,下面for语句会有所差别。
	delayus();
	for(i=0;i<8;i++)
	{
		SCL=1;					//上升沿时,IIC设备将数据放在sda线上,并在高电平期间数据已经稳定,可以接收啦
		delayus();
		k=(k<<1)|SDA;		//将k左移一位跟SDA或运算,再赋给k	
		SCL=0;					//拉低SCL,使发送端可以把数据放在SDA上  
		delayus();		
	}
	return k;
}

void write_add(uchar address, uchar dat)			//指定地址写一个字节
{
	start();
	write_byte(0xa0);
	ack();
	write_byte(address);
	ack();
	write_byte(dat);
	ack();
	stop();
}

char read_add(uchar address)				//随机读取一个字节
{
	uchar dat;
	start();
	write_byte(0xa0);
	ack();
	write_byte(address);
	ack();
	start();
	write_byte(0xa1);
	ack();
	dat=read_byte();
	stop();
	return dat;
}
//****************************Main主程序**************************************//
#include <reg52.h>
#define uchar unsigned char
#define uint unsigned int
#include"AT24C02.h"		//包含AT24C02头文件
sbit s1=P3^0;
sbit s2=P3^1;
sbit s3=P3^2;
sbit rd=P3^7;
sbit lcden=P3^4;
sbit rs=P3^5;
sbit dula=P2^6;
sbit wela=P2^7;
sbit beep=P2^3;
char shi,fen,miao;
uchar s1num,count;
uchar code table0[]="  2020-6-4 MON";			//字符2020前面3个空格
uchar code table1[]="00:00:00";
void delay_us()					//us级延时程序
{;;}
void delay_ms(uchar z)	//ms级延时程序
{
	uint i,j;
	for(i=z;i>0;i--)
		for(j=110;j>0;j--);
}

void buzzer()				//定义蜂鸣器程序
{
	beep=0;
	delay_ms(100);
	beep=1;

}

void write_com(uchar com)	//液晶写指令
{
	rs=0;
	lcden=0;
	P0=com;
	delay_ms(5);
	lcden=1;
	delay_ms(5);
	lcden=0;
}

void write_dat(uchar dat)	//液晶写数据
{
	rs=1;
	lcden=0;
	P0=dat;
	delay_ms(5);
	lcden=1;
	delay_ms(5);
	lcden=0;
}

void write_sfm(uchar add,uchar dat)		//写时分秒程序
{
	uchar shi,ge;
	shi=dat/10;				//将时分秒分别分解成一个两位数,以便后续的位操作
	ge=dat%10;
	write_com(0x80+0x40+add);			//在液晶第2行写指令
	write_dat(0x30+shi);						//0x30地址的数据为0
	write_dat(0x30+ge); 
}
void init_1602()							//初始化液晶
{
	uchar num;
	dula=0;
	wela=0;
	num=0;
	s1num=0;
	count=0;
	rd=0;
	lcden=0;
	shi=0;
	fen=0;
	miao=0;
	init_AT24C02_02();			
	write_com(0x38);
	write_com(0x0c);
	write_com(0x06);
	write_com(0x08);
	write_com(0x01);
	write_com(0x80);
	for(num=0;num<14;num++)		//显示日期,加空格总共14个字节
	{
		write_dat(table0[num]);
		delay_ms(5);
	}
	write_com(0x80+0x40+4);
	for(num=0;num<8;num++)		//显示时分秒
	{
		write_dat(table1[num]);	
		delay_ms(5);	
	}
	miao=read_add(1);	//首次上电从AT24C02中读取出存储器的数据,地址可以随机定义,只要整个程序用的地址相同即可。
	fen=read_add(2);		
	shi=read_add(3);
	write_sfm(10,miao);	//在第十位写秒数据
	write_sfm(7,fen);
	write_sfm(4,shi);
	TMOD=0x01;		//设置T0定时器为工作方式1
	TH0=(65536-50000)/256;	//装初值
	TL0=(65536-50000)%256;
	EA=1;			//开总中断
	ET0=1;		//开定时器0中断
	TR0=1;		//启动定时器0
}

void keyscan()	//按键扫描程序
{
	if(s1==0)		//先定义功能键被按下,不然加减键为无效。
	{
		delay_ms(5);
		if(s1==0)		//再次确认被按下,即去抖动
		{
			s1num++;	//记录功能键被按下次数
			while(!s1);	//按键释放
			buzzer();		//蜂鸣器短鸣提示
			if(s1num==1)		//功能键按下1次
			{
				TR0=0;		//定时器停止计时
				write_com(0x80+0x40+11);		//光标在11位处,调节11的大小可以进行光标位置设置
				write_com(0x0f);						//光标闪烁
			}	
			if(s1num==2)
			{
				write_com(0x80+0x40+8);
				write_com(0x0f);
			}
			if(s1num==3)
			{
				write_com(0x80+0x40+5);
				write_com(0x0f);
			}
			if(s1num==4)		//功能键按下4次
			{
				s1num=0;		//按键次数清0
				write_com(0x0c);		//取消光标闪烁
				TR0=1;			//定时器继续计数
			}
		}
	}
	if(s1num!=0)		//只有功能键被按下,加减键才有效
	{
		if(s2==0)		//增加键被按下
		{
			delay_ms(5);
			if(s2==0)		//再次确认增加键按下,去抖动
			{
				while(!s2);		//按键释放,只有按键释放了才可以认为一个完整的按键完成
				buzzer();
				if(s1num==1)		//功能键按下一次,此时选择调整秒
				{
					miao++;
					if(miao==60)		//当秒数大于60就清0
						miao=0;
					write_sfm(10,miao);	//在第10位写秒,此时写的时一个两位数,调用的write_sfm()函数
					write_com(0x80+0x40+11);	//光标定位在11位,由于前面已经定义光标闪烁,所以这里不用写write_com(0x0f)
					write_add(1,miao);		//将变化的值写入AT24C02记忆起来,掉电恢复时可以显示此值
				}
				if(s1num==2)
				{
					fen++;
					if(fen==60)
						fen=0;
					write_sfm(7,fen);
					write_com(0x80+0x40+8);
					write_add(2,fen);
				}
				if(s1num==3)
				{
					shi++;
					if(shi==24)
						shi=0;
					write_sfm(4,shi);
					write_com(0x80+0x40+5);
					write_add(3,shi);
				}
			}
		}
		if(s3==0);		//减少键被按下
		{
			delay_ms(5);
			if(s3==0)	//再次确认,去抖
			{
				while(!s3);
				buzzer();
				if(s1num==1)
				{
					miao--;	
					if(miao==-1)//当秒数被减到-1时,秒数清0。
						miao=59;
					write_sfm(10,miao);
					write_com(0x80+0x40+11);
					write_add(1,miao);
				}
				if(s1num==2)
				{
					fen--;
					if(fen==-1)
						fen=59;
					write_sfm(7,fen);
					write_com(0x80+0x40+8);
					write_add(2,fen);
				}
				if(s1num==3)
				{
					shi--;
					if(shi==-1)
						shi=23;
					write_sfm(4,shi);
					write_com(0x80+0x40+5);
					write_add(3,shi);
				}
			}
		}			
	}		
}

void main()		//主程序
{
	init_1602();		//初始化1602液晶
	while(1)	//进入while语句不停的进行按键扫描,来确认是否有按键按下
	{
		keyscan();
	}
}

void timer0() interrupt 1	//定时器0工作方式1
{
	TH0=(65536-50000)/256;	//装初值,因为工作方式1无法自动重装初值,所以这里再次装初值。
	TL0=(65536-50000)%256;
	count++;								//将1s拆分成20个50ms,这里对50ms进行计数来累加到1s
	if(count==20)						//当计数20次时,即为1s
	{
		count=0;							//清0重新计数
		miao++;
		if(miao==60)					//这里是没有按键被按下时,时钟自动的计数
		{
			miao=0;
			fen++;
			if(fen==60)
			{
				fen=0;
				shi++;
				if(shi==24);
				{
					shi=0;
				}
				write_sfm(4,shi);			//在第4位写小时的数据
				write_add(3,shi);			//写入AT24C02进行掉电记忆,这里的3为地址,整个程序都要相同。
			}
			write_sfm(7,fen);
			write_add(2,fen);
		}
		write_sfm(10,miao);
		write_add(1,miao);
	}
}

1602字符库
在这里插入图片描述

  • 2
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值