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

📄 newds1302.c

📁 非常经典~~的 一个~~~~ds1302液晶时钟
💻 C
字号:
#include<reg52.h>
#define uint unsigned int
#define uchar unsigned char
/*lcd管脚定义*/
sbit lcdrs=P2^0;
sbit lcden=P2^1;
sbit lcdrw=P3^2;
bit lcdzt;

/*ds1302管脚定义*/
sbit dsce=P2^2;
sbit dsclk=P2^3;
sbit dsdata=P2^4;
/*ACC的定义*/
sbit a0=ACC^0;
sbit a7=ACC^7;

sbit key1=P2^5;
sbit key2=P2^6;
sbit key3=P2^7;

uchar kk=0,adda=0,yueb;
uchar *weekda[]={"","777","111","222","333","444","555","666"};


uchar  ds_time[]={0,0,0,0,0,0,0};

uchar code ds_data_init[]={0x08,0x08,0x8,0x01,0x08,0x01,0x08};

//uchar code ds_write_add[]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};

void delay(uchar);			//延时,C最少=90 a=5
//void delay1(uint a);				//长时间延时用于键盘检测
/**ds1302的驱动*/
void ds_write(uchar); 						//往ds1302中写入一字节的数据或地址 ,aa=数据或地址
void  ds_write_b(uchar,uchar);				//往ds1302中写一字节数据
void ds_write_bs(uchar *time);				//写字令,多字节
void ds_write_reg(uchar ,uchar *pwrite);	//写寄存器指令,多字节

uchar ds_read(); 					//往ds1302中读取一字节数据,放在ACC中
uchar ds_read_b(uchar);				//往ds1302中读取一字节数据, 地址为cc 读出的数据放在ee中
void ds_read_bs(uchar *time1);		//读字令,多字节
void dsread_reg(uchar ,uchar *preg);	//读寄存器 ,多字节

//void ds_bcdzh();					//把BCD码转换成十六进制的
void ds_bcdzh(uchar *p);	//把BCD码转换成十六进制的
uchar dectobcd(uchar);//bcd转十六进,
void time_dec_bcd();//把ds_time数组里的值转换成bcd码并放在数组里
void runyear();//判断是否润年,并返回相应的月份天数
/*LCD的驱动*/
void lcd_com(uchar);		//向lcd发指令
void lcd_data(uchar);		//向lcd发送数据
void lcd_init();			//lcd初始化

/*关于显示*/
void lcd_dfs(uchar,uchar);//	用来刷新分秒天 aa=数据 bb=LCD地址
void lcd_yydw();			//显示年月日天星期
void week(uchar);			//星期的处理

void jbsm(uchar *p2);		//键盘扫描
/*结构体typedef
 struct sys
{
uchar miao;
uchar  fen;
uchar  shi;
uchar  day;
uchar  yue;
uchar  week;
uchar  year;
}dssj,dssja={0x05,0x05,0x22,0x25,0x11,0x01,0x08}; */ 



void delay(uchar a)		//延时,C最少=90 a=5
{
uchar b,c;
for(b=a;b>0;b--)
for(c=90;c>0;c--);
}

void delay1(uint a)		//长时间延时用于键盘检测
{
uint b,c;
for(b=a;b>0;b--)
for(c=150;c>0;c--);
}

void ds_write(uchar aa) 	//往ds1302中写入一字节的数据或地址 ,aa=数据或地址
{
	uchar i;
	ACC = aa;
	for(i=8; i>0; i--)
		{	
		dsdata = a0;//相当于汇编中的 RRC 
		dsclk = 1;
		dsclk = 0;
		ACC=ACC>>1;
		}
}

uchar ds_read()		//往ds1302中读取一字节数据,放在ACC中
{
	uchar i;	
		for(i=8; i>0; i--)
		{
		ACC = ACC >>1;//相当于汇编中的 RRC 
		a7 = dsdata;
		dsclk = 1;
		dsclk = 0;
		}
	return(ACC);
}

uchar ds_read_b(uchar cc)	//往ds1302中读取一字节数据, 地址为cc 读出的数据放在ee中
{
	uchar ee;
	dsce=0;
	dsclk=0;
	dsce=1;

	ds_write(cc);
	ee=ds_read();

	dsclk=1;
	dsce=0;
	return ee;
}

void  ds_write_b(uchar ff ,uchar gg)	//往ds1302中写一字节数据, 地址为ff 要写入的数据放在gg中
{
	dsce=0;
	dsclk=0;
	dsce=1;

	ds_write(ff);
	ds_write(gg);

	dsclk=1;
	dsce=0;
}

void ds_write_bs(uchar *time)    //写字令,多字节 ,格式为: 秒 分 时 日 月 星期 年
{
	uchar i;
	ds_write_b(0x8e,0x00);// 控制命令,WP=0,写操作
	dsce = 0;
	dsclk = 0;
	dsce = 1;
	ds_write(0xbe);//0xbe:时钟多字节写命令 
	
		for (i = 8; i>0; i--)//8Byte = 7Byte 时钟数据 + 1Byte 控制
		{
		ds_write(*time); // 写1Byte数据
		time++;	
		}
		
	dsclk = 1;
	dsce = 0;
}

void ds_read_bs(uchar *time1)    //读字令,多字节,格式为: 秒 分 时 日 月 星期 年
{
	uchar i;
	dsce = 0;
	dsclk = 0;
	dsce = 1;
	ds_write(0xbf);// 0xbf:时钟多字节读命令 
		for (i=8; i>0; i--)	
		{
		*time1 = ds_read();//读1Byte数据 
		time1++;
		}
	dsclk = 1;
	dsce = 0;
}


void lcd_com(uchar aa)	//向lcd发指令
{
	lcdrs=0;
	P0=aa;
	delay(5);
	lcden=1;
	delay(5);
	lcden=0;
	delay(1);
	lcdrs=1;
}

void lcd_readzt()		//LCD读状态
{
uchar lcdzta;
lcdrs=0;
lcdrw=1;
lcden=1;
P0=0xff;
lcdzta=P0;
lcdzta<<1;
lcdzt=CY;
}

void lcd_init()			//lcd初始化
{
	lcden=0;
	lcd_com(0x38);
	lcd_com(0x0c);
	lcd_com(0x06);
	lcd_com(0x01);
	lcd_com(0x80);

		ds_write_bs(&ds_data_init);	//往ds1302中写入多字节
		ds_read_bs(&ds_time);		//往ds1302中读出多字节
		ds_bcdzh(&ds_time);		//把BCD码转换成十六进制的
		
		lcd_dfs(ds_time[2],0xc4);		//时
		lcd_data(':');
		lcd_dfs(ds_time[1],0xc7);		//分
		lcd_data(':');
		lcd_dfs(ds_time[0],0xca);	//秒

		lcd_com(0x80);
		lcd_data('2');
		lcd_data('0');
		lcd_dfs(ds_time[6],0x82);	//年
		lcd_data('-');
		lcd_dfs(ds_time[4],0x85);		//月
		lcd_data('-');
		lcd_dfs(ds_time[3],0x88);		//天
		lcd_com(0x8b);
		week(ds_time[5]);			//星期
}

void lcd_data(uchar bb)			//向lcd发送数据
{
	lcdrs=1;
	P0=bb;
	delay(5);
	lcden=1;
	delay(5); 
	lcden=0;
	delay(1);
	lcdrs=0;
}


 void lcd_dfs(uchar aa,uchar bb)//	用来刷新分秒天 aa=数据 bb=LCD地址
{
	uchar a=0,b=0;
	a=aa%10;
	b=aa/10;
		lcd_com(bb);
		lcd_data(b+0x30);
		lcd_data(a+0x30);
}

void lcd_sfm()//显示时分秒
{
	lcd_dfs(ds_time[2],0xc4);//时
	lcd_dfs(ds_time[1],0xc7);//分
	lcd_dfs(ds_time[0],0xca);//秒
}

