单片机控制时钟芯片DS1302之模块化编程及待解决的问题

时间:2014-03-05 17:45:56   收藏:0   阅读:384

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

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

bubuko.com,布布扣

bubuko.com,布布扣

(2)设置工作模式为24小时,时间为2014年星期天3月2日23点59分50秒

设置过程:修改ds1302.h的宏

#define DS1302_DEFAULT_HOUR_MODE	DS1302_HOUR_REGISTER_24HOURS_MODE

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

bubuko.com,布布扣

bubuko.com,布布扣

(3)设置ds1302时钟不启动,12小时模式,时间为2014年星期天3月2日11点59分55秒

设置方法:修改ds1302.h的宏:

#define DS1302_DEFAULT_CLOCK  DS1302_CLOCK_DISABLE

bubuko.com,布布扣

15秒之后,截图

bubuko.com,布布扣

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

测试程序

/*################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

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!