51单片机DS1302时钟LCD1602显示(可以按键设置时钟)

DS1302实时时钟具有能计算2100年之前的秒、分、时、日、日期、星期、月、年的能力,还有闰年调整的能力。

图1:DS1302引脚示意图在这里插入图片描述
其中:
X1、X2:32.768KHz晶振接入引脚。
GND:地。
:复位引脚,低电平有效,操作时高电平。
I/O:数据输入/输出引脚,具有三态功能。
SCLK:串行时钟输入引脚。
Vcc1:工作电源引脚。
Vcc2:备用电源引脚。 接入电池断电时提供1302电源

图2:控制寄存器
控制寄存器
图3:日历、时钟寄存器
在这里插入图片描述
在这里插入图片描述
图4:单字节读写时序
在这里插入图片描述
LCD时序图(写命令(RS=L):设置显示坐标,写数据(RS=H))
在这里插入图片描述
LCD1602关键性的指令设置
1.清屏指令
在这里插入图片描述
功能:<1> 清除液晶显示器,即将 DDRAM 的内容全部填入"空白"的 ASCII
码 20H;
<2> 光标归位,即将光标撤回液晶显示屏的左上方;
<3> 将地址计数器(AC)的值设为 0。

2.进入模式设置指令

在这里插入图片描述
功能 : 设定每次定入 1 位数据后光标的移位方向 , 并且设定每次写入的一个字符是否移动。参数设定的情况如下所示:
位名 设置
I/D 0=写入新数据后光标左移 1=写入新数据后光标右移
S 0=写入新数据后显示屏不移动 1=写入新数据后显示屏整体右
移 1 个字符

3:显示开关控制指令
在这里插入图片描述
功能:控制显示器开/关、光标显示/关闭以及光标是否闪烁。参数设定的情
况如下:
位名 设置
D 0=显示功能关 1=显示功能开
C 0=无光标 1=有光标
B 0=光标闪烁 1=光标不闪烁

4.功能设定指令
在这里插入图片描述
功能:设定数据总线位数、显示的行数及字型。参数设定的情况如下:
位名 设置
DL 0=数据总线为 4 位 1=数据总线为 8 位
N 0=显示 1 行 1=显示 2 行
F 0=5×7 点阵/每字符 1=5×10 点阵/每字符

5:显示字符地址

在这里插入图片描述
要显示字符时要先输入显示字符地址,也就是告诉模块在哪里显示字符,例如第二行第一个字符的地址是 40H, 那么是否直接写入 40H 就可以将光标定位
在第二行第一个字符的位置呢?这样不行,因为写入显示地址时要求最高位 D7
恒定为高电平 1 所以实际写入的数据应该是 01000000B(40H)
+10000000B(80H)=11000000B(C0H)。在 1602 中我们就用前 16 个就行了。第二行也一样用前 16 个地址。

/*
 实验效果       :1602显示时钟,按K3进入时钟设置,按K1选择设置的时分秒日月,按K2选择
选择设置加1。
*/
#include <reg52.h>
#include <intrins.h>
#define lcd1602data P0

typedef unsigned char u8;
typedef unsigned int u16;

sbit E=P2^7;		 //设置液晶端口	   使能信号
sbit RW=P2^5;		   //读写选择  读:H/写:L
sbit RS=P2^6;		   //数据命令选择  数据:H/命令:L

sbit  key1=P3^1;
sbit  key2=P3^0;
sbit  key3=P3^2;


sbit SCLK=P3^6;			//设置时钟端口
sbit IO=P3^4;
sbit RST=P3^5;	 

u16 read[]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};		 //设置秒分时日月周年读寄存器
u16 write[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};			//设置秒分时日月周年写寄存器
u8 time[]={0x30,0x30,0x22,0x08,0x02,0x05,0x19};			 //存放初始时间

u16 setmark,setplace;					 //setmark检测key3是否按下,setplace选择要调整的时间块。

void delay_ms(u16 n);
void initConfiguration();
void lcdDisplay();
void lcdwrite_com(u8 datas);
void lcdwrite_datas(u8 datas);
void lcdinit();
void writebyte(u8 address,u8 datas);
u8 readbyte(u8 address);
void ds1302init();
void read_time();

void main()
{
	 u16 i;
	 initConfiguration();			//初始化
	 lcdinit();
	 ds1302init();
	 while(1)
	 {
		 if(setmark==0)				//时钟正常运作
		 {
		 	read_time();	
		 }
		 else								//调整时间
		 {
		 	 if(key1==0)
			 {
			 	delay_ms(1);
				if(key1==0)
				{
				 	 setplace++;					//按下key1要调整的时间块加一
					 setplace%=7;
				}
				while(i<50&&key1==0)				//等待key1松开
				 {
					i++;
					delay_ms(10);
				 }
				 i=0;
			 }


			 if(key2==0)
			 {
			 	 delay_ms(1);
				 if(key2==0)								//按下key2对应的初始时间加一
				 {
				 	 time[setplace]++;
					if((time[setplace]&0x0f)>9)					 //换成BCD码。
					{
						time[setplace]=time[setplace]+6;
					}
					if((time[setplace]>=0x60)&&(setplace<2))		//分秒只能到59
					{
						time[setplace]=0;
					}
					if((time[setplace]>=0x24)&&(setplace==2))		//小时只能到23
					{
						time[setplace]=0;
					}
					if((time[setplace]>=0x32)&&(setplace==3))		//日只能到31
					{
						time[setplace]=0;	
					}
					if((time[setplace]>=0x13)&&(setplace==4))		//月只能到12
					{
						time[setplace]=0;
					}	
					if((time[setplace]>=0x7)&&(setplace==5))		//周只能到7
					{
						time[setplace]=1;
					}
																	 
				 }
				 while((i<50)&&(0==key2))
				 {
				 	i++;
					delay_ms(10);
				 }
				 i=0;
			 }

		 }
		 lcdDisplay();
	 }
}

void delay_ms(u16 n)			 //准确延时一毫秒,晶振12M
{
	u16 a,b;
	for(;n>0;n--)
	{
		for(a=199;a>0;a--)
		{
			for(b=1;b>0;b--)
			{
			 	;
			}
		}
	}
}


void initConfiguration()	 //初始化外部中断0
{
	EA=1;
	IT0=1;
	EX0=1;	
}

void init0() interrupt 0		//按下key3时间保持不变
{
	 delay_ms(10);
	 if(key3==0)
	 {
	 	setmark=~setmark;
		setplace=0;
		ds1302init();
	 }
}

void lcdDisplay()				  //显示函数
{
	
	lcdwrite_com(0x80+0x00);				//确定写数据的位置
	lcdwrite_datas('2');
	lcdwrite_datas('0');
	lcdwrite_datas('0'+time[6]/16);				//写入年份的高位
	lcdwrite_datas('0'+(time[6]&0x0f));		//低位
	lcdwrite_datas('-');
	lcdwrite_datas('0'+time[4]/16);
	lcdwrite_datas('0'+(time[4]&0x0f));	 //里面的小括号很重要
	lcdwrite_datas('-');		
	lcdwrite_datas('0'+time[3]/16);
	lcdwrite_datas('0'+(time[3]&0x0f));
	 
	lcdwrite_com(0x8c);
	lcdwrite_datas('0'+(time[5]&0x07));

	lcdwrite_com(0xc0);						  //跳线帽Joe接vcc
	lcdwrite_datas('0'+time[2]/16);
	lcdwrite_datas('0'+(time[2]&0x0f));
	lcdwrite_datas('-');
	lcdwrite_datas('0'+time[1]/16);
	lcdwrite_datas('0'+(time[1]&0x0f));
	lcdwrite_datas('-');
	lcdwrite_datas('0'+time[0]/16);			 
	lcdwrite_datas('0'+(time[0]&0x0f));
}

void lcdwrite_com(u8 datas)			 //lcd液晶写入指令操作        模拟时序
{
	E=0;
	RW=0;
	RS=0;

	lcd1602data=datas;
	delay_ms(1);

	E=1;
	//delay_ms(1);
	E=0;
	
}

void lcdwrite_datas(u8 datas)		 //lcd液晶写入数据操作
{
	E=0;
	RW=0;
	RS=1;

	lcd1602data=datas;
	delay_ms(1);				   //延时不能太长否则调整不灵敏

	E=1;
	//delay_ms(1);
	E=0;
	
}

void lcdinit()						 //LCD液晶初始化
{
	lcdwrite_com(0x38);			//8位总线,显示两行,5x7点阵
	lcdwrite_com(0x0c);				//开显示功能,无关标
	lcdwrite_com(0x06);				//光标右移,即数据依次右移
	lcdwrite_com(0x01);				//清屏
	lcdwrite_com(0x80);				//第一个数据位置
}




void writebyte(u8 address,u8 datas)			  //在寄存器里写时间数据,模拟时序
{
	u8 i;
	RST=0;
	_nop_();

	SCLK=0;
	_nop_();
	RST=1;
	_nop_();
	for(i=0;i<8;i++)
	{
		IO=address&0x01;
		address>>=1;
		SCLK=1;
		_nop_();
		SCLK=0;
		_nop_();	
	}
	for(i=0;i<8;i++)
	{
		IO=datas&0x01;
		datas>>=1;
		SCLK=1;
		_nop_();
		SCLK=0;
		_nop_();	
	}
	RST=0;
}

u8 readbyte(u8 address)			  //读寄存器里的时间数据
{
	u8 i,datas,dat;
	RST=0;
	//_nop_();
	SCLK=0;
	//_nop_();
	RST=1;
	//_nop_();
	for(i=0;i<8;i++)
	{
		IO=address&0x01;
		address>>=1;
		SCLK=1;
		_nop_();
		SCLK=0;
		_nop_();	
	}
	//_nop_();
	for(i=0;i<8;i++)
	{
		dat=IO;
		datas=(datas>>1)|(dat<<7);
		SCLK=1;
		_nop_();
		SCLK=0;
		_nop_();
	}
	RST=0;
	//_nop_();
	SCLK=1;
	//_nop_();
	IO=0;
	//_nop_();
	IO=1;
	//_nop_();
	return datas;
}