void lcd_yydw()//显示年月日天星期
{
	lcd_dfs(ds_time[6],0x82);//年
	lcd_dfs(ds_time[5],0x85);//月
	lcd_dfs(ds_time[4],0x88);//天
	lcd_com(0x8b);
	week(ds_time[3]);//星期
}

void week(uchar cc)//星期的处理
{
	uchar a,f;
	a=cc%10;
	for (f=0;f<3;f++)
	lcd_data(*weekda[a]); 
}

void dsread_reg(uchar rbs ,uchar *preg)//寄存器多字节读取
{
	uchar i;
	dsce = 0;
	dsclk = 0;
	dsce = 1;
	ds_write(0xff);//0xbf:时钟多字节读命令 
		for (i=rbs; i>0; i--)
		{
		*preg = ds_read();/* 读1Byte数据 */
		preg++;
		}
	dsclk = 1;
	dsce = 0;
} 

void ds_write_reg(uchar wbs ,uchar *pwrite)    //寄存器写指令,多字节
{
	uchar i;
	ds_write_b(0x8e,0x00);/* 控制命令,WP=0,写操作*/
	dsce = 0;
	dsclk = 0;
	dsce = 1;
	ds_write(0xfe);/* 0xbe:时钟多字节写命令 */
	
		for (i = wbs; i>0; i--)/*共31字节*/	
		{
		ds_write(*pwrite); /* 写1Byte数据*/	
		pwrite++;	
		}
	dsclk = 1;
	dsce = 0;
}

void ds_bcdzh(uchar *p)//把BCD码转换成十六进制的,用指针方式,并放在ds_time中
{
	uchar i,ee=*p;
	for(i=0;i<7;i++)
		{
		*p=(((*p)&0x70)>>4)*10+((*p)&0x0f);
		p++;
		ee=*p;
		}
}

/*void ds_bcdzh()//把BCD码转换成十六进制的
{
dssj.miao=(((dssj.miao&0x70)>>4)*10)+(dssj.miao&0x0f);
dssj.fen=(((dssj.fen&0x70)>>4)*10)  + (dssj.fen&0x0f);
dssj.shi=(((dssj.shi&0x70)>>4)*10)  + (dssj.shi&0x0f);
dssj.day=(((dssj.day&0x70)>>4)*10)  + (dssj.day&0x0f);
dssj.yue=(((dssj.yue&0x70)>>4)*10)  + (dssj.yue&0x0f);
dssj.week=(((dssj.week&0x70)>>4)*10)+(dssj.week&0x0f);
dssj.year=(((dssj.year&0x70)>>4)*10)+(dssj.year&0x0f);
}*/

//bcd转十六进,注意DEC数值,比如日大于了相应月的最大日期,DS1302将会错乱。
uchar dectobcd(uchar dec)//bcd转十六进,
{
 uchar bcd;
 bcd=0;
 while(dec>=10)              
{
  dec-=10;                         
  bcd++;
 } 
 bcd<<=4;
 bcd|=dec;
 return bcd;
}

void time_dec_bcd()//把ds_time数组里的值转换成bcd码并放在数组里
{
uchar dtb;
for(dtb=0;dtb<7;dtb++)
ds_time[dtb]=dectobcd(ds_time[dtb]);
//ds_write_bs(&ds_time);    //写字令,多字节 把数组里的bcd码写入ds1302k ,格式为: 秒 分 时 日 月 星期 年
}

void runyear()//判断是否润年,并返回相应的月份天数
{
bit yeara=0;
uchar yuea=ds_time[4];
uint ryear;
ryear=2000;
ryear=ryear+ds_time[6];
if((ryear%100!=0)&&(ryear%4==0)||(ryear%400==0))		{yeara=1;}

if(yeara==0&&yuea==2)	{yueb=28;}
if(yeara==1&&yuea==2)	{yueb=29;}
	if(yuea!=2)
	{
	if((yuea%2!=0&&yuea<8)||(yuea%2==0&&yuea>7)) {yueb=31;}
	if((yuea%2!=0&&yuea>8)||(yuea%2==0&&yuea<7)) {yueb=30;}
	}
//return yueb;
}

