DS1302驱动(STM32)

一、前期准备
单片机:STM32F103ZET6
开发环境:MDK5.14
库函数:标准库V3.5
DS1302模块:淘宝有售
DS1302驱动(STM32)_第1张图片

二、实验效果
在这里插入图片描述

DS1302驱动(STM32)_第2张图片

三、驱动原理
根据数据手册看时序,注意寄存器地址,读0x80、写0x81,支持时间修改,重新上电,时间数据一直走。
需要完整工程或者有问题的请加QQ:1002521871,验证:呵呵。

四、驱动代码
ds1302.h

#ifndef __DS_1302_H__
#define	__DS_1302_H__
#include "stm32f10x.h"
#include "delay.h"
#include "gpio.h"

/*	IO Definitions	*/
#define		SCLK			PAout(0)	//时钟
#define		SDA				PAout(1)	//数据	
#define		RST				PAout(2)	//DS1302复位(片选)

#define		SCLK_Pin		GPIO_Pin_0
#define		SDA_Pin			GPIO_Pin_1
#define		RST_Pin			GPIO_Pin_2

#define 	DS1302PORT      GPIOA
#define     DS1302CLKLINE   RCC_APB2Periph_GPIOA	

#define 	DS1302_W_ADDR 	0x80
#define 	DS1302_R_ADDR 	0x81

typedef struct 
{
	uint8_t second;
	uint8_t minute;
	uint8_t hour;
	uint8_t day;
	uint8_t month;
	uint8_t week;
	uint8_t year;
} __Date;

extern __Date ModifyDate;

extern void DS1302Configuration(void);
extern void read_time(uint8_t *timedata);
extern void ModifyCurrntTime(void);
extern uint8_t time[7];
#endif

ds1302.c

#include "ds1302.h"

uint8_t time[7] = {0x50, 0x30, 0x15, 0x05, 0x06, 0x02, 0x18};
// 				   second,minute,hour,date,month,week,year

__Date ModifyDate;

GPIO_InitTypeDef    GPIO;
//Enable APB2 Bus


void DS1302_RST(void)//令SCK=0;RST=1
{
	RST	 = 0;//停止数据传送
	SCLK = 0;//时钟总线清零
	RST	 = 1;//数据操作
}

//写一个字节
void DS1302_Write_Byte(uint8_t dat)
{
	uint8_t i;
	RCC_APB2PeriphClockCmd(DS1302CLKLINE, ENABLE);
	GPIO.GPIO_Pin   = SDA_Pin;
	GPIO.GPIO_Mode  = GPIO_Mode_Out_PP;
	GPIO_Init(DS1302PORT, &GPIO);
	
	for(i = 0; i < 8; i ++)
	{
		SDA	 = dat & 0x01;
		SCLK = 1;
		SCLK = 0;
		dat	>>= 1;
 	}
}

//读一个字节
//对于数据输出:开始的8 个SCLK 周期,输入一个读命令字节,数据字节在后8 个SCLK周期的下降沿输出
//注意,第一个数据字节的第一个下降沿发生后,命令字的最后一位被写入
//(Note that the first data bit to be transmitted occurs on the first falling edge after the last bit of the command byte is written. ),
//也就是命令字节最后一个字节写入后产生的下降沿使得第一个数据位被读取
uint8_t DS1302_Read_Byte(void)
{
	uint8_t i, dat = 0;//用dat存储读到的数据
	
	RCC_APB2PeriphClockCmd(DS1302CLKLINE, ENABLE);
	GPIO.GPIO_Pin   = SDA_Pin;
    GPIO.GPIO_Mode  = GPIO_Mode_IN_FLOATING;
    GPIO_Init(DS1302PORT, &GPIO);
	
	for(i = 0; i < 8; i ++)
	{
		dat >>= 1;	
		if(BIT_ADDR(GPIOA_IDR_Addr,1) == 1)
		  dat |= 0x80;//因为从低位开始读
		SCLK = 1;
		SCLK = 0;	//由上面解释可以知道:我们首先应该判断	if(SDA==1),然后进行SCK=1,SCK=0
	}
	return dat;
}

