这里将我编写的STC12C5A60S2单片机控制SPI协议时钟芯片ds1302的程序共享一下,是希望前辈们给予斧正 。
更新:
2014/04/22 10:48
2014/04/07 09:22
2014/04/03 16:43
2014/03/29 08:23
2014/03/04 20:43
(补充:以下代码只需要修改ds1302.h文件中含有 “选择” 字样的部分,就可以达到复用的效果)
对于lcd2004部分,请参考《单片机控制2004A液晶屏之模块化编程》点击进入
同时程序中有一个地方也是有疑问的,希望大家给予指点 : 在ds1302AddressReadByte(....)函数中有一部分代码如下:
//以下为DS1302复位的稳定时间,必须的。(这句话摘抄于范例代码)
ds1302_sclk_bit= 1;
_nop_();
ds1302_io_bit= 0;
_nop_();
ds1302_io_bit= 1;
_nop_();
我发现这一块代码中,ds1302_io_bit=0 ; 这一句代码不能少,这一块代码中只需要这一句,而屏蔽其他语句
现象也正确,但是这一块的代码是什么用处呢?在datasheet中没有找到对应的说明啊?????不理解)
问题已经解决,容后添加说明
以下为实验的记录(成功)
实验一:12小时模式,允许时钟起振
设置工作模式为12小时模式,设置为上午(2014年星期天3月2日11点59分50秒)
设置过程:(直接编译测试程序) 随机截取其中两张图片如下:
实验二:12小时模式,禁止时钟起振
(2)修改ds1302.h的宏:
#define DS1302_DEFAULT_CLOCK DS1302_SECOND_REGISTER_CLOCK_HALT_DISABLE/*根据需要选择,一般选择时钟起振*/
为:
#define DS1302_DEFAULT_CLOCK DS1302_SECOND_REGISTER_CLOCK_HALT_ENABLE/*根据需要选择,一般选择时钟起振*/
实验三:24小时模式,允许时钟起振
(3)设置工作模式为24小时,时间为2014年星期天3月2日23点59分50秒
设置过程:(1)修改主函数的时间变量
将主函数的
ds1302RTC_info time ={DS1302_HOUR_REGISTER_12HOURS_MODE,
DS1302_HOUR_REGISTER_12HOURS_MODE,
14,7,3,2,11,59,55};
修改为
ds1302RTC_info time ={DS1302_HOUR_REGISTER_24HOURS_MODE,
/*在24小时模式下,第二个数据时没有意义的,
因为在24小时模式下,是以"时"的数据来区分上/下午的,这里用"0",也可以用其他数字,
无所谓*/
0,
14,7,3,2,23,59,55};
(2)修改ds1302.h的宏:
将实验二的:
#define DS1302_DEFAULT_CLOCK DS1302_SECOND_REGISTER_CLOCK_HALT_ENABLE/*根据需要选择,一般选择时钟起振*/
修改为
#define DS1302_DEFAULT_CLOCK DS1302_SECOND_REGISTER_CLOCK_HALT_DISABLE/*根据需要选择,一般选择时钟起振*/
随机截取其中两张图片如下:
程序部分只需要注意中文注释的地方即可
测试程序
( 第一次时需要ds1302SetRealTimeClock(time);,第二次屏蔽掉这一句话,重新编译下载,关闭电源,时间也会更新,前提:有备用电源)
#include
#include "lcd2004.h"
#include "ds1302.h"
void timeDisplay(ds1302RTC_info);
void main(void)
{
ds1302RTC_info time ={DS1302_HOUR_REGISTER_12HOURS_MODE,
DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE,
14,7,3,2,11,59,55};
lcd2004Init();
lcd2004WriteCommand(0x0c); /*为了显示更清楚,临时设置光标不显示,
也可以在lcd2004的内部函数修改*/
lcd2004AddressWriteString(LCD2004_ROW0,0,"Chip:DS1302");
ds1302Init() ;
ds1302SetRealTimeClock(time);
while(1)
{
ds1302GetRealtimeClock(&time);
timeDisplay(time);
}
}
void timeDisplay(ds1302RTC_info time)
{
lcd2004AddressWriteByte(LCD2004_ROW1, 0,'0'+time.year/10) ; //year
lcd2004AddressWriteByte(LCD2004_ROW1, 1,'0'+time.year%10) ;
lcd2004AddressWriteByte(LCD2004_ROW1, 2,'/');
lcd2004AddressWriteByte(LCD2004_ROW1, 3,'0'+time.day/10); //day
lcd2004AddressWriteByte(LCD2004_ROW1, 4,'0'+time.day%10);
lcd2004AddressWriteByte(LCD2004_ROW1, 5,'/');
lcd2004AddressWriteByte(LCD2004_ROW1, 6,'0'+time.month/10) ; //month
lcd2004AddressWriteByte(LCD2004_ROW1, 7,'0'+time.month%10) ;
lcd2004AddressWriteByte(LCD2004_ROW1, 8,'/');
lcd2004AddressWriteByte(LCD2004_ROW1, 9,'0'+time.date/10) ; //date
lcd2004AddressWriteByte(LCD2004_ROW1,10,'0'+time.date%10) ;
lcd2004AddressWriteByte(LCD2004_ROW1,11,'-');
lcd2004AddressWriteByte(LCD2004_ROW1,12,'0'+time.hour/10) ; //hour
lcd2004AddressWriteByte(LCD2004_ROW1,13,'0'+time.hour%10) ;
lcd2004AddressWriteByte(LCD2004_ROW1,14,':');
lcd2004AddressWriteByte(LCD2004_ROW1,15,'0'+time.minute/10) ; //minute
lcd2004AddressWriteByte(LCD2004_ROW1,16,'0'+time.minute%10) ;
lcd2004AddressWriteByte(LCD2004_ROW1,17,':');
lcd2004AddressWriteByte(LCD2004_ROW1,18,'0'+time.second/10) ; //second
lcd2004AddressWriteByte(LCD2004_ROW1,19,'0'+time.second%10) ;
if (time.hourMode== DS1302_HOUR_REGISTER_12HOURS_MODE)
{//12小时制
if(time.amOrPmOn12HoursMode == DS1302_HOUR_REGISTER_PM_ON_12HOURS_MODE)
lcd2004AddressWriteString(LCD2004_ROW2,0,"AM/PM:PM");
else if(time.amOrPmOn12HoursMode == DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE)
lcd2004AddressWriteString(LCD2004_ROW2,0,"AM/PM:AM");
else
lcd2004AddressWriteString(LCD2004_ROW2,0,"Error : AM/PM");
}
else if (time.hourMode== DS1302_HOUR_REGISTER_24HOURS_MODE)
{//24小时制
lcd2004AddressWriteString(LCD2004_ROW2,0,"AM/PM:NULL");
}
else
lcd2004AddressWriteString(LCD2004_ROW2,0,"Error : 12/24 HourMode") ;
}
/*################ds1302.h start################*/
#ifndef __DS1302_H__
#define __DS1302_H__
#include
#include "common.h"
sbit ds1302_sclk_bit = P3^6 ; /*根据硬件连接选择*/
sbit ds1302_io_bit = P3^4 ; /*根据硬件连接选择*/
sbit ds1302_rst_bit = P3^5 ; /*根据硬件连接选择*/
typedef struct {
UB8 hourMode ; //12或24小时模式
UB8 amOrPmOn12HoursMode ; //上午或下午(12小时模式下才有意义)
UB8 year ; /*年*/
UB8 day ; /*星期*/
UB8 month ; /*月*/
UB8 date ; /*日*/
UB8 hour ; /*时*/
UB8 minute ; /*分*/
UB8 second ; /*秒*/
}ds1302RTC_info ;
//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*/
//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
//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_SECOND_REGISTER_CLOCK_HALT_ENABLE 0x80
#define DS1302_SECOND_REGISTER_CLOCK_HALT_DISABLE (0x80 & (~(0x01<<7)))
/*DS1302_SECOND_REGISTER_CLOCK_HALT_ENABLE或者DS1302_SECOND_REGISTER_CLOCK_HALT_DISABLE*/
#define DS1302_DEFAULT_CLOCK DS1302_SECOND_REGISTER_CLOCK_HALT_DISABLE/*根据需要选择,一般选择时钟起振*/
//control register
#define DS1302_CONTROL_REGISTER_PROTECT_ENABLE 0x80
#define DS1302_CONTROL_REGISTER_PROTECT_DISABLE (0x80 & (~(0x01<<7)))
//error
#define DS1302_YEAR_OVERFOLW -1 /*about year*/
#define DS1302_DAY_OVERFLOW -2 /*abotu day*/
#define DS1302_MONTH_OVERFLOW -3 /*about month*/
#define DS1302_DATE_OVERFLOW -4 /*about date*/
#define DS1302_DATE_OVERFLOW_FOR_30DAYS_MONTH -5
#define DS1302_DATE_OVERFLOW_FOR_FEBRUARY_ON_LEAP_YEAR -6
#define DS1302_DATE_OVERFLOW_FOR_FEBRUARY_ON_NOT_LEAP_YEAR -7
#define DS1302_HOUR_MODE_OVERFLOW -8 /*about hour mode*/
#define DS1302_HOUR_OVERFLOW_FOR_12HOURS_MODE -9 /*about hour*/
#define DS1302_HOUR_OVERFLOW_FOR_24HOURS_MODE -10
#define DS1302_MINUTE_OVERFLOW -11 /*about minute*/
#define DS1302_SECOND_OVERFLOW -12 /*about second*/
#define DS1302_SECOND_REGISTER_HALT_MODE_OVERFLOW -11 /*about second-register_RTC_halt*/
/*****************外部接口函数******************/
//初始化,设置起振使能设置,使能写保护
extern void ds1302Init(void) ;
//设置时间
extern SB8 ds1302SetRealTimeClock(ds1302RTC_info time) ;
//读取时间
extern void ds1302GetRealtimeClock(ds1302RTC_info *time) ;
//地址写数据
extern void ds1302RegisterWrite(UB8 registerAddress,UB8 dataCode) ;
//地址读取数据
extern UB8 ds1302RegisterRead(UB8 registerAddress) ;
/*
================
设置时间(独立设置)
================
*/
extern void ds1302SetYear(UB8 year) ; //年
extern void ds1302SetDay(UB8 day) ; //星期
extern void ds1302SetMonth(UB8 month) ; //月
extern void ds1302SetDate(UB8 date) ; //日
extern void ds1302SetHour(UB8 hour) ; //小时
extern void ds1302SetMinute(UB8 minute) ; //分钟
extern void ds1302SetSecond(UB8 second) ; //秒钟
/*模式设置,入参为结构体,但是只用到了其中的time.hourMode和tiem.amOrPmOn12HoursMode(12小时下)
所以外部调用时,可以临时定义一个变量,设置time.hourMode和tiem.amOrPmOn12HoursMode(12小时下),就可以了。
这里是为了内部实现的方便,所以这里的入参复杂点*/
extern SB8 ds1302HourModeSetting(ds1302RTC_info time) ;
/**********************************************/
#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
QQ :279729201
Email :[email protected]
声明 :经过试验,DS1302内部的时钟部分是没有严格的数据检测功能的,具体是:
在实验室,将秒钟设置为70s,之后,读出并显示,秒钟数为70,并不断变化,
虽然经过一段时间后,ds1302会因为"进位"而硬件"自动调整过来",但是这并
不是真正意义上的"调整",所以,我在程序中增加了时间数据合法性的检测,虽然
看起开比较繁琐。
Modification:
=================
2014/04/22 10:48
Reason:
1.将hourMode和amOrPmOn12HoursMode加入结构体。
=================
=================
2014/04/20 20:48
Reason:
1.将ds1302HourModeSetting(...)声明为外部接口函数,并修改入参。
=================
=================
2014/04/07 09:13
Reason:
1.将设置年星期月日时分秒的相关函数设置为了外部接口函数。
=================
=================
2014/04/03 16:43
Reason:
1.添加ds1302RTC_info结构代替之前的数组格式,使得结构更加紧凑。
=================
=================
2014/03/29 08:23
Reason:
1.修改对寄存器的配置方法。
例如:对秒寄存器的"秒"数据进行配置时,之前的方法是禁止写保护的前提下,
首先读出数据:
temp = ds1302RegisterRead(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE|\
DS1302_REGISTER_READ) ;
然后利用
ds1302AddressWriteByte(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE,temp | decimal2BCD(second)) ;
去将"秒"数据一起写进寄存器中,这里看似没有问题,但是,却有一个
致命的错误(虽然这种错误最后会因为DS1302的硬件自动调整过来(需要一段时间),
但是这样依靠硬件去调整的做法是不严谨的)。
这句话有些难以理解,举例说明:
假如读出的"秒"数据是"0x01秒",而我们恰巧需要设置的"秒"数据,为"0x00秒",
这时候会因为我们的代码中有类似 " 0 | 1"这样的代码,结果为1秒,所以
我们需要设置的秒数就没有被正确的设置进去。
正确的做法是:
读出的数据temp需要将我们设置的"秒"的有效位即bit0~bit6进行清零,然后再"|",
就可以保证我们需要设置的时间被正确写入。
2.增加函数
ds1302RegisterRead(UB8 registerAddress) ;
ds1302RegisterWrite(UB8 registerAddress, UB8 dataCode) ;
3.添加函数
static UB8 decimal2BCD(UB8 dataCode) ;
static UB8 BCD2Decimal(UB8 dataCode) ;
=================
=================
2014/03/04 20:43
Reason:
1.这里的读写方式都是普通字节读写,还有爆发模式读写功能未写,待定。
2.备注:在12小时制模式下,AM到PM的跳变是在11:59:59到12:00:00之间完成的,
而不是在12:59:59到13:00:00之间完成的。
=================
***************************************************************************/
#include
#include
#include "common.h"
#include "ds1302.h"
/*外部接口函数在ds1302.h中声明*/
/*****************内部函数*********************/
static void delay5usForDs1302(void) ; //@11.0592MHz
static void ds1302WriteByte(UB8 dataCode) ;
static void ds1302AddressWriteByte(UB8 deviceInternalAddress,UB8 dataCode) ;
static UB8 ds1302ReadByte(void) ;
static UB8 ds1302AddressReadByte(UB8 deviceInternalAddress) ;
static UB8 decimal2BCD(UB8 dataCode) ;
static UB8 BCD2Decimal(UB8 dataCode) ;
/*时间读取*/
static UB8 ds1302GetYear(void) ;
static UB8 ds1302GetDay(void) ;
static UB8 ds1302GetMonth(void) ;
static UB8 ds1302GetDate(void) ;
//年数据的读取比较特殊,直接在ds1302GetRealtimeClock(..)内部处理了
static UB8 ds1302GetMinute(void) ;
static UB8 ds1302GetSecond(void) ;
static SB8 ds1302ClockSetting(UB8 flag) ;
/**********************************************/
/******************************************************
Function :delay5usForDs1302
Input :N/A
Output :N/A
Return :N/A
Description :N/A
Note :参照datasheet的tcc和tcwh,5V供电时最小1us,2v供电时最小4us
由STC-ISP V6.67软件针对相应MCU生成,若MCU不同
最好也要修改此函数。
******************************************************/
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
******************************************************/
static 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
******************************************************/
static 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 :ds1302RegisterRead
Input :ds1302s register address
Output :N/A
Return :the value of ds1302's register
Description :N/A
Note :读取寄存器操作需要关闭写保护
******************************************************/
UB8 ds1302RegisterRead(UB8 registerAddress)
{
unsigned registerValue ;
ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE);
registerValue = ds1302AddressReadByte(registerAddress ) ;
ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE);
return registerValue ;
}
/******************************************************
Function :ds1302RegisterWrite
Input :ds1302s register address,the value which is ready to ds1302
Output :N/A
Return :N/A
Description :N/A
Note :写寄存器操作需要关闭写保护
******************************************************/
void ds1302RegisterWrite(UB8 registerAddress,UB8 dataCode)
{
ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_DISABLE);
ds1302AddressWriteByte(registerAddress, dataCode);
ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE);
}
/******************************************************
Function :decimal2BCD
Input :decimal data
Output :N/A
Return :BCD data
Description :transfrom decimal to BCD
Note :注意,这里的转换只限于十进制0~99之间的整数数值向BCD
码的转换。(两位数)
******************************************************/
static UB8 decimal2BCD(UB8 dataCode)
{
return (dataCode %10 + dataCode /10 *16) ;
}
/******************************************************
Function :BCD2Decimal
Input :BCD data
Output :N/A
Return :decimal data
Description :transfrom BCD to decimal
Note :注意,这里转换只限于BCD码向十进制的0~99之间的转换.(1字节)
******************************************************/
static UB8 BCD2Decimal(UB8 dataCode)
{
return (dataCode %16 + dataCode /16 *10) ;
}
/******************************************************
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码格式
******************************************************/
void ds1302SetYear(UB8 year)
{
ds1302RegisterWrite(DS1302_YEAR_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE, decimal2BCD(year) ) ;
}
/******************************************************
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
******************************************************/
static UB8 ds1302GetYear(void)
{
UB8 yearCode ;
yearCode = ds1302RegisterRead( DS1302_YEAR_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
return (BCD2Decimal(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码格式
******************************************************/
void ds1302SetDay(UB8 day)
{
ds1302RegisterWrite( DS1302_DAY_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE, decimal2BCD(day)) ;
}
/******************************************************
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码,需要转化为十进制
******************************************************/
static UB8 ds1302GetDay(void)
{
UB8 dayCode ;
dayCode = ds1302RegisterRead(DS1302_DAY_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
return (BCD2Decimal(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码
******************************************************/
void ds1302SetMonth(UB8 month)
{
ds1302RegisterWrite(DS1302_MONTH_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE, decimal2BCD(month)) ;
}
/******************************************************
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码,需要转换为十进制
******************************************************/
static UB8 ds1302GetMonth(void)
{
UB8 monthCode ;
monthCode = ds1302RegisterRead(DS1302_MONTH_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
return (BCD2Decimal(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码
******************************************************/
void ds1302SetDate(UB8 date)
{
ds1302RegisterWrite(DS1302_DATE_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE, decimal2BCD(date)) ;
}
/******************************************************
Function :ds1302GetDate
Input :N/A
Output :N/A
Return :the data from ds1302's date-register.
Description :N/A
Note :读取的"日"数据,需要转换为十进制
******************************************************/
static UB8 ds1302GetDate(void)
{
UB8 dateCode ;
dateCode = ds1302RegisterRead(DS1302_DATE_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
return (BCD2Decimal(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/24小时制),以及
上/下午(12小时制时),最安全的做法是先将数据读出来,再将需要设置的
相应位清空,然后再以" | "的方式进行设置相应位。
******************************************************/
void ds1302SetHour(UB8 hour)
{
unsigned char hourCode ;
hourCode = ds1302RegisterRead(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
if(hourCode & (0x01<<7))
{//12小时模式
hourCode &=(~(0x1f)) ;
}
else
{//24小时模式
hourCode &=(~(0x3f)) ;
}
ds1302RegisterWrite(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE, hourCode | decimal2BCD(hour)) ;
}
/******************************************************
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码
******************************************************/
void ds1302SetMinute(UB8 minute)
{
ds1302RegisterWrite(DS1302_MINUTE_REGISTER_ADDRESS_BASE_VALUE |
DS1302_REGISTER_WRITE, decimal2BCD(minute)) ;
}
/******************************************************
Function :ds1302GetMinute
Input :N/A
Output :N/A
Return :the value from ds1302's minute-register.
Description :N/A
Note :读出的"分"数据位BCD码,需要转换为十进制
******************************************************/
static UB8 ds1302GetMinute(void)
{
UB8 minuteCode ;
minuteCode = ds1302RegisterRead(DS1302_MINUTE_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
return (BCD2Decimal(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比较特殊,最高位是时钟起振的使能端。在设置
"秒"数值时,为了不会影响到最高位的值,最安全的算法就是先读出值
然后再将需要设置的相应位清空,再以 "|"的方式设置相应位。
******************************************************/
void ds1302SetSecond(UB8 second)
{
UB8 secondCode ;
/*先读出值,是为了后面写"秒"数值时,不会影响到最高位的"起始/停止"位*/
secondCode = ds1302RegisterRead(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
secondCode &=~(0x7e);
ds1302RegisterWrite(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE, secondCode | decimal2BCD(second)) ;
}
/******************************************************
Function :ds1302GetSecond
Input :N/A
Output :N/A
Return :N/A
Description :read value form ds1302's second-register
Note :second-register比较特殊,最高位是时钟起振使能位,
这一位并不是真正意义的"秒"数值,所以需要将读出来的
值的最高位清零,然后进行数据码制转换,这样得到的数
值才是真正意义上的"秒"数值。
******************************************************/
static UB8 ds1302GetSecond(void)
{
UB8 secondCode ;
secondCode = ds1302RegisterRead(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
/*最高位不是有效地"秒"数据*/
secondCode &= ~(0x01 << 7);
return (BCD2Decimal(secondCode)) ;
}
/******************************************************
Function :ds1302SetRealTimeClock
Input :ds1302RTC_info data
Output :N/A
Return :N/A
Description :set ds1302's RTC (real time clock)
Note :经过试验,DS1302内部没有严格的数据检测功能,不论写的数据是否合法,都
会写进去,所以需要软件检测一下时间的合法性。
******************************************************/
SB8 ds1302SetRealTimeClock(ds1302RTC_info time)
{
if(time.year < DS1302_MIN_YEAR_VALUE || time.year > DS1302_MAX_YEAR_VALUE)
return DS1302_YEAR_OVERFOLW ;
if(time.day < DS1302_MIN_DAY_VALUE || time.day > DS1302_MAX_DAY_VALUE)
return DS1302_DAY_OVERFLOW ;
if(time.month < DS1302_MIN_MONTH_VALUE || time.month > DS1302_MAX_MONTH_VALUE)
return DS1302_MONTH_OVERFLOW ;
//月份比较特殊
if(time.date < DS1302_MIN_DATE_VALUE || time.date > DS1302_MAX_DATE_VALUE_FOR_31DAYS_MONTH)
{//对于所有月份(包含大月)
return DS1302_DATE_OVERFLOW ;
}
else if(time.month == 4 ||time.month == 6 ||time.month == 9 ||time.month == 11 )
{//(对于小月)
if(time.date > DS1302_MAX_DATE_VALUE_FOR_30DAYS_MONTH)
return DS1302_DATE_OVERFLOW_FOR_30DAYS_MONTH ;
}
else if(time.month == 2)
{
if( ( (!(time.year %4)) && (time.year%100) ) || (!(time.year %400)))
{
if(time.date > DS1302_MAX_DATE_VALUE_FOR_LEAP_YEAR_FEBRUARY)
return DS1302_DATE_OVERFLOW_FOR_FEBRUARY_ON_LEAP_YEAR ;
}
else
{
if(time.date > DS1302_MAX_DATE_VALUE_FOR_NOT_LEAP_YEAR_FRBRUARY)
return DS1302_DATE_OVERFLOW_FOR_FEBRUARY_ON_NOT_LEAP_YEAR ;
}
}
if((time.hourMode != DS1302_HOUR_REGISTER_12HOURS_MODE) && \
(time.hourMode != DS1302_HOUR_REGISTER_24HOURS_MODE))
{
return DS1302_HOUR_MODE_OVERFLOW ;
}
else if(time.hourMode == DS1302_HOUR_REGISTER_12HOURS_MODE)
{
if(time.hour < DS1302_MIN_HOUR_VALUE_ON_12HOURS_MODE ||\
time.hour > DS1302_MAX_HOUR_VALUE_ON_12HOURS_MODE)
return DS1302_HOUR_OVERFLOW_FOR_12HOURS_MODE;
}
else if(time.hourMode == DS1302_HOUR_REGISTER_24HOURS_MODE)
{
if(time.hour < DS1302_MIN_HOUR_VALUE_ON_24HOURS_MODE ||\
time.hour > DS1302_MAX_HOUR_VALUE_ON_24HOURS_MODE)
return DS1302_HOUR_OVERFLOW_FOR_24HOURS_MODE;
}
if(time.minute < DS1302_MIN_MINUTE_VALUE || time.minute > DS1302_MAX_MINUTE_VALUE)
return DS1302_MINUTE_OVERFLOW ;
if(time.second < DS1302_MIN_SECOND_VALUE || time.second > DS1302_MAX_SECOND_VALUE)
return DS1302_SECOND_OVERFLOW ;
//时钟模式选择:12/24小时制,上/下午选择(12小时模式下才设置)
ds1302HourModeSetting(time) ;
ds1302SetYear(time.year) ;
ds1302SetDay(time.day) ;
ds1302SetMonth(time.month) ;
ds1302SetDate(time.date) ;
ds1302SetHour(time.hour) ;
ds1302SetMinute(time.minute) ;
ds1302SetSecond(time.second) ;
return 0;
}
/******************************************************
Function :ds1302GetRealtimeClock
Input :N/A
Output :ds1302's RTC information
Return :am or pm flaag
Description :N/A
Note :这里的返回值只对12小时模式有有用,是上/下午
标志位,对于24小时模式而言是无用的。
******************************************************/
void ds1302GetRealtimeClock(ds1302RTC_info *time)
{
UB8 temp ;
time->year = ds1302GetYear() ;
time->day = ds1302GetDay();
time->month = ds1302GetMonth();
time->date = ds1302GetDate();
//小时寄存器比较特殊
temp = ds1302RegisterRead(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_READ) ;
if(temp & (0x01<<7))
{//12小时模式
time->hourMode = DS1302_HOUR_REGISTER_12HOURS_MODE ;
if(temp & (0x01<<5))
time->amOrPmOn12HoursMode = DS1302_HOUR_REGISTER_PM_ON_12HOURS_MODE ;
else
time->amOrPmOn12HoursMode = DS1302_HOUR_REGISTER_AM_ON_12HOURS_MODE ;
temp &=~( 0x80| 0x40 | 0x20) ;
time->hour = BCD2Decimal(temp);
}
else
{
time->hourMode = DS1302_HOUR_REGISTER_24HOURS_MODE ;
temp &=~( 0x80| 0x40) ;
time->hour = BCD2Decimal(temp);
}
time->minute=ds1302GetMinute();
time->second=ds1302GetSecond();
}
/******************************************************
Function :ds1302HourModeSelect
Input :the mode when ds1302 work
Output :N/A
Return :0 (ok)
-1 (error)
Description :N/A
Note :为了安全,先将小时寄存器里面数据读出来,设置相应位,
然后将数据再写进去。
******************************************************/
SB8 ds1302HourModeSetting(ds1302RTC_info time)
{
UB8 temp ;
if((time.hourMode != DS1302_HOUR_REGISTER_12HOURS_MODE) && \
(time.hourMode != DS1302_HOUR_REGISTER_24HOURS_MODE))
return DS1302_HOUR_MODE_OVERFLOW ;
temp = ds1302RegisterRead(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE | \
DS1302_REGISTER_READ) ;
temp &=~(0x01<<7);
temp |= time.hourMode ;
/*若为12小时制,还需要设置上/下午*/
if(time.hourMode == DS1302_HOUR_REGISTER_12HOURS_MODE)
{
temp &=~(0x01<<5) ;
temp |= time.amOrPmOn12HoursMode;
}
ds1302RegisterWrite(DS1302_HOUR_REGISTER_ADDRESS_BASE_VALUE |
DS1302_REGISTER_WRITE, temp) ;
return 0;
}
/******************************************************
Function :ds1302ClockSetting
Input :control clock start or stop
Output :N/A
Return :N/A
Description :时钟起振允许/禁止控制
Note :N/A
******************************************************/
static SB8 ds1302ClockSetting(UB8 flag)
{
UB8 temp ;
if((flag != DS1302_SECOND_REGISTER_CLOCK_HALT_DISABLE) && \
(flag != DS1302_SECOND_REGISTER_CLOCK_HALT_ENABLE))
return DS1302_SECOND_REGISTER_HALT_MODE_OVERFLOW;
temp = ds1302RegisterRead(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE | \
DS1302_REGISTER_READ) ;
temp &=~(0x01<<7) ;
temp |= flag ;
ds1302RegisterWrite(DS1302_SECOND_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE, temp ) ;
return 0;
}
/******************************************************
Function :ds1302Init
Input :N/A
Output :N/A
Return :N/A
Description:DS1302初始化
Note :上电时,时钟起振允许和写保护都是未定义的状态(参照datasheet),
需要设置一下
******************************************************/
void ds1302Init(void)
{
//是否时能时钟,初始上电状态未确定,需要设置
ds1302ClockSetting(DS1302_DEFAULT_CLOCK) ;
//写保护在初始上电时是不确定的,这里打开写保护
ds1302AddressWriteByte(DS1302_CONTROL_REGISTER_ADDRESS_BASE_VALUE |\
DS1302_REGISTER_WRITE,DS1302_CONTROL_REGISTER_PROTECT_ENABLE);
}
/*################ds1302.c end################*/
补充: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__*/