51单片机DS1302时钟

一、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;
}

  • 20
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是一个基于51单片机DS1302时钟模块使用代码示例: ```c #include <REG52.h> #include <intrins.h> #define uchar unsigned char #define uint unsigned int sbit RST = P3^4; sbit DAT = P3^5; sbit CLK = P3^6; // 延时函数 void Delay(uint i) { while(i--); } // 向DS1302写入一个字节 void DS1302_WriteByte(uchar dat) { uchar i; for (i = 0; i < 8; i++) { DAT = dat & 0x01; CLK = 0; CLK = 1; dat >>= 1; } } // 从DS1302读取一个字节 uchar DS1302_ReadByte() { uchar i, dat = 0; for (i = 0; i < 8; i++) { dat >>= 1; if (DAT) dat |= 0x80; CLK = 0; CLK = 1; } return dat; } // 启动DS1302时钟 void DS1302_Start() { RST = 1; CLK = 1; _nop_(); _nop_(); _nop_(); RST = 0; DS1302_WriteByte(0x8e); DS1302_WriteByte(0x00); RST = 1; } // 停止DS1302时钟 void DS1302_Stop() { RST = 0; CLK = 0; _nop_(); _nop_(); _nop_(); RST = 1; DS1302_WriteByte(0x8e); DS1302_WriteByte(0x80); RST = 1; } // 写入DS1302时间 void DS1302_WriteTime(uchar year, uchar month, uchar day, uchar hour, uchar minute, uchar second) { DS1302_Start(); DS1302_WriteByte(0xbe); DS1302_WriteByte(second); DS1302_WriteByte(minute); DS1302_WriteByte(hour); DS1302_WriteByte(day); DS1302_WriteByte(month); DS1302_WriteByte(year); DS1302_Stop(); } // 读取DS1302时间 void DS1302_ReadTime(uchar *year, uchar *month, uchar *day, uchar *hour, uchar *minute, uchar *second) { DS1302_Start(); DS1302_WriteByte(0xbf); *second = DS1302_ReadByte(); *minute = DS1302_ReadByte(); *hour = DS1302_ReadByte(); *day = DS1302_ReadByte(); *month = DS1302_ReadByte(); *year = DS1302_ReadByte(); DS1302_Stop(); } void main() { uchar year, month, day, hour, minute, second; DS1302_WriteTime(0x21, 0x10, 0x13, 0x10, 0x30, 0x00); while (1) { DS1302_ReadTime(&year, &month, &day, &hour, &minute, &second); printf("20%d-%d-%d %d:%d:%d\n", year, month, day, hour, minute, second); Delay(1000); } } ``` 在上述代码中,定义了DS1302的RST、DAT、CLK引脚,以及自定义了延时函数`Delay`。然后定义了向DS1302写入一个字节的函数`DS1302_WriteByte`,从DS1302读取一个字节的函数`DS1302_ReadByte`,启动DS1302时钟的函数`DS1302_Start`,停止DS1302时钟的函数`DS1302_Stop`,写入DS1302时间的函数`DS1302_WriteTime`,以及读取DS1302时间的函数`DS1302_ReadTime`。 在`main`函数中,首先调用`DS1302_WriteTime`函数设置初始时间,然后通过`DS1302_ReadTime`函数读取当前时间,并通过串口输出。最后通过`Delay`函数延迟1秒,实现时钟的运行。需要注意的是,DS1302时钟模块的时间格式为BCD码,需要进行转换才能得到实际的时间。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值