IIC軟件模擬實現


1 IIC總線的連接
IIC傳輸數據的時候只用其實只需要兩根線,一根是“SCL”為時鍾線,一根是“SDA”為數據線

我們來看一下器件是怎么連接在IIC總線上的!

 

可以看到,SDA和SCL都接了上拉電阻,在總線空閑的時候,SDA和SCL都應該為高電平,當總線上的任何一個器件輸出低電平,那總線都將變為低電平。

數據有效性

 

我們記住只要記住一條:IIC總線在進行數據傳輸時,當SCL線為高,SDA線必須保持穩定,也就是說,在當拉高SCL線的時候,SDA線不能改變其電平,只有當SCL為低電平的時候才允許SDA線進行跳變,需要注意的是這個規定只是在進行數據傳輸的時候起作用,其他時候比如生成起始信號的時候可以不理睬。

2 IIC的電平信號
在使用IIC總線的時候我們主要有以下幾個信號。

一,起始信號當我們使用IIC總線的時候第一個發送的就是這個信號

 

 

IIC協議規定當SCL為高電平的時候,SDA由高到低跳變,為起始信號

下面來看一下代碼

//起始信號
void IIC_Start(void)
{
  SDA = 1;        //先將SDA和SCL都拉高為起始信號做准備
  SCL = 1;
  Delay5us();    //延時穩定
  SDA = 0;        //拉低SDA線,又高到低跳變,起始
  Delay5us();    //延時穩定
  SCL = 0;       //拉低SCL線,鉗住IIC總線
}

二 停止信號

 

IIC協議規定當SCL為高電平的時候,SDA由低到高跳變,為停止信號,和起始信號正好相反

下面來看一下代碼

//停止
void IIC_Stop(void)
{	
  SCL = 0;        //先將SDA和SCL都拉低為起始信號做准備
  SDA = 0;
  Delay2us();    //延時穩定
  SCL = 1;        //拉高SCL等待SDA上升沿
    Delay2us();    //延時穩定
  SDA = 1;        //拉高SDA
  Delay5us();
  SCL = 0;         //拉低SCL,鉗住總線

}

三 應答信號

IIC協議規定當SCL為高電平的時候,SDA為低,為起始信號,注意這里是需要在SCL的高電平到來之前SDA線需先將低電平准備好,並在SCL為高期間穩定

下面來看代碼

//答應
void IIC_Ack(void)
{
  SCL = 0;                //先將SDA和SCL都拉低為起始信號做准備
  SDA = 0;
  Delay2us();            //延時穩定
  SCL = 1;                //將SCL拉高
  Delay5us();               //在此延時階段,SDA一直為低
  SCL = 0;                    //拉低SCL,鉗住總線
}

四 非應答信號

這個就和答應信號相反,SCL為高期間,SDA也為高並保持穩定就可以了!

下面看代碼

//不答應
void IIC_NAck(void)
{
  SCL = 0;                //將SCL拉低為高電平做准備
  SDA = 1;                //將SDA先拉高
  Delay2us();
  SCL = 1;            //拉高SCL
  Delay5us();
  SCL = 0;            //鉗住總線
}

五 等待答應信號
發送器每發送完一個字節(8個脈沖),在第9個脈沖間釋放總線,接收器返回一個ACK信號,協議規定,低電平為有效應答,高電平為無效應答。

 

看以下代碼

//等待答應
bit IIC_Wait_Ack(void)
{
  uint8_t temp = 0; //定義臨時計數變量
  SDA = 1; //先拉高SDA
  Delay5us(); //延時穩定
  SCL = 1; //拉高SCL准備讀取SDA線,SDA和SCL同時為高,釋放總線控制權
  Delay5us();
  while(SDA) //當SDA拉低變為低電平的時候表示有效答應,調出循環
  {
    temp++;
    if(temp>250) //當循環250次后SDA還沒有拉低,則表示沒有答應信號(不准確的延時)
    {
      IIC_Stop();
      return 1;	//沒有答應返回1 
    }
  }
  SCL = 0;
  return 0;	//有答應,返回0
}

 

六 發送1個字節

//發動1個字節
void IIC_Send_Byte(uint8_t dat)
{
  uint8_t t; //臨時計數變量
  SCL = 0; //拉低SCL,鉗住總線,准備發送數據
  for(t=0;t<8;t++) //循環8次,一次發送1位
  {
    SDA = (dat&0x80)>>7; //去低四位,然后左移七位,先發高位
    dat=dat<<1; //將數據右移一位,等待下一此發送
    SCL = 1; //拉高SCL,等待從器件讀取SDA
    Delay2us(); //延時穩定
    SCL= 0; //拉低SCL,鉗住總線,准備發送數據
    Delay2us(); //延時穩定
  }
}

 

七 讀取1個字節

//	功能說明: CPU從I2C總線設備讀取8bit數據
//	返 回 值: 讀到的數據
uint8_t IIC_Read_Byte(uint8_t ack)
{

  uint8_t i,value;

  /* 讀到第1個bit為數據的bit7 ,先讀高位后讀低位*/
  value = 0;
  for (i = 0; i < 8; i++)
  {
    value <<= 1; 數據左移,為下一此讀取騰出位置
    SCL = 1;
    Delay2us();
    if (SDA) //如果SDA為1,則value自加
    {
      value++;
    }
    SCL = 0; //鉗住總線,准備下一此讀取
    Delay2us();
  }
    if(ack==0) //讀取完畢,判斷答應信號
    i2c_NAck();
  else
    i2c_Ack();
  return value; //返回讀取到的值
}

好了,以上就是模擬IIC的基本使用方法了!


免責聲明!

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



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