void ds1302init()					 //在寄存器里写入初始时间
{
	u8 i;
	writebyte(0x8e,0x00);			 //关闭写保护寄存器
	for(i=0;i<7;i++)
	{
		writebyte(write[i],time[i]);
	}
	writebyte(0x8e,0x80);				 //打开写保护寄存器
}

void read_time()					  //读取时钟时间    time数组存储
{
	u8 i;
	for(i=0;i<7;i++)
	{
		time[i]=readbyte(read[i]);
	}
}

以上是我在学习过程中的一点总结,用的是普中的51单片机·。

  • 47
    点赞
  • 346
    收藏
    觉得还不错? 一键收藏
  • 14
    评论
DS1302是一种实时时钟芯片,常用于单片机的时钟系统。结合LCD1602显示屏,可以实现显示时间的功能。下面提供一个基于Keil环境下的51单片机DS1302时钟LCD1602显示代码,同时可以利用按键设置时钟。 代码中使用了DS1302LCD1602的驱动程序,需要预先调用相关的库文件。同时,通过定义多个函数分别实现初始化、显示设置时间等功能。 代码如下: #include<reg52.h> #include<intrins.h> #include<DS1302.h> #include<LCD1602.h> sbit Key1=P3^2; //定义按键 sbit Key2=P3^3; sbit write=P0^0; //定义DS1302写控制信号 sbit read=P0^1; //定义DS1302读控制信号 sbit ck=P0^2; //定义DS1302时钟控制信号 void Delay(unsigned int n) //延时函数 { int i, j; for (i = 0; i < n; i++) for (j = 0; j < 120; j++) ; } void Main() //主函数 { DS1302_Init(); //DS1302初始化 LCD1602_Init(); //LCD1602初始化 Set_K(); //设置K值 while (1) { unsigned char key=i; //按键变量 if (Key1==0) //判断按键 { Delay(10); if (Key1==0) { key=1; //设置按键值 } while(!Key1); //等待按键释放 } if (Key2==0) { Delay(10); if (Key2==0) { key=2; } while(!Key2); } switch(key) //判断按键值 { case 1:Set_Time();break; //设置时间 case 2:LCD_ShowTime();break; //显示时间 } } } void Set_Time() //设置时间函数 { unsigned char key; //按键变量 LCD_Clear(); //清屏 LCD_WriteString("Please set time:"); //显示提示信息 LCD_SetPosition(2, 0); while (1) //等待按键 { if (Key1==0) { Delay(10); if (Key1==0) { key=1; //设置按键值 } while(!Key1); } if (Key2==0) { Delay(10); if (Key2==0) { key=2; } while(!Key2); } switch(key) //根据按键设置时间 { case 1: //设置时钟LCD_Clear(); LCD_WriteString("Please set hour:"); DS1302_Set(0x80); //打开写保护 DS1302_Set(0x82,10); //设置地址,初始值为10 while (key!=3) { if (Key1==0) { Delay(10); if (Key1==0) { if (DS1302_Get(0x82)>=23) //判断最大值 { DS1302_Set(0x82,0); //超过最大值则归零 } else { DS1302_Set(0x82,DS1302_Get(0x82)+1); //递增1 } key=3; } while(!Key1); } if (Key2==0) { Delay(10); if (Key2==0) { DS1302_Set(0x82, 0); //重置 key=3; } while(!Key2); } } DS1302_Set(0x80); //关闭写保护 break; case 2: //设置分钟值,代码与设置小时值类似,略 case 3: //设置秒值,代码与设置小时值类似,略 case 4: //设置日期,代码略 case 5: //设置月份,代码略 case 6: //设置星期几,代码略,注意星期几的取值范围 case 7: //设置年份,代码略 } if (key>=7) //设置完毕 { break; } } } void LCD_ShowTime() //显示时间函数 { DS1302_GetTime(); //获取时间 LCD_WriteString("Now time is:"); LCD_SetPosition(2, 0); LCD_WriteNum(DS1302_Get(0x82)); LCD_WriteString(":"); LCD_WriteNum(DS1302_Get(0x84)); LCD_WriteString(":"); LCD_WriteNum(DS1302_Get(0x86)); LCD_WriteString(" "); LCD_WriteNum(DS1302_Get(0x88)); LCD_WriteString("/"); LCD_WriteNum(DS1302_Get(0x8A)); LCD_WriteString("/"); LCD_WriteNum(DS1302_Get(0x8C)); } 以上是一个基于Keil环境下的51单片机DS1302时钟LCD1602显示代码,同时可以利用按键设置时钟。需要注意的是,此代码仅供参考,需要根据实际连接情况和要求进行相应调整。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值