蓝桥杯单片机设计点2:DS1302时钟芯片的读写

DS1302是蓝桥杯单片机常用的芯片之一,这个芯片并不难,需要背诵的部分是比较少的。

但我自己在学习研究的时候发现,其读写操作是有些许值得斟酌的地方。

此处对其进行一些介绍,但我只介绍编程时需要必备的硬件设计、芯片手册内容,

完整的有关此芯片的介绍,各位看官还需要多查阅DS1302芯片手册才是。

基础好的可以直接跳过DS1302的入门介绍。

附上文章所讲的整个工程下载地址:

https://download.csdn.net/download/qq_64257614/87786967?spm=1001.2014.3001.5503

目录

目录

一、DS1302芯片极简入门介绍:

寄存器介绍:

读取和写入更改时间位 秒例子介绍:

一次性赋值七个时间量介绍:

二、DS1302芯片数据处理:

读取数据处理:

写入数据处理:

三、实践突破:

四、实验效果:

下面为防止资源无法下载,附上工程所有代码:

#include " DS1303_Review.h"

#include "public.h"

#include "Timer.h"

#include "ds1302.h"

#include "smg.h"

 #include "key_4589.h"


 


一、DS1302芯片极简入门介绍:

寄存器介绍:

DS1302有两块存储器,日历时钟寄存器静态RAM存储器

前者用于记录时间,后者用于记录其他数据

日历时钟寄存器:又分为  读寄存器   和   写寄存器

以下是日历寄存器的地址:

 这么看大家可能一头雾水,那我将它简化一下就十分明了了:

我们以时间位的设置读取 为线索来看这张表:

时间位读寄存器写寄存器范围
0x810x800x   00~59
0x830x820x   00~59
0x850x840x  01~12/00~23
0x870x860x  01~31
0x890x880x  01~12
0x8b0x8a0x  01~7
0x8d0x8c0x  00~99

(1)秒寄存器(80H和81H)的位7(CH)为时钟暂停标志位:

      CH=1;时钟振荡停止

      CH=0;时钟开始运行

(2)控制寄存器(8EH和8FH)的位7(WP)为写保护位:

     WP=0;允许        对时钟或RAM寄存器 进行写操作

     WP=1;禁止        对任何寄存器             进行写操作

读取和写入更改时间位 秒例子介绍:

对DS1302进行操作时,我们可以根据这张表:以更改和读取  秒  来介绍

1.先找到要操作的时间位   

2.查表得到它的读写寄存器:

时间位读寄存器写寄存器范围
0x810x800x   00~59

3.找到并复制  官方驱动的这俩个函数:

     第一个是写函数,第二个是读函数

   void Write_Ds1302_Byte( unsigned char address,unsigned char dat ) ;

    unsigned char Read_Ds1302_Byte ( unsigned char address );

4.读操作如此写,即可读取当前秒数:

second=Read_Ds1302_Byte ( 0x81);


//此句可读取当前秒数
//second 是一个U8类型变量

5.因为DS1302是有读写保护的,所以在进行写操作之前

        还需要向地址写入指令,取消写保护:

	Write_Ds1302_Byte(0x8e,0x00);//允许写入数据

6.写操作如此写,即可更改秒数:

//更改秒数为25
Write_Ds1302_Byte(0x80,0x25) ;

 7.写操作结束后,别忘了打开写保护,继续禁止写入:

	Write_Ds1302_Byte(0x8e,0x80);//禁止写入数据

此外其他时间位数值的设定和读取也都是同样的方法,只需选择对应的地址读写即可。

一次性赋值七个时间量介绍:

此处介绍一个习惯:

就是将 读地址写地址分别写入俩个数组,顺序是 秒   分   时   日   月   周  年   

unsigned char Read_DS1302_adrr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//定义DS1302读操作的日历时钟存储器地址
//秒   分   时   日   月   周  年		

															
unsigned char Write_DS1302_adrr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//定义DS1302写操作的日历时钟寄存器地址
//秒   分   时   日   月   周  年	

这样在之后   七个时间量就能   一次性 用循环来进行赋值初始化了,单独赋值也十分方便:

一次性初始化时间量例子:

此例为初始化1302为     2023年,周一,5月15日,22时,29分,50秒:

u8 Timer[10]={0x50,0x29,0x22,0x15,0x05,0x01,0x23};
//		    秒   分   时   日   月   周   年	

void DS1302_config()     //ds1302时钟初始化写入
{
	char i;
	Write_Ds1302_Byte(0x8e,0x00);//允许写入数据
	for(i=0;i<7;i++)             //写入7个字节的时间参数
	{
		Write_Ds1302_Byte(Write_DS1302_adrr[i],Timer[i]);
	}
	Write_Ds1302_Byte(0x8e,0x80);//禁止写入数据
}


void DS1302_Timer()   //读取当前时钟数据
{
	char i;
	for(i=0;i<3;i++)   //读取7个字节的实时时间
	{
		Timer[i]=Read_Ds1302_Byte(Read_DS1302_adrr[i]);
	}
}

二、DS1302芯片数据处理:

读取数据处理:

终于,我们学会了读取DS1302的内容,但该如何处理它读取到的数据呢?

要想将16进制数转化为10进制,只需进行/16和%16操作即可:

这样我们就能给数码管打印时间值了。

//读取的值数据类型 与 写入时一样:
u8 Timer[10]={0x50,0x59,0x23,0x05,0x04,0x03,0x23};


Timer[2]/16;  //时 十位
Timer[2]%16;  //时 个位

Timer[1]/16;  //分 十位
Timer[1]%16;  //分 个位 

Timer[0]/16;  //秒 十位
Timer[0]%16;  //秒 个位

写入数据处理:

有些题目要求我们在时钟运转时,能更改时间,那么数据该如何写入呢?

1.首先定义一个    char 类型的变量    将当前读取到的时间转换成10进制后存入:

不用unsigned char 是因为不能判断 加减操作边界 小于0的情况,

char time_temp;
unsigned char read_t[4]={0,0,0};



void read_DS1302_Timer()   //读取当前时钟数据
{
	char i;
	for(i=0;i<3;i++)   //读取7个字节的实时时间
	{
		Timer[i]=Read_Ds1302_Byte(Read_DS1302_adrr[i]);
		read_t[i]=Timer[i]/16*10+Timer[i]%16;
	}
}


//存下当前秒数
time_temp=read_t[0];

2.再定义俩个  unsigned char 类型的变量   备用

	u8 time_temp_1;
	u8 time_temp_2;	

2.对该十进制数变量进行需要的加减操作后,在通过辅助转化为16进制数,最后进行写操作写入:

char time_temp;
u8 time_temp_1;
u8 time_temp_2;	
u8 read_t[4]={0,0,0};



void read_DS1302_Timer()   //读取当前时钟数据
{
	char i;
	for(i=0;i<3;i++)   //读取7个字节的实时时间
	{
		Timer[i]=Read_Ds1302_Byte(Read_DS1302_adrr[i]);
		read_t[i]=Timer[i]/16*10+Timer[i]%16;
	}
}


//存下当前秒数
time_temp=read_t[0];


time_temp=Timer[cho]/16*10+Timer[cho]%16;
time_temp++;
time_temp_1=time_temp/10;
time_temp_2=time_temp%10;
time_temp=time_temp_1*16+time_temp_2;

Write_Ds1302_Byte(0x8e,0x00);//允许写入数据
Write_Ds1302_Byte(Write_DS1302_adrr[0],time_temp);//写入数据
Write_Ds1302_Byte(0x8e,0x80);//禁止写入数据

最后还是提醒一下,变量加减自己注意边界哦!!!!

三、实践突破:

学会了基础,就要开始操作了,现在让我们进入以下实践:

	此实验主要总结回顾1302的一些数据操作:
	
	1.开机就开始显示时间,数码管都不闪烁
	2.时间初始化为:2023年,周一,5月15日,22时,29分,50秒:
	3.按下S5 开始选择 时、分、秒	/ 时、分、秒被选中时闪烁
	4.此时闪烁的位可以通过按下 S4 S8分别进行加减操作
	5.按下S9取消选中,数码管都不闪烁
	

此实践考察矩阵按键和以上教学分享的所有操作,文首的工程便是它.

大家可以自己在四梯科技的竞赛板子上开始实践,实在GET不到设计灵感了,

可以下载文首链接的资源工程。

四、实验效果:

DS1302时钟芯片的读写实验效果

下面为防止资源无法下载,附上工程所有代码:

#include " DS1303_Review.h"

#include " DS1303_Review.h"
void read_DS1302_Timer();   //读取当前时钟数据
void DS1302_config();             //ds1302时钟初始化写入
void ds1302_gai(u8 sj,u8 sz);     //改时间函数


void main()
{
	u8 key_value;
	char time_temp;
	u8 time_temp_1;
	u8 time_temp_2;	
	
	cls_led_buzz_smg();     //初始化清除外设
	Timer0Init();
	Timer1Init();
	DS1302_config();        //ds1302时钟初始化写入
	
	while(1)
	{
		key_value=key_return();
		switch(key_value)
		{
			case 5:cho++;if(cho>=4) cho=0;break;
			case 4:
							if(cho!=0)
							{
								time_temp=read_t[cho-1];
								time_temp++;
								//防越界
								if(cho==1 && time_temp>=60) time_temp=60; 
								if(cho==2 && time_temp>=60)	time_temp=60;
								if(cho==3 && time_temp>=24)	time_temp=24;	
								
								time_temp_1=time_temp/10;
								time_temp_2=time_temp%10;
								time_temp=time_temp_1*16+time_temp_2;
								ds1302_gai(cho-1,time_temp);
							}	
							break;			
			case 8:
							if(cho!=0)
							{
								time_temp=read_t[cho-1];
								time_temp--;
								//防越界
								if(time_temp<=0)  time_temp=0;
								
								time_temp_1=time_temp/10;
								time_temp_2=time_temp%10;
								time_temp=time_temp_1*16+time_temp_2;
								ds1302_gai(cho-1,time_temp);	
							}	
							break;	
			case 9:cho=0;break;			
		}
		
		if(timer_flag==1)
		{
			timer_flag=0;
			read_DS1302_Timer();   //读取当前时钟数据
		}
		
	}
}

void DS1302_config()     //ds1302时钟初始化写入
{
	char i;
	Write_Ds1302_Byte(0x8e,0x00);//允许写入数据
	for(i=0;i<7;i++)             //写入7个字节的时间参数
	{
		Write_Ds1302_Byte(Write_DS1302_adrr[i],Timer[i]);
	}
	Write_Ds1302_Byte(0x8e,0x80);//禁止写入数据
}

void read_DS1302_Timer()   //读取当前时钟数据
{
	char i;
	for(i=0;i<3;i++)   //读取7个字节的实时时间
	{
		Timer[i]=Read_Ds1302_Byte(Read_DS1302_adrr[i]);
		read_t[i]=Timer[i]/16*10+Timer[i]%16;
	}
}


//sj选择改的时间 0——秒 1——分钟 2——小时
//sz是输入改的数值
void ds1302_gai(u8 sj,u8 sz)    //改时间函数
{
	switch(sj)
	{
		case 0:
						Write_Ds1302_Byte(0x8e,0x00);//允许写入数据
							Write_Ds1302_Byte(Write_DS1302_adrr[0],sz);
					break;
		case 1:	
						Write_Ds1302_Byte(0x8e,0x00);//允许写入数据
							Write_Ds1302_Byte(Write_DS1302_adrr[1],sz);					
					break;			
		case 2:	
						Write_Ds1302_Byte(0x8e,0x00);//允许写入数据
							Write_Ds1302_Byte(Write_DS1302_adrr[2],sz);
					break;		
	}
		Write_Ds1302_Byte(0x8e,0x80);//禁止写入数据
}
#ifndef _DS1303_Review_h_
#define _DS1303_Review_h_

#include "stc15f2k60s2.h"
#include "key_4589.h"
#include "public.h"
#include "smg.h"
#include "Timer.h"
#include "ds1302.h"


#endif

#include "public.h"

#include "public.h"


void inint_74hc573(u8 choice)  
{
	switch(choice)
	{
		case 4:P2=(P2&0X1F)|0X80;break;
		case 5:P2=(P2&0X1F)|0Xa0;break;
		case 6:P2=(P2&0X1F)|0Xc0;break;
		case 7:P2=(P2&0X1F)|0Xe0;break;
	}
}

void cls_led_buzz_smg()  //初始化清除外设
{
	inint_74hc573(5);
	buzz = 0;
	inint_74hc573(4);
	P0 = 0xff;
	inint_74hc573(6);
	P0 = 0xff;
	inint_74hc573(7);
	P0 = 0xff;
}	
#ifndef _public_h_
#define _public_h_

#include "stc15f2k60s2.h"
#include "public.h"


//数据类型重定义
typedef unsigned int u16;
typedef unsigned char u8;
typedef int u32;

//定义蜂鸣器管脚
sbit buzz=P0^6;

void inint_74hc573(u8 choice);  
void cls_led_buzz_smg();  //初始化清除外设

#endif

#include "Timer.h"

#include "Timer.h"

u8 timer_flag;  //时间读取标志位
u8 cho;         //秒,分,时 选取闪烁标志位
//0 无选择 1 秒 2 分 3 时

u8 lm;//亮灭控制位
u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8;
u8 read_t[4]={0,0,0};

unsigned char Read_DS1302_adrr[7]={0x81,0x83,0x85,0x87,0x89,0x8b,0x8d};
//定义DS1302读操作的日历时钟存储器地址
//																		秒   分   时   日   月   周  年																		
unsigned char Write_DS1302_adrr[7]={0x80,0x82,0x84,0x86,0x88,0x8a,0x8c};
//定义DS1302写操作的日历时钟寄存器地址
//																		秒   分   时   日   月   周  年	

u8 Timer[10]={0x50,0x29,0x22,0x15,0x05,0x01,0x23};
//					  秒   分   时   日   月   周   年	

void nr_fuzhi();  //根据显示模式给nr1~nr8赋值

void Timer0Init(void)	//1毫秒@12.000MHz
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0x01;		//设置定时器模式
	TL0 = 0x18;		  //设置定时初始值
	TH0 = 0xFC;		  //设置定时初始值
	TF0 = 0;		    //清除TF0标志
	TR0 = 1;		    //定时器0开始计时
	
	EA=1;
	ET0=1;
}

void timer0_server() interrupt 1
{
	u8 i;
	TL0 = 0x18;		//设置定时初始值
	TH0 = 0xFC;		//设置定时初始值	
	i++;
	if(i==8)
		{
			i=0;
			nr_fuzhi(); 			//赋值数码管打印内容
			smg_display(nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8); //打印数码管
		}
}


void Timer1Init(void)		//1毫秒@12.000MHz
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x01;		//设置定时器模式
	TL1 = 0x18;		//设置定时初始值
	TH1 = 0xFC;		//设置定时初始值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	
	EA=1;
	ET1=1;
}

void Timer1_server() interrupt 3
{
	u8 i;
	u16 j,k;
	TL1 = 0x18;		//设置定时初始值
	TH1 = 0xFC;		//设置定时初始值	
	i++;
	if(i==200)
	{
		i=0;
		timer_flag=1;
	}
	
	if(cho!=0)  //亮灭控制
	{
		j++;k++;
		if(j==400)
		{
			j=0;
			lm=1;
		}
		if(k==800)
		{
			k=0;
			lm=0;
		}
	}
	
}


void nr_fuzhi()             //根据显示模式给nr1~nr8赋值
{
	
	nr1=Timer[2]/16;  //时 十位
	nr2=Timer[2]%16;	//时 个位
	nr3=17;
	nr4=Timer[1]/16;  //分 十位
  nr5=Timer[1]%16;  //分 个位 
	nr6=17;
	nr7=Timer[0]/16;  //秒 十位
	nr8=Timer[0]%16;	//秒 个位
	if(lm==1)
	{
			switch(cho)
			{
				case 1:nr7=nr8=16;break;  //秒灭
				case 2:nr4=nr5=16;break;  //分灭
				case 3:nr1=nr2=16;break;	//时灭
				case 0:break;
	}
 }
}
#ifndef _Timer_h_
#define _Timer_h_

#include "stc15f2k60s2.h"
#include "key_4589.h"
#include "public.h"
#include "smg.h"

extern unsigned char Read_DS1302_adrr[];
//定义DS1302读操作的日历时钟存储器地址															
extern unsigned char Write_DS1302_adrr[];
//定义DS1302写操作的日历时钟寄存器地址

extern u8 Timer[];
extern u8 timer_flag;  //时间读取标志位
extern u8 cho;         //秒,分,时 选取闪烁标志位
extern u8 read_t[];


void Timer0Init(void);	
void timer0_server();
void Timer1Init(void);
void Timer1_server();

#endif

#include "ds1302.h"

#include "ds1302.h"
void Write_Ds1302(unsigned  char temp) 
{
	unsigned char i;
	for (i=0;i<8;i++)     	
	{ 
		SCK = 0;
		SDA = temp&0x01;
		temp>>=1; 
		SCK=1;
	}
}   

//
void Write_Ds1302_Byte( unsigned char address,unsigned char dat )     
{
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1; 	_nop_();  
 	Write_Ds1302(address);	
 	Write_Ds1302(dat);		
 	RST=0; 
}

//
unsigned char Read_Ds1302_Byte ( unsigned char address )
{
 	unsigned char i,temp=0x00;
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
 	RST=1;	_nop_();
 	Write_Ds1302(address);
 	for (i=0;i<8;i++) 	
 	{		
		SCK=0;
		temp>>=1;	
 		if(SDA)
 		temp|=0x80;	
 		SCK=1;
	} 
 	RST=0;	_nop_();
 	SCK=0;	_nop_();
	SCK=1;	_nop_();
	SDA=0;	_nop_();
	SDA=1;	_nop_();
	return (temp);			
}
#ifndef _ds1302_h_
#define _ds1302_h_

#include "stc15f2k60s2.h"
#include "intrins.h"


sbit SCK=P1^7;
sbit SDA=P2^3;
sbit RST=P1^3;

unsigned char Read_DS1302_adrr[];
//定义DS1302读操作的日历时钟存储器地址															
unsigned char Write_DS1302_adrr[];
//定义DS1302写操作的日历时钟寄存器地址

unsigned char Read_Ds1302_Byte ( unsigned char address );
void Write_Ds1302_Byte( unsigned char address,unsigned char dat );
void Write_Ds1302(unsigned  char temp);


#endif

#include "smg.h"

#include "smg.h"


//数码管字库
/*
数组下标对应段码速查:
	0_0  1_1  2_2  3_3  4_4  5_5 
       6_6  7_7  8_8  9_9  10_a 
       11_b 12_c	13_d 14_e 15_f 
       16_空 17_根线 18_H 19_P 
	20_0. 21_1. 22_2. 23_3. 24_4. 25_5.
				26_6. 27_7. 28_8. 29_9. 30_u
*/
u8 code smgZK[31]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,
	                      0x82,0xf8,0x80,0x90,0x88,
                        0x83,0xc6,0xa1,0x86,0x8e,
                        0xff,0xbf,0x89,0x8c,
									 0x40,0x79,0x24,0x30,0x19,0x12,
									      0x02,0x78,0x00,0x10,0xc1
									};
void Delay250us()		//@12.000MHz   必要的打印延时
{
	unsigned char i, j;

	i = 3;
	j = 232;
	do
	{
		while (--j);
	} while (--i);
}

void smg_display(u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8)   //数码管打印函数  一次打印八个
{
	u8 i;
	i=0;
	for(i=0;i<=8;i++)
	{
			inint_74hc573(6);
			switch(i)
			{
				case 1:
				{
							P0=0X01;
							inint_74hc573(7);
							P0=smgZK[nr1];
							Delay250us();
							P0=0Xff;
				break;
				}
				case 2:
				{
							P0=0X02;
							inint_74hc573(7);
							P0=smgZK[nr2];
							Delay250us();
							P0=0Xff;
				break;
				}
				case 3:
				{
							P0=0X04;
							inint_74hc573(7);
							P0=smgZK[nr3];
							Delay250us();
							P0=0Xff;
				break;
				}
				case 4:
				{
							P0=0X08;
							inint_74hc573(7);
							P0=smgZK[nr4];
							Delay250us();
							P0=0Xff;
				break;
				}
				case 5:
				{
							P0=0X10;
							inint_74hc573(7);
							P0=smgZK[nr5];
							Delay250us();
							P0=0Xff;
				break;
				}
				case 6:
				{
							P0=0X20;
							inint_74hc573(7);
							P0=smgZK[nr6];
							Delay250us();
							P0=0Xff;
				break;	
				}					
				case 7:
				{
							P0=0X40;
							inint_74hc573(7);
							P0=smgZK[nr7];
							Delay250us();
							P0=0Xff;
				break;
				}					
				case 8:
				{
							P0=0X80;
							inint_74hc573(7);
							P0=smgZK[nr8];
							Delay250us();
							P0=0Xff;
				break;					
				}
				
			}
	}
}
#ifndef _smg_h_
#define _smg_h_

#include "stc15f2k60s2.h"
#include "public.h"


void smg_display(u8 nr1,nr2,nr3,nr4,nr5,nr6,nr7,nr8);   //数码管打印函数  一次打印八个

#endif

 #include "key_4589.h"

#include "key_4589.h"

void Delay12ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 141;
	j = 16;
	do
	{
		while (--j);
	} while (--i);
}



void key_scan_inint(u8 n)
{
	switch(n)
	{
		case 1:X1=0;X2=1;Y1=1;Y2=1;break;
		case 2:X1=1;X2=0;Y1=1;Y2=1;break;
	}
}

u8 key_return()
{
	u8 key_value;
	key_value=0;
	
	Delay12ms();     //消抖
	
	key_scan_inint(1);
	if(Y1==0)
	{
		while(Y1==0);key_value=4;
	}
	if(Y2==0)
	{
		while(Y2==0);key_value=8;
	}	
	
	key_scan_inint(2);
	if(Y1==0)
	{
		while(Y1==0);key_value=5;
	}
	if(Y2==0)
	{
		while(Y2==0);key_value=9;
	}	
	
	return key_value;
}
#ifndef _key_4589_h_
#define _key_4589_h_

#include "stc15f2k60s2.h"
#include "public.h"

sbit X1=P3^3;
sbit X2=P3^2;
sbit Y1=P4^4;
sbit Y2=P4^2;

u8 key_return();

#endif

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

NULL指向我

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

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

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

打赏作者

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

抵扣说明:

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

余额充值