单片机控制时钟芯片DS1302之模块化编程及待解决的问题
这里将我编写的STC12C5A60S2单片机控制EEPROM芯片ds1302的程序共享一下,是希望前辈们给予斧正 。
(补充:以下代码只需要修改.h文件中含有 “选择” 字样的部分,就可以达到复用的效果)
(提示:因为其中的宏较多,建议source insight查看代码)
对于LCD2004模块,请参考我后来才更新的另一篇文章《单片机控制2004A液晶屏之模块化编程》
同时程序中有一个地方也是有疑问的,希望大家给予指点 : 在ds1302AddressReadByte(....)(ds1302.c的167~175行)函数中有一部分代码如下:
//以下为DS1302复位的稳定时间,必须的。(这句话摘抄于范例代码) ds1302_sclk_bit= 1; _nop_(); ds1302_io_bit= 0; _nop_(); ds1302_io_bit= 1; _nop_();
我发现这一块代码中,ds1302_io_bit=0 ; 这一句代码不能少,这一块代码中只需要这一句,而屏蔽其他语句
现象也正确,但是为什么和datasheet中没有对应???????????????????????????????????????????(不理解)
以下为实验的记录(成功)
(1)设置工作模式为12小时模式,设置为上午(2014年星期天3月2日11点59分50秒)
设置过程:修改ds1302.h中的宏
#define DS1302_DEFAULT_HOUR_MODE DS1302_HOUR_REGISTER_12HOURS_MODE #define DS1302_DEFAULT_AM_OR_PM DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE
随机截取其中两张图片如下:
(2)设置工作模式为24小时,时间为2014年星期天3月2日23点59分50秒
设置过程:修改ds1302.h的宏
#define DS1302_DEFAULT_HOUR_MODE DS1302_HOUR_REGISTER_24HOURS_MODE
随机截取其中两张图片如下:
(3)设置ds1302时钟不启动,12小时模式,时间为2014年星期天3月2日11点59分55秒
设置方法:修改ds1302.h的宏:
#define DS1302_DEFAULT_CLOCK DS1302_CLOCK_DISABLE
15秒之后,截图
程序部分只需要注意中文注释的地方即可
测试程序
/*################main.c start################*/
#include <reg52.h> #include <stdlib.h> #include "common.h" #include "lcd2004.h" #include "ds1302.h" UB8 time_data[7]={0,0,0,0,0,0,0}; UB8 temp ; void timeDisplay(void); void main(void) { lcd2004Init(); lcd2004WriteCommand(0x0c); /*为了显示更清楚,临时设置光标不显示, 也可以在lcd2004的内部函数修改*/ ds1302Init() ; //设置时间,2014年星期天,3月2日11点59分50秒 ds1302SetRealTimeClock(14,7,3,2,11,59,55); lcd2004AddressWriteString(LCD2004_ROW0,0,"Chip:DS1302"); while(1) { //读时间 temp = ds1302GetRealtimeClock(time_data); timeDisplay(); } } void timeDisplay(void) { //Year lcd2004AddressWriteByte(LCD2004_ROW1,0,‘0‘+time_data[0]/10) ; lcd2004AddressWriteByte(LCD2004_ROW1,1,‘0‘+time_data[0]%10) ; lcd2004AddressWriteByte(LCD2004_ROW1,2,‘/‘); //day lcd2004AddressWriteByte(LCD2004_ROW1,3,‘0‘+time_data[1]/10); lcd2004AddressWriteByte(LCD2004_ROW1,4,‘0‘+time_data[1]%10); lcd2004AddressWriteByte(LCD2004_ROW1,5,‘/‘); //month lcd2004AddressWriteByte(LCD2004_ROW1,6,‘0‘+time_data[2]/10) ; lcd2004AddressWriteByte(LCD2004_ROW1,7,‘0‘+time_data[2]%10) ; lcd2004AddressWriteByte(LCD2004_ROW1,8,‘/‘); //date lcd2004AddressWriteByte(LCD2004_ROW1,9,‘0‘+time_data[3]/10) ; lcd2004AddressWriteByte(LCD2004_ROW1,10,‘0‘+time_data[3]%10) ; lcd2004AddressWriteByte(LCD2004_ROW1,11,‘-‘); //hour lcd2004AddressWriteByte(LCD2004_ROW1,12,‘0‘+time_data[4]/10) ; lcd2004AddressWriteByte(LCD2004_ROW1,13,‘0‘+time_data[4]%10) ; lcd2004AddressWriteByte(LCD2004_ROW1,14,‘:‘); //minute lcd2004AddressWriteByte(LCD2004_ROW1,15,‘0‘+time_data[5]/10) ; lcd2004AddressWriteByte(LCD2004_ROW1,16,‘0‘+time_data[5]%10) ; lcd2004AddressWriteByte(LCD2004_ROW1,17,‘:‘); //second lcd2004AddressWriteByte(LCD2004_ROW1,18,‘0‘+time_data[6]/10) ; lcd2004AddressWriteByte(LCD2004_ROW1,19,‘0‘+time_data[6]%10) ; //12小时制 #if (DS1302_DEFAULT_HOUR_MODE == DS1302_HOUR_REGISTER_12HOURS_MODE) { if(temp == DS1302_HOUR_REGISTER_PM_ON_12HOURS_MODE) lcd2004AddressWriteString(LCD2004_ROW2,0,"AM/PM:PM"); else if(temp == DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE) lcd2004AddressWriteString(LCD2004_ROW2,0,"AM/PM:AM"); else lcd2004AddressWriteString(LCD2004_ROW2,0,"AM/PM:ERROR"); } //24小时制 #elif (DS1302_DEFAULT_HOUR_MODE == DS1302_HOUR_REGISTER_24HOURS_MODE) lcd2004AddressWriteString(LCD2004_ROW2,0,"AM/PM:NULL"); #else #error Please select correct DS1302_DEFAULT_HOUR_MODE. #endif }
/*################main.c end################*/
/*################ds1302.h start################*/
#ifndef __DS1302_H__ #define __DS1302_H__ #include <reg52.h> #include "common.h" sbit ds1302_sclk_bit = P3^6 ; sbit ds1302_io_bit = P3^4 ; sbit ds1302_rst_bit = P3^5 ; //ds1302 registers address #define DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE 0x80 #define DS1302_MINUTE_REGISTER_ADDRESS_BASE_VALUE 0x82 #define DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE 0x84 #define DS1302_DATE_REGISTER_ADDRESS_BASE_VALUE 0X86 #define DS1302_MONTH_REGISTER_ADDRESS_BASE_VALUE 0X88 #define DS1302_DAY_REGISTER_ADDRESS_BASE_VALUE 0X8a #define DS1302_YEAR_REGISTER_ADDRESS_BASE_VALUE 0X8c #define DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE 0x8e #define DS1302_TRICKLE_CHARGER_REGISTER_ADDRESS_BASE_VALUE 0x90 #define DS1302_CLOCK_BURST_REGISTER_ADDRESS_BASE_VALUE 0xbe #define DS1302_REGISTER_READ 0x01 #define DS1302_REGISTER_WRITE (0x01 & (~(0x01<<0))) //year valid value 0~99(2000~2099) #define DS1302_MIN_YEAR_VALUE 0 #define DS1302_MAX_YEAR_VALUE 99 //day valid value 1~7 //(Monday,Tuesday,Wednesday,Thursday,Thursday,Saturday,Sunday) #define DS1302_MIN_DAY_VALUE 1 #define DS1302_MAX_DAY_VALUE 7 //month valid value 1~12 : //January,February,March,April,May,June, //July,August,Septenber,October,November,Deceber #define DS1302_MIN_MONTH_VALUE 1 #define DS1302_MAX_MONTH_VALUE 12 //date valid value 1~31 #define DS1302_MIN_DATE_VALUE 1 #define DS1302_MAX_DATE_VALUE_FOR_31DAYS_MONTH 31 #define DS1302_MAX_DATE_VALUE_FOR_30DAYS_MONTH 30 #define DS1302_MAX_DATE_VALUE_FOR_LEAP_YEAR_FEBRUARY 29 #define DS1302_MAX_DATE_VALUE_FOR_NOT_LEAP_YEAR_FRBRUARY 28 //hour mode :12-hours and 24-hours #define DS1302_HOUR_REGISTER_24HOURS_MODE (0x80 &(~(0x01<<7)))/*24 hours a day*/ #define DS1302_HOUR_REGISTER_12HOURS_MODE 0x80 /*12 hours a day*/ #define DS1302_DEFAULT_HOUR_MODE DS1302_HOUR_REGISTER_12HOURS_MODE/*根据需要选择*/ //hour valid value on 24-hours mode :00~23 #define DS1302_MIN_HOUR_VALUE_ON_24HOURS_MODE 0 #define DS1302_MAX_HOUR_VALUE_ON_24HOURS_MODE 23 //hour valid value on 12-hours mode :1~12 #define DS1302_MIN_HOUR_VALUE_ON_12HOURS_MODE 1 #define DS1302_MAX_HOUR_VALUE_ON_12HOURS_MODE 12 #define DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE (0x20 & (~(0x01<<5))) #define DS1302_HOUR_REGISTER_PM_ON_12HOURS_MODE 0x20 #define DS1302_DEFAULT_AM_OR_PM DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE/*根据需要选择*/ //minute valid value:00~59 #define DS1302_MIN_MINUTE_VALUE 00 #define DS1302_MAX_MINUTE_VALUE 59 //second valid value:00~59 #define DS1302_MIN_SECOND_VALUE 00 #define DS1302_MAX_SECOND_VALUE 59 #define DS1302_CLOCK_ENABLE (0x80 & (~(0x01<<7))) #define DS1302_CLOCK_DISABLE 0x80 #define DS1302_DEFAULT_CLOCK DS1302_CLOCK_ENABLE/*根据需要选择,一般选择时钟起振*/ //control register #define DS1302_CONTROL_REGISTER_PROTECT_ENABLE 0x80 #define DS1302_CONTROL_REGISTER_PROTECT_DISABLE (0x80 & (~(0x01<<7))) //error #define DS1302_YEAR_VALUE_OVERFLOW -1 #define DS1302_DAY_VALUE_OVERFLOW -2 #define DS1302_MONTH_VALUE_OVERFLOW -3 #define DS1302_DATE_VALUE_OVERFLOW -4 #define DS1302_HOUR_VALUE_OVERFLOW -5 #define DS1302_MINUTE_VALUE_OVERFLOW -6 #define DS1302_SECOND_VALUE_OVERFLOW -7 #define DS1302_HOUR_REGISTER_HOUR_MODE_OVERFLOW -8 extern SB8 ds1302SetRealTimeClock(UB8 year,UB8 day,UB8 month,UB8 date, UB8 hour,UB8 minute,UB8 second) ; extern UB8 ds1302GetRealtimeClock(UB8 table[]); extern UB8 ds1302AddressReadByte(UB8 deviceInternalAddress) ; extern void ds1302AddressWriteByte(UB8 deviceInternalAddress,UB8 dataCode); extern void ds1302Init(void) ; #endif /*__DS1302_H__*/
/*################ds1302.h end################*/
/*################ds1302.c start################*/
/*************************************************************************** Module :ds1302.c Purpose :Implementation of ds1302. module. Version :0.01 2014/02/03 12:00(OK) Complier:Keil 8051 C complier V9.01 MCU :STC12C5A60S2 Author :yangrui Email :yangrui90s@163.com Modification: ================= 2014/03/04 20:43 Reason: 1.这里的读写方式都是普通字节读写,还有爆发模式读写功能未写,待定。 2.ds1302SetRealTimeClock函数中添加安全性判断。没有判断时, 我将秒钟设置为62,分钟设置为58,则分钟和秒钟的跳变过 程是这样的: 58:62--->58:79-->58:40-->58:59-->59:00,之后似乎就正常了 这里说明ds1302内部没有这样的一个安全监测机制,所以 为了防止调用时入参错误,也为了便与调试,就加了判断。 ================= ***************************************************************************/ #include <reg52.h> #include <intrins.h> #include "common.h" #include "ds1302.h" /****************************************************** Function :delay5usForDs1302 Input :N/A Output :N/A Return :N/A Description :N/A Note :tcc和tcwh,5V供电时最小1us,2v供电时最小4us ******************************************************/ static void delay5usForDs1302(void) //@11.0592MHz { unsigned char i; _nop_(); _nop_(); _nop_(); i = 10; while (--i); } /****************************************************** Function :ds1302WriteByte Input :the data ready to write into ds1302 Output :N/A Return :N/A Description :N/A Note :data input on rising edge ******************************************************/ static void ds1302WriteByte(UB8 dataCode) { UB8 i; for(i=0 ; i<8 ; i++) { ds1302_sclk_bit = LOW_LEVEL ; //_nop_() ; ds1302_io_bit = (bit)(dataCode & (0x01 << i) );/*bit 0 first*/ //_nop_() ; ds1302_sclk_bit = HIGH_LEVEL ; //_nop_() ; } } /****************************************************** Function :ds1302AddressWriteByte Input :address, data Output :N/A Return :N/A Description :write dataCode to ds1302‘s deviceInternalAddress Note :N/A ******************************************************/ void ds1302AddressWriteByte(UB8 deviceInternalAddress,UB8 dataCode) { ds1302_rst_bit = LOW_LEVEL ; ds1302_sclk_bit = LOW_LEVEL ; _nop_(); ds1302_rst_bit = HIGH_LEVEL ; delay5usForDs1302() ; ds1302WriteByte(deviceInternalAddress) ; ds1302WriteByte(dataCode) ; ds1302_sclk_bit = LOW_LEVEL ; ds1302_rst_bit = LOW_LEVEL ; delay5usForDs1302(); } /****************************************************** Function :ds1302ReadByte Input :N/A Output :N/A Return :the data from ds1302 Description :N/A Note :data output on falling edge ******************************************************/ static UB8 ds1302ReadByte(void) { UB8 i ; UB8 dataCode ; for(i=0 ; i<8 ; i++) { dataCode >>= 1; ds1302_sclk_bit = LOW_LEVEL ; //_nop_() ; if(ds1302_io_bit) { dataCode |= 0x80 ; } ds1302_sclk_bit = HIGH_LEVEL ; //_nop_() ; } return dataCode ; } /****************************************************** Function :ds1302AddressReadByte Input :address Output :N/A Return :the data from ds1302‘s deviceInternalAddress Description :N/A Note :N/A ******************************************************/ UB8 ds1302AddressReadByte(UB8 deviceInternalAddress) { unsigned char dat; unsigned char i=0; ds1302_rst_bit=LOW_LEVEL; ds1302_sclk_bit=LOW_LEVEL; _nop_(); ds1302_rst_bit=HIGH_LEVEL; delay5usForDs1302() ; ds1302WriteByte(deviceInternalAddress); dat = ds1302ReadByte(); ds1302_sclk_bit = LOW_LEVEL ; ds1302_rst_bit=LOW_LEVEL; delay5usForDs1302(); //以下为DS1302复位的稳定时间,必须的(这句话摘抄于范例代码),不懂 ds1302_sclk_bit= 1; _nop_(); ds1302_io_bit= 0;/*这一块代码中,这一句代码不能少,这一块代码中只需要这一句 现象也正确,但是为什么和datasheet中没有对应?????????????????????????? ????????????????????????????????????????????????????????????????????*/ _nop_(); ds1302_io_bit= 1; _nop_(); return dat ; } /****************************************************** Function :ds1302SetYear Input :the value which ready write to ds1302‘s year-register. Output :N/A Return :N/A Description :set ds1302 year register value Note :"年"数据需转换为BCD码格式 ******************************************************/ static void ds1302SetYear(UB8 year) { //decimal to BCD year = year %10 + year /10 *16 ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); ds1302AddressWriteByte(DS1302_YEAR_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE, year); ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); } /****************************************************** Function :ds1302GetYear Input :N/A Output :N/A Return :year value from ds1302‘s year-register. (Decimal) Description :read year value from ds1302‘s year register Note :"真实"的年份应该是BCD转换为十进制,然后 +2000 ******************************************************/ UB8 ds1302GetYear(void) { UB8 yearCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); yearCode = ds1302AddressReadByte(DS1302_YEAR_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); //BCD to decimal yearCode = yearCode %16 + yearCode/16 *10; return yearCode ; } /****************************************************** Function :ds1302SetDay Input :the value which ready to write to ds1302‘s day-register Output :N/A Return :N/A Description :set ds1302‘s day-register value Note :"星期"数据需转换为BCD码格式 ******************************************************/ static void ds1302SetDay(UB8 day) { //decimal to BCD day = day% 10 +day /10 *16 ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); ds1302AddressWriteByte(DS1302_DAY_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,day); ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); } /****************************************************** Function :ds1302GetDay Input :N/A Output :N/A Return :day value from ds1302‘s day-register. Description :read day value from ds1302‘s day-register. Note :读出的数据位BCD码,需要转化为十进制 ******************************************************/ UB8 ds1302GetDay(void) { UB8 dayCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); dayCode = ds1302AddressReadByte(DS1302_DAY_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); //BCD to decimal dayCode = dayCode%16 + dayCode/16 *10; return dayCode ; } /****************************************************** Function :ds1302SetMonth Input :the value which ready to write to ds1302‘s month-register. Output :N/A Return :N/A Description :set ds1302‘s month-register. Note :设置"月"数据,需要转换为BCD码 ******************************************************/ static void ds1302SetMonth(UB8 month) { //decimal to BCD month = month%10 + month/10 *16 ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); ds1302AddressWriteByte(DS1302_MONTH_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,month); ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); } /****************************************************** Function :ds1302GetMonth Input :N/A Output :N/A Return :the value from ds1302‘s month-register. Description :read value from ds1302‘s month-register. Note :读出的"月"数据位BCD码,需要转换为十进制 ******************************************************/ UB8 ds1302GetMonth(void) { UB8 monthCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); monthCode = ds1302AddressReadByte(DS1302_MONTH_REGISTER_ADDRESS_BASE_VALUE| DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); //BCD to decimal monthCode = monthCode%16 + monthCode/16 *10; return monthCode ; } /****************************************************** Function :ds1302SetDate Input :the data which ready to write to ds1302‘s date-register. Output :N/A Return :N/A Description :set ds1302‘s date-register value. Note :设置"日"数据,需要转换为BCD码 ******************************************************/ static void ds1302SetDate(UB8 date) { //decimal to BCD date = date%10 + date/10 *16 ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); ds1302AddressWriteByte(DS1302_DATE_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,date); ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); } /****************************************************** Function :ds1302GetDate Input :N/A Output :N/A Return :the data from ds1302‘s date-register. Description :N/A Note :读取的"日"数据,需要转换为十进制 ******************************************************/ UB8 ds1302GetDate(void) { UB8 dateCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); dateCode = ds1302AddressReadByte(DS1302_DATE_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); //BCD to decimal dateCode = dateCode%16 + dateCode/16 *10; return dateCode ; } /****************************************************** Function :ds1302SetHour Input :the value which ready to write to ds1302‘s hour-register Output :N/A Return :N/ Description :set ds1302‘s hour-register value. Note :设置"时"数据格式需要转换为BCD码。同时需要选择时间模式、上下午 信息(对于12小时制) ******************************************************/ static void ds1302SetHour(UB8 hour) { //decimal to BCD hour = hour%10 + hour/10 *16 ; //关闭写保护 ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); #if (DS1302_DEFAULT_HOUR_MODE== DS1302_HOUR_REGISTER_12HOURS_MODE) { //最高位设置1,也就是12小时模式 ds1302AddressWriteByte(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE | /*"时"数据*/ DS1302_REGISTER_WRITE,hour | \ /*12小时模式"*/ DS1302_HOUR_REGISTER_12HOURS_MODE | /*上/下午*/ DS1302_DEFAULT_AM_OR_PM); } #elif (DS1302_DEFAULT_HOUR_MODE== DS1302_HOUR_REGISTER_24HOURS_MODE) { //最高位设置0,也就是24小时模式 ds1302AddressWriteByte(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,hour | DS1302_HOUR_REGISTER_24HOURS_MODE); } #else { #error Please select DS1302_DEFAULT_HOUR_MODE to Set hour-information . } #endif //打开写保护 ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); } #if (DS1302_DEFAULT_HOUR_MODE == DS1302_HOUR_REGISTER_12HOURS_MODE) /*对于12小时模式,需要"上/下 午 的标志信息,所以需要输出"*/ UB8 ds1302GetHour(UB8 *AmOrPmFlag) { UB8 hourCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); hourCode = ds1302AddressReadByte(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE| DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); /*上午/下午 标志位*/ if((hourCode & 0x20) == 0x20)/*第一次在这里未加括号,出现了错误,注意优先级*/ *AmOrPmFlag = DS1302_HOUR_REGISTER_PM_ON_12HOURS_MODE ; else *AmOrPmFlag = DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE ; /*在12小时制中最高位三位不是有效地"小时"数据*/ hourCode &=~( 0x80 | 0x40 | 0x20); //BCD to decimal hourCode = hourCode%16 +hourCode/16 *10; return hourCode ; } #elif (DS1302_DEFAULT_HOUR_MODE == DS1302_HOUR_REGISTER_24HOURS_MODE) /*对于24小时制,读"小时"数据时,不需要"上午/下午"的信息,所以也就没有可变入参*/ UB8 ds1302GetHour(void) { UB8 hourCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); hourCode = ds1302AddressReadByte(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE| DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); /*最高位和次高位两位不是"小时"数据,因为24小时制 时最高位和次高位就是0,所以这一步可以省略*/ hourCode &=~(0xc0); //BCD to decimal hourCode = hourCode%16 +hourCode/16 *10; return hourCode ;//"小时"数据 } #else #error Please select DS1302_DEFAULT_HOUR_MODE to Get hour-information. #endif /****************************************************** Function :ds1302SetMinute Input :the value which ready to write to ds1302‘s minute-regisetr. Output :N/A Return :N/A Description :set ds1302‘s hour-register value Note :设置"分"数据,需要转换为BCD码 ******************************************************/ static void ds1302SetMinute(UB8 minute) { //decimal to BCD minute = minute%10 + minute/10 *16 ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); ds1302AddressWriteByte(DS1302_MINUTE_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,minute) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); } /****************************************************** Function :ds1302GetMinute Input :N/A Output :N/A Return :the value from ds1302‘s minute-register. Description :N/A Note :读出的"分"数据位BCD码,需要转换为十进制 ******************************************************/ UB8 ds1302GetMinute(void) { UB8 minuteCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); minuteCode = ds1302AddressReadByte(DS1302_MINUTE_REGISTER_ADDRESS_BASE_VALUE| DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); //BCD to decimal minuteCode = minuteCode%16 +minuteCode/16 *10; return minuteCode ; } /****************************************************** Function :ds1302SetSecond Input :the value which ready to write to ds1302‘s second-register. Output :N/A Return :N/A Description :set ds1302‘s second-register value. Note :second-register比较特殊,最高位是时钟起振的使能端。在设置 "秒"数值时,为了不会影响到最高位的值,最安全的算法就是先读出值 然后再 "|"的方式。 ******************************************************/ static void ds1302SetSecond(UB8 second) { UB8 temp ; //decimal to BCD second = second%10 + second/10 *16 ; /*先读出值,是为了后面写"秒"数值时,不会影响到最高位的"起始/停止"位*/ ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); temp = ds1302AddressReadByte(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE| DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); //写回去 ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); ds1302AddressWriteByte(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,temp | second) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); } /****************************************************** Function :ds1302GetSecond Input :N/A Output :N/A Return :N/A Description :read value form ds1302‘s second-register Note :second-register比较特殊,最高位是时钟起振使能位, 这一位并不是真正意义的"秒"数值,所以需要将读出来的 值的最高位清零,然后进行数据码制转换,这样得到的数 值才是真正意义上的"秒"数值。 ******************************************************/ UB8 ds1302GetSecond(void) { UB8 secondCode ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); secondCode = ds1302AddressReadByte(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE| DS1302_REGISTER_READ) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE); /*最高位不是有效地"秒"数据*/ secondCode &= ~(0x80); //BCD to decimal secondCode = secondCode%16 +secondCode/16 *10; return secondCode ; } /****************************************************** Function :ds1302SetRealTimeClock Input :year day month date hour minute second Output :N/A Return :0 (ok) -1(year value overflow) -2(daay value overflow) -3(month value overflow) -4(date value overflow) -5(hour value overflow) -6(minute value overflow) -7(second value overflow) Description :set ds1302‘s RTC (real time clock) Note :这里加判断是很必要的。没有判断时,我将秒钟设置为62, 分钟设置为58,则分钟和秒钟的跳变过程是这样的: 58:62--->58:79-->58:40-->58:59-->59:00,之后似乎就正常了 这里说明ds1302内部没有这样的一个安全监测机制,所以 为了防止调用时入参错误,也为了便与调试,就加了判断。 ******************************************************/ SB8 ds1302SetRealTimeClock(UB8 year,UB8 day,UB8 month,UB8 date, UB8 hour,UB8 minute,UB8 second) { if(year < DS1302_MIN_YEAR_VALUE || year > DS1302_MAX_YEAR_VALUE) return DS1302_YEAR_VALUE_OVERFLOW ; if(day < DS1302_MIN_DAY_VALUE || day > DS1302_MAX_DAY_VALUE) return DS1302_DAY_VALUE_OVERFLOW ; if(month < DS1302_MIN_MONTH_VALUE || month > DS1302_MAX_MONTH_VALUE) return DS1302_MONTH_VALUE_OVERFLOW ; //可以确定月份: 1~12 //大月 if((month == 1) || (month ==3) || (month == 5) || (month == 7) || (month == 8) || (month == 10) || (month == 12)) { if(date < DS1302_MIN_DATE_VALUE || date > DS1302_MAX_DATE_VALUE_FOR_31DAYS_MONTH) return DS1302_DATE_VALUE_OVERFLOW ; } else if(month==2)//二月 { // for leap year,闰年 if(( ((year+2000)%4==0) && ((year+2000)%100 !=0) ) || ((year+2000)%400==0) ) { if(date < DS1302_MIN_DATE_VALUE|| date > DS1302_MAX_DATE_VALUE_FOR_LEAP_YEAR_FEBRUARY) return DS1302_DATE_VALUE_OVERFLOW ; } else //非闰年 { if(date < DS1302_MIN_DATE_VALUE|| date > DS1302_MAX_DATE_VALUE_FOR_NOT_LEAP_YEAR_FRBRUARY) return DS1302_DATE_VALUE_OVERFLOW ; } } //小月 else if((month == 4) || (month == 6) || (month == 9) || (month == 11)) { if(date < DS1302_MIN_DATE_VALUE || date > DS1302_MAX_DATE_VALUE_FOR_30DAYS_MONTH) return DS1302_DATE_VALUE_OVERFLOW ; } #if(DS1302_DEFAULT_HOUR_MODE== DS1302_HOUR_REGISTER_24HOURS_MODE)/*24 hours a day*/ { if(hour < DS1302_MIN_HOUR_VALUE_ON_24HOURS_MODE|| hour > DS1302_MAX_HOUR_VALUE_ON_24HOURS_MODE) return DS1302_HOUR_VALUE_OVERFLOW ; } #elif(DS1302_DEFAULT_HOUR_MODE == DS1302_HOUR_REGISTER_12HOURS_MODE)/*12 hours a day*/ { if(hour < DS1302_MIN_HOUR_VALUE_ON_12HOURS_MODE|| hour > DS1302_MAX_HOUR_VALUE_ON_12HOURS_MODE) return DS1302_HOUR_VALUE_OVERFLOW ; } #else #error Pleast select DS1302_DEFAULT_HOUR_MODE to Set RealTimeClock. #endif if(minute < DS1302_MIN_MINUTE_VALUE || minute > DS1302_MAX_MINUTE_VALUE) return DS1302_MINUTE_VALUE_OVERFLOW ; if(second < DS1302_MIN_SECOND_VALUE || second > DS1302_MAX_SECOND_VALUE) return DS1302_SECOND_VALUE_OVERFLOW ; ds1302SetYear(year) ; ds1302SetDay(day) ; ds1302SetMonth(month) ; ds1302SetDate(date) ; ds1302SetHour(hour) ; ds1302SetMinute(minute) ; ds1302SetSecond(second) ; return 0; } /****************************************************** Function :ds1302GetRealtimeClock Input :the room for data from user Output :the seven registers‘ value Return :am or pm flaag Description :N/A Note :这里的返回值只对12小时模式有有用,是上/下午 标志位,对于24小时模式而言是无用的。 ******************************************************/ UB8 ds1302GetRealtimeClock(UB8 table[]) { UB8 AmOrPmFlag ; table[0]=ds1302GetYear(); table[1]=ds1302GetDay(); table[2]=ds1302GetMonth(); table[3]=ds1302GetDate(); #if(DS1302_DEFAULT_HOUR_MODE == DS1302_HOUR_REGISTER_12HOURS_MODE) table[4] = ds1302GetHour(&AmOrPmFlag); #else table[4] = ds1302GetHour(); #endif table[5]=ds1302GetMinute(); table[6]=ds1302GetSecond(); return AmOrPmFlag; } /****************************************************** Function :ds1302HourModeSelect Input :the mode when ds1302 work Output :N/A Return :0 (ok) -1 (error) Description :N/A Note :12-hour mode or 24-hour mode ******************************************************/ static SB8 ds1302HourModeSetting(UB8 mode) { if((mode != DS1302_HOUR_REGISTER_12HOURS_MODE) && (mode != DS1302_HOUR_REGISTER_24HOURS_MODE)) return DS1302_HOUR_REGISTER_HOUR_MODE_OVERFLOW ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE); ds1302AddressWriteByte(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE, mode) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE) ; return 0; } /****************************************************** Function :ds1302ClockSetting Input :control clock start or stop Output :N/A Return :N/A Description :N/A Note :N/A ******************************************************/ static void ds1302ClockSetting(UB8 flag) { ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE) ; ds1302AddressWriteByte(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE, flag) ; ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE | DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE) ; } /****************************************************** Function : Input : Output : Return : Description : Note : ******************************************************/ void ds1302Init(void) { ds1302HourModeSetting(DS1302_DEFAULT_HOUR_MODE) ; ds1302ClockSetting(DS1302_DEFAULT_CLOCK) ; }
/*################ds1302.c start################*/
补充:common.h
#ifndef __COMMON_H__ #define __COMMON_H__ typedef unsigned char UB8 ; typedef unsigned short int UW16 ; typedef unsigned long UL32 ; typedef char SB8; typedef short int SW16 ; typedef long SL32 ; #define HIGH_LEVEL 1 #define LOW_LEVEL 0 #endif /*__COMMON_H__*/
单片机控制时钟芯片DS1302之模块化编程及待解决的问题,布布扣,bubuko.com
原文:http://blog.csdn.net/yagnruinihao/article/details/20484085