DS3231的使用(二) (附IIC源碼)


本節主要講述IIC的使用及源碼實現。

IIC數據有效性:只有在SCL線為低時,SDA線才允許改變電平。

初始宏定義如下:

 1 /**************宏定義***************/
 2 #define DS_SCL  BIT6        //DS_SCL = P1.6
 3 #define DS_SDA  BIT5        //DS_SDA = P1.5
 4 #define DS_SCL_IN           P1DIR &= ~DS_SCL
 5 #define DS_SCL_OUT        P1DIR |= DS_SCL
 6 #define DS_SCL_L             P1OUT &= ~DS_SCL
 7 #define DS_SCL_H            P1OUT |= DS_SCL
 8 #define DS_SDA_IN          P1DIR &= ~DS_SDA
 9 #define DS_SDA_OUT       P1DIR |= DS_SDA
10 #define DS_SDA_L            P1OUT &= ~DS_SDA
11 #define DS_SDA_H           P1OUT |= DS_SDA
12 #define DS_SDA_BIT        P1IN & DS_SDA
13 #define DS_SDA_IN_H      P1REN |= DS_SDA

 

IIC時序圖(取自DS3231數據手冊):

先看前一部分(開始與結束):

從時序圖可以看出來,開始信號為SCL為高時,SDA由高變低;結束信號為SCL為低時,SDA由低變高。

 1 /*******************************************
 2 函數名稱:DS_Start
 3 功    能:I2C起始數據
 4 參    數:無
 5 返回值  :無
 6 ********************************************/
 7 void DS_Start(void)
 8 {
 9 DS_SDA_OUT;          //設置IO口方向
10 DS_SCL_OUT;
11 DS_SCL_H;            //SCL、SDA先拉高
12 Delay_us(5);         //delay應該有個最小時間要求
13 DS_SDA_H;
14 Delay_us(5);
15 DS_SDA_L;            //SDA拉低表明開始
16 Delay_us(5);
17 DS_SCL_L;            //SCL拉低,數據傳輸准備就緒
18 Delay_us(5);
19 }
 1 /*******************************************
 2 函數名稱:DS_Stop
 3 功    能:I2C終止數據
 4 參    數:無
 5 返回值  :無
 6 ********************************************/
 7 void DS_Stop(void)
 8 {
 9 DS_SDA_OUT;          //設置IO口方向
10 DS_SCL_OUT;
11 DS_SCL_L;            //先把SCL、SDA拉低,給結束信號做准備
12 Delay_us(5);
13 DS_SDA_L;
14 Delay_us(5);
15 DS_SCL_H;            //SCL拉高
16 Delay_us(5);
17 DS_SDA_H;            //當SCL為高,SDA由低變高為結束信號
18 Delay_us(1);
19 }

發送數據與讀數據:

由圖可知,開始信號后,應把SCL拉低,准備數據傳輸,SDA電平變化后,再拉高SCL,發送數據(最高位先發送),循環8次(一個字節)。

讀取函數同理,只不過過程是反的,SDA是輸入,主機做接收端。

 1 /*******************************************
 2 函數名稱:DS_Send_Byte
 3 功    能:I2C發送數據
 4 參    數:data
 5 返回值  :data
 6 ********************************************/
 7 void DS_Send_Byte(u8 data)
 8 {
 9 DS_SDA_OUT;           //設置IO口輸出方向
10 DS_SCL_OUT;
11 DS_SCL_L;             //SCL為低時,允許SDA改變電平
12 unsigned char temp;
13 for(temp=0x80;temp!=0;temp>>=1)
14     {
15      if(temp&data==0) //高位先發
16      {
17        DS_SDA_L;
18      }
19      else
20      {
21        DS_SDA_H;
22      }
23       Delay_us(5);
24        DS_SCL_H;      //SCL拉高 發送數據
25       Delay_us(5);
26        DS_SCL_L;
27     }
28 }
 1 /*******************************************
 2 函數名稱:DS_Read
 3 功    能:I2C接收數據
 4 參    數:data
 5 返回值  :data
 6 ********************************************/
 7 unsigned char DS_Read(void)
 8 {
 9    unsigned char temp;
10    unsigned char data;
11 
12    DS_SDA_IN;              //主機做接收,SDA線為輸入
13    DS_SDA_IN_H ; 
14    for(temp=0x80;temp!=0;temp>>=1)
15    {
16     DS_SCL_H;              //SCL拉高,保證接收數據時SDA不改變
17     Delay_us(5);
18     if(DS_SDA_BIT==1)
19     {
20      data|=temp;           //高電平保留
21     }
22      else
23     {
24      data&=~temp;
25     }
26     DS_SCL_L;              //SCL拉低,數據准備
27     }
28     return data;
29 }

主機應答信號與非應答信號:

