STM32F407IG单片机读写SD2405ALPI实时时钟程序(包括:读时钟时间、写时间到时钟、时间报警中断、倒计时中断)

具体的IIC时序图和分析过程请参见下面网友的文章

            https://blog.csdn.net/ybhuangfugui/article/details/52151835

本人在STM32F407单片机上亲测读时钟、写时钟、时间中断以及倒计时(秒、分钟)功能全部OK  , 作者:霸王猫(BA_WANG_MAO)  2020.10

 

SD2405ALPI.C


#define RCC_SD2405ALPI_PORT 		RCC_AHB1Periph_GPIOE
#define GPIO_SD2405ALPI_PORT		GPIOE
#define GPIO_SD2405ALPI_SCL_Pin		GPIO_Pin_6
#define GPIO_SD2405ALPI_SDA_Pin		GPIO_Pin_5



#define SD2405ALPI_SCL_1()  	  GPIO_SetBits(			GPIO_SD2405ALPI_PORT, GPIO_SD2405ALPI_SCL_Pin)			// SCL = 1
#define SD2405ALPI_SCL_0()  	  GPIO_ResetBits(		GPIO_SD2405ALPI_PORT, GPIO_SD2405ALPI_SCL_Pin)			// SCL = 0
#define SD2405ALPI_SDA_1()  	  GPIO_SetBits(			GPIO_SD2405ALPI_PORT, GPIO_SD2405ALPI_SDA_Pin)			// SDA = 1
#define SD2405ALPI_SDA_0()  	  GPIO_ResetBits(		GPIO_SD2405ALPI_PORT, GPIO_SD2405ALPI_SDA_Pin)			// SDA = 0
#define SD2405ALPI_SDA_READ()     GPIO_ReadInputDataBit(GPIO_SD2405ALPI_PORT, GPIO_SD2405ALPI_SDA_Pin)			// 读SDA口线状态
#define SD2405ALPI_SCL_READ()     GPIO_ReadInputDataBit(GPIO_SD2405ALPI_PORT, GPIO_SD2405ALPI_SCL_Pin)			// 读SCL口线状态






void SD2405ALPI_bsp_Init(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	
	RCC_AHB1PeriphClockCmd(RCC_SD2405ALPI_PORT, ENABLE);//打开GPIO时钟
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;;  	//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;		//开漏输出,必须配置为开漏输出(GPIO_OType = GPIO_OType_OD)。如果配置为推挽,读取时钟时肯定会失败。
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_InitStructure.GPIO_Pin = GPIO_SD2405ALPI_SCL_Pin | GPIO_SD2405ALPI_SDA_Pin;	
	GPIO_Init(GPIO_SD2405ALPI_PORT , &GPIO_InitStructure);
	// 给一个停止信号, 复位I2C总线上的所有设备到待机模式
	SD2405ALPI_I2CStop();
}



void SD2405ALPI_SDA_INPUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;

	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;  		//输入模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;		//开漏输出,必须配置为开漏输出(GPIO_OType = GPIO_OType_OD)。如果配置为推挽,读取时钟时肯定会失败。
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Pin =  GPIO_SD2405ALPI_SDA_Pin;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
	GPIO_Init(GPIO_SD2405ALPI_PORT , &GPIO_InitStructure);
}



void SD2405ALPI_SDA_OUTPUT(void)
{
	GPIO_InitTypeDef GPIO_InitStructure;
	
	
	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;;  	//输出模式
	GPIO_InitStructure.GPIO_OType = GPIO_OType_OD;		//开漏输出,必须配置为开漏输出(GPIO_OType = GPIO_OType_OD)。如果配置为推挽,读取时钟时肯定会失败。
	GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//GPIO_PuPd_NOPULL;
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;	
	GPIO_InitStructure.GPIO_Pin =  GPIO_SD2405ALPI_SDA_Pin;
	GPIO_Init(GPIO_SD2405ALPI_PORT , &GPIO_InitStructure);
}



void SD2405ALPI_delay_us(uint8_t time)
{
	uint8_t i;

	
	for (i = 0 ; i < time ; i++)
	{
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();
		__NOP();		
	}
}



