- #include<stm32f4xx.h>
-
- /********************软件模拟IIC*********************/
- /*****************PB8=SCL,PB9=SDA*****************/
-
-
- #define DS3231_ADDRESS_Write 0xD0
- #define DS3231_ADDRESS_Read 0xD1
-
-
- /**************DS3231内部寄存器地址***************/
-
- #define DS3231_SEC 0x00 // 秒
- #define DS3231_MIN 0x01 //分
- #define DS3231_HOUR 0x02 //时
- #define DS3231_WEEK 0x03 //周
- #define DS3231_DATE 0x04 //日
- #define DS3231_MONTH 0x05 //月
- #define DS3231_YEAR 0x06 //年
-
- #define DS3231_AL1SEC 0x07
- #define DS3231_AL1MIN 0x08
- #define DS3231_AL1HOUR 0x09
- #define DS3231_AL1WDAY 0x0A
-
- #define DS3231_AL2MIN 0x0B
- #define DS3231_AL2HOUR 0x0C
- #define DS3231_AL2WDAY 0x0D
-
- #define DS3231_CONTROL 0x0E
- #define DS3231_STATUS 0x0F
- #define DS3231_AGING_OFFSET 0x0F
- #define DS3231_TMP_High 0x11
- #define DS3231_TMP_LOW 0x12
-
- /******DS3231内部寄存器地址******/
- /**************END**************/
-
-
- #define Read_IIC_SDA GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_9) //定义Read_IIC_SDA为PB11的输入值
-
- #define IIC_SCL_H() GPIO_SetBits(GPIOB,GPIO_Pin_8) //定义IIC_SCL_H()函数为将RES(PB10)置高电平
- #define IIC_SCL_L() GPIO_ResetBits(GPIOB,GPIO_Pin_8) //定义IIC_SCL_L()函数为将RES(PB10)置低电平
-
- #define IIC_SDA_H() GPIO_SetBits(GPIOB,GPIO_Pin_9) //定义IIC_SDA_H()函数为将RES(PB11)置高电平
- #define IIC_SDA_L() GPIO_ResetBits(GPIOB,GPIO_Pin_9) //定义IIC_SDA_L()函数为将RES(PB11)置低电平
-
-
- //最后读取到的时间数据将赋值到下面这几个变量
- u8 RTC_Sec,RTC_Min,RTC_Hour,RTC_Week,RTC_Date,RTC_Month;
- u16 RTC_Year;
-
-
- void IIC2_SoftInit(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE);
- GPIO_InitStructure.GPIO_Pin=GPIO_Pin_8 | GPIO_Pin_9; //10--SCL 11--SDA;PB10 PB11
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT;
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //OD开漏
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- }
-
- /******* 设置SDA为输出*******/
-
- void SDA_OUT(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Pin= GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_OUT; //推挽输出
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //OD开漏
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //上拉
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- }
-
- /******* 设置SDA为输入*******/
-
- void SDA_IN(void)
- {
- GPIO_InitTypeDef GPIO_InitStructure;
- GPIO_InitStructure.GPIO_Pin= GPIO_Pin_9;
- GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_InitStructure.GPIO_Mode=GPIO_Mode_IN; //上拉输入
- GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //OD开漏
- GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL; //上拉
- GPIO_Init(GPIOB, &GPIO_InitStructure);
- }
-
-
-
- void IIC_Start(void) //起始信号
- {
- SDA_OUT(); //把SDA作为输出,初始化为推挽输出
- IIC_SDA_H(); //SDA输出高电平
- IIC_SCL_H(); //SCL输出高电平
- Delay_us(2);
- IIC_SDA_L(); //SDA输出低点评
- Delay_us(2);
- IIC_SCL_L(); //SCL输出低电平
- Delay_us(2);
- }
-
- void IIC_Stop(void) //停止信号
- {
- IIC_SCL_H(); //SCL输出高电平
- IIC_SDA_L(); //SDA输出低点评
- Delay_us(2);
- IIC_SDA_H(); //SDA输出高电平
- Delay_us(2);
- }
-
-
- u8 IIC_Wait_Ask(void) //等待应答信号
- {
- u8 count;
- IIC_SDA_H();
- Delay_us(2);
- SDA_IN();
- Delay_us(2);
- IIC_SCL_H();
- Delay_us(2);
- while(Read_IIC_SDA)
- {
- count++;
- if(count>250)
- {
- IIC_Stop(); //如果长时间无应答,则认为从站故障,终止数据传输,并返回1
- return 1;
- }
- }
- IIC_SCL_L();
- Delay_us(1);
- return 0;
- }
-
-
-
- void IIC_Ack(void) //应答信号
- {
- IIC_SCL_L();
- SDA_OUT();
- IIC_SDA_L();
- Delay_us(2);
- IIC_SCL_H();
- Delay_us(2);
- IIC_SCL_L();
- }
-
- void IIC_NAck(void) //主机不产生应答信号NACK
- {
- IIC_SCL_L();
- SDA_OUT();
- IIC_SDA_H();
- Delay_us(2);
- IIC_SCL_H();
- Delay_us(2);
- IIC_SCL_L();
- }
-
-
-
- void IIC_WriteByte(u8 data) //写1Byte数据,每个数据都是以写1Byte作为基本单位
- {
- u8 i;
- SDA_OUT(); //SDA切换到数据输出模式
- Delay_us(2);
- for(i=0;i<8;i++) //循环传输1Byte数据,即8bit
- {
- IIC_SCL_L(); //SCL置低电平,为下个Bit数据做准备
- Delay_us(2);
- if(data & 0x80) //MSB,如果date的第八位为1
- IIC_SDA_H(); //则SDA置高
- else
- IIC_SDA_L(); //否则置低
- Delay_us(1);
- IIC_SCL_H(); //SCL拉高,产生一个时钟信号,从机读取SDA状态
- Delay_us(2); //延时,丛机在这段时间读取SDA状态
- IIC_SCL_L(); //延时后拉低SCL,为下个Bit数据做准备
- data<<=1; //date左移1位,下一bit变成第八位
- }
- }
-
- //读1个字节,ack=1时,发送ACK,ack=0,发送nACK
-
-
-
- u8 IIC_Read_Byte(const unsigned char ack)
- {
- u8 i,receive=0;
- SDA_IN(); //SDA设置为输入
- Delay_us(2);
- for(i=0;i<8;i++ )
- {
- IIC_SCL_L();
- Delay_us(2);
- IIC_SCL_H();
- receive<<=1;
- Delay_us(2);
- if(Read_IIC_SDA)
- receive++;
- Delay_us(2);
- }
- if (!ack)
- IIC_NAck(); //发送nACK
- else
- IIC_Ack(); //发送ACK
- return receive;
- }
-
-
- void IIC_DS3231_ByteWrite(u8 WriteAddr,u8 date)
- {
- IIC_Start(); //起始信号
- IIC_WriteByte(DS3231_ADDRESS_Write); //DS3231设备地址,写
- IIC_Wait_Ask(); //等待应答
- IIC_WriteByte(WriteAddr); //寄存器地址
- IIC_Wait_Ask(); //等待应答
- IIC_WriteByte(date); //写入数据
- IIC_Wait_Ask(); //等待应答
- IIC_Stop(); //结束信号
- }
-
- u8 IIC_DS3231_ByteRead(u8 ReadAddr)
- {
- u8 data = 0;
- IIC_Start(); //产生起始位
- IIC_WriteByte(DS3231_ADDRESS_Write); //发送从机地址(写模式D0)
- IIC_Wait_Ask(); //等待应答
- IIC_WriteByte(ReadAddr); //发送寄存器地址
- IIC_Wait_Ask(); //等待应答
- IIC_Start(); //重复起始信号
- IIC_WriteByte(DS3231_ADDRESS_Read); //发送从机地址(读模式)
- IIC_Wait_Ask(); //等待应答
- data = IIC_Read_Byte(0); //读取数据,参数设为0 --- NACK
- IIC_Stop();
- return data;
- }
-
- void IIC_DS3231_ReadAll(void) //读取所有时间数据并转换
- {
- u8 Data_Sec,Data_Min,Data_Hour,Data_Week,Data_Date,Data_Month,Data_Year;
- u8 Low,High;
-
- Data_Sec= IIC_DS3231_ByteRead(DS3231_SEC); //读取数据秒
- Data_Min = IIC_DS3231_ByteRead(DS3231_MIN); //读取数据分
- Data_Hour = IIC_DS3231_ByteRead(DS3231_HOUR); //读取数据时
- Data_Week = IIC_DS3231_ByteRead(DS3231_WEEK); //读取数据周
- Data_Date = IIC_DS3231_ByteRead(DS3231_DATE); //读取数据日
- Data_Month = IIC_DS3231_ByteRead(DS3231_MONTH); //读取数据月
- Data_Year = IIC_DS3231_ByteRead(DS3231_YEAR); //读取数据年
-
- Low=Data_Sec&0x0f; //取低四位
- High=(( Data_Sec& 0xf0) >> 4); //取高四位
- RTC_Sec=High*10+Low; //转换秒(高四位*10+低四位)
-
- Low=Data_Min&0x0f;
- High=(( Data_Min& 0xf0) >> 4);
- RTC_Min=High*10+Low; //转换分
-
- Low=Data_Hour&0x0f;
- High=(( Data_Hour& 0x30) >> 4);
- RTC_Hour=High*10+Low; //转换时(高两位*10+低四位)
-
- RTC_Week=Data_Week; //转换周(不需要转换)
-
- Low=Data_Date&0x0f;
- High=(( Data_Date& 0xf0) >> 4);
- RTC_Date=High*10+Low; //转换日
-
- Low=Data_Month&0x0f;
- High=(( Data_Month& 0x10) >> 4);
- RTC_Month=High*10+Low; //转换月
-
- Low=Data_Year&0x0f;
- High=(( Data_Year& 0xf0) >> 4);
- RTC_Year=((Data_Month>>7)+20)*100+High*10+Low; //转换年(世纪*100+高四位*10+低四位)
- }
-
- void IIC_DS3231_WriteAll(u16 Year,u8 Month,u8 Date,u8 Week,u8 Hour,u8 Min,u8 Sec)
- {
- u8 Sec_Date,Min_Date,Hour_Date,Week_Date,Date_Date,Month_Date,Year_Date;
- u8 H_Bit,L_Bit;
-
- H_Bit=(Sec/10)<<4; //取高四位
- L_Bit=Sec%10; //取低四位
- Sec_Date=H_Bit|L_Bit; //合并成八位
-
- H_Bit=(Min/10)<<4;
- L_Bit=Min%10;
- Min_Date=H_Bit|L_Bit;
-
- H_Bit=Hour/10;
- L_Bit=Hour%10;
- Hour_Date=(H_Bit<<4)|L_Bit;
-
- Week_Date=Week;
-
- H_Bit=Date/10;
- L_Bit=Date%10;
- Date_Date=(H_Bit<<4)|L_Bit;
-
- if(Year/100==20)
- {
- H_Bit=Month/10;
- L_Bit=Month%10;
- Month_Date=(H_Bit<<4)|L_Bit;
-
- H_Bit=(Year-2000)/10;
- L_Bit=(Year-2000)%10;
- Year_Date=(H_Bit<<4)|L_Bit;
-
- }
- else
- {
- H_Bit=Month/10+8; //05h第8位如果是1,则为22世纪
- L_Bit=Month%10;
- Month_Date=(H_Bit<<4)|L_Bit;
-
- H_Bit=(Year-2100)/10;
- L_Bit=(Year-2100)%10;
- Year_Date=(H_Bit<<4)|L_Bit;
- }
- IIC_DS3231_ByteWrite(DS3231_YEAR,Year_Date);
- IIC_DS3231_ByteWrite(DS3231_MONTH,Month_Date);
- IIC_DS3231_ByteWrite(DS3231_DATE,Date_Date);
- IIC_DS3231_ByteWrite(DS3231_WEEK,Week_Date);
- IIC_DS3231_ByteWrite(DS3231_HOUR,Hour_Date);
- IIC_DS3231_ByteWrite(DS3231_MIN,Min_Date);
- IIC_DS3231_ByteWrite(DS3231_SEC,Sec_Date);
-
- }
-
- void DS3231_Init(void) //DS3231初始化
- {
- IIC_DS3231_ByteWrite(0x0E,0x40); //使能1Hz方波,使能振荡器
- IIC_DS3231_ByteWrite(0x0F,0x00); //启动振荡器
- Delay_ms(100); //延时等待完全起振
- }