转载:DS1302时钟芯片驱动(3线串行通信)
作者:互联网
原地址:https://blog.csdn.net/beyondmike/article/details/78127610
/***************************************************************************** FileName : DS1302.c Function : DS1302驱动 Author : mike Email : hxtiou@163.com Version : V1.0 Date : 2019-10-21 注意:DS1302写寄存器是地址是偶数,读的时候地址+1 比如:往0x80地址写入0x01,读取时需要从0x81读取 DS1302控制字: bit7 bit6 bit5 bit4 bit3 bit2 bit1 bit0 1 RAM/-CK A4 A3 A2 A1 A1 RD/-WR [7] :控制字的最高有效位(位7)必须是逻辑1,如果它为 0 则不能把数据写入DS1302; [6] :如果为0,则表示存取日历时钟数据,为1表示存取RAM数据; [5:1]:指示操作单元的地址; [0] :0表示要进行写操作,为1表示进行读操作; 控制字总是从最低位开始输出.在控制字指令输入后的下一个SCLK时钟的上升沿时数据 被写入DS1302,数据输入从最低位(0位)开始.同样,在紧跟8位的控制字指令后的下一个 SCLK脉冲的下降沿,读出DS1302的数据,读出的数据也是从最低位到最高位. 存取日历时钟(BCD码):其中9~31地址不能存储数据 写入地址:0x00|0x80~0x3E|0x80 = 0x80~0xBE(取偶数) 读取地址:0x00|0x81~0x3E|0x81 = 0x81~0xBF(取奇数) 存取RAM:其中31地址不能存储数据 写入地址:0x00|0xC0~0x3E|0xC0 = 0xC0~0xFE(取偶数) 读取地址:0x00|0xC1~0x3E|0xC1 = 0xC1~0xFF(取奇数) 0x80---秒寄存器的BIT7表示时间暂停位,BIT7为1时停止工作,0时开始工作 0x84---小时寄存器的BIT表示12/24小时制,BIT7为1表示12时制,为0表示24时制; BIT5为AM/PM位,BIT5为1表示PM,0表示AM 0x8E---写保护<写入0x00表示允许进行写操作,0x80表示不允许写操作> 写日期时间寄存器: 0x80---秒 0x82---分 0x84---时 0x86---日 0x88---月 0x8A---星期 0x8C---年 读日期时间寄存器: 0x81---秒 0x83---分 0x85---时 0x87---日 0x89---月 0x8B---星期 0x8D---年 *****************************************************************************/ #include "include.h" #include "DS1302.h" type_time t_time; #if 0 u8 max_day[12]={31,28,31,30,31,30,31,31,30,31,30,31}; //各月的天数 /********************************************************** 检查是否润年,返回当前二月最大天数 判断润年的完整公式为A=X4*10+X3,B=4,A/B;A=B*10+X2,B=4,A/B;A=B*10+X1,B=4,A/B **********************************************************/ u8 chk_max_day(void) { if(t_time.month == 2) { if(t_time.year % 4) //t_time.year取值00~99 return (29); //如果是润年,返回29天。 else return (28); //否则为28天。 } else { return max_day[t_time.month-1]; } } #endif void ds1302_write_byte(u8 dat)//写一个字节 { u8 i; DS1302_IO_OUT(); delay(5); for(i = 8;i > 0;i --) { if(dat & 0x01) { DS1302_IO_HIGH(); } else { DS1302_IO_LOW(); } dat >>= 1; DS1302_CLK_HIGH(); delay(5); DS1302_CLK_LOW(); delay(5); } } u8 ds1302_read_byte(void)//读一个字节 { u8 i = 0; u8 dat = 0; DS1302_IO_IN(); delay(5); for(i = 8;i > 0;i --) { dat >>= 1; if(DS1302_IO_IS_HIGH()) { dat |= BIT(7); } else { dat &= ~BIT(7); } DS1302_CLK_HIGH(); //下降沿读取数据 delay(5); DS1302_CLK_LOW(); delay(5); } return dat; } void ds1302_write(u8 adr,u8 dat)//向1302芯片写函数,指定写入地址,数据 { DS1302_RST_LOW(); DS1302_CLK_LOW(); DS1302_RST_HIGH(); ds1302_write_byte(adr); ds1302_write_byte(dat); DS1302_RST_LOW(); DS1302_CLK_HIGH(); } u8 ds1302_read(u8 adr)//从1302读数据函数,指定读取数据来源地址 { u8 temp = 0; DS1302_RST_LOW(); DS1302_CLK_LOW(); DS1302_RST_HIGH(); ds1302_write_byte(adr); temp = ds1302_read_byte(); DS1302_RST_LOW(); //DS1302_CLK_HIGH(); return temp; } u8 bcd_dec(u8 bcd)//BCD码转10进制函数 { return ((bcd/16)*10+(bcd%16)); } u8 dec_bcd(u8 dec)//10进制转BCD码 { return ((dec/10)*16+(dec%10)); } void ds1302_write_time(void)//写入时间日期 { ds1302_write(0x8E,0x00); //允许写 //t_time.wday = week_conversion(t_time.year,t_time.month,t_time.day); ds1302_write(0x80,dec_bcd(t_time.second)); //秒 ds1302_write(0x82,dec_bcd(t_time.minute)); //分 ds1302_write(0x84,dec_bcd(t_time.hour)); //时 ds1302_write(0x86,dec_bcd(t_time.day)); //日 ds1302_write(0x88,dec_bcd(t_time.month)); //月 //ds1302_write(0x8A,dec_bcd(t_time.wday)); //星期 ds1302_write(0x8C,dec_bcd(t_time.year)); //年 ds1302_write(0x8E,0x80); //禁止写 } void ds1302_read_time(void) //读取时间数据 { t_time.second = bcd_dec(ds1302_read(0x81)&0x7F); //秒 t_time.minute = bcd_dec(ds1302_read(0x83)); //分 t_time.hour = bcd_dec(ds1302_read(0x85)&0x1F); //时 t_time.day = bcd_dec(ds1302_read(0x87)); //日 t_time.month = bcd_dec(ds1302_read(0x89)); //月 //t_time.wday = bcd_dec(ds1302_read(0x8B)); //星期 t_time.year = bcd_dec(ds1302_read(0x8D)); //年 t_time.wday = week_conversion(t_time.year,t_time.month,t_time.day); //printf("%d : %d : %d\n",t_time.hour,t_time.minute,t_time.second); //printf("日期 : 20%d年%d月%d日 星期%d\n",t_time.year,t_time.month,t_time.day,t_time.wday); //printf("时间 : %02d : %02d : %02d\n\n",t_time.hour,t_time.minute,t_time.second); } void ds1302_conversion_hourly(u8 hourly,u8 ampm) //转换12/24小时制,AM/PM<此函数未验证> { ds1302_write(0x8E,0x00); //允许写 if(hourly == HOURLY_12) //12小时制 { t_time.hour |= BIT(7); if(ampm == HOURLY_PM) //PM t_time.hour |= BIT(5); else if(ampm == HOURLY_AM) t_time.hour &= ~BIT(5); } else if(hourly == HOURLY_24) //24小时制 { t_time.hour &= ~BIT(7); } ds1302_write(0x84,dec_bcd(t_time.hour)); ds1302_write(0x8E,0x80); //禁止写 } void ds1302_write_ram(void)//写入RAM的记忆信息 { ds1302_write(0x8E,0x00); //允许写 /* 此处记忆闹钟数据,地址范围0xc0,0xc2...~0xe4 ds1302_write(0xc0,0x08);//闹钟一小时位 ds1302_write(0xc2,0x00);//闹钟一分钟位 ds1302_write(0xc4,0x08);//闹钟二小时位 ds1302_write(0xc5,0x00);//闹钟二分钟位 */ ds1302_write(0x8E,0x80); //禁止写 } void ds1302_reset(void)//复位---写入寄存器时间日期和记忆信息 { //默认时间日期初始化 t_time.second = 0; t_time.minute = 0; t_time.hour = 8; t_time.day = 1; t_time.month = 10; t_time.year = 17; t_time.wday = week_conversion(t_time.year,t_time.month,t_time.day); //写入时间日期 //ds1302_write_time(); /********************************************************************* //写入RAM的记忆信息 ds1302_write_ram(); *********************************************************************/ ds1302_write_time(); ds1302_write(0x8E,0x00); //允许写 ds1302_write(0xFC,0x99); //用于判断是否曾经初始化过时间 ds1302_write(0x8E,0x80); //禁止写 } void ds1302_init(void) //1302芯片初始化 { u8 temp = 0; DS1302_IO_INIT(); DS1302_RST_LOW(); DS1302_CLK_LOW(); temp = ds1302_read(0xFD); //判断振荡器是否为开 if(temp != 0x99) //如果特定寄存器的数据不是默认写入的值---重写默认时间 { ds1302_reset(); //重新写入时间 printf("DS1302 reinit ......\n"); } /********************************************************************************/ ds1302_write(0x8E,0x00); //允许写 ds1302_write(0xFA,0x89); //写0x89 ds1302_write(0x8E,0x80); //禁止写 //delay_ms(10); temp = ds1302_read(0xFB); if(temp == 0x89) //读取写进去的值 { printf("DS1302 init successful !\n"); } else { printf("DS1302 init error !\n"); } /********************************************************************************/ ds1302_read_time(); //读取时间 t_time.second &= 0x7F; //启动DS1302时钟振荡器(0x80寄存器的bit7置0) ds1302_write(0x8E,0x00); //允许写 /********************************************************/ ds1302_write(0x80,dec_bcd(t_time.second)); ds1302_write(0x90,TCS_OFF|DS_OFF); //充电被禁止 //ds1302_conversion_hourly(HOURLY_12,HOURLY_PM);//设置小时制 /********************************************************/ //ds1302_write(0x90,TCS_ON|DS_DIODE_TWO|CS_RES_8K); //启动充电---2个二极管,8K电阻涓流充电 ds1302_write(0x8E,0x80); //禁止写 /* if(t_time.second > 59) t_time.second = 0; if(t_time.minute > 59) t_time.minute = 0; if(t_time.hour > 23) t_time.hour = 0; if(t_time.day > 31) t_time.day = 1; if(t_time.month > 12) t_time.month = 1; if(t_time.year > 99) t_time.year = 0; */ } /**************************************************************************** 算法:日期+年份+所过闰年数+月较正数之和除7 的余数就是星期,但如果是在闰年又不到 3月份,上述之和要减一天再除7,星期数为0 century=0 为21世纪,century=1 为20世纪 输入输出数据均为BCD数据 年月日为16进制数 *****************************************************************************/ u8 week_conversion(u8 year,u8 month,u8 day) //星期转换 { u16 y = year + 2000; //一月和二月被当作前一年的 if((month==1)||(month==2)) { month+=12; y--; } //u8 week=(day+2*month+3*(month+1)/5+y+y/4-y/100+y/400)%7; //printf("new:%d.%d.%d\n",y,month,day); return (day+2*month+3*(month+1)/5+y+y/4-y/100+y/400)%7+1; }
/***************************************************************************** FileName : ds1302.h Function : DS1302驱动 Author : mike Email : hxtiou@163.com Version : V1.0 Date : 2019-10-21 Note : 注意:DS1302写寄存器是地址是偶数,读的时候地址+1 比如:往0x80地址写入0x01,读取时需要从0x81读取 *****************************************************************************/ #ifndef DS1302_H #define DS1302_H #define BIT(n) (1 << n) #define DS1302_IO_INIT() P2DIR &= ~BIT(0);P3DIR &= ~BIT(7);P0DIR &= ~BIT(6) //IO初始化 #define DS1302_CLK_HIGH() P2 |= BIT(0) #define DS1302_CLK_LOW() P2 &= ~BIT(0) #define DS1302_IO_HIGH() P3 |= BIT(7) #define DS1302_IO_LOW() P3 &= ~BIT(7) #define DS1302_RST_HIGH() P0 |= BIT(6) #define DS1302_RST_LOW() P0 &= ~BIT(6) #define DS1302_IO_IN() P3DIR |= BIT(7);P3PU0 |= BIT(7) #define DS1302_IO_OUT() P3DIR &= ~BIT(7);P3PU0 &= ~BIT(7) #define DS1302_IO_IS_HIGH() (P3 & BIT(7)) #define SEC_ADR 0x80 #define MIN_ADR 0x82 #define HOU_ADR 0x84 #define DAY_ADR 0x86 #define MON_ADR 0x88 #define YEA_ADR 0x8C #define WRITE_SW_ADR 0x8E //写保护地址 #define CHARGE_ADR 0x90 //充电写地址<读为0x91> #define TCS_ON 0xA0 #define TCS_OFF 0x00 #define DS_DIODE_ONE 0x04 //VCC2和VCC1之间1个二极管充电 #define DS_DIODE_TWO 0x08 //VCC2和VCC1之间2个二极管充电 #define DS_OFF 0x00 //充电被禁止 #define CS_RES_NO 0x01 //无电阻 #define CS_RES_2K 0x01 //2K电阻 #define CS_RES_4K 0x02 //4K电阻 #define CS_RES_8K 0x03 //8K电阻 #define HOURLY_24 0x00 #define HOURLY_12 0x01 #define HOURLY_PM 0x00 #define HOURLY_AM 0x01 typedef struct { u8 year; //取值00~99 u8 month; u8 day; u8 hour; u8 minute; u8 second; u8 wday; } type_time; extern type_time t_time; u8 bcd_dec(u8 bcd); u8 dec_bcd(u8 dec); void ds1302_write(u8 adr,u8 dat); u8 ds1302_read(u8 adr); void ds1302_init(void); void ds1302_write_time(void); void ds1302_read_time(void); u8 week_conversion(u8 year,u8 month,u8 day); #endif
标签:ds1302,u8,DS1302,write,time,串行,dec,时钟 来源: https://www.cnblogs.com/fly2199/p/14993369.html