//清除写保护
void DS1302_CLR_WP(void)
{
  	DS1302_RST();
	RST = 1;
	DS1302_Write_Byte(0x8E);//写入地址
	DS1302_Write_Byte(0x00);//写入数据
	//写完后
	SDA = 0;
	RST = 0;
}

//设置写保护
void DS1302_SET_WP(void)
{
	DS1302_RST();
	RST = 1;
	DS1302_Write_Byte(0x8E);//写入地址
	DS1302_Write_Byte(0x80);//写入数据
	//写完后
	SDA = 0;
	RST = 0;
}

//写入ds1302
void DS1302_Write(uint8_t addr, uint8_t dat)
{
	DS1302_RST();
	RST = 1;
	DS1302_Write_Byte(addr);//写入地址
	DS1302_Write_Byte(dat);//写入数据
	//写完后
	RST = 0;
	SDA = 0;
}

//从ds1302读数据
uint8_t DS1302_Read(uint8_t addr)
{
	uint8_t temp = 0;//存储读出来的数据
	DS1302_RST();
	RST = 1;
	DS1302_Write_Byte(addr);//写入地址
	temp = DS1302_Read_Byte();//写入数据
	//写完后
	RST = 0;
	SDA = 0;
	return temp;
}

//void delay(uint16_t n)
//{ 
//  while(n--);
//}


/**
 * 设定时钟数据
 其中涉及二进制和BCD转换  因为ds1302存BCD ,但是机器只认识二进制
 例如:存入ds1302为50  0101 0000  那么我们写入的是ds1302_write(80)
*/
//void set_time(uint8_t *timedata)

void DS1302Configuration(void)
{
 	uint8_t i;
	uint8_t temp = 0;
	RCC_APB2PeriphClockCmd(DS1302CLKLINE, ENABLE);
    //Register IO 
    GPIO.GPIO_Pin   = SCLK_Pin | RST_Pin | SDA_Pin;
    GPIO.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO.GPIO_Mode  = GPIO_Mode_Out_PP;
    GPIO_Init(DS1302PORT, &GPIO);
	

	if (DS1302_Read(0xcf) != 0xaa)
	{
		DS1302_CLR_WP();
		temp = DS1302_W_ADDR;//写入起始位置
		for(i = 0; i < 7; i ++)
		{
			DS1302_Write(temp, time[i]);
			temp += 2;
		}
	//	DS1302_Write(0x90, 0xa5);
		DS1302_Write(0xce, 0xaa);
		DS1302_SET_WP();
	}
}

/**
 * 读时钟数据(BCD格式)
*/
void read_time(uint8_t *timedata)
{

   uint8_t i, temp;
   temp = DS1302_R_ADDR;//读起始位置
   for(i = 0; i < 7; i ++)
   {
     timedata[i] = DS1302_Read(temp);
	 temp += 2;
   }
}

void ModifyCurrntTime(void)
{
	DS1302_CLR_WP();
	DS1302_Write(0x80, ModifyDate.second);
	DS1302_Write(0x82, ModifyDate.minute);
	DS1302_Write(0x84, ModifyDate.hour);
	DS1302_Write(0x86, ModifyDate.day);
	DS1302_Write(0x88, ModifyDate.month);
	DS1302_Write(0x8A, ModifyDate.week);
	DS1302_Write(0x8C, ModifyDate.year);
	DS1302_Write(0xce, 0xaa);
	DS1302_SET_WP();
}

由于作者能力有限,有不妥之处欢迎指正,邮箱[email protected]

你可能感兴趣的:(嵌入式常用模块驱动,DS1302,STM32,实时时钟,驱动,时间修改)