基于stm32的智能时钟的实践(1) --- DS1302

1 前言

        DS1302 是美国DALLAS公司推出的一种高性能、低功耗、带RAM的实时时钟电路,它可以对年、月、日、周、时、分、秒进行计时,具有闰年补偿功能,工作电压为2.0V~5.5V。采用三线接口与CPU进行同步通信,并可采用突发方式一次传送多个字节的时钟信号或RAM数据。DS1302内部有一个31×8的用于临时性存放数据的RAM寄存器。DS1302是DS1202的升级产品,与DS1202兼容,但增加了主电源/后备电源双电源引脚,同时提供了对后备电源进行涓细电流充电的能力。

        市场上常用的如下图所示

        封装图如下所示

2 时钟芯片的写入与读取

如下图所示就是该时钟芯片的基本的工作模式

CE为使能端,IO为数据的发送和接受端,CLK为时序端,就是由这三个简单的引脚控制.

2.1设置GPIO

我们所操作的就是这三个端口,在stm32上面就是三个你所设置好的GPIO

如下就是设置GPIO的相关代码

/**
 * @brief GPIO初始化
 * @param 
 * @retval
 */
void DS1302_GPIO_Config()
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	RCC_DS1302_CMD(RCC_DS1302,ENABLE);
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = DS1302_SCLK;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_Port_SCLK,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = DS1302_CE;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_Port_CE,&GPIO_InitStructure);
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = DS1302_IO;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_Port_IO,&GPIO_InitStructure);
	
	GPIO_WriteBit(GPIO_Port_SCLK,DS1302_SCLK,Bit_RESET);
	GPIO_WriteBit(GPIO_Port_CE,DS1302_CE,Bit_RESET);
	GPIO_WriteBit(GPIO_Port_IO,DS1302_IO,Bit_RESET);
}

void DS1302_DATAOUT_Config()//配置双向I/O端口为输出态
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_DS1302_CMD(RCC_DS1302_IO, ENABLE);
 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
	GPIO_InitStructure.GPIO_Pin = DS1302_IO;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_Port_IO,&GPIO_InitStructure);
	
	GPIO_WriteBit(GPIO_Port_IO,DS1302_IO,Bit_RESET);
}

void DS1302_DATAINPUT_Config()//配置双向I/O端口为输入态
{
	GPIO_InitTypeDef GPIO_InitStructure;
	RCC_DS1302_CMD(RCC_DS1302_IO, ENABLE);
 
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_InitStructure.GPIO_Pin = DS1302_IO;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_Port_IO,&GPIO_InitStructure);
}

这里的代码没有难度,因为需要输出和输入两种模式,所以需要IO端口有两种模式,这在后面的主机与DS1302的通信中将会运用.

那么,DS1302如何实现和主机的通信呢?

2.2通信的实现

如下就是通信的规则

这十分的简单,就是在拉高CE后读写.

CLK上升沿写入数据

CLK下降沿读取数据

读取数据和写入数据都是先要写入DS1302寄存器的地址,有了地址,才能写入和读取.

如下代码就是读取和写入的相关代码

void DS1302_WriteOnebyte(uint8_t data)
{
	DS1302_DATAOUT_Config();
	uint8_t count = 0;
	SCLK_L;
	for(count = 0;count < 8;count++)
	{
		SCLK_L;
		if(data&0x01)
		{
			DATA_H;
		}
		else
		{
			DATA_L;
		}
		SCLK_H;
		data >>= 1;
	}
}

/**
 * @brief  向DS1302指定寄存器发送数据
 * @param  addres-指向的寄存器地址,data-需要发送的数据
 * @retval 无
 */
void DS1302_WriteByte(uint8_t address,uint8_t data)//向指定寄存器地址发送数据
{
	u8 temp1=address;
	u8 temp2=data;
	CE_L;
	SCLK_L;
	Delay_us(1);
	CE_H;
	Delay_us(2);
	DS1302_WriteOnebyte(temp1);
	DS1302_WriteOnebyte(temp2);
	CE_L;
	SCLK_L;
	Delay_us(2);
}
 
/**
 * @brief  在DS1302读取数据
 * @param  读取数据的寄存器的地址
 * @retval 无
 */
uint8_t DS1302_ReadByte(uint8_t address)//从指定地址读取一字节数据
{
	u8 temp3=address;
	u8 count=0;
	u8 return_data=0x00;
	CE_L;SCLK_L;Delay_us(3);
	CE_H;Delay_us(3);
	DS1302_WriteOnebyte(temp3);
	DS1302_DATAINPUT_Config();//配置I/O口为输入
	Delay_us(2);
	for(count=0;count<8;count++)
	{
		Delay_us(2);//使电平持续一段时间
		return_data>>=1;
		SCLK_H;Delay_us(4);//使高电平持续一段时间
		SCLK_L;Delay_us(14);//延时14us后再去读取电压,更加准确
		if(GPIO_ReadInputDataBit(GPIOC,GPIO_Pin_10))
		{
			return_data=return_data|0x80;
		}
	}
	Delay_us(2);
	CE_L;DATA_L;
	return return_data;
}

