⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 clock.c

📁 利用单片机和1602显示日期和时间的程序
💻 C
字号:
#include <reg51.h>
#include <intrins.h>
unsigned char code dis_week[]={"SUN,MON,TUE,WED,THU,FRI,SAT"};
unsigned char code para_month[13]={0,0,3,3,6,1,4,6,2,5,0,3,5};	//星期月参变数
unsigned char data dis_buf1[17];//lcd上排显示缓冲区
unsigned char data dis_buf2[17];//lcd下排显示缓冲区
unsigned char data year,month,date,week;//年、月、日、星期
unsigned char hour,min,sec,sec100;//时、分、秒、10ms
unsigned char data flag,vkey,skey;//设置状态计数标志、按键先前值、按键当前值
sbit	 rs = P3^0;//LCD数据/命令选择端(H/L)
sbit	 rw = P3^1;//LCD读/写选择端(H/L)
sbit	 ep = P3^2;//LCD使能控制
sbit	PRE = P1^1;				//调整键(AN3)
sbit	SET = P1^2;				//调整键(AN4)
sbit  in=P3^3;	//外部中断1 触发
//sbit JJ=P2^0;

unsigned char scan_key();//检测独立键盘
void delay(unsigned char ms);//延时子程序
void lcd_init();//LCD初始化
bit  chek_busy();//测试LCD忙碌状态程序
void write_cmd(char cmd);//写入指令到LCD程序
void write_dat(char dat);//写入数据到LCD程序
void lcd_pos(char pos);//LCD数据指针位置程序
void update_disbuf(unsigned char t1,unsigned char t2[]);//更新显示缓冲区函数
bit leap_year();//判断是否为闰年
unsigned char week_proc();//星期自动计算与显示函数
void pro_timedate();//时间日期处理程序
void pro_display() reentrant;//显示处理程序
unsigned char scan_key();		//按键扫描程序
void pro_key();					//按键处理程序


//LCD初始化设定
void lcd_init()
{					
	write_cmd(0x08);
	delay(5);
	write_cmd(0x01);		//清除LCD的显示内容
	delay(5);
	write_cmd(0x06);		//LCD显示光标移动设置(光标地址指针加1,整屏显示不移动)
	delay(5);
	write_cmd(0x0c);		//LCD开显示及光标设置(光标不闪烁,不显示"-")

}


//测试LCD忙碌状态
bit chek_busy()
{	
	bit result;
	rs = 0;
	rw = 1;
	ep = 1;
	_nop_();
	_nop_();
	_nop_();
	_nop_();
	result =(bit)(P0&0x80);	//LCD的D0--D7中,D7=1为忙碌,D7=0为空闲
	ep = 0;
	return result;	
}

//写入指令到LCD
void write_cmd(char cmd)
{							
	//while(chek_busy());	//当chek_busy为1时,再次检测LCD忙碌状态,chek-busy为0时,开始写指令
	rs = 0;
	rw = 0;
	ep = 0;	
	P0 = cmd;
	delay(3);
	ep = 1;
	delay(3);
	ep = 0;		
}

//写入数据到LCD
void write_dat(char dat)	
{							
	//while(chek_busy());	//当chek_busy为1时,再次检测LCD忙碌状态,chek_busy为0时,开始写数据
	rs = 1;
	rw = 0;
	ep = 0;
	P0 = dat;
	delay(3);
	ep = 1;
	delay(3);
	ep = 0;	
}
//LCD数据指针位置程序
void lcd_pos(char pos)
{						
	write_cmd(pos|0x80);	//数据指针=80+地址码(00H~27H,40H~67H)
}

unsigned char scan_key()
{
	skey=0x00;									//给变量vkey置初值
	skey|=PRE;									//读取PRE键的状态
	skey=skey<<1;								//将PRE键的状态存于skey的B1位
	skey|=SET;									//读取SET键的状态,并存于skey的B0位
	return skey;								//返回skey的键值(即PRE,SET的状态)	
}

