[單晶片]-寫I2C通訊(MPU6050為範例)

因為使用到MPU6050因此自己寫了I2C的架構
主要參考網路上許多範例
在此把學習到的東西寫下

I2C架構 主要是利用兩條線

SCL     // I2C 的CLK
SDA    // I2C 的DATA線

每次要傳送1Byte資料的時候前後都得加上開始和結束訊號
每個晶片通訊都有自己特殊的規範,可以參考晶片的datasheet

以下介紹為一般I2C的架構,地址等函式設定則針對MPU6050做優化


一般而言需要開始信號和結束信號才代表一次的command傳遞完成








上圖代表著開始訊號和結束訊號
開始訊號是由SDA和SCL拉HIGH後,之後SDA拉到LOW
結束訊號是由SCL為高位時,將SDA從LOW拉到HIGH

開始訊號程式碼範例:
delay一段時間讓晶片確認收到

        SDA=1
        SCL=1;
        delay(20);
        SDA=0;
        delay(20);
        SCL=0; 

結束訊號程式碼範例:

        delay(20);
        SDA=0;
        delay(20);
        SCL=1;
        delay(20);
        SDA=1;
        delay(20);


之後我們必須做一個寫資料和讀資料的動作
資料的輸出和輸入都是從最前面的BIT開始
當SCL=0時 SDA資料是混亂的,因此改變SDA的值
當SCL=1時 SDA資料是穩定的,因此接收SDA的值
利用此方式寫下讀取和寫入

另外需要注意的是I2C傳送中確認是否收到資料
會利用ACK或是NACK來確認

ACK為將SDA拉到HIGH後 晶片會將腳位拉回LOW 表示成功接收資料
NACK為 傳送資料完畢後,將SDA拉到HIGH表示成功傳送資料

WRITE_BYTE的範例程式碼

void i2c_write_byte(char address,int mode)
    
    {
        int count=0;   //計數用
        char temp=0,ACK; 
        //因為address 只有7bit+1biy(R/W)
        if(mode==0)   // 0=write資料用  1=read用 2=不改  
        {
        address=address<<1;  //向左移 表示最後一個bit為0
        }
        else if(mode==1)
        {
      address=(address<<1)|1; //向左移後 or最後一個bit為1
        }
        else if (mode==2)
        {
        address=address ;
            //internal_register 不改
        }
            // WRITE
        for(count=0;count<8;count++)
        {
            
            temp=address>>(7-count)&0x01;  //寫入的資料
            delay(20);
            SDA=temp;
            delay(20);
            SCL=1;
            delay(20);
            SCL=0;
        }
        
        //WRITE

            //ACK 的寫入
         delay(20);
         SDA=1;
         delay(20);
         SCL=1;
         delay(20);
         ACK=SDA;
         delay(20);
         SCL=0;
         delay(20);
        

    
        
        
           //ACK

        
    }
    
上面mode有分三種的原因在於,希望呼叫副程式的時候不需要改Address
因為不同用法會有不同的移向

read模式bit7為1
write模式bit7為0
寫入內部位置時不需更改 因此分三模式可以根據自己需要而改寫


READ_BYTE的範例程式碼

char i2c_read_byte(void)
    
    {
        int count=0;
        char word=0,temp=0; 
        
        
        for(count=0;count<8;count++)
        
        {
        word=word<<1;  //先接收到的資料往右位移
        delay(20);
        SCL=1;
        delay(20);
        word|=SDA;     //用OR如果資料為1就是顯示1
        delay(20);
        SCL=0;
            
        }
        //指令之間要delay 讓sensor及時感測和傳輸資料  如果clock跳太過就會導致錯誤
        delay(20);
        SDA=1;
        delay(20);
        SCL=1;
        delay(20);
        SCL=0;
    
        
        return word;

        
    }

接下來就是要讀取一個資料和寫入一個資料所需要的動作
只要結合上述副程式便能夠完成。

溝通的流程














MPU6050 本身Address (0x68)

寫入資料:

Write的步驟如下

1.寫入裝置位置(0x68,0)模式0=write
2.寫入內部address 模式2 不須更改
3.寫入資料

程式碼範例如下

WRITE_ALL

    void i2c_write_all(char internal_address,char command)
    {
        i2c_start();
        i2c_write_byte(0x68,0);
        i2c_write_byte(internal_address,2);
        i2c_write_byte(command,2);
        i2c_stop();

    }


READ_ALL

    char i2c_read_all(char internal_address)
    
    {
        char word=0;
        
        i2c_start();
        i2c_write_byte(0x68,0);
        i2c_write_byte(internal_address,2);
        i2c_start();
        i2c_write_byte(0x68,1);
        word=i2c_read_byte();
        i2c_stop();
        
        return word;
    }


這些完成後變成完成MPU6050的溝通

另外使用上需要注意事項為

MPU6050 GY521模組
雖然DATASHEET上寫的預設除了幾個Address以外都為0
但是實際使用上發現
一開始模組處於sleep狀態
如果想要得到測量值,必須先甦醒

初始化指令如下

 
     //i2c initial
     i2c_write_all(0x6b,0x00);  //I2C START MPU6050從SLEEP醒來 

     //i2c initail

便可以順利得到測試數據。


正常使用MPU6050模組

如果有想到問題再額外補上
大致如此



留言

這個網誌中的熱門文章

[研發替代役]-威聯通QNAP面試

[研發替代役]-明緯面試