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

2023-10-29

具体的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地址)演示


 

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

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

随机推荐

  • 使用 Nginx + Gunicorn 部署 Flask 项目

    使用 Nginx Gunicorn 部署 Flask 项目 Flask Web 项目开发完成后 开发人员只是在开发环境运行 只有本地可以访问到项目 如果要让用户访问到项目 需要将项目部署到生产环境上 在服务器运行项目 本文就使用阿里云服务器
  • C++ primer 【笔记】C++中this指针的用法详解

    1 this指针的用处 一个对象的this指针并不是对象本身的一部分 不会影响sizeof 对象 的结果 this作用域是在类内部 当在类的非静态成员函数中访问类的非静态成员的时候 编译器会自动将对象本身的地址作为一个隐含参数传递给函数 也
  • 【Linux命令详解

    文章标题 简介 一 参数列表 二 使用介绍 1 分页显示文件内容 2 搜索关键词 3 显示行号 4 显示特定内容 5 只显示匹配行 6 忽略大小写搜索 7 输出到文件 8 动态查看文件增长 9 开启对二进制文件的支持 10 显示控制字符 1
  • 博客搬家系列(六)-爬取今日头条文章

    博客搬家系列 六 爬取今日头条文章 一 前情回顾 博客搬家系列 一 简介 https blog csdn net rico zhou article details 83619152 博客搬家系列 二 爬取CSDN博客 https blog
  • 前端和后端就业前景如何?

    我个人的信息来源有两个渠道 一个是观察公司内网发布的招聘信息 另一个是观察朋友圈内猎头经常发布的招聘信息 基本算是从横向与纵向两个视角 较为全面的了解当前市场 先说结论 就国内市场而言 前端开发要求较容易 而发展前景相应的受限 发布的职位也
  • 数值作业:顺序消去法解线性方程组之C语言代码

    实际上后面的Guass列主选主元 全选主元 都是由顺序高斯消元法稍加改动变化而来的 但是顺序消元会出现一个问题 如果我们要保留的那个元的系数很小 那么在消元过程中 势必会用很大的数字乘以次方程后再加到别的方程上消去别的方程中的改元 这样就会
  • 《FFmpeg Basics》中文版-09-overlay-画中画

    正文 overlay视频技术经常被使用 常见的例子是放置在电视屏幕上的电视频道标志 通常位于右上角 以标识特定的频道 另一个例子是画中画功能 可以在主屏幕的其中一个角落显示小窗口 小窗口包含选定的电视频道或其他内容 同时在主屏幕上观看节目
  • Three.js基础介绍

    文章目录 前言 项目引入 项目介绍 推荐理由 场景展示 总结 前言 Three js是基于原生WebGL封装运行的三维引擎 在所有WebGL引擎中 Three js是国内文资料最多 使用最广泛的三维引擎 项目引入 Three js中文网 g
  • android 相机预览编译 libyuv 处理 YUV 数据

    下载源码 需翻墙 Android Studio 新建一个 NDK 项目 源码拷贝到 cpp 目录下 include 下面是头文件 source 下面是源码 其它文件基本用不到不用管 CMakeLists txt 是 cmake 编译脚本 现
  • IBM的语音识别(IBM speech to text 语言转换成文字)

    1 登陆网址https www ibm com watson developercloud speech to text html并注册 2 打开网址https console ng bluemix net catalog category
  • 前女友

    点击这个会出现代码 简而言之 要满足v1 v2 但是md5 v1 md5 v2 1 可以通过 PHP处理0e开头md5时hash字符串漏洞 0e开头md5所代表的值相同 来构造 下面这篇文章中有关于这个的构造 https blog csdn
  • 南航829数据结构历年真题答案

    2013年真题 第四题 问题描述 已知有两个带头结点的单链表A和B 元素值递增有序 编写函数调整删减链表 使A链表的元素值为A B的交集 并成为一个递减有序的单链表 要求写出算法思想以及相应代码 代码 2013数据结构第四题 include
  • 使用null,not in翻车了(oracle)

    水平有限 如有错误 请多指正 由于对null和not in理解得不是很透彻 导致在生产环境出问题了 请看下面的sql 为了简单 sql做过调整 select sd prestpword pres from ci pres pres wher
  • 全球第二大成人网站,黄了!

    推荐大家关注一个公众号 点击上方 编程技术圈 关注 星标或置顶一起成长 后台回复 大礼包 有惊喜礼包 每日英文 To give up is easy But to hold it together when everyone else th
  • 历届试题 高僧斗法  (博弈)

    题目 历届试题 高僧斗法 时间限制 1 0s 内存限制 256 0MB 锦囊1 博弈论 NIM取子游戏 锦囊2 将两个两个看成一组 他们之间的间隔可以看成一个NIM取子游戏 问题描述 古时丧葬活动中经常请高僧做法事 仪式结束后 有时会有 高
  • tomcat加载jar包顺序

    概述 项目使用springMVC serviceImpl注入的一个bean无法找到 究其原因是无法找到日志类 其实在spring的配置文件中配置了bean 而且程序代码在其他人的机子上运行不报错 我这边抱错 类找不到apache commo
  • 华为手机如何固定横屏_华为手机屏幕如何转为横屏?很简单,只需这样设置

    设置华为手机横屏显示 需要打开手机的 自动旋转 功能 在使用时将手机机身横置即可 以华为P20Pro为例 详细操作步骤如下 1 从屏幕顶部向下滑动 调出系统的通知面板 2 向下拖拽通知面板 让面板显示全部快捷功能 3 在通知面板中 找到并打
  • SQLyog快捷键,这一篇就够!!

    我们在使用SQLyog进操作时 如果不使用快捷键 会很麻烦 尤其是多行注释这种骚操作 所以在非常忙碌的工作中 使劲的挤了挤 挤出点时间 来整理一下sqlyog的常用快捷键骚操作 一 连接 Ctrl M 创建一个新的连接 Ctrl N 使用当
  • C# 参数传递(引用类型参数)

    目录 一 引言 二 引用类型参数作为值参数传递 三 引用类型参数作为引用参数传递 一 引言 方法中参数的传递方式主要有值参数传递和引用参数传递 ref out 而参数有可以分为值类型参数和引用类型参数 这里主要讲一讲引用类型参数的值 引用参
  • STM32F407IG单片机读写SD2405ALPI实时时钟程序(包括:读时钟时间、写时间到时钟、时间报警中断、倒计时中断)

    具体的IIC时序图和分析过程请参见下面网友的文章 https blog csdn net ybhuangfugui article details 52151835 本人在STM32F407单片机上亲测读时钟 写时钟 时间中断以及倒计时 秒