void jbsm()				//键盘扫描
{
uchar *p; uchar ds_wadd;
	key1=1;
	key2=1;
	key3=1;
	runyear();
	if(key1==0)
	{
		delay1(100);		//功能键
		if(key1==0)
		{
			while(!key1);
			kk++;
			lcd_com(0x0f);							//发送LCD命令,开启光标,并闪烁
			switch(kk)
			{//add--液晶地址 adat=秒分时......
			case 1: adda=0xca; *p=ds_time[0]; ds_wadd=0;break;//秒位
			case 2: adda=0xc7; *p=ds_time[1]; ds_wadd=1; break;//分位
			case 3: adda=0xc4; *p=ds_time[2]; ds_wadd=2; break;//时位
			case 4: adda=0x8b; *p=ds_time[5]; ds_wadd=5;break;//星期
			case 5: adda=0x88; *p=ds_time[3]; ds_wadd=3;break;//天
			case 6: adda=0x85; *p=ds_time[4]; ds_wadd=4; break;//月
			case 7: adda=0x82; *p=ds_time[6]; ds_wadd=6; break;//年
			case 8: kk=0; 
			time_dec_bcd();			//转换成bcd码
			ds_write_bs(&ds_time);	//往ds1302中写入多字节时钟
			lcd_com(0x0c);
			break;					//结束调时操作
			}
			lcd_com(adda);			//让光标在指定地址闪烁
			
		}
	}

	if(kk!=0)		//按键加一
	{
		if(key2==0)
		{
			delay1(100);
			if(key2==0)
			{
			while(!key2);
			(*p)++;
			if(((kk==1)||(kk==2))&&((*p)==60)) 	{*p=0;}//秒分加一
			if((kk==3)&&(*p)==24)	{*p=00;}//小时加一

			if((kk==5)&&(*p)==yueb+1)	{*p=1;}//日期加一
			if((kk==6)&&(*p)==13)	{*p=1;}//月份加一
			if((kk==7)&&(*p)==100)	{*p=0;}//年份加一
			lcd_dfs(*p,adda);
			lcd_com(adda);
			if(kk==4){if((kk==4)&&(*p)==8) *p=1; week(*p);lcd_com(adda);}//星期加一
			}
			ds_time[ds_wadd]=*p;
		}
		
		if(key3==0)//按键减一
		{
			delay1(100);
			if(key3==0)
			{
			while(!key3);
			(*p)--;
			if(((kk==1)||(kk==2))&&((*p)==255)) 	{*p=59;}//秒分减一
			if((kk==3)&&(*p)==255)	{*p=23;}//小时减一
			if((kk==5)&&(*p)==0)	{*p=yueb;}//日期减一
			if((kk==6)&&(*p)==0)	{*p=12;}//月份减一
			if((kk==7)&&(*p)==0)	{*p=99;}//年份减一
			lcd_dfs(*p,adda);
			lcd_com(adda);
			if(kk==4){if((kk==4)&&(*p)==0) *p=7; week(*p);lcd_com(adda);}//星期加一
			}
		}ds_time[ds_wadd]=*p;
	}
}

void main()
{
lcd_init();

		while(1)
		{		
			if(kk==0)
			{
			ds_read_bs(&ds_time);	//读取ds1302时钟信号---突发模式
			ds_bcdzh(&ds_time);	//BCD转换,指针方式
			//ds_bcdzh();			//另一种方式BCD转换
			lcd_sfm();			//时分秒刷新
			//lcd_yydw();
			}
		jbsm();
			/*	ds_write_reg(8 ,&dssja);
			dsread_reg(8 ,&dssj);
			lcd_sfm();
			while(1);*/
		}
}

⌨️ 快捷键说明

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