那么又有一个问题,写入的地址是什么呢,当然啊,生产厂家早就给我们设置好了固定的地址,用于存储各种时钟数据,只等待我们用户写入数据了

如下图所示就是DS1302的地址

 到此为止,其实对于DS1302的基本操作已经实现了,就是读取和写入.

3 基本应用

#include "Device/Include/stm32f10x.h"   // Device header
#include "clock.h"
#include "OLED.h"
#include "DS1302.h"
#include "Delay.h"
unsigned char Week[24] = {' ',' ',' ','M','o','n','T','u','e','W','e','d','T','h','u','F','r','i','S','a','t','S','u','n'};
unsigned char TimE[7] = {0x50,0x59,0x23,0x29,0x11,0x23,0x05};  //秒、分、时、日、月、年、周几
unsigned char Buff[7] = {0};                //缓冲区
unsigned char Buff2[7] = {0};
unsigned char CommanD[7] = {0x80,0x82,0x84,0x86,0x88,0x8C,0x8A};
unsigned char Temp;
unsigned char Change = 0;
unsigned char Change2 = 0;
unsigned char i;
unsigned char j = 1;
unsigned char flag;                 //闪烁标志位

/**
 * @brief  初始化时钟UI
 * @param
 * @retval
 */
void clock_Init()
{
	OLED_ShowString(1,3,"clock by zp");
	OLED_ShowString(2,1,"date:");
	OLED_ShowString(2,10,"-");
	OLED_ShowString(2,13,"-");
	OLED_ShowString(3,1,"time:");
	OLED_ShowString(3,8,":");
	OLED_ShowString(3,11,":");
}

/**
 * @brief  将数据写入单片机
 * @param
 * @retval
 */
void clock_in()
{
	DS1302_WriteByte(0x8E,0x00);                    //打开写入权限
	DS1302_WriteByte(CommanD[0],TimE[0]);
	DS1302_WriteByte(CommanD[1],TimE[1]);
	DS1302_WriteByte(CommanD[2],TimE[2]);
	DS1302_WriteByte(CommanD[3],TimE[3]);
	DS1302_WriteByte(CommanD[4],TimE[4]);
	DS1302_WriteByte(CommanD[5],TimE[5]);
	DS1302_WriteByte(CommanD[6],TimE[6]);
	DS1302_WriteByte(0x8E,0x80);                    //关闭写入权限
}

/**
 * @brief将数据从单片机读出来
 * @param
 * @retval
 */
void clock_out()
{
	Temp = DS1302_ReadByte(CommanD[0]+1);
	Buff[0] = Temp/16*10+Temp%16;
	Temp = DS1302_ReadByte(CommanD[1]+1);
	Buff[1] = Temp/16*10+Temp%16;
	Temp = DS1302_ReadByte(CommanD[2]+1);
	Buff[2] = Temp/16*10+Temp%16;
	Temp = DS1302_ReadByte(CommanD[3]+1);
	Buff[3] = Temp/16*10+Temp%16;
	Temp = DS1302_ReadByte(CommanD[4]+1);
	Buff[4] = Temp/16*10+Temp%16;
	Temp = DS1302_ReadByte(CommanD[5]+1);
	Buff[5] = Temp/16*10+Temp%16;
	Buff[6] = DS1302_ReadByte(CommanD[6]+1);
}

	
/**
 * @brief  将读取到的数据显示到屏幕上
 * @param
 * @retval
 */
void clock_Show()
{
	OLED_ShowNum(2,6,20,2);
	OLED_ShowNum(3,12,Buff[0],2); 
	OLED_ShowNum(3,9,Buff[1],2);
	OLED_ShowNum(3,6,Buff[2],2);
	OLED_ShowNum(2,14,Buff[3],2);
	OLED_ShowNum(2,11,Buff[4],2);
	OLED_ShowNum(2,8,Buff[5],2);
	i = Buff[6]*3;                                //使用for循环乱套
	OLED_ShowChar(3,14,Week[i]);
	OLED_ShowChar(3,15,Week[i+1]);
	OLED_ShowChar(3,16,Week[i+2]);
}

这段代码其实就是将DS1302的数据进行一些简单的处理,在显示器上显示相关信息.

 其中关键的就是对几种简单数据的简单的处理

比如,我们存进去的秒是30秒

存进去的时候,按照规则,会以BCD码的形式存入,所以出来的时候还要进行BCD码转换的操作就是代码中的 clock_out() 函数

包括对于周的处理,使用的方法虽然简单,但是也是完全自己写的,没有丝毫借鉴.

最后关于此显示器的相关介绍代码,我将会在该实践项目之后的章节给出,我正在学习中.

4 下节预告

在下节,我会进一步完善我的时钟,将会加入修改,闹钟功能.敬请期待.

  • 3
    点赞
  • 64
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值