📄 newds1302.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 + -