基于Protues的DS1302仿真实验

目的

使用DS1302芯片实时时钟功能,将时间读出,并在8位7段数码管上显示。

显示的格式为XX-XX-XX(年-月-日),然后刷屏0.5秒,再显示XX-XX-XX(时-分-秒)

硬件内容

结构图

图1

        由图1所知,DS1302通过三条线和CPU连接。CE是数据传输控制线,开始数据传输时CE需置高电平,而芯片上电时候,CE需为低电平;I/O是数据传输线,数据的写入和读出都是从这条线上进行;SCLK是串行时钟线。

图2

         由图2可知,通过I/O口写入或读出数据。写入的命令会通过命令控制逻辑来进一步实现对实时时钟的控制(写/读)

图3

        图3为命令字结构,数据传输时第7位必须为1;第6为0表示对时钟/日历数据进行操作,1表示对RAM进行操作;第1-5位表示指定寄存器的,第0位写1/0分别表示进行读/写操作

图4

        图4为RTC寄存器地址的定义,想要对时钟进行数据的写入和读出,就需要知道寄存器的每一位表示什么意思,而且需要知道写入和读出的指令。下面将对个别寄存器进行举例说明。

        第一个为秒寄存器,读的指令是81h,写指令是80h。BIT7是时钟暂停位,置1时DS1302暂停,BIT4-6为秒的十位,BIT0-3为秒的个位.

        第二个为时寄存器,读的指令是83h,写指令是82h。BIT7为12/24制的选择。

        BIT5:当时钟为12制时,表示AM/PM,即上午和下午的选择;当时钟为24制时,和BIT4表示时的十位。

        BIT0-3:时的个位。

图5

        图5是数据传输的时序图。

        数据输入:输入写命令字的 8个SCLK周期后 ,接下来的 8个SCLK周期的上升沿数据字节被输入,如 不慎发生, 多余的 SCLK 周期将被忽略,数据输入以位 0开始.

        数据输出:输入读命令字的 8个SCLK周期后, 随后的 8个SCLK周期的下降沿,一个数据字节被输出。 注意第一个数据位的传送发生在命令字节被写完后的第一个下降沿.只要 CE保持高电平,若 不慎发生,多余的 SCLK周期会重新发送数据字节. 此操作允许连续不断的脉冲串模式读取能力.并且,I/O管脚在 SCLK的每个上升沿被置为三 态.数据输出从位 0开始

注意:时钟寄存器的内容为BCD码格式

软件内容

设计思路:

        要对把时间显示出来,就需要对时钟芯片完成初始化,初值写入,数据读出。根据图5可知,不论是单字节写还是单字节读,都是在16个SCLK周期中完成的,其中前8个周期是命令的写入,是选择对某个寄存的读或写;而后8个周期是要写或读的数据。

        再仔细看图5,就可以发现写是在时钟上升沿完成的;而读是在下降沿完成的。

        所以,读取时间的流程为:初始化——>数据写入(命令+数据)——>数据读出(命令)

        整体分为三个部分,即main(主函数),smg_dispaly(数码管显示函数),ds1302(时钟芯片函数)。

        main:定义数组来存放从ds1302读出的数据,在主函数中完成16进制转BCD码的任务,再将存有BCD时间数据的数组传入数码管显示函数中即可。

        smg_dispaly: 实现数据的动态显示。

        ds1302:完成初始化任务,定义写函数和读函数,将读出的数据返回到主函数

     因为读取出的数据也是 BCD 码,而 BCD 码即是 4 位表示一个十进制数,类似于一个 字节的十六进制数据的高 4 位和低 4 位一样,所以想要转成十进制的数据只需要分别对数据进行除16(得到十位)和对16取余(得到个位)即可

        

以上为流程图

代码

#include "public.h"
#include "ds1302.h"
#include "smg.h"


/*******************************************************************************
* 函 数 名       : main
* 函数功能		 : 主函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void main()
{	
	u8 time[6],big_time[8],sml_time[8];		//定义存放数据的数组
	u8 i;
	ds1302_init();			//初值写入
	
	while(1)
	{	
		for(i=0;i<6;i++)
		{
			time[i]=ds1302_read(DS_RE_ORD[i]);		//将时间数据读出
		}
		
			big_time[0]=time[0]/16;//年的十位
			big_time[1]=time[0]%16;//年的个位
			big_time[2]=10;//“-”
			big_time[3]=time[1]/16;//月的十位
			big_time[4]=time[1]%16;//月的个位
			big_time[5]=10;
			big_time[6]=time[2]/16;//日的十位
			big_time[7]=time[2]%16;//日的个位
		
			smg_display(big_time);//显示年月日
		
			SEG=0xff;//清屏
			delay_10us(50000);//延时5毫秒
			
		
			big_time[0]=time[3]/16;//时的十位
			big_time[1]=time[3]%16;//时的个位
			big_time[2]=10;
			big_time[3]=time[4]/16;//分的十位
			big_time[4]=time[4]%16;//分的个位
			big_time[5]=10;
			big_time[6]=time[5]/16;//秒的十位
			big_time[7]=time[5]%16;//秒的个位
			
			smg_display(big_time);
			
			SEG=0xff;
			delay_10us(50000);	
				
	}
}

#ifndef _ds1302_H
#define _ds1302_H

#include "public.h"

//管脚定义
sbit CE=P1^0;
sbit I_O=P1^2;
sbit SCLK=P1^1;

//函数声明

extern u8 DS_RE_ORD[6];
void ds1302_init();
u8 ds1302_read(u8 ord);

#endif




#include "ds1302.h"
#include "intrins.h"


u8 DS_WE_ORD[6]={0x8c,0x88,0x86,0x84,0x82,0x80};		//年、月、日、时、分、秒的写入指令
u8 DS_WE_TIME[6]={0x22,0x09,0x06,0x09,0x51,0x00};		//初始时间数据22年09月06日09时51分00秒

u8 DS_RE_ORD[6]={0x8d,0x89,0x87,0x85,0x83,0x81};		//年、月、日、时、分、秒的读出指令
/*******************************************************************************
* 函 数 名       : ds1302_start()
* 函数功能		 : 开始传输函数
* 输    入       : 无
* 输    出    	 : 无
*******************************************************************************/
void ds1302_start()
{
	CE=0;		//数据传输开始,CE置0
	_nop_();
	SCLK=0;		//CE置1,时钟引脚置0
	_nop_();
	
	
	CE=1;
	_nop_();
	
}
/*******************************************************************************
* 函 数 名       : ds1302_write()
* 函数功能		 : 初值设置函数,包括对年、月、日、时、分、秒的设置,即写入数据
* 输    入       : ord,dat
* 输    出    	 : 无
*******************************************************************************/
void ds1302_write(u8 ord,u8 dat)
{
	u8 i=0;
	ds1302_start();					//开始传输数据
	
	for(i=0;i<8;i++)
	{
		I_O=ord&0x01;		//取出命令字的第一位
		ord>>=1;	//左移一位
		
		SCLK=1;								
		SCLK=0;		
	}
	
	
		for(i=0;i<8;i++)
	{
		I_O=dat&0x01;		//写入数据字的第一位
		dat>>=1;
		
		SCLK=1;	
		SCLK=0;		
	}
	
}

/*******************************************************************************
* 函 数 名       : ds1302_read()
* 函数功能		 : 读取一位数据
* 输    入       : ord
* 输    出    	 : dat
*******************************************************************************/
u8 ds1302_read(u8 ord)
{
	u8 i;
	u8 dat_bit=0;
	
	u8 dat_byte=0;

	
	ds1302_start();
	
	for(i=0;i<8;i++)	//一次写一位,将命令写入
	{
		I_O=ord&0x01;		//取出命令字的第一位
		ord>>=1;
		
		SCLK=0;				
		SCLK=1;
		
		
	}
			
	for(i=0;i<8;i++)
	{
		
		SCLK=1;			
		SCLK=0;
		
		if(I_O==1)				//如果是1,则左移i位;0则不管
		dat_byte|=(0x01<<i);
		
	}
	
	

	
		return dat_byte;
}

/*******************************************************************************
* 函 数 名       : ds1302_init()
* 函数功能		 : 初值写入
* 输    入       : ord
* 输    出    	 : dat
*******************************************************************************/
void ds1302_init()
{
	u8 i=0;
	
	ds1302_write(0x8e,0x00);			//给写保护寄存器写入0,允许写入
	
	for(i=0;i<6;i++)
	{
		ds1302_write(DS_WE_ORD[i],DS_WE_TIME[i]);			//将初值写入
	}

}

#ifndef _smg_H
#define _smg_H

#include "public.h"


#define SEG	P2	//使用宏定义数码管段码口

#define DIS P3
//定义数码管位选信号控制脚


extern u8 gsmg_code[17];

void smg_display(u8 dat[]);

#endif




#include "smg.h"

//共阳极数码管显示0~F的段码数据
u8 gsmg_code[17]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,
				0x80,0x90,0xbf,0x83,0xc6,0xa1,0x86,0xbf};

//控制段位显示数据
u8 dis[8]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};

/*******************************************************************************
* 函 数 名       : smg_display
* 函数功能		 : 动态数码管显示
* 输    入       : dat:要显示的数据
* 输    出    	 : 无
*******************************************************************************/
void smg_display(u8 dat[])
{
		u8 i;
	
		
		for(i=0;i<8;i++)
	{
		SEG=gsmg_code[dat[i]];
		DIS=dis[i];
		delay_10us(7000);
	}
	
	
}

#include "public.h"

/*******************************************************************************
* 函 数 名       : delay_10us
* 函数功能		 : 延时函数,ten_us=1时,大约延时10us
* 输    入       : ten_us
* 输    出    	 : 无
*******************************************************************************/
void delay_10us(u16 ten_us)
{
	while(ten_us--);	
}

/*******************************************************************************
* 函 数 名       : delay_ms
* 函数功能		 : ms延时函数,ms=1时,大约延时1ms
* 输    入       : ms:ms延时时间
* 输    出    	 : 无
*******************************************************************************/
void delay_ms(u16 ms)
{
	u16 i,j;
	for(i=ms;i>0;i--)
		for(j=110;j>0;j--);

原理图

 

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值