51 江科大 学习笔记 DS1302可调时钟

1.DS1302定时器流程图

 2.DS1302芯片介绍

DS1302是由美国DALLAS公司推出的具有涓细电流充电能力的低功耗实时时钟芯片。它可以对年、月、日、周、时、分、秒进行计时且具有闺年补偿等多种功能。

DS1302引脚定义和应用电路

 DS1302内存结构框图

 寄存器定义

 3.时序定义

配置八位寄存器

 由上图时序编译DS1302的写入函数

void DS1302_WriteByte(unsigned char Command,Data) //写入数据,送入字节Command和数据Data
{
	unsigned char i;
	DS1302_CE=1;                                   //给CE写入高电平
	for(i=0;i<8;i++) 								
	{
		DS1302_IO=Command&(0x01<<i);               //将Command里的第i位赋予IO,依次左移
		DS1302_SCLK=1;                             //根据前8个脉冲循环写入8次高低电平
	    DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)                                //将Data里的第i位赋予IO,依次左移
	{
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
	    DS1302_SCLK=0;
	}
	DS1302_CE=0;
}

 

 注意READ的SCLK的时序,相比于WRITE的SCLK方波,READ少了一个,并且从第八个开始与前面的高低位相反,故编译时要着重注意

unsigned char DS1302_ReadByte(unsigned char Command)    //读取字节
{
	unsigned char i,Data=0x00;
	Command|=0x01;                                     //将传入Command的地址第一位置为1,变成READ的地址
    DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);                   
		DS1302_SCLK=0;                                 //这里采用先低后高的置位,使得结束时刚好落在SCLK脉冲的正中间
	    DS1302_SCLK=1;
	}
	for(i=0;i<8;i++)
	{
		//重复置1,过滤多的一个脉冲 READ的时序只有15个
		DS1302_SCLK=1;
	    DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	}
	DS1302_CE=0;
	DS1302_IO=0;
	return Data;                                            //将读取时间的BCD码返回
}

BCD码

BCD码(Binary-Coded Decimal‎),用4位二进制数来表示1位十进制中的0~9这10个数码,是一种二进制的数字编码形式,用二进制编码的十进制代码。

 源文件编写

跟着江科大的51可调时钟视频打的

【51单片机入门教程-2020版 程序全程纯手打 从零开始入门】

DS1302.c

#include <REGX52.H>



#define DS1302_WP   	0x8E  //DS1302的写保护
#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


//对三个要用引脚的重定义,方便后续使用
sbit DS1302_SCLK=P3^6;
sbit DS1302_IO=P3^4;
sbit DS1302_CE=P3^5;


unsigned char DS1302_Time[]={23,4,8,22,26,15,6};

//DS1302的初始化
void DS1302_Init()
{
	DS1302_SCLK=0;
	DS1302_CE=0;
}

//Command时写入时间的地址,Data是写入时间的数据(BCD)
void DS1302_WriteByte(unsigned char Command,Data) //写入字节,送入字节Command和数据Data
{
	unsigned char i;
	DS1302_CE=1;                                   //给CE写入高电平
	for(i=0;i<8;i++) 								
	{
		DS1302_IO=Command&(0x01<<i);               //将Command里的第i位赋予IO,依次左移
		DS1302_SCLK=1;                             //根据前8个脉冲循环写入8次高低电平
	    DS1302_SCLK=0;
	}
	for(i=0;i<8;i++)                                //将Data里的第i位赋予IO,依次左移
	{
		DS1302_IO=Data&(0x01<<i);
		DS1302_SCLK=1;
	    DS1302_SCLK=0;
	}
	DS1302_CE=0;
}
unsigned char DS1302_ReadByte(unsigned char Command)    //读取字节
{
	unsigned char i,Data=0x00;
	Command|=0x01;                                     //将传入Command的地址第一位置为1,变成READ的地址
    DS1302_CE=1;
	for(i=0;i<8;i++)
	{
		DS1302_IO=Command&(0x01<<i);                   
		DS1302_SCLK=0;                                 //这里采用先低后高的置位,使得结束时刚好落在SCLK脉冲的正中间
	    DS1302_SCLK=1;
	}
	for(i=0;i<8;i++)
	{
		//重复置1,过滤多的一个脉冲 READ的时序只有15个
		DS1302_SCLK=1;
	    DS1302_SCLK=0;
		if(DS1302_IO){Data|=(0x01<<i);}
	}
	DS1302_CE=0;
	DS1302_IO=0;
	return Data;                                            //将读取时间的BCD码返回
}
//DS1302_SetTime 封装了DS1302_WriteByte,将DS1302的年月日等等全部设置
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);  //关闭写保护
}
//DS1302_ReadTime是对DS1302_ReadByte的封装,将ReadByte读入的BCD数据转化为十进制的年月日并存入DS1302_Time数组中
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;    
 
}





main.c的源码

#include <REGX52.H>
#include "LCD1602.h"
#include "DS1302.h"
#include "Delay.h"
#include "Key.h"
#include "timer0.h"



unsigned char KeyNum,MODE,TimeSetSelect,TimeSetFlashFlag;


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(KeyNum==2)
	{
		TimeSetSelect++;
		TimeSetSelect%=6;    //越界清0
	}
	if(KeyNum==3)    //加年月日
	{
		DS1302_Time[TimeSetSelect]++;
		if(DS1302_Time[0]>99){DS1302_Time[0]=1;}            //年
		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)            //大月判断
		{
			if(DS1302_Time[2]>31){DS1302_Time[2]=1;}
			if(DS1302_Time[2]<1){DS1302_Time[2]=31;}
		}
		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;}
				if(DS1302_Time[2]<1){DS1302_Time[2]=30;}
			}
		else if(DS1302_Time[1]==2)        //二月比较特殊,需要单独判断
		{
			if(DS1302_Time[0]%4==0 ||  DS1302_Time[0]/100!=0)           //闰年判断
			{
				if(DS1302_Time[2]>29){DS1302_Time[2]=1;}
				if(DS1302_Time[2]<1){DS1302_Time[2]=29;}
			}
			else
			{
				if(DS1302_Time[2]>28){DS1302_Time[2]=1;}
				if(DS1302_Time[2]<1){DS1302_Time[2]=28;}
			}
		}			
		
		if(DS1302_Time[3]>24){DS1302_Time[3]=1;}
		if(DS1302_Time[4]>60){DS1302_Time[4]=1;}
		if(DS1302_Time[5]>60){DS1302_Time[5]=1;}
	}
	if(KeyNum==4)                  //减年月日(与加近乎一样)
	{
		DS1302_Time[TimeSetSelect]--;
				if(DS1302_Time[0]<0){DS1302_Time[0]=99;}
		if(DS1302_Time[1]<1){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 ||  DS1302_Time[0]/100!=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(TimeSetSelect==0 && TimeSetFlashFlag==1){LCD_ShowString(1,1,"  ");}          //被TimeSetSelect选择的位闪烁,方便调试
	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);}
	
	
}	


void main()
{
	LCD_Init();
	DS1302_Init();
	Timer0_Init();
	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:TimeShow();break;                //进入调试时间模式
			case 1:TimeSet();break;                //保存调试时间
		}
		
	}
	
}
void Timer0_Routine() interrupt 1
{
	static unsigned int T0Count;
	TL0 = 0x18;				
	TH0 = 0xFC;	
		T0Count++;
		if(T0Count>=500)
		{
				T0Count=0;
			TimeSetFlashFlag=!TimeSetFlashFlag;    //逻辑取反
		}
}

第一次写博客,没写之前很多思路都打不开,这篇也是临摹的别人的思路一点点的推进,如有说明不对的地方,请谅解并帮忙指出,谢谢

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
嗨!对于学习STM32的笔记,我可以给你一些基本的指导。首先,你需要了解STM32是一系列由STMicroelectronics公司开发的32位微控制器。它们具有广泛的应用领域,包括嵌入式系统、物联网和工业自动化等。 在学习STM32时,你可以按照以下步骤进行: 1. 硬件准备:获取一块STM32开发板,例如STM32F4 Discovery或NUCLEO系列。这些开发板通常带有一些外设和接口,便于学习和实验。 2. 开发环境搭建:下载并安装Keil MDK或者IAR Embedded Workbench等集成开发环境(IDE)。这些IDE提供了编译器、调试器和其他工具,方便你编写和调试STM32的代码。 3. 学习基本知识:了解STM32的体系结构、寄存器和外设等基本知识。可以通过阅读相关的参考手册、数据手册和应用笔记来深入了解。 4. 编写代码:使用C/C++语言编写STM32的应用程序。你可以使用相关的库函数来简化开发过程,如标准外设库(StdPeriph Library)或者新的STM32Cube库。 5. 调试和测试:使用调试器和仿真器来调试和测试你的代码。这些工具能够帮助你单步执行代码、观察寄存器和内存的状态,以及检查外设的操作。 6. 实践项目:尝试一些小型的项目,如LED闪烁、按键输入和PWM输出等,以巩固你的学习成果。随着经验的积累,你可以尝试更复杂的项目,如通信接口、传感器应用和无线通信等。 记得在学习过程中多查阅官方文档、参考资料和在线论坛,以便解决遇到的问题。祝你学习STM32的旅程愉快!如果你有具体的问题,欢迎随时向我提问。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Richard 刘

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值