// 
//开启SD2405的I2C总线
//--------------------------------------------------------------
//启动I2C总线,当时钟SCL为高电平时,数据线SDA产生一个下降沿
// 
BOOL SD2405ALPI_I2CStart(void)
{
	SD2405ALPI_SDA_OUTPUT();	
	SD2405ALPI_SDA_1();			//发送起始条件的数据信号(释放SDA总线)
	SD2405ALPI_delay_us(20);
	
	SD2405ALPI_SCL_1();				
	SD2405ALPI_delay_us(50);	//起始条件建立时间大于4.7us,延时		
	SD2405ALPI_SDA_INPUT();	
	if (!SD2405ALPI_SDA_READ()) //如果SDA线为低电平则总线忙,退出
		return (FALSE);
	
	SD2405ALPI_SDA_OUTPUT();	
	SD2405ALPI_SDA_0();			//发送起始信号
	SD2405ALPI_delay_us(50);
	
	//SD2405ALPI_SDA_INPUT();	//警告:此处如果增加SD2405ALPI_SDA_INPUT()语句,总线就出错然后返回FALSE
	while (SD2405ALPI_SDA_READ()) //如果SDA线为高电平则总线出错,退出
		return FALSE;			
	SD2405ALPI_SCL_0();			//时序图上SDA从高到低后,SCL必须回到低电平,才允许SDA上的数据改变
								//钳住I2C总线准备发送或接收数据(解释:I2C 总线在空闲状态下都是被上
								//拉为高电平的,所以当它们处于低电平时就表示忙的状态.)
	SD2405ALPI_delay_us(10);
	return (TRUE);
}



// 
//关闭SD2405的I2C总线
//终止I2C总线,当时钟SCL为高电平时,数据线SDA产生一个上升沿表示I2C总线停止信号
// 
void SD2405ALPI_I2CStop(void)
{
	SD2405ALPI_SDA_OUTPUT();
	SD2405ALPI_SDA_0();		//发送结束条件的数据信号
	SD2405ALPI_delay_us(10);
	
	SD2405ALPI_SCL_0();		//发送结束条件的时钟信号
	SD2405ALPI_delay_us(30);
	SD2405ALPI_SCL_1();	
	SD2405ALPI_delay_us(50);		
	SD2405ALPI_SDA_1();		//发送I2C总线结束信号
	SD2405ALPI_delay_us(10);
}



// 
//发送 ACK
//SCL在高电平期间,SDA被从设备拉为低电平表示应答
// 
void SD2405ALPI_I2CAck(void)
{	
	SD2405ALPI_SDA_OUTPUT();
	SD2405ALPI_SDA_0();			// CPU驱动SDA = 0 
	SD2405ALPI_delay_us(10);
	
	SD2405ALPI_SCL_1();	
	SD2405ALPI_delay_us(50);
	SD2405ALPI_SCL_0();
	SD2405ALPI_delay_us(10);
}



// 
//发送 NO ACK
// 
void SD2405ALPI_I2CNoAck(void)
{	
	SD2405ALPI_SDA_OUTPUT();
	SD2405ALPI_SDA_1();			// CPU驱动SDA = 1
	SD2405ALPI_delay_us(10);

	//SD2405ALPI_SCL_0();	
	//SD2405ALPI_delay_us(30);
	SD2405ALPI_SCL_1();
	SD2405ALPI_delay_us(50);
	SD2405ALPI_SCL_0();
	SD2405ALPI_delay_us(10);
}



// 
//读取 ACK信号(返回为:1 = 有ACK ,0 = 无ACK)
// 
BOOL SD2405ALPI_I2CWaitAck(void) 
{
	uint8_t errtime = 255;
	
	
	SD2405ALPI_SDA_INPUT();
	SD2405ALPI_SCL_0();
	SD2405ALPI_delay_us(30);
	
	SD2405ALPI_SCL_1();			// CPU驱动SCL = 1, 此时器件会返回ACK应答
	SD2405ALPI_delay_us(50);
	while (SD2405ALPI_SDA_READ())
	{
		errtime--;
		SD2405ALPI_delay_us(10);
		if (!errtime)
		{
			SD2405ALPI_delay_us(10);
			SD2405ALPI_SCL_0();
			SD2405ALPI_I2CStop();
			return (FALSE);
		}
	}
	SD2405ALPI_SCL_0();	
	SD2405ALPI_delay_us(10);
	return (TRUE);	
}



// 
//MCU向SD2405发送一个字节(数据从高位到低位)
// 
void SD2405ALPI_I2CSendByte(uint8_t data)
{
	uint8_t i;
	

	SD2405ALPI_SDA_OUTPUT();
	
	for (i = 0 ; i < 8 ; i++)
	{
		SD2405ALPI_SCL_0();
		SD2405ALPI_delay_us(10);
		
		if (data & 0x80)
			SD2405ALPI_SDA_1(); 
		else  
			SD2405ALPI_SDA_0();
		
		data <<= 0x01;
		SD2405ALPI_delay_us(10);			//保证时钟高电平周期大于 4us
		SD2405ALPI_SCL_1();	
		SD2405ALPI_delay_us(50);			//保证时钟高电平周期大于 4us
	}
	SD2405ALPI_SCL_0();
	SD2405ALPI_delay_us(10);
}



// 
//MCU从SD2405读入一字节(数据从高位到低位)
// 
uint8_t SD2405ALPI_I2CReceiveByte(void)
{
	uint8_t i;
	uint8_t data = 0x00;

		
	//SD2405ALPI_SDA_INPUT();
	//SD2405ALPI_SDA_1(); 			//置数据总线为输入方式,作为接收方要释放SDA.
	//SD2405ALPI_delay_us(10);
	
	for (i = 0 ; i < 8 ; i++)		//第1个读到的bit为数据的bit7
	{
		SD2405ALPI_SDA_OUTPUT();
		SD2405ALPI_SDA_1();			//使能内部上拉,准备读取数据
		SD2405ALPI_delay_us(10);		
		
		SD2405ALPI_SCL_0();			//置时钟线为低准备接收数据位
		SD2405ALPI_delay_us(30);	//时钟低电平周期大于4.7us
		SD2405ALPI_SCL_1();			//置时钟线为高使数据有效
		SD2405ALPI_delay_us(50);
		SD2405ALPI_SDA_INPUT();
		data <<= 0x01;            	//数据从高位开始读取
		if (SD2405ALPI_SDA_READ())
			data |= 0x01;
		SD2405ALPI_delay_us(10);
	}
	SD2405ALPI_SCL_0();
	SD2405ALPI_delay_us(10);
	return (data);
}



// 
//I2C写一个字节
// 
BOOL SD2405ALPI_I2CWriteOneByte(uint8_t DeviceAddress , uint8_t register_address , uint8_t data)
{		
	if (!SD2405ALPI_I2CStart()) 
		return (FALSE);
	SD2405ALPI_I2CSendByte(DeviceAddress);  	//器件地址
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(register_address);	//设置写寄存器地址
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(data);				//写数据
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CStop(); 
	return	(TRUE);
}



// 
//I2C读一个字节程序
// 
uint8_t SD2405ALPI_I2CReadOneByte(uint8_t DeviceAddress , uint8_t register_address)
{		
	uint8_t data;
	
	
	if (!SD2405ALPI_I2CStart())
		return (FALSE);
	SD2405ALPI_I2CSendByte(DeviceAddress);
	if (!SD2405ALPI_I2CWaitAck())
	{
		SD2405ALPI_I2CStop(); 
		return (FALSE);
	}
  	SD2405ALPI_I2CSendByte(register_address);	//设置要读的地址
	SD2405ALPI_I2CWaitAck();
	
	SD2405ALPI_I2CStart();	
 	SD2405ALPI_I2CSendByte(DeviceAddress+1);	
	SD2405ALPI_I2CWaitAck();	
	data = SD2405ALPI_I2CReceiveByte();			//读数据
	SD2405ALPI_I2CNoAck();
	SD2405ALPI_I2CStop(); 
	return (data);
}



// 
//SD2405写允许程序
// 
BOOL SD2405ALPI_WriteTimeOn(void)
{		
//	SD2405ALPI_I2CStart();
//	SD2405ALPI_I2CSendByte(0x64);      
//	SD2405ALPI_I2CWaitAck();   
//	SD2405ALPI_I2CSendByte(0x10);		//设置写地址10H
//	SD2405ALPI_I2CWaitAck();	
//	SD2405ALPI_I2CSendByte(0x80);		//置WRTC1=1
//	SD2405ALPI_I2CWaitAck();
//	SD2405ALPI_I2CStop(); 
	if (!SD2405ALPI_I2CWriteOneByte(0x64 , 0x10 , 0x80))	//设置写地址10H,置WRTC1=1
		return (FALSE);	
	
	//SD2405ALPI_I2CStart();
	//SD2405ALPI_I2CSendByte(0x64);      
	//SD2405ALPI_I2CWaitAck();   
	//SD2405ALPI_I2CSendByte(0x0F);		//设置写地址0FH
	//SD2405ALPI_I2CWaitAck();	
	//SD2405ALPI_I2CSendByte(0x84);		//置WRTC2=1,置WRTC3=1
	//SD2405ALPI_I2CWaitAck();
	//SD2405ALPI_I2CStop(); 
	if (!SD2405ALPI_I2CWriteOneByte(0x64 , 0x0F , 0x84))	//设置写地址0FH,置WRTC2=1,置WRTC3=1
		return (FALSE);
	return (TRUE);
}



// 
//SD2405写禁止程序
// 
BOOL SD2405ALPI_WriteTimeOff(void)
{		
	//SD2405ALPI_I2CStart();
	//SD2405ALPI_I2CSendByte(0x64);      
	//SD2405ALPI_I2CWaitAck();   
	//SD2405ALPI_I2CSendByte(0x0F);		//设置写地址0FH
	//SD2405ALPI_I2CWaitAck();	
	//SD2405ALPI_I2CSendByte(0x0) ;		//置WRTC2,WRTC3=0
	//SD2405ALPI_I2CWaitAck();
	if (!SD2405ALPI_I2CWriteOneByte(0x64 , 0x0F , 0x00))	//设置写地址0FH,置WRTC2=0,置WRTC3=0
		return (FALSE);
	
	
	//SD2405ALPI_I2CSendByte(0x0) ;		//置WRTC1=0(10H地址)
	//SD2405ALPI_I2CWaitAck();
	//SD2405ALPI_I2CStop();
	if (!SD2405ALPI_I2CWriteOneByte(0x64 , 0x10 , 0x00))	//设置写地址10H,置WRTC1=0
		return (FALSE);
	return (TRUE);
}



///
//BCD转换成16进制数(例如:0x16转换成16)---读时钟使用(例如:读的秒=26代表:0x26,为BCD码,需要转换成十进制:38)
// 
uint8_t BCDtoHEX(uint8_t BCD)
{	
	uint8_t tempData;
	
	tempData = (BCD >> 4) * 10 + (BCD & 0x0F);
	return (tempData);
}



///
//16进制数转换成BCD码(例如:16转换成0x16)---写时钟使用(写的秒=26,为十进制,需要转换成BCD码=0x26))
// 
uint8_t HEXtoBCD(uint8_t HEX)
{
	uint8_t tempData;
	
	tempData = ((HEX / 10) << 0x04) + (HEX % 10);
	return (tempData);
}



/// 
//读SD2405实时数据寄存器
// 
BOOL SD2405ALPI_I2CReadTime(uint8_t *second , uint8_t *minute , uint8_t *hour , uint8_t *week , uint8_t *day , uint8_t *month , uint8_t *year)
{
	
	if (!SD2405ALPI_I2CStart())
		return (FALSE);
	SD2405ALPI_I2CSendByte(0x65); 
	if (!SD2405ALPI_I2CWaitAck())
	{
		SD2405ALPI_I2CStop();		
		return (FALSE);
	}
	*second = BCDtoHEX(SD2405ALPI_I2CReceiveByte());
	SD2405ALPI_I2CAck();
	*minute = BCDtoHEX(SD2405ALPI_I2CReceiveByte());
	SD2405ALPI_I2CAck();
	*hour =   BCDtoHEX(SD2405ALPI_I2CReceiveByte() & 0x3F);														//hour,最高位=0:代表十二小时制;最高位=1:代表二十四小时制
	SD2405ALPI_I2CAck();
	*week =   BCDtoHEX(SD2405ALPI_I2CReceiveByte());
	SD2405ALPI_I2CAck();
	*day =    BCDtoHEX(SD2405ALPI_I2CReceiveByte());
	SD2405ALPI_I2CAck();
	*month =  BCDtoHEX(SD2405ALPI_I2CReceiveByte());
	SD2405ALPI_I2CAck();
	*year =   BCDtoHEX(SD2405ALPI_I2CReceiveByte());	
	SD2405ALPI_I2CNoAck();	//注:最后一个数据不应答
	SD2405ALPI_I2CStop();
	return (TRUE);
}



///
//写SD2405实时数据寄存器
//Android 星期对应的数字
//   1---星期天
//   2---星期一
//   3---星期二
//   4---星期三
//   5---星期四
//   6---星期五
//   7---星期六
//SD2405ALPI 星期对应的数字(7进制)
//   0---星期天
//   1---星期一
//   2---星期二
//   3---星期三
//   4---星期四
//   5---星期五
//   6---星期六
// 
BOOL SD2405ALPI_I2CWriteTime(uint8_t second , uint8_t minute , uint8_t hour , uint8_t week , uint8_t day , uint8_t month , uint8_t year)
{	
	SD2405ALPI_WriteTimeOn();
	if (!SD2405ALPI_I2CStart())
		return (FALSE);
	SD2405ALPI_I2CSendByte(0x64);      
	if (!SD2405ALPI_I2CWaitAck())
	{
		SD2405ALPI_I2CStop();
		return (FALSE);
	}
	SD2405ALPI_I2CSendByte(0x00);		//设置写起始地址(00H=秒寄存器)
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(HEXtoBCD(second));
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(HEXtoBCD(minute));
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(HEXtoBCD(hour)|0x80);																	//hour ,最高位=0:代表十二小时制;最高位=1:代表二十四小时制
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(HEXtoBCD(week));
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(HEXtoBCD(day));
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(HEXtoBCD(month));
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(HEXtoBCD(year));
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CStop();

	if (!SD2405ALPI_I2CStart())
		return (FALSE);
	SD2405ALPI_I2CSendByte(0x64);      
	if (!SD2405ALPI_I2CWaitAck())
	{
		SD2405ALPI_I2CStop();
		return (FALSE);
	}			
	SD2405ALPI_I2CSendByte(0x12);		//设置写起始地址
	SD2405ALPI_I2CWaitAck();		
	SD2405ALPI_I2CSendByte(0x00);		//清零数字调整寄存器
	SD2405ALPI_I2CWaitAck();        
	SD2405ALPI_I2CStop();  
	SD2405ALPI_WriteTimeOff();
	return (TRUE);
}



///
//设置SD2405中断程序(设置报警时间:2012年2月14日 8:00)
// 
void SD2405ALPI_WriteALARM(uint8_t hour , uint8_t minute) 
{	
	SD2405ALPI_WriteTimeOn();
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      //发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x08);      //发送起始地址(0x08=分钟报警寄存器)
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(HEXtoBCD(minute));   //分钟
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();
	
	
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      //发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x09);      //发送起始地址(0x09=小时报警寄存器)
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(HEXtoBCD(hour));     //小时
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();	
	

	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      //发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x0E);      //发送起始地址(0x0E=报警允许寄存器)
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x06);      //设置报警允许(使能小时、分钟报警)
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();

	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      //发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x10);      //发送起始地址(0x10=CTR2控制寄存器)
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x92);      //设置INT中断选通(INTS1,INTS0),及报警中断总允许位(INTAE)
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();
	SD2405ALPI_WriteTimeOff();
}



///
//关闭报警中断
// 
void SD2405ALPI_ClrALARM(void) 
{
	SD2405ALPI_WriteTimeOn();
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      //发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x10);      //发送起始地址
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x90);      //清报警中断总允许位(INTAE)
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();
	SD2405ALPI_WriteTimeOff();
}



///
//设置倒计时中断(单位:分钟)
// 
BOOL SD2405ALPI_SetDjs(uint8_t djs_Minute) 
{
	SD2405ALPI_WriteTimeOn();
	if (!SD2405ALPI_I2CStart())
		return (FALSE);
	SD2405ALPI_I2CSendByte(0x64);      	//发送SD2405写寄存器命令
	if (!SD2405ALPI_I2CWaitAck())
	{
		SD2405ALPI_I2CStop();
		return (FALSE);
	}
	SD2405ALPI_I2CSendByte(0x10);      	//发送起始地址(0x10=CTR2控制寄存器)
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0xF0);      	//清倒计时中断总允许位(INTDE)
	SD2405ALPI_I2CWaitAck();			//【WRTC=1】写寄存器允许,【IM=1】周期性报警,【INTS1=1,INTS0=1】倒计时中断
	SD2405ALPI_I2CStop();				//【INTDE=0】--->清除倒计时中断允许

	
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      	//发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x10);      	//发送起始地址(0x10=CTR2控制寄存器)
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0xF4);      	//【WRTC=1】写寄存器允许设置周期性中断(IM=1);INT中断选通(INTS1=1,INTS0=1选择倒计时中断),配置倒计时中断总允许位(INTDE=1)
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();
	
	
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      	//发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();  
	SD2405ALPI_I2CSendByte(0x11);      	//发送起始地址(0x11=CTR3控制寄存器)
	SD2405ALPI_I2CWaitAck(); 
	SD2405ALPI_I2CSendByte(0x30);		//选择定时器频率源(TDS1=1、TDS0=1)为1/60Hz
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();

	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      	//发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck(); 
	SD2405ALPI_I2CSendByte(0x13);      	//发送起始地址(0x13=倒计时寄存器)
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(djs_Minute);	//设置计数初值(单位:分钟)
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();
	SD2405ALPI_WriteTimeOff();
	return (TRUE);
}



///
//关闭倒计时中断
// 
void SD2405ALPI_ClrDjs(void) 
{
	SD2405ALPI_WriteTimeOn();	
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      	//发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x10);      	//发送起始地址(0x10=CTR2控制寄存器)
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0xF0);      	//清倒计时中断总允许位(INTDE)
	SD2405ALPI_I2CWaitAck();		  	//【WRTC=1】写寄存器允许,【IM=1】周期性报警,【INTS1=1,INTS0=1】倒计时中断
	SD2405ALPI_I2CStop();				//【INTDE=0】--->清除倒计时中断允许
	SD2405ALPI_WriteTimeOff();
}



///
//设置频率中断
// 
void SD2405ALPI_SetFrq(void)
{
	SD2405ALPI_WriteTimeOn();
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      //发送SD2405写寄存器命令,
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x10);      //发送起始地址
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0xA1);      //设置频率中断总允许位(INTFE)
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CSendByte(0x09);      //设置2Hz频率中断总
	SD2405ALPI_I2CWaitAck();			
	SD2405ALPI_I2CStop();
	SD2405ALPI_WriteTimeOff();
}



///
//关闭频率中断
// 
void SD2405ALPI_ClrFrq(void) 
{
	SD2405ALPI_WriteTimeOn();
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(0x64);      //发送SD2405写寄存器命令
	SD2405ALPI_I2CWaitAck();   
	SD2405ALPI_I2CSendByte(0x10);      //发送起始地址
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CSendByte(0xA0);      //清频率中断总允许位(INTFE)
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStop();
	SD2405ALPI_WriteTimeOff();
}



//|************I2C连续读多个字节************|
//|***尾缀B、C、F型读EEPROM程序(连续读)***|
BOOL SD2405ALPI_I2CReadSerial(uint8_t DeviceAddress , uint8_t Address , uint8_t length , uint8_t *ps)
{
	uint8_t	i;


	if (!SD2405ALPI_I2CStart())
		return (FALSE);
	SD2405ALPI_I2CSendByte(DeviceAddress); 		//器件地址
	if (!SD2405ALPI_I2CWaitAck())
	{
		SD2405ALPI_I2CStop(); 
		return (FALSE);
	}
  	SD2405ALPI_I2CSendByte(Address);			//设置要读的寄存器地址
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CStart();	
 	SD2405ALPI_I2CSendByte(DeviceAddress + 1);
	SD2405ALPI_I2CWaitAck();
	for (i = 0 ; i < length - 1 ; i++ , ps++)
	{
		*ps = SD2405ALPI_I2CReceiveByte();		//读数据
		SD2405ALPI_I2CAck();
	}
	*ps = SD2405ALPI_I2CReceiveByte();	
	SD2405ALPI_I2CNoAck();
	SD2405ALPI_I2CStop(); 
	return	(TRUE);
}



//|******************I2C连续写多个字节******************|
//|******尾缀B、C型和F型写EEPROM程序(连续写)演示******|
BOOL SD2405ALPI_I2CWriteSerial(uint8_t DeviceAddress , uint8_t Address , uint8_t length , uint8_t *ps)
{
	uint8_t	i;


	if (!SD2405ALPI_I2CStart())
		return (FALSE);
	SD2405ALPI_I2CSendByte(DeviceAddress);      //器件地址(或EEPROM页地址)
	if (!SD2405ALPI_I2CWaitAck())
	{
		SD2405ALPI_I2CStop(); 
		return (FALSE);
	}
  	SD2405ALPI_I2CSendByte(Address);			//设置起始地址
	SD2405ALPI_I2CWaitAck();
	for (i = 0 ; i < length ; i++)
	{ 	
		SD2405ALPI_I2CSendByte(*(ps++));		//B、C型最多连续发送16个字节数据,F型最多连续发送8个字节数据,若使
		SD2405ALPI_I2CAck();					//用的是NVSRAM则无此限制,可连续写任意多个数据直到存储器的末地址。
	}
	SD2405ALPI_I2CStop(); 
	return	(TRUE);
}



/******尾缀D、E型写EEPROM程序(连续写)******/
void SD2405ALPI_WriteEE_DE(uint8_t sramadd_hi , uint8_t sramadd_lo , uint8_t sramdata)
{
	uint8_t n;

	
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(EE_FirstPage_Address);	//发送页地址
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CSendByte(sramadd_hi);			//先发送高8位地址
	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CSendByte(sramadd_lo);			//再发送低8位地址
	SD2405ALPI_I2CWaitAck();  
	for (n = 0 ; n < 8 ; n++)
	{
		SD2405ALPI_I2CSendByte(sramdata++);		//D型最多连续发送32个字节数据,E型最多连续发送64个字节数据,若使用
		SD2405ALPI_I2CWaitAck();				//的是NVSRAM则无此限制,可连续写任意多个数据直到存储器的末地址。
	}
	SD2405ALPI_I2CStop();
	        
}



/******D、E型读EEPROM程序******/
void SD2405ALPI_ReadEE_DE(uint8_t sramadd_hi , uint8_t sramadd_lo , uint8_t m , uint8_t buffer[])
{
	uint8_t n;

	
	SD2405ALPI_I2CStart();
	SD2405ALPI_I2CSendByte(EE_FirstPage_Address);		//发送页地址
  	SD2405ALPI_I2CWaitAck();
	SD2405ALPI_I2CSendByte(sramadd_hi);			//先发送高8位地址
	SD2405ALPI_I2CWaitAck();	
	SD2405ALPI_I2CSendByte(sramadd_lo);			//再发送低8位地址
	SD2405ALPI_I2CWaitAck(); 
	SD2405ALPI_I2CStart();					//重发起始信号
	SD2405ALPI_I2CSendByte(EE_FirstPage_Address+1);//发送读EEPROM命令
  	SD2405ALPI_I2CWaitAck();
	for (n = 0 ; n < m ; n++)				//可读任意多个数据,直到存储器的末地址
	{
		buffer[n] = SD2405ALPI_I2CReceiveByte();
		if (n != m-1)				//最后一个数据不应答
		{
			SD2405ALPI_I2CAck();
		}
	}
	SD2405ALPI_I2CNoAck();
	SD2405ALPI_I2CStop();
}



//	I2CWriteSerial(EE_FirstPage_Address,0,8,Sram);	//Sram1数据写入EEPROM的00-07地址
//	Delayms(6);					//写完EEPROM以后需要延时10ms
//	I2CReadSerial(EE_FirstPage_Address,0,8,data1);	//读从EEPROM第一页的00地址开始读8字节数据(00-07地址)演示

SD2405ALPI.h 

#ifndef __SD2405ALPI_H__
#define __SD2405ALPI_H__


#include "stm32f4xx.h"

//EEPROM/NVSRAM地址定义。尾缀为A的内部不带EEPROM存储器
#define		EE_FirstPage_Address		0xA0//第一页(尾缀B、C、D、E、F型有)
#define		EE_SecondPage_Address		0xA2//第二页(尾缀B、C型有)
#define		EE_ThirdPage_Address		0xA4//第三页(尾缀C型)
#define		EE_FourthPage_Address		0xA6//第四页(尾缀C型)
#define		EE_FifthPage_Address		0xA8//第五页(尾缀C型)
#define		EE_SixthPage_Address		0xAA//第六页(尾缀C型)
#define		EE_SeventhPage_Address		0xAC//第七页(尾缀C型)
#define		EE_EighthPage_Address		0xAE//第八页(尾缀C型)



void SD2405ALPI_bsp_Init(void);
void SD2405ALPI_I2CStop(void);
void SD2405ALPI_WriteALARM(uint8_t BCD_hour , uint8_t BCD_minute);
BOOL SD2405ALPI_I2CWriteTime(uint8_t BCD_second , uint8_t BCD_minute , uint8_t BCD_hour , uint8_t BCD_week , uint8_t BCD_day , uint8_t BCD_month , uint8_t BCD_year);
BOOL SD2405ALPI_I2CReadTime(uint8_t *BCD_second , uint8_t *BCD_minute , uint8_t *BCD_hour , uint8_t *BCD_week , uint8_t *BCD_day , uint8_t *BCD_month , uint8_t *BCD_year);
BOOL SD2405ALPI_SetDjs(uint8_t DECIMAL_djs_Minute);



#endif



//	I2CWriteSerial(EE_FirstPage_Address,0,8,Sram);	//Sram1数据写入EEPROM的00-07地址
//	Delayms(6);					//写完EEPROM以后需要延时10ms
//	I2CReadSerial(EE_FirstPage_Address,0,8,data1);	//读从EEPROM第一页的00地址开始读8字节数据(00-07地址)演示


 

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
SD2405AL实时时钟模块介绍: SD2400系列是一种具有内置晶振、支持IIC串行接口的高精度实时时钟芯片,CPU可使用该接口通过5位地址寻址来读写片内32字节寄存器的数据(包括时间寄存器、报警寄存器、控制寄存器、通用SRAM寄存器)。 SD2400系列内置晶振,该芯片可保证时钟精度为±5ppm(在25℃下),即年误差小于2.5 分钟;该芯片内置时钟精度调整功能,可以在很宽的范围内校正时钟的偏差(分辨力3ppm),通过外置或内置的数字温度传感器可设定适应温度变化的调整值,实现在宽温范围内高精度的计时功能。 SD2400系列内置的一次性工业级电池或充电电池可保证在外部掉电情况下时钟使用寿命为5~8年时间;内部具备电源切换电路,当芯片检测到主电源VDD掉到电池电压以下,芯片会自动转为由备电电池供电。 SD2400系列内置单路定时/报警中断输出,报警中断时间最长可设至100年;内置频率中断输出和倒计时中断输出。 SD2400系列采用了多种提高芯片可靠性的技术,可满足对实时时钟芯片的各种需要,是在选用高精度实时时钟时的理想选择。 该模块采用Gadgeteer接口,同时很好的兼容Arduino(UNO、MegaDue等)和Maple系列控制板,也可与其他微控制器协同使用。 SD2405AL实时时钟模块特性: 低功耗: 1.0μA 典型值(时钟电路部分,Ta=25℃)。 工作电压:3.3V~5.5V,工作温度:民用级0℃~70℃,工业级-40℃~85℃。 标准IIC总线接口方式, 时钟电路最高速度400KHZ(4.5V~5.5V)。 年、月、日、星期、时、分、秒的BCD码输入/输出,并可通过独立的地址访问各时间寄存器 闰年自动调整功能(从2000年~2099年)。 可选择12/24小时制式. 内置年、月、日、星期、时、分、秒共7字节的报警数据寄存器及1字节的报警允许寄存器。 内置12字节通用SRAM寄存器可用于存储用户的一般数据。 三种中断均可选择从INT脚输出,并具有两个中断标志位. 可设定并自动重置的单路报警中断功能(时间范围最长设至100年),年、月、日、星期、时、分、秒报警共有96种组合方式,并有单事件报警和周期性报警两种中断输出模式. 周期性频率中断输出:从32768Hz~1/16Hz……1秒共十五种方波脉冲. 自动重置的8位倒计时定时器,可选的4种时钟源(4096HZ、64HZ、1HZ、1/60HZ)。 内置晶振,出厂前已对时钟进行校准,时钟精度为±5ppm(在25℃±1℃下),即年误差小于2.5 分钟。 内置时钟精度数字调整功能,可通过程序来调整走时的快慢。用户采用外置或内置的温度传感器,设定适应温度变化的调整值,可实现在宽温范围内高精度的计时功能(在-10℃~50℃小于5 ppm, 在-40℃~85℃小于10ppm)。 内置备电自动切换功能 ,芯片依据不同的电压自动从VDD切换到VBAT或从VBAT切换到VDD。 在VBAT模式下,芯片具有中断输出允许或禁止的功能,可满足在备用电池供电时输出中断的需要。 内置的充电电池及充电电路,累计电池电量超过550mAh,电池使用寿命为5~8年时间;内置的一次性民用级电池使用寿命为3~5年,一次性工业级电池使用寿命为5~8年时间。 内置的16kbit~256kbit非易失性SRAM(C/D/E型),其读写次数为100亿次,且内部延时小于300ns。 内置的2kbit~256kbitE2PROM(F/B/C/D/E型),其擦次数100万次 内置IIC总线0.5秒自动复位功能(从Start命令开始计时),保证时钟数据的有效性及可靠性,避免总线挂死问题。 内置三个时钟数据保护位, 避免对数据的误操作,可更好地保护时钟数据。 内置VBAT模式IIC总线通信禁止功能,从而避免在电池供电时CPU对时钟操作所消耗的电池电量,也可避免在主电源上、下电的过程中因CPU的I/O端口所输出的不受控的杂波信号对时钟芯片的误操作,进一步提高时钟芯片的可靠性。 内置上电复位电路及指示位;内置电源稳压,内部计时电压可低至1.5V。 芯片管脚抗静电(ESD)>4KV。 外形尺寸:36x31x14mm 实物购买链接:https://item.taobao.com/item.htm?spm=2013.1.20141001.2.LgLOhp&id=17280765860&scm=1007.10115.36023.100200300000000&pvid=5ade1258-3a58-432a-90dd-c2c12ae31961&idnum=0

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值