单片机控制SPI协议时钟芯片DS1302之模块化编程及待解决的问题(持续更新中)

这里将我编写的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秒)

设置过程:(直接编译测试程序)    随机截取其中两张图片如下:

单片机控制SPI协议时钟芯片DS1302之模块化编程及待解决的问题(持续更新中)_第1张图片

单片机控制SPI协议时钟芯片DS1302之模块化编程及待解决的问题(持续更新中)_第2张图片


实验二:12小时模式,禁止时钟起振

(2)修改ds1302.h的宏:

#define DS1302_DEFAULT_CLOCK DS1302_SECOND_REGISTER_CLOCK_HALT_DISABLE/*根据需要选择,一般选择时钟起振*/
为:

#define DS1302_DEFAULT_CLOCK DS1302_SECOND_REGISTER_CLOCK_HALT_ENABLE/*根据需要选择,一般选择时钟起振*/
单片机控制SPI协议时钟芯片DS1302之模块化编程及待解决的问题(持续更新中)_第3张图片
大概10秒后:

单片机控制SPI协议时钟芯片DS1302之模块化编程及待解决的问题(持续更新中)_第4张图片

实验三: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/*根据需要选择,一般选择时钟起振*/

随机截取其中两张图片如下:

单片机控制SPI协议时钟芯片DS1302之模块化编程及待解决的问题(持续更新中)_第5张图片

单片机控制SPI协议时钟芯片DS1302之模块化编程及待解决的问题(持续更新中)_第6张图片


程序部分只需要注意中文注释的地方即可

测试程序

第一次时需要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__*/


 

你可能感兴趣的:(单片机)