目录
DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时且具有闰年补偿等多种功能
RTC(Real Time Clock):实时时钟,是一种集成电路,通常称为时钟芯片

| 引脚名 | 作用 | 引脚名 | 作用 |
| VCC2 | 主电源 | CE | 芯片使能 |
| VCC1 | 备用电池 | IO | 数据输入/输出 |
| GND | 电源地 | SCLK | 串行时钟 |
| X1、X2 | 32.768KHz晶振 |




BCD码(Binary Coded Decimal):用4位二进制数来表示1位十进制数
例:0001 0011表示13,1000 0101表示85,0001 1010不合法
在十六进制中的体现:0x13表示13,0x85表示85,0x1A不合法
BCD码转十进制:DEC=BCD/16*10+ BCD%16;(2位BCD)
十进制转BCD码: BCD=DEC/10+16+DEC%10;(2位BCD)
显示年月日、时分秒
按下按键1选择模式【显示/更改】,按下按键2选择要更改的数,按键3【+】,按键4【-】

- #include <REGX52.H>
- #include "LCD1602.h"
- #include "DS1302.h"
- #include "Key.h"
- #include "Timer0.h"
-
- unsigned char KeyNumber,MODE,TimeSetSelect,TimeSetFlashFlag;
- unsigned char YEAR(unsigned char year,month);
- void TimeShow();
- void TimeSet();
-
-
- void main(){
- LCD_Init();
- DS1302_Init();
- Timer0_Init();
-
- DS1302_SetTime();
- LCD_ShowString(1,1," - - ");
- LCD_ShowString(2,1," : : ");
-
-
- while(1){
- KeyNumber = Key();
- if(KeyNumber==1){
- if(MODE==0)MODE=1;
- else if(MODE==1){MODE=0;DS1302_SetTime();}
- }
- switch(MODE)
- {
- case 0: TimeShow();break;
- case 1: TimeSet();break;
- }
-
- }
- }
- //显示
- void TimeShow(){
- DS1302_ReadTime();
- LCD_ShowNum(1,1,DS1302_Time[0],2);
- LCD_ShowNum(1,4,DS1302_Time[1],2);
- LCD_ShowNum(1,7,DS1302_Time[2],2);
- LCD_ShowNum(2,1,DS1302_Time[3],2);
- LCD_ShowNum(2,4,DS1302_Time[4],2);
- LCD_ShowNum(2,7,DS1302_Time[5],2);
- }
- //修改
- void TimeSet(){
- //选择需要更改的位
- if(KeyNumber == 2)
- {
- TimeSetSelect++;
- TimeSetSelect%=6;
- }
- //增加更改位的数,并判断是否越界
- if(KeyNumber == 3)
- {
- DS1302_Time[TimeSetSelect]++;
- if(DS1302_Time[0]>99){DS1302_Time[0]=0;}
- if(DS1302_Time[1]>12){DS1302_Time[1]=1;}
-
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==31)
- {
- if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
- }
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==30)
- {
- if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
- }
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==29)
- {
- if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
- }
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==28)
- {
- if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
- }
-
- if(DS1302_Time[3]>24){DS1302_Time[3]=0;}
- if(DS1302_Time[4]>59){DS1302_Time[4]=0;}
- if(DS1302_Time[5]>59){DS1302_Time[5]=0;}
- }
- //减小更改位的数,并判断是否越界
- if(KeyNumber == 4)
- {
- DS1302_Time[TimeSetSelect]--;
- if(DS1302_Time[0]>100){DS1302_Time[0]=99;}
- if(DS1302_Time[1]<1){DS1302_Time[1]=12;}
-
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==31)
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=31;}
- if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
- }
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==30)
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=30;}
- if(DS1302_Time[2]>30){DS1302_Time[2]=1;}
- }
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==29)
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=29;}
- if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
- }
- if(YEAR(DS1302_Time[0]+2000,DS1302_Time[1])==28)
- {
- if(DS1302_Time[2]<1){DS1302_Time[2]=28;}
- if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
- }
-
- if(DS1302_Time[3]>100){DS1302_Time[3]=24;}
- if(DS1302_Time[4]>100){DS1302_Time[4]=59;}
- if(DS1302_Time[5]>100){DS1302_Time[5]=59;}
- }
- //显示更改后的数据
- if(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1," ");}
- else{LCD_ShowNum(1,1,DS1302_Time[0],2);}
-
- if(TimeSetSelect==1 && TimeSetFlashFlag==1){LCD_ShowString(1,4," ");}
- else{LCD_ShowNum(1,4,DS1302_Time[1],2);}
-
- if(TimeSetSelect==2 && TimeSetFlashFlag==1){LCD_ShowString(1,7," ");}
- else{LCD_ShowNum(1,7,DS1302_Time[2],2);}
-
- if(TimeSetSelect==3 && TimeSetFlashFlag==1){LCD_ShowString(2,1," ");}
- else{LCD_ShowNum(2,1,DS1302_Time[3],2);}
-
- if(TimeSetSelect==4 && TimeSetFlashFlag==1){LCD_ShowString(2,4," ");}
- else{LCD_ShowNum(2,4,DS1302_Time[4],2);}
-
- if(TimeSetSelect==5 && TimeSetFlashFlag==1){LCD_ShowString(2,7," ");}
- else{LCD_ShowNum(2,7,DS1302_Time[5],2);}
-
- /*LCD_ShowNum(2,10,TimeSetSelect,2);
- LCD_ShowNum(2,13,TimeSetFlashFlag,2);*/
- }
-
- //闰年判断,月份天数判断
- unsigned char YEAR(unsigned char year,month){
- if(year%400==0||year%4==0&&year%100!=0)
- {
- if(month==2)
- return 29;
- }
- else
- {
- if(month==1||month==3||month==5||month==7||month==8||month==10||month==12)
- return 31;
- else if(month==4||month==6||month==9||month==11)
- return 30;
- else
- return 28;
- }
- return 0;
- }
- //定时器
- void Timer0_Routine() interrupt 1
- {
- static unsigned int count0 = 0;
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- count0++;
- if(count0 == 300){
- count0 = 0;
- TimeSetFlashFlag=!TimeSetFlashFlag;
- }
-
- }
- #include <REGX52.H>
-
- #define DS1302_SECOND 0x80
- #define DS1302_MINUTE 0x82
- #define DS1302_HOUR 0x84
- #define DS1302_DATE 0x86
- #define DS1302_MONTH 0x88
- #define DS1302_DAY 0x8A
- #define DS1302_YEAR 0x8C
- #define DS1302_WP 0x8E
-
- sbit DS1302_SCLK=P3^6;
- sbit DS1302_IO=P3^4;
- sbit DS1302_CE=P3^5;
-
- unsigned char DS1302_Time[]={22,12,31,23,59,58,2};
-
- /**
- * @brief BCD转10进制
- * @param
- * @retval
- */
- unsigned char BCD_10(unsigned char Num){
- unsigned char Temp;
- Temp = Num/10*16+Num%10;
- return Temp;
- }
-
- /**
- * @brief 10进制转BCD码
- * @param
- * @retval
- */
- unsigned char Ten_BCD(unsigned char Num){
- unsigned char Temp;
- Temp = Num/16*10+Num%16;
- return Temp;
- }
-
- /**
- * @brief 初始化DS1302
- * @param
- * @retval
- */
- void DS1302_Init(){
- DS1302_SCLK=0;
- DS1302_CE=0;
- }
-
- /**
- * @brief 写入字节
- * @param
- * @retval
- */
- void DS1302_WriteByte(unsigned char Command,Data){
- unsigned char i;
- DS1302_CE=1;
-
- for(i=0;i<8;i++){
- DS1302_IO=Command&(0x01<<i);
- DS1302_SCLK=1;
- DS1302_SCLK=0;
- }
- for(i=0;i<8;i++){
- DS1302_IO=Data&(0x01<<i);
- DS1302_SCLK=1;
- DS1302_SCLK=0;
- }
- DS1302_CE=0;
- }
-
- /**
- * @brief 读取字节
- * @param
- * @retval
- */
- unsigned char DS1302_ReadByte(unsigned char Command){
-
- unsigned char i,Data=0x00;
- Command|=0x01;
- DS1302_CE=1;
- for(i=0;i<8;i++){
- DS1302_IO=Command&(0x01<<i);
- DS1302_SCLK=0;
- DS1302_SCLK=1;
- }
- for(i=0;i<8;i++){
- DS1302_SCLK=1;
- DS1302_SCLK=0;
- if(DS1302_IO){Data|=(0x01<<i);}
- }
- DS1302_CE=0;
- DS1302_IO=0;
- return Data;
- }
-
- /**
- * @brief 将数组内容写入
- * @param
- * @retval
- */
- void DS1302_SetTime(){
- DS1302_WriteByte(DS1302_WP,0x00);
- DS1302_WriteByte(DS1302_YEAR,BCD_10(DS1302_Time[0]));
- DS1302_WriteByte(DS1302_MONTH,BCD_10(DS1302_Time[1]));
- DS1302_WriteByte(DS1302_DATE,BCD_10(DS1302_Time[2]));
- DS1302_WriteByte(DS1302_HOUR,BCD_10(DS1302_Time[3]));
- DS1302_WriteByte(DS1302_MINUTE,BCD_10(DS1302_Time[4]));
- DS1302_WriteByte(DS1302_SECOND,BCD_10(DS1302_Time[5]));
- DS1302_WriteByte(DS1302_DAY,BCD_10(DS1302_Time[6]));
- DS1302_WriteByte(DS1302_WP,0x80);
- }
-
- /**
- * @brief 读出数组内容
- * @param
- * @retval
- */
- void DS1302_ReadTime(){
-
- DS1302_Time[0]=Ten_BCD(DS1302_ReadByte(DS1302_YEAR));
- DS1302_Time[1]=Ten_BCD(DS1302_ReadByte(DS1302_MONTH));
- DS1302_Time[2]=Ten_BCD(DS1302_ReadByte(DS1302_DATE));
- DS1302_Time[3]=Ten_BCD(DS1302_ReadByte(DS1302_HOUR));
- DS1302_Time[4]=Ten_BCD(DS1302_ReadByte(DS1302_MINUTE));
- DS1302_Time[5]=Ten_BCD(DS1302_ReadByte(DS1302_SECOND));
- DS1302_Time[6]=Ten_BCD(DS1302_ReadByte(DS1302_DAY));
- }
-
- #ifndef __SD1302_H__
- #define __SD1302_H__
-
- extern unsigned char DS1302_Time[];
-
- void DS1302_Init();
- void DS1302_ReadTime();
- void DS1302_SetTime();
-
- #endif
-
- void Delay(unsigned int t) //延时函数
- {
-
- unsigned char i, j;
- while(t){
- i = 2;
- j = 239;
- do
- {
- while (--j);
- } while (--i);
- t--;
- }
-
-
- }
- #ifndef __DELAY_H__
- #define __DELAY_H__
-
- void Delay(unsigned int t);
-
- #endif
- #include <REGX52.H>
- #include "Delay.h"
-
- /**
- * @brief 获取独立按键键码
- * @param 无
- * @retval KeyNumber 键码
- */
- unsigned char Key(){
- unsigned char KeyNumber = 0;
-
- if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber = 1;}
- if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber = 2;}
- if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber = 3;}
- if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber = 4;}
-
- return KeyNumber;
- }
- #ifndef __KEY_H__
- #define __KEY_H__
-
- unsigned char Key();
-
- #endif
- #include <REGX52.H>
-
- //引脚配置:
- sbit LCD_RS=P2^6;
- sbit LCD_RW=P2^5;
- sbit LCD_EN=P2^7;
- #define LCD_DataPort P0
-
- //函数定义:
- /**
- * @brief LCD1602延时函数,12MHz调用可延时1ms
- * @param 无
- * @retval 无
- */
- void LCD_Delay()
- {
- unsigned char i, j;
-
- i = 2;
- j = 239;
- do
- {
- while (--j);
- } while (--i);
- }
-
- /**
- * @brief LCD1602写命令
- * @param Command 要写入的命令
- * @retval 无
- */
- void LCD_WriteCommand(unsigned char Command)
- {
- LCD_RS=0;
- LCD_RW=0;
- LCD_DataPort=Command;
- LCD_EN=1;
- LCD_Delay();
- LCD_EN=0;
- LCD_Delay();
- }
-
- /**
- * @brief LCD1602写数据
- * @param Data 要写入的数据
- * @retval 无
- */
- void LCD_WriteData(unsigned char Data)
- {
- LCD_RS=1;
- LCD_RW=0;
- LCD_DataPort=Data;
- LCD_EN=1;
- LCD_Delay();
- LCD_EN=0;
- LCD_Delay();
- }
-
- /**
- * @brief LCD1602设置光标位置
- * @param Line 行位置,范围:1~2
- * @param Column 列位置,范围:1~16
- * @retval 无
- */
- void LCD_SetCursor(unsigned char Line,unsigned char Column)
- {
- if(Line==1)
- {
- LCD_WriteCommand(0x80|(Column-1));
- }
- else if(Line==2)
- {
- LCD_WriteCommand(0x80|(Column-1+0x40));
- }
- }
-
- /**
- * @brief LCD1602初始化函数
- * @param 无
- * @retval 无
- */
- void LCD_Init()
- {
- LCD_WriteCommand(0x38);//八位数据接口,两行显示,5*7点阵
- LCD_WriteCommand(0x0c);//显示开,光标关,闪烁关
- LCD_WriteCommand(0x06);//数据读写操作后,光标自动加一,画面不动
- LCD_WriteCommand(0x01);//光标复位,清屏
- }
-
- /**
- * @brief 在LCD1602指定位置上显示一个字符
- * @param Line 行位置,范围:1~2
- * @param Column 列位置,范围:1~16
- * @param Char 要显示的字符
- * @retval 无
- */
- void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char)
- {
- LCD_SetCursor(Line,Column);
- LCD_WriteData(Char);
- }
-
- /**
- * @brief 在LCD1602指定位置开始显示所给字符串
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param String 要显示的字符串
- * @retval 无
- */
- void LCD_ShowString(unsigned char Line,unsigned char Column,char *String)
- {
- unsigned char i;
- LCD_SetCursor(Line,Column);
- for(i=0;String[i]!='\0';i++)
- {
- LCD_WriteData(String[i]);
- }
- }
-
- /**
- * @brief 返回值=X的Y次方
- */
- int LCD_Pow(int X,int Y)
- {
- unsigned char i;
- int Result=1;
- for(i=0;i<Y;i++)
- {
- Result*=X;
- }
- return Result;
- }
-
- /**
- * @brief 在LCD1602指定位置开始显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:0~65535
- * @param Length 要显示数字的长度,范围:1~5
- * @retval 无
- */
- void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
- {
- unsigned char i;
- LCD_SetCursor(Line,Column);
- for(i=Length;i>0;i--)
- {
- LCD_WriteData(Number/LCD_Pow(10,i-1)%10+'0');
- }
- }
-
- /**
- * @brief 在LCD1602指定位置开始以有符号十进制显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:-32768~32767
- * @param Length 要显示数字的长度,范围:1~5
- * @retval 无
- */
- void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length)
- {
- unsigned char i;
- unsigned int Number1;
- LCD_SetCursor(Line,Column);
- if(Number>=0)
- {
- LCD_WriteData('+');
- Number1=Number;
- }
- else
- {
- LCD_WriteData('-');
- Number1=-Number;
- }
- for(i=Length;i>0;i--)
- {
- LCD_WriteData(Number1/LCD_Pow(10,i-1)%10+'0');
- }
- }
-
- /**
- * @brief 在LCD1602指定位置开始以十六进制显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:0~0xFFFF
- * @param Length 要显示数字的长度,范围:1~4
- * @retval 无
- */
- void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
- {
- unsigned char i,SingleNumber;
- LCD_SetCursor(Line,Column);
- for(i=Length;i>0;i--)
- {
- SingleNumber=Number/LCD_Pow(16,i-1)%16;
- if(SingleNumber<10)
- {
- LCD_WriteData(SingleNumber+'0');
- }
- else
- {
- LCD_WriteData(SingleNumber-10+'A');
- }
- }
- }
-
- /**
- * @brief 在LCD1602指定位置开始以二进制显示所给数字
- * @param Line 起始行位置,范围:1~2
- * @param Column 起始列位置,范围:1~16
- * @param Number 要显示的数字,范围:0~1111 1111 1111 1111
- * @param Length 要显示数字的长度,范围:1~16
- * @retval 无
- */
- void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length)
- {
- unsigned char i;
- LCD_SetCursor(Line,Column);
- for(i=Length;i>0;i--)
- {
- LCD_WriteData(Number/LCD_Pow(2,i-1)%2+'0');
- }
- }
- #ifndef __LCD1602_H__
- #define __LCD1602_H__
-
- //用户调用函数:
- void LCD_Init();
- void LCD_ShowChar(unsigned char Line,unsigned char Column,char Char);
- void LCD_ShowString(unsigned char Line,unsigned char Column,char *String);
- void LCD_ShowNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
- void LCD_ShowSignedNum(unsigned char Line,unsigned char Column,int Number,unsigned char Length);
- void LCD_ShowHexNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
- void LCD_ShowBinNum(unsigned char Line,unsigned char Column,unsigned int Number,unsigned char Length);
-
- #endif
- #include <REGX52.H>
-
- void Timer0_Init(void) //1毫秒@12.000MHz
- {
- TMOD &= 0xF0; //设置定时器模式
- TMOD |= 0x01; //设置定时器模式
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- TF0 = 0; //清除TF0标志
- TR0 = 1; //定时器0开始计时
- ET0 = 1;
- EA = 1;
- PT0 = 0;
- }
-
- /* 定时器中断函数模板
- void Timer0_Routine() interrupt 1
- {
- static unsigned int count0 = 0;
- TL0 = 0x18; //设置定时初值
- TH0 = 0xFC; //设置定时初值
- count0++;
- if(count0 == 1000){
- count0 = 0;
- }
-
- }
- */
- #ifndef __TIMER0_H__
- #define __TIMER0_H__
-
- void Timer0_Init(void);
-
- #endif
模块化编程