//Timer0中断处理程序,秒的产生
void timer0() interrupt 1 
{
	//TH0=(63336-45872)/256;			
	//TL0=(63336-45872)%256;	
	TH0=0x4c;
	TL0=0x00;	
	sec100++;
	if(sec100>=20)///1秒时间 (100*10ms=1000ms=1s)
		{sec100 = 0;
		 pro_timedate();//调用时间和日期处理程序
		}
	if (sec&0x01)										//"NJUPT"闪一秒,停一秒
		update_disbuf(0x20,"        ");	   //0x00表示显示00位置的自定义字符		
	else 
  		update_disbuf(0x20,"NJUPT   ");   
	pro_display();  //调用显示处理函数
}

void int0() interrupt 2
{
	TR0=0;									//禁止Timer0
	EA=0;									//禁止中断
	write_cmd(0x0e);							//显示光标"_",整个光标不闪烁
	flag=0;			
	vkey=0x03;
	while(flag^0x07)
		{skey = scan_key();					//扫描按键状态
		if (skey^vkey)						//若skey与vkey相同,跳出循环,相异执行循环体
			{	delay(5);					//去按键抖动	
				skey = scan_key();			//转回扫描按键状态			
				if (skey^vkey)				//若skey与vkey相同,跳出循环,相异执行循环体		
			 		{	vkey=skey;			//将skey的值付给vkey	
						if (skey==0x01)		//PRE键按下
							{	 flag++;	//调整标志位加1 
									switch (flag)	//将光标置于相应调整位置
									{	
									  		
										case 1:	update_disbuf(0x50,"time:   ");
												pro_display();
												lcd_pos(0x05);break;		//光标置年调整位置										  	
										case 2:	lcd_pos(0x08);break;		//光标置月调整位置
										case 3:	lcd_pos(0x0b);break;		//光标置日调整位置
											
										case 4: 	lcd_pos(0x49);break;		//光标置时调整位置
										case 5:	lcd_pos(0x4c);break;		//光标置分调整位置
										case 6:	lcd_pos(0x4f);break;		//光标置秒调整位置
												
										default:break;
									}
							}
						if (skey==0x02)		    //SET键按下
							{	
								pro_key();		//转设置按键处理程序
							}
					}
			}								 
		}								 
	write_cmd(0x0c);							//设置LCD开显示及光标不闪烁,不显示"-"
	write_cmd(0x01);	//清除LCD的显示内容
	in=1;
	EA=1; 							//CPU开中断,INT0,INT1,开中断
	TR0=1;									//Timer0启动
}
void pro_key()
{
	switch (flag)
		{ 
		case 1:year++;
				if	(year> 99) year= 0;
				week_proc();                        //星期自动运算
				update_disbuf(0x50,"time:   ");
				pro_display();
				lcd_pos(0x05);break;
	 	case 2:month++;
				if (month>12) month=1;
				week_proc();						//星期自动运算
				update_disbuf(0x50,"time:   ");
				pro_display();
				lcd_pos(0x08);break;
		case 3:date++;
				if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
					if (date>31) date=1;			//大月31天
				if (month==4||month==6||month==9||month==11)		
				 	if (date>30) date=1;			//小月30天
				if (month==2)			
					{if(leap_year())				//闰年的条件
						{if (date>29) date=1;}		//闰年2月为29天
					 else
						{if (date>28) date=1;}}		//平年2月为28天	
				week_proc();					    //星期自动运算
				update_disbuf(0x50,"time:   ");
				pro_display();
				lcd_pos(0x0b);break;
		
		case 4:hour++;
				if (hour>23) hour=0;
				update_disbuf(0x50,"time:   ");
				pro_display();
				lcd_pos(0x49);break;	
		case 5:min++;
				if (min>59) min=0;
				update_disbuf(0x50,"time:   ");
				pro_display();
				lcd_pos(0x4c);break;
		case 6:sec++;
				if (sec>59) sec=0;
				update_disbuf(0x50,"time:   ");
				pro_display();
				lcd_pos(0x4f);break;
		default: break ;												 
		}
}	

// 延时子程序
void delay(unsigned char ms) 
{	
    unsigned char x,y;
	for(x=ms;x>0;x--)
		for(y=110;y>0;y--);
}
//计算闰年子程序
bit leap_year()
{
	bit leap;
	if((year%4==0&&year%100!=0)||year%400==0)//闰年的条件
		leap=1;
	else
		leap=0;
	return leap;
}