主機接收完從機數據后,要發送應答或者非應答信號。

 1 /*******************************************
 2 函數名稱:DS_Ack
 3 功    能:I2C發送應答信號
 4 參    數:無
 5 返回值  :無
 6 ********************************************/
 7 void DS_Ack(void)
 8 {
 9 DS_SDA_OUT;    //主機為接收端   發送應答信號
10 DS_SCL_L;        //SCL拉低,允許SDA改變電平
11 DS_SDA_L;       //SDA低電平為應答
12 DS_SCL_H;
13 Delay_us(5);
14 DS_SCL_L;
15 }
 1 /*******************************************
 2 函數名稱:DS_NAck
 3 功    能:I2C發送非應答信號
 4 參    數:無
 5 返回值  :無
 6 ********************************************/
 7 void DS_NAck(void)
 8 {
 9 DS_SDA_OUT;   //此時,相當於主機在接收數據,是被動方
10 DS_SCL_L;     //SCL拉低,允許SDA改變電平
11 DS_SDA_H;     //SDA高電平為非應答
12 DS_SCL_H;
13 Delay_us(5);
14 DS_SCL_L;
15 }

主機接收從機應答信號:

從機在接收主機數據后,從機要發送一個應答信號,主機判斷此應答信號為應答信號或者非應答信號,做下一步處理。

/*******************************************
函數名稱:DS_Get_Ack
功    能:I2C接收應答信號
參    數:無
返回值  :ack
********************************************/
uchar DS_Get_Ack(void)
{
    unsigned char ack;
    DS_SDA_IN;         //釋放數據線,准備接收應答
    DS_SDA_IN_H ;      //SDA線輸入上拉
    DS_SCL_H;          //SCL線拉高
    if(DS_SDA_BIT==1)
    {
     ack=0;//無應答信號
    }
    else
    {
     ack=1;//有應答信號
    }
    DS_SCL_L;
    Delay_us(5);
}

下面是DS3231傳輸時序圖:

由圖可知,在發送開始信號后,DS3231接收的第一個字節的前7位是從機地址,即DS3231地址,第八位為讀/寫操作。

  

從DS3231的數據手冊中可以看出來,DS3231的地址為1101000,所以主機操作的寫地址為0XD1,讀地址為0XD0。(不要寫反)讀寄存器指針的方式是開始信號-寫器件地址-寫寄存器地址-開始信號-接收數據-停止。

 1 /*******************************************
 2 函數名稱:DS3231_WriteByte
 3 功    能:I2C總線給DS3231發送單字節
 4 參    數:WriteAddr DataToWrite
 5 返回值  :無
 6 ********************************************/
 7 void DS3231_WriteByte(u8 WriteAddr,u8 DataToWrite)
 8 {
 9 DS_Start();
10 DS_Send_Byte(0XD1);       //發送器件地址    
11 DS_Get_Ack();
12 DS_Send_Byte(WriteAddr);  //發送首地址
13 DS_Get_Ack();
14 DS_Send_Byte(DataToWrite);//發送數據
15 DS_Get_Ack();
16 DS_Stop();
17 Delay_ms(1);
18 }

 

 1 /*******************************************
 2 函數名稱:DS3231_ReadByte
 3 功    能:I2C總線從DS3231接收單字節
 4 參    數:ReadAddr DataToRead
 5 返回值  :Data
 6 ********************************************/
 7 uchar DS3231_ReadByte(u8 ReadAddr)
 8 {
 9   uchar R_Data=0;
10   DS_Start();
11   DS_Send_Byte(0XD0);//讀地址
12   DS_Ack();
13   DS_Send_Byte(ReadAddr);
14   DS_Ack();
15   DS_Start();
16   DS_Send_Byte(0XD1);
17   R_Data=DS_Read();
18   Delay_us(5);
19   DS_NAck();
20   DS_Stop();
21   return R_Data;
22 }
 1 /*******************************************
 2 函數名稱:Readtime
 3 功    能:讀取DS3231時間
 4 參    數:R_tmpdate
 5 返回值  :無
 6 ********************************************/
 7 void Read_RTC()
 8 {   unsigned char rtc_address[6]={0x00,0x01,0x02,0x04,0x05,0x06};
 9     unsigned char R_tmpdate[6];
10     unsigned char i,*p;
11      p=rtc_address;             //地址傳遞
12     for(i=0;i<6;i++)            //分6次讀取 秒分時日月年
13     {
14       R_tmpdate[i]=DS3231_ReadByte(*p); 
15       p++;
16     }
17 }
 1 void ModifyTime(uchar yea,uchar mon,uchar da,uchar hou,uchar min,uchar sec)
 2 {
 3   uchar temp=0;
 4 
 5   DS3231_WriteByte(0x06,temp);//修改年
 6 
 7   DS3231_WriteByte(0x05,temp);//修改月
 8 
 9   DS3231_WriteByte(0x04,temp);//修改日
10 
11   DS3231_WriteByte(0x02,temp);//修改時
12 
13   DS3231_WriteByte(0x01,temp);//修改分
14 
15   DS3231_WriteByte(0x00,temp);//修改秒
16 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM