51单片机完全学习——RTC(DS1302)

一、DS1302介绍

1、SPI数字接口访问:3线或4线,同步,主从,串行。

2、内部存着一个时间点信息,可以读写,上电自动走表。

二、原理图分析和接线

通过观察原理图我们知道,这个开发板将DS1302的3根通信线,作为J3引了出来,我们只需要使用3根杜邦线,将这3根线和单片机的引脚连接即可。至于使用那个引脚自己选择即可。

三、数据手册分析

我们通过看数据手册得出下面几点:该芯片可以实时计算年、月、日、时、分、秒、星期,并有闰年调节功能,工作在宽电压,读写可以单字节也可以多字节。

四、时序图分析

(1)横轴代表时间,纵轴是同一时间点各个通信线上的状态,从左往右3条线一起看,不能分开来分析,首先变化的是CE从低电平变成了高电平,此时SCLK和I/O线上的点平变化才有意义,不然芯片都工作不了。其次在SCLK从低电平变到高电平之前,I/O线上的数据必须准备好,并且持续一段时间,等SCLK从低电平到高电平变化完之后,才可以改变,这样数据才能正确传输。
(2)从静态与动态2个角度去看
(3)大小端:一个字节发出去,高位在前还是低位在前。
(4)上升沿读取,下降沿写入、注意SCLK工作频率

五、编写读和写函数

有了下面这两个函数,我们就可以对DS1302进行读和写的操作了。需要注意的是DS1302有写保护功能,我们再给他写入数据之前,一定要先关闭他的写保护功能。

uchar ds1302_read(uchar command)
{
	uchar i = 0, date = 0, date1 = 0;
	CE = 0;      //先将信号线都进行复位
	_nop_();     //每次操作完成信号线之后,加一段延时等待信号稳定
	SCLK = 0;
	_nop_();
	CE = 1;      //将CE线拉高,使能芯片
	_nop_(); 
	 
	
	for (i=0; i<8; i++)
	{
		IO =  command & 0x01;	//取出最低位
		_nop_(); 
		SCLK = 1;               //产生上升沿,将数据发出去
		_nop_(); 	
		command >>= 1;          //将已经发出的最低位移出去,准备发下一位
		SCLK = 0;               //为下一次产生上升沿做准备
		_nop_();		
		
	}
	for (i=0; i<8; i++)
	{
		date1 = IO;	            //将IO线上的电平读出来,保存一下,因为IO这个变量不能直接进行移位           
		date = (date >> 1) | (date1 << 7);  //将先接收到的数据放到最高位,然后在进行右移
		_nop_();                            //这样最后先接收到的就在最低位,后接收到的就在最高位
		SCLK = 1;               //方便下一次产生下降沿
		_nop_(); 
		SCLK = 0;               //产生下降沿,这样数据就准备好了,我们就可以进行读取了
		_nop_();	
	}
    CE = 0;                     //将芯片使能关闭
	_nop_(); 
	return date;
}

void ds1302_write(uchar command, uchar date)
{
	uchar i = 0, dat = 0;
	CE = 0;
	_nop_();	
	SCLK = 0;
	_nop_(); 
	CE = 1;
	_nop_(); 

	for (i=0; i<8; i++)
	{
		dat = command & 0x01;
		IO = dat;
		command >>= 1;		
		_nop_(); 
		SCLK = 1;
		_nop_(); 		
		SCLK = 0;
		_nop_(); 
	}
	for (i=0; i<8; i++)
	{
		dat = date & 0x01;
		IO = dat;
		date >>= 1;	
		_nop_(); 
		SCLK = 1;
		_nop_();   
		SCLK = 0;
		_nop_(); 
	}
	CE = 0;
	_nop_(); 	
}

六、时间的写入和读取

我们需要注意的是:在这里我们的时间写入包括读取通过串口打印,都是使用的是十六进制的格式进行的,因为DS1302给我们提供的时间格式是BCD编码的,它本质上是十六进制,但是看起来像十进制的一种编码方式。因此我们在使用串口接收的时候一定要调整到HEX接收模式,不然的话收到的就是一些乱码。

void main(void)
{
	uchar dat = 0, i = 0;
	uchar code write[7] = {0x80, 0x82, 0x84, 0x86, 0x88, 0x8a, 0x8c};
	uchar code read[7]  = {0x81, 0x83, 0x85, 0x87, 0x89, 0x8b, 0x8d};
	uchar code settime[7] = {0x50, 0x59, 0x23, 0x16, 0x10, 0x03, 0x24};
	uart_init();
	ds1302_write(0x8E, 0x00);   //关闭写保护功能
	for (i=0; i<7; i++)         //设置时间
	{
		ds1302_write(write[i], settime[i]);  
	}
	ds1302_write(0x8E, 0x80);   //打开写保护功能  
	while(1)
	{
		for (i=0; i<7; i++)    //读取时间,注意串口接收一定要设置为HEX接收
		{
			dat = ds1302_read(read[i]);
			uart_send_byte(dat);
		} 
		delay1s();
		
  }
}

七、添加16进制到10进制的转换

针对上面的问题,为了使程序的输入和输出用起来更符合常理,同时在时间设置时可以使用10进制,输出时间可以使用字符输出打印,因此就加了这一功能。

//初始化函数,可以直接设置时间
void ds1302_init(uchar *dat)
{
	uchar i = 0;
	ds1302_write(0x8E, 0x00);   //关闭写保护功能
	for (i=0; i<7; i++)
	{
		dat[i] = shi_to_bcd(dat[i]);
	}
	for (i=0; i<7; i++)
	{
		ds1302_write(write[i], dat[i]); 
	}
	ds1302_write(0x8E, 0x80);   //打开写保护功能
}
//读取时间函数,将读取到的时间打印在串口上
void read_time(void)
{
	uchar i = 0, dat = 0;
	for (i=0; i<7; i++)
	{
		dat = ds1302_read(read[i]);
		dat = bcd_to_shi(dat);
		uart_send_num(dat);
		uart_send_byte('-');
	} 
	delay1s();
}
//BCD编码转换10进制
uchar bcd_to_shi(uchar dat)
{
	uchar date = 0;
	date = (dat & 0x0f) + (dat >> 4) * 10;
	return date;
}
//10进制转换BCD编码
uchar shi_to_bcd(uchar dat)
{
	uchar date;
	date = ((dat / 10)<< 4) + (dat % 10);
	return date;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值