一、DS1302时钟芯片
DS1302是一种低功耗实时时钟芯片,实时时钟计算年、月、日、时、分、秒、星期,直到 2100 年,并有闰年调节功能。每月的天数和闰年的天数可自动调整。时钟操作可通过 AM/PM 指示决定采用 24 或 12 小时格式。DS1302 与 单片机之间能简单地采用同步串行的方式进行通信,仅需用到三根通信线:1、CE使能线;2、I/O 数据线;3、SCLK 串行时钟线;
二、示例代码案例
main.c文件
#include <REGX52.H>
#include "lcd1602.h"
#include "DS1302.h"
#include "Delay.h"
#include "Timer0.h"
#include "Key.h"
unsigned char KeyNum,MODE,TimerSetSelect,TimerSetFlashFlag;
//时间的显示
void TimerShow(void){
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 TimerSet(void){
if(KeyNum==2){
TimerSetSelect++;
TimerSetSelect%=6;
}
//时间增加
if(KeyNum==3){
//操控具体的时间
DS1302_Time[TimerSetSelect]++;
//设置年月日时分秒星期的规范
if(DS1302_Time[0]>99){DS1302_Time[0]=0;}
if(DS1302_Time[1]>12){DS1302_Time[1]=1;}
//月份设置
if(DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7
|| DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12)
{
//2月份
if(DS1302_Time[2]>31){
DS1302_Time[2]=1;
}
}
else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11)
{
if(DS1302_Time[2]>30){
DS1302_Time[2]=1;
}
}
//闰年和平年时间处理
else if(DS1302_Time[1]==2)
{
if(DS1302_Time[0]%4==0)
{
if(DS1302_Time[2]>29)
{
DS1302_Time[2]=1;
}
}
else
{
if(DS1302_Time[2]>28)
{
DS1302_Time[2]=1;
}
}
}
if(DS1302_Time[3]>23){DS1302_Time[3]=0;}
if(DS1302_Time[4]>59){DS1302_Time[4]=0;}
if(DS1302_Time[5]>59){DS1302_Time[5]=0;}
}
//时间减少
if(KeyNum==4){
DS1302_Time[TimerSetSelect]--;
if(DS1302_Time[0]<0){DS1302_Time[0]=99;}
if(DS1302_Time[1]<0){DS1302_Time[1]=12;}
if(DS1302_Time[1]==1 || DS1302_Time[1]==3 || DS1302_Time[1]==5 || DS1302_Time[1]==7
|| DS1302_Time[1]==8 || DS1302_Time[1]==10 || DS1302_Time[1]==12)
{
if(DS1302_Time[2]<1){
DS1302_Time[2]=31;
}
if(DS1302_Time[2]>31){
DS1302_Time[2]=1;
}
}
else if(DS1302_Time[1]==4 || DS1302_Time[1]==6 || DS1302_Time[1]==9 || DS1302_Time[1]==11)
{
if(DS1302_Time[2]<1){
DS1302_Time[2]=30;
}
if(DS1302_Time[2]>30){
DS1302_Time[2]=1;
}
}
else if(DS1302_Time[1]==2)
{
if(DS1302_Time[0]%4==0)
{
if(DS1302_Time[2]<1)
{
DS1302_Time[2]=29;
}
if(DS1302_Time[2]>29)
{
DS1302_Time[2]=1;
}
}
else
{
if(DS1302_Time[2]<1)
{
DS1302_Time[2]=28;
}
if(DS1302_Time[2]>28)
{
DS1302_Time[2]=1;
}
}
}
if(DS1302_Time[3]<0){DS1302_Time[3]=23;}
if(DS1302_Time[4]<0){DS1302_Time[4]=59;}
if(DS1302_Time[5]<0){DS1302_Time[5]=59;}
}
//选择时悬停等待的数字闪烁效果
if(TimerSetSelect==0 && TimerSetFlashFlag==1 ){LCD_ShowString(1,1," ");}
else{LCD_ShowNum(1,1,DS1302_Time[0],2);}
if(TimerSetSelect==1 && TimerSetFlashFlag==1 ){LCD_ShowString(1,4," ");}
else{LCD_ShowNum(1,4,DS1302_Time[1],2);}
if(TimerSetSelect==2 && TimerSetFlashFlag==1 ){LCD_ShowString(1,7," ");}
else{LCD_ShowNum(1,7,DS1302_Time[2],2);}
if(TimerSetSelect==3 && TimerSetFlashFlag==1 ){LCD_ShowString(2,1," ");}
else{LCD_ShowNum(2,1,DS1302_Time[3],2);}
if(TimerSetSelect==4 && TimerSetFlashFlag==1 ){LCD_ShowString(2,4," ");}
else{LCD_ShowNum(2,4,DS1302_Time[4],2);}
if(TimerSetSelect==5 && TimerSetFlashFlag==1 ){LCD_ShowString(2,7," ");}
else{LCD_ShowNum(2,7,DS1302_Time[5],2);}
}
void main(){
LCD_Init();
DS1302_Init();
Timer0_Init();
LCD_ShowString(1,1,"RTC");
LCD_ShowString(1,1," - - ");
LCD_ShowString(2,1," : : ");
DS1302_SetTime();
while(1){
KeyNum=Key();
if(KeyNum==1){
if(MODE==0){MODE=1;}
else if(MODE==1){MODE=0;DS1302_SetTime();}
}
switch(MODE){
case 0: TimerShow();break;
case 1: TimerSet();break;
}
}
}
//中断处理程序
void Timer0_Routine() interrupt 1
{
static unsigned int T0Count;
//定时器每次到达了65536就会溢出为0,
//所以每次需要重新设定初始值
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
T0Count++;
//每隔1秒执行一次中断,计数器每隔一秒溢出发出一次中断信号
if(T0Count>=3000){
T0Count=0;
//根据TimerSetFlashFlag的1或0,执行不同的过程
TimerSetFlashFlag=!TimerSetFlashFlag;
}
}
DS1302.C文件
#include <REGX52.H>
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;
sbit DS1302_SCLK=P3^6;
//定义年月日时分秒星期
#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
char DS1302_Time[]={
24,4,10,21,59,55,3
};
//时钟初始化
void DS1302_Init(void){
DS1302_CE=0;//将使能位置0,低电平;
DS1302_SCLK=0;//将时钟位置0,低电平;
}
/**
*@breaf DS1302单字节写入函数
*@param command:写入控制指令的指令,包含要写入寄存器的地址;
*@param Data:将要写入的数据内容;
*@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;//使能位置低电平;
}
/**
*@breaf DS1302单字节读出函数
*@param command:写入控制指令的指令,包含要读出寄存器的地址;
*@retval Data:读出的数据;
*/
unsigned char DS1302_ReadByte(unsigned char Command){
unsigned char i,Data=0x00;
Command |=0x01;
DS1302_CE=1;
for(i=0;i<8;i++){
//0100 0000
//0000 0001
//0000 0000
DS1302_IO=Command&(0x01<<i);
DS1302_SCLK=0;
DS1302_SCLK=1;
}
for(i=0;i<8;i++){
//下降沿读数据
DS1302_SCLK=1;
DS1302_SCLK=0;
//将IO为1时DATA为1,将data最高位置为1
if(DS1302_IO){Data |= (0x01<<i);}
}
DS1302_CE=0;
DS1302_IO=0;
return Data;
}
//十进制转BCD码
void DS1302_SetTime(void){
DS1302_WriteByte(DS1302_WP,0x00);
DS1302_WriteByte(DS1302_YEAR,DS1302_Time[0]/10*16+DS1302_Time[0]%10);
DS1302_WriteByte(DS1302_MONTH,DS1302_Time[1]/10*16+DS1302_Time[1]%10);
DS1302_WriteByte(DS1302_DATE,DS1302_Time[2]/10*16+DS1302_Time[2]%10);
DS1302_WriteByte(DS1302_HOUR,DS1302_Time[3]/10*16+DS1302_Time[3]%10);
DS1302_WriteByte(DS1302_MINUTE,DS1302_Time[4]/10*16+DS1302_Time[4]%10);
DS1302_WriteByte(DS1302_SECOND,DS1302_Time[5]/10*16+DS1302_Time[5]%10);
DS1302_WriteByte(DS1302_DAY,DS1302_Time[6]/10*16+DS1302_Time[6]%10);
DS1302_WriteByte(DS1302_WP,0x80);
}
//BCD码转十进制
void DS1302_ReadTime(void){
unsigned char Temp;
Temp=DS1302_ReadByte(DS1302_YEAR);
DS1302_Time[0]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MONTH);
DS1302_Time[1]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DATE);
DS1302_Time[2]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_HOUR);
DS1302_Time[3]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_MINUTE);
DS1302_Time[4]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_SECOND);
DS1302_Time[5]=Temp/16*10+Temp%16;
Temp=DS1302_ReadByte(DS1302_DAY);
DS1302_Time[6]=Temp/16*10+Temp%16;
}
lcd1602.c文件
#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');
}
}
key.c文件
#include <REGX52.H>
#include "Delay.h"
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;
}
Timer0.c文件
#include <REGX52.H>
#include <INTRINS.H>
void Timer0_Init(void) //1毫秒@12.000MHz
{
// TL0=64536%256+1;
// TH0=64536/256;
TMOD &= 0xF0; //设置定时器模式
TL0 = 0x18; //设置定时初值
TH0 = 0xFC; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
//中断设置
ET0=1;
EA=1;
PT0=0;
}