DS3231——IIC的使用及源碼實(shí)現(xiàn)
一剔猿、IIC
IIC數(shù)據(jù)有效性:只有在SCL線為低時(shí)猾愿,SDA線才允許改變電平。
1、初始宏定義如下:
#define DS_SCL? BIT6???????//DS_SCL = P1.6
#define DS_SDA? BIT5???????//DS_SDA = P1.5
#define DS_SCL_IN?????????? P1DIR &= ~DS_SCL
#define DS_SCL_OUT??????? P1DIR |= DS_SCL
#define DS_SCL_L???????????? P1OUT &= ~DS_SCL
#define DS_SCL_H??????????? P1OUT |= DS_SCL
#define DS_SDA_IN????????? P1DIR &= ~DS_SDA
#define DS_SDA_OUT?????? P1DIR |= DS_SDA
#define DS_SDA_L????? ??????P1OUT &= ~DS_SDA
#define DS_SDA_H?????????? P1OUT |= DS_SDA
#define DS_SDA_BIT??????? P1IN & DS_SDA
#define DS_SDA_IN_H????? P1REN |= DS_SDA?
二、IIC時(shí)序
2.1 開(kāi)始與結(jié)束
從時(shí)序圖可以看出來(lái),開(kāi)始信號(hào)為SCL為高時(shí)畅涂,SDA由高變低;結(jié)束信號(hào)為SCL為低時(shí)道川,SDA由低變高午衰。
函數(shù)名稱:DS_Start
功??? 能:I2C起始數(shù)據(jù)
參??? 數(shù):無(wú)
返回值? :無(wú)
voidDS_Start(void)
{
DS_SDA_OUT;????????? //設(shè)置IO口方向
DS_SCL_OUT;DS_SCL_H;??????????? //SCL、SDA先拉高
Delay_us(5);???????? //delay應(yīng)該有個(gè)最小時(shí)間要求
DS_SDA_H;
Delay_us(5);
DS_SDA_L;??????????? //SDA拉低表明開(kāi)始
Delay_us(5);
DS_SCL_L;??????????? //SCL拉低冒萄,數(shù)據(jù)傳輸準(zhǔn)備就緒
Delay_us(5);
}?
函數(shù)名稱:DS_Stop
功??? 能:I2C終止數(shù)據(jù)
參??? 數(shù):無(wú)
返回值? :無(wú)
void DS_Stop(void)
{
DS_SDA_OUT;????????? //設(shè)置IO口方向
DS_SCL_OUT;
DS_SCL_L;??????????? //先把SCL臊岸、SDA拉低,給結(jié)束信號(hào)做準(zhǔn)備
Delay_us(5);
DS_SDA_L;
Delay_us(5);
DS_SCL_H;??????????? //SCL拉高
Delay_us(5);
DS_SDA_H;???? ???????//當(dāng)SCL為高尊流,SDA由低變高為結(jié)束信號(hào)
Delay_us(1);
}
2.2 發(fā)送數(shù)據(jù)與讀數(shù)據(jù):
由圖可知帅戒,開(kāi)始信號(hào)后,應(yīng)把SCL拉低,準(zhǔn)備數(shù)據(jù)傳輸逻住,SDA電平變化后钟哥,再拉高SCL,發(fā)送數(shù)據(jù)(最高位先發(fā)送)瞎访,循環(huán)8次(一個(gè)字節(jié))腻贰。
讀取函數(shù)同理,只不過(guò)過(guò)程是反的扒秸,SDA是輸入播演,主機(jī)做接收端。
函數(shù)名稱:DS_Send_Byte
功??? 能:I2C發(fā)送數(shù)據(jù)
參??? 數(shù):data
返回值? :data
void DS_Send_Byte(u8 data)
{
DS_SDA_OUT;?? ????????//設(shè)置IO口輸出方向
DS_SCL_OUT;
DS_SCL_L;???????????? //SCL為低時(shí)伴奥,允許SDA改變電平
unsigned char temp;
for(temp=0x80;temp!=0;temp>>=1)?
?? {?
? if(temp&data==0) ? ?//高位先發(fā)???
?{ ? ? ?DS_SDA_L; ? ? ? } ? ??
?else ? ?{ ? ? DS_SDA_H; ? ? }??
? Delay_us(5);????
??DS_SCL_H;?????//SCL拉高發(fā)送數(shù)據(jù)?
? Delay_us(5);??????
? DS_SCL_L;???
?}
}?
函數(shù)名稱:DS_Read
功??? 能:I2C接收數(shù)據(jù)
參??? 數(shù):data
返回值? :data
unsigned char DS_Read(void)
{??
unsigned char temp;??
unsigned char data;?
?DS_SDA_IN;????????????? //主機(jī)做接收写烤,SDA線為輸入??
DS_SDA_IN_H ; ??
for(temp=0x80;temp!=0;temp>>=1)??
{???
DS_SCL_H;????????????? //SCL拉高,保證接收數(shù)據(jù)時(shí)SDA不改變???
Delay_us(5);???
if(DS_SDA_BIT==1) ? ?
?{????
data|=temp;?????????? //高電平保留?
?? }????
else ? ?
{????
data&=~temp;???
}???
DS_SCL_L;????????? ????//SCL拉低拾徙,數(shù)據(jù)準(zhǔn)備???
}???
return data;
}?
2.3?主機(jī)應(yīng)答信號(hào)與非應(yīng)答信號(hào):
主機(jī)接收完從機(jī)數(shù)據(jù)后洲炊,要發(fā)送應(yīng)答或者非應(yīng)答信號(hào)。
函數(shù)名稱:DS_Ack
功??? 能:I2C發(fā)送應(yīng)答信號(hào)
參??? 數(shù):無(wú)
返回值? :無(wú)
void DS_Ack(void)
{
DS_SDA_OUT;??? //主機(jī)為接收端?? 發(fā)送應(yīng)答信號(hào)
DS_SCL_L;??????? //SCL拉低尼啡,允許SDA改變電平
DS_SDA_L;?????? //SDA低電平為應(yīng)答
DS_SCL_H;
Delay_us(5);
DS_SCL_L;
}
函數(shù)名稱:DS_NAck
功??? 能:I2C發(fā)送非應(yīng)答信號(hào)
參??? 數(shù):無(wú)
返回值? :無(wú)
void DS_NAck(void)
{
DS_SDA_OUT;?? //此時(shí)选浑,相當(dāng)于主機(jī)在接收數(shù)據(jù),是被動(dòng)方
DS_SCL_L;???? //SCL拉低玄叠,允許SDA改變電平
DS_SDA_H;???? //SDA高電平為非應(yīng)答
DS_SCL_H;
Delay_us(5);
DS_SCL_L;
}?
2.4?主機(jī)接收從機(jī)應(yīng)答信號(hào):
從機(jī)在接收主機(jī)數(shù)據(jù)后古徒,從機(jī)要發(fā)送一個(gè)應(yīng)答信號(hào),主機(jī)判斷此應(yīng)答信號(hào)為應(yīng)答信號(hào)或者非應(yīng)答信號(hào)读恃,做下一步處理隧膘。
函數(shù)名稱:DS_Get_Ack
功??? 能:I2C接收應(yīng)答信號(hào)
參??? 數(shù):無(wú)
返回值? :ack
uchar DS_Get_Ack(void)
{
???unsigned char ack;
???DS_SDA_IN;???????? //釋放數(shù)據(jù)線,準(zhǔn)備接收應(yīng)答
???DS_SDA_IN_H ;????? //SDA線輸入上拉
???DS_SCL_H;????????? //SCL線拉高
???if(DS_SDA_BIT==1)
??? {
????ack=0;//無(wú)應(yīng)答信號(hào)
??? }
???else
??? {
????ack=1;//有應(yīng)答信號(hào)
??? }
???DS_SCL_L;
???Delay_us(5);
}
二寺惫、DS3231傳輸時(shí)序
由圖可知疹吃,在發(fā)送開(kāi)始信號(hào)后,DS3231接收的第一個(gè)字節(jié)的前7位是從機(jī)地址西雀,即DS3231地址萨驶,第八位為讀/寫操作。
從DS3231的數(shù)據(jù)手冊(cè)中可以看出來(lái)艇肴,DS3231的地址為1101000腔呜,所以主機(jī)操作的寫地址為0XD1,讀地址為0XD0再悼。(不要寫反)讀寄存器指針的方式是開(kāi)始信號(hào)-寫器件地址-寫寄存器地址-開(kāi)始信號(hào)-接收數(shù)據(jù)-停止核畴。
函數(shù)名稱:DS3231_WriteByte
功??? 能:I2C總線給DS3231發(fā)送單字節(jié)
參??? 數(shù):WriteAddrDataToWrite
返回值? :無(wú)
void DS3231_WriteByte(u8 WriteAddr,u8DataToWrite)
{
DS_Start();
DS_Send_Byte(0XD1);?????? //發(fā)送器件地址???
DS_Get_Ack();
DS_Send_Byte(WriteAddr);? //發(fā)送首地址
DS_Get_Ack();
DS_Send_Byte(DataToWrite);//發(fā)送數(shù)據(jù)
DS_Get_Ack();
DS_Stop();
Delay_ms(1);
}
函數(shù)名稱:DS3231_ReadByte
功??? 能:I2C總線從DS3231接收單字節(jié)
參??? 數(shù):ReadAddrDataToRead
返回值? :Data
uchar DS3231_ReadByte(u8 ReadAddr)
{
?uchar R_Data=0;
?DS_Start();
?DS_Send_Byte(0XD0);//讀地址
?DS_Ack();
?DS_Send_Byte(ReadAddr);
?DS_Ack();
?DS_Start();
?DS_Send_Byte(0XD1);
?R_Data=DS_Read();
?Delay_us(5);
?DS_NAck();
?DS_Stop();
?return R_Data;
}
函數(shù)名稱:Readtime
功??? 能:讀取DS3231時(shí)間
參??? 數(shù):R_tmpdate
返回值? :無(wú)
void Read_RTC()
{??unsigned char rtc_address[6]={0x00,0x01,0x02,0x04,0x05,0x06};
???unsigned char R_tmpdate[6];
???unsigned char i,*p;
????p=rtc_address;???????????? //地址傳遞
???for(i=0;i<6;i++)??????????? //分6次讀取秒分時(shí)日月年
??? {
?????R_tmpdate[i]=DS3231_ReadByte(*p);
?????p++;
??? }
}
void ModifyTime(uchar yea,uchar mon,ucharda,uchar hou,uchar min,uchar sec)
{
?uchar temp=0;
?DS3231_WriteByte(0x06,temp);//修改年
?DS3231_WriteByte(0x05,temp);//修改月
?DS3231_WriteByte(0x04,temp);//修改日
?DS3231_WriteByte(0x02,temp);//修改時(shí)
?DS3231_WriteByte(0x01,temp);//修改分
?DS3231_WriteByte(0x00,temp);//修改秒
}