//星期的自动运算和处理
unsigned char week_proc()
{	unsigned char num_leap;	
	unsigned char c;
	num_leap=year/4-year/100+year/400;//自00年起到year所经历的闰年数
	if( leap_year()&& month<=2 )	  //既是闰年且是1月和2月	
		c=5;
	else 
		c=6;
	week=(year+para_month[month]+date+num_leap+c)%7;//计算对应的星期
	return week;
}
//时间和日期处理程序
void pro_timedate()
{	
	sec++;
	if(sec > 59)
		{sec = 0;
		 min++;
		 if(min>59)
			{min=0;
			 hour++;
			 if(hour>23)
				{hour=0;
				 date++;
				 if (month==1||month==3||month==5||month==7||month==8||month==10||month==12)
					 if (date>31) {date=1;month++;}					//大月31天
				 if (month==4||month==6||month==9||month==11)		
				 	 if (date>30) {date=1;month++;}					//小月30天
				 if (month==2)			
					 {if( leap_year())								//闰年的条件
						{if (date>29) {date=1;month++;}}			//闰年2月为29天
					 else
						{if (date>28) {date=1;month++;}}			//平年2月为28天	
					 }				
				 if (month>12) {month=1;year++;}
				 if (year>99) year=0;
				}
			}
		}
	week_proc();
}
//显示处理程序
void pro_display() reentrant
{	unsigned char i;
	lcd_pos(0x00);
	for (i=0;i<=15;i++)
		{write_dat(dis_buf1[i]);}

	lcd_pos(0x40);
	for (i=0;i<=15;i++)
		{write_dat(dis_buf2[i]);}
}

//更新显示缓冲区
void update_disbuf(unsigned char t1,unsigned char t2[])	
{	dis_buf1[0]=t1; 			//空格
	dis_buf1[1]=0x20; 			//空格
	dis_buf1[2]=50; 			//'2' 
	dis_buf1[3]=48;             //'0'
	dis_buf1[4]=year/10+48; //年
	dis_buf1[5]=year%10+48; 
	dis_buf1[6]='/';			///'/
	dis_buf1[7]=month/10+48;//月
	dis_buf1[8]=month%10+48; 
	dis_buf1[9]='/'; 			//'/'
	dis_buf1[10]=date/10+48;//日
	dis_buf1[11]=date%10+48;
	dis_buf1[12]=0x20;			//'-'
	dis_buf1[13]=dis_week[4*week];
	dis_buf1[14]=dis_week[4*week+1];
	dis_buf1[15]=dis_week[4*week+2];

	dis_buf2[0]=t2[0]; 
	dis_buf2[1]=t2[1]; 
	dis_buf2[2]=t2[2]; 
	dis_buf2[3]=t2[3];
	dis_buf2[4]=t2[4]; 
	dis_buf2[5]=t2[5];
	dis_buf2[6]=t2[6];			//空格
	dis_buf2[7]=t2[7];
	dis_buf2[8]=hour/10+48; 
	dis_buf2[9]=hour%10+48; 
	dis_buf2[10]=0x3a;			//':'
	dis_buf2[11]=min/10+48;
	dis_buf2[12]=min%10+48;
	dis_buf2[13]=0x3a;			//':'
	dis_buf2[14]=sec/10+48;
	dis_buf2[15]=sec%10+48;

}
//主程序,初始化及初值设定
void main()
{	
	lcd_init();		                   	//初始化LCD
	hour=0;min=0;sec=0;				    //开机时的时,分,秒显示
	year= 5; month=1;date=1;     		//开机时的年,月,日,星期显示
	week_proc();
	update_disbuf(0x20,"NJUPT   ");
	pro_display();
	TMOD = 0x01;						//定时器0工作于模式1, 16位定时方式
	//TH0=(63336-45872)/256;				//Timer0置10ms定时初值 
	//TL0=(63336-45872)%256;	
	TH0=0x4c;
	TL0=0x00;			
	EA=1;	//CPU开中断
	EX1=1;//开外部中断1
	ET0=1;//Timer0开中断
	PX1=1;;//设置INT1为中断最高优先级
	//IT1=1;					//外部INT0设置为电平触发方式
	TR0 = 1;							//Timer0启动
	while(1)
	{
		if(PRE==0)		//软控制触发外部中断1
			in=0;
		else
			in=1;
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -