欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 教育 > 高考 > 蓝桥杯_DS1302时钟

蓝桥杯_DS1302时钟

2025/3/28 21:48:33 来源:https://blog.csdn.net/2301_81650162/article/details/146420480  浏览:    关键词:蓝桥杯_DS1302时钟

一 DS13302时钟简介

DS1302是时钟的芯片,可以显示对应的时钟和日期,这里有一个前提,需要连接着电源,如果把程序在今天烧录到板子里,然后不连电,第二天的数据并不准确,所以说,如果想要准确的日期,那么需要一直给板子提供电源。

这里所说的数据,使用841BCD码来保存并传输,传输八位数据,这八位数据的最后一位,决定着是读还是写;1表示读,0表示写,如果想要真正运行DS1302,需要先写再读。

二 原理

上面这个是板子提供的原理图中的电路图,在这里,我们只需要关注三条线:RST、I/O、SCLK,这三根线决定着数据的传输,接下来详细的介绍一下:

  • RST:是控制着整体写的过程,并且只有把RST的电压拉高才能往里面写数据
  • SCLK:这是一个时钟,他一直以某一种速度发送频率,低电平高电平一直发送,他的作用是控制着节奏,并且是有一个上升沿读取一个。(RST必须是高电平)
  • I/O:他的作用主要是发送地址 + 数据,并且他遵循先写低位,再写高位

三 写的过程

微观

现在,假设,我要写86,换成BCD码,1000 0110,先从最低位,从右边第一位的0开始写起,向右走,现在把1000 0110中的0拿出来,然后再将1000 0110向右移一位,(最后一位去掉,最前面加个零)变成了0100 0011,再重复循环,取八位值

宏观

先将RST拉低,等一会,SCLK拉低,等一会,再将RST拉高,等一会,把数据的地址+data写进去,最后再关闭RST

可视化:

四 写和读的区别

在读的时候,和写的过程有不同的地方,在写的时候,我们当SCLK有上升沿的时候,进行一次数据的写,但是在读的时候,读地址:SCLK是上升沿;读数据:SCLK是下降沿

可视化:

五 代码层面

不用慌张要背这么多代码,因为在比赛的时候,会有范例代码给到我们,我们只需要到对应的文件夹中赋值即可,接下来说一下详细过程:

在比赛提供的文件夹中,将ds1302.c和.h的两个文件放到我们的代码中,然后打开ds1302.c文件进行代码的编辑。

DS1302.c

写函数(set_RTC)

在该文件中,我们需要将想要设置的时分秒(假设是22点59分55秒),转化成8421BCD码,转化成计算机所能看得懂的数字,随后,再将计算机看的懂得数字再转成最后实现的时间。

这里的设置的时分秒它属于是一个数组,ucRTC[3]

在写的过程中,要先把高位赋值成0,因为高位(WP)决定着这个写的功能,WP的位置是在8Eh,随后我们看到write一列,我们想要设置时分秒,我们需要找到对应的寄存器的位置,84h、82h、80h。最后一定要记得把WP高位再给关闭了。

相应的写函数的代码为:

//设置1302时分秒函数
//入口参数是数组,包含时、分、秒数据
void Set_RTC(unsigned char *ucRTC)	//这里的*,待定
{unsigned char temp;	//中间局部变量,存放时分秒Write_Ds1302_Byte(0x8e,0);	//WP=0 允许写write操作//这里需要记忆://0x8e WP=0,允许写的操作;0x80不允许//0x84 小时//0x82 分钟//0x80 秒temp = ((ucRTC[0] / 10 ) << 4) + (ucRTC[0] % 10) ;	//数组的第零个数据,是小时,23 // 2(0010)对应的是高位,3(0011)对应的是低位Write_Ds1302_Byte(0x84,temp);	temp = ((ucRTC[1] / 10 ) << 4) + (ucRTC[1] % 10) ;	//数组的第一个数据,是分钟,59 Write_Ds1302_Byte(0x82,temp);	temp = ((ucRTC[2] / 10 ) << 4) + (ucRTC[2] % 10) ;	//数组的第一个数据,是秒,59 Write_Ds1302_Byte(0x80,temp);	Write_Ds1302_Byte(0x8e,0x80);	//WP=1 禁止写write操作}

在temp和ucRTC[]之间的转换我给大家举个例子,例如,我现在要写23这个数字,我们先把2这个数字提取出来,需要先让23除以10,得出来了一个2,但是这个2计算机是识别不了的,自动把2写成了8421BCD码,也就是0010,然后我们将0010向左移动四位,然后再加上“23除以10取余,也就得到了3,3转换为BCD码成了0011”,最后23这个人能看懂的数字,转换成了0010 0011,并赋值给temp。

读函数(Read_RTC)

在上面的写函数已经将23这个数字,转换成了0010 0011,我们现在又需要将这个8421BCD码转换成人能看得懂的形式,那么如何取高四位和第四位呢,先将这个BCD码向右移动四位,得到了0010,然后将0010如何将0010转换成十进制也就是我们能看得懂的代码呢,我们需要将他再乘以10,就成了十进制,随后将0010 0011和0x0F相与,就可以得到第四位的东西,也就是0011,把他们相加就是最后的呈现数字啦。当然,也要记得把对应的地址写出来哦,对应读的地址,时分秒分别在85h、83h、81h。

//读取DS1302时分秒的函数
//入口参数:将读取到的时分秒数据存放到数组指针当中
void Read_RTC(unsigned char *ucRTC)
{unsigned char temp;temp = Read_Ds1302_Byte ( 0x85);	//读取小时ucRTC[0] = ((temp >> 4)*10 )+( temp & 0x0F );	//读取的是23(BCD),但是转成十进制的数是35,不能直接赋值,要进行BCD到十进制的转换temp = Read_Ds1302_Byte ( 0x83);	//读取分钟ucRTC[1] = ((temp >> 4)*10 )+( temp & 0x0F );temp = Read_Ds1302_Byte ( 0x81);	//读取秒ucRTC[2] = ((temp >> 4)*10 )+( temp & 0x0F );	}

main.c

在主函数中,我们想要实现的功能是按一下按键,变成计时器,再按一下按键,是时钟

要特别强调一点,这里虽然代码很长,但是这是基于上一篇文章“通过按键控制数码管显示数字”,如果大家有所看不懂的,请先看懂上一篇文章,再来本章学习。

#include <STC15F2K60S2.H>
#include "Timer.h"
#include "dsp_init.h"
#include "dsp_seg.h"
#include "stdio.h"
#include "key.h"
#include "ds1302.h"
#include "dsp_led.h"//函数声明,三个东西主体循环
void Key_Process(void);		//按键处理,底层的数据
void Seg_Process(void);		//显示处理,显示信息的生成
void Led_Process(void);		//LED状态信息//全局变量
//显示专用
unsigned char seg_buf[8];		//放置字符串转换后的段码到数组
unsigned char seg_string[10];	//放置字符串
unsigned char pos = 0;	//中断显示专用//按键专用
unsigned char Key_Val;	//按键的数值存储变量
unsigned char Key_Down;	
unsigned char Key_Old;//按键和显示函数减速专用,基本不变,我不写试一下
unsigned char Key_Slow_Down;
unsigned char Seg_Slow_Down;//可能会改变
//unsigned_char Seg_Show_Num;	//准备显示出来的数值//运行时间
unsigned int ms_count = 0;
unsigned char s_count = 0;
//运行状态
unsigned char Change_State;
unsigned char ucled;//使用1302时,基本不变
unsigned char ucRTC[3] = {23,23,55};	//数组初始值,里面放的是时分秒void main()
{Cls_Peripheral();		//清除外设Timer1Init();		//定时器1,1ms进入一次Set_RTC(ucRTC);		//23.59.55while(1){Key_Process();		//按键处理,底层的数据Seg_Process();		//显示处理,显示信息的生成Led_Process();}}//定时器初始化
//-----------------------------------------------/* Timer1_interrupt routine */
void tm1_isr() interrupt 3 
{if(++Key_Slow_Down == 10) Key_Slow_Down = 0;if(++Seg_Slow_Down == 10) Seg_Slow_Down = 0;if(++ms_count == 1000)	//记录运行时间{s_count++;ms_count = 0;}Seg_Disp( seg_buf,pos);//数码管显示if(++pos == 8){pos = 0;}Led_Disp(ucled);//ucled显示}//key_process的函数内部
void Key_Process(void)		//按键处理,底层的数据
{//读取按键按下的编号数值Key_Val = Key_Read();	Key_Down = Key_Val & (Key_Old ^ Key_Val);Key_Old = Key_Val;//以上这五行,就是检验下降沿//根据代码改变if(Key_Down)	//如果捕捉到下降沿跳变{//Seg_Show_Num = Key_Down;if(++Change_State == 2) Change_State = 0;	//保证Change_State在0、1之间翻滚}}//seg_process的函数内部
void Seg_Process(void)		//显示处理,显示信息的生成
{if(Seg_Slow_Down) return;Seg_Slow_Down = 1;switch(Change_State){case 0: 	Read_RTC(ucRTC);	//读取1302内部时分秒的数据,放到预定义的数组空间中sprintf(seg_string,"%02d-%02d-%02d",(unsigned int)ucRTC[0],(unsigned int)ucRTC[1],(unsigned int)ucRTC[2]);break;case 1:sprintf(seg_string,"%8d",(unsigned int)s_count);break;}//永远不变Seg_Tran(seg_string, seg_buf);}//Led_Process的函数内部
void Led_Process(void)		
{switch(Change_State){case 0: 	ucled = 0xF0;break;case 1:ucled = 0x0F;break;}}

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com

热搜词