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