MPU6050的Arduino實現

Arduino有多種通信方式,每一種通信方式都有相對應的類來支持:
1)硬件串口通信——HardwareSerial 類庫
2)軟件模擬串口通信——SoftwareSerial 類庫
3)IIC總線的使用——Wire 類庫
4)SPI總線的使用——SPI 類庫

MPU6050的數據接口用的是I2C總線協議,因此我們需要Wire類庫的幫助來實現Arduino與MPU6050之間的通信。
MPU6050的數據寫入和讀出均通過其芯片內部的寄存器實現,這些寄存器的地址都是1個字節,也就是8位的尋址空間,其寄存器的詳細列表說明書請點擊下載:
使用Arduino的Wire類庫來學習MPU6050與arduino的IIC通信,比直接學習MPU6050與單片機或其他更高級芯片的通信要容易許多。在arduino平臺上完成MPU6050的測試後,應該轉而在其他平臺上使用MPU6050。當然能夠實現設備通信只是邁出了其中的一小步,更重要的是在獲得慣性測量單元的數據後,會對數據進行處理。最後,能夠使用MPU6050來做一些小項目是最好的,例如平衡車、四軸飛行器等等。

一、瞭解 wire.h
1.庫包含的函數:
    1) Wire.begin()和Wire.begin(address):初始化IIC連接。無參數,設備以主機模式加入IIC總線;寫參數,設備以從機模式加入IIC總線,address爲一個7位的從機地址。語法爲:
    begin():           
    begin(address): 
    返回值:none
   
    2) Wire.requestFrom():主機向從機發送數據請求信號(n*一個字節)。使用後,從機可以使用onRequest()註冊一個事件以響應主機請求。隨後,數據可以被主設備用available()和read()函數接收。語法爲:
    Wire.requestFrom(address, quantity):設備(從機)的地址、請求的字節數
    Wire.requestFrom(address, quantity, stop):stop參數爲boolean型值,值爲true則發送停止命令,釋放IIC總線;值爲false則發送重新開始信息,並繼續保持IIC總線的有效連接。
    返回值:none

    3) Wire.beginTransmission():設定傳輸數據到指定地址的從機設備。隨後可以使用write()函數發送數據,並搭配endTransmission():函數結束數據傳輸。
    語法:wire.beginTransmission(address):
    返回值:none

    4) Wire.endTransmission():結束一個由beginTransmission()開始的並且由write()排列的從機的傳輸。語法爲:
    Wire.endTransmission()
    Wire.endTransmission(stop):stop爲biilean型值,值爲true(沒有填寫stop參數時,等效使用true)則發送一個停止信息;值爲false則發送一個重新開始信息,並繼續保持IIC總線的有效連接。
    返回值:0 成功   1 數據溢出   2 發送addtess時從機接受到NACK   3 發送數據時接受到NACK   4 其他錯誤

    5) Wire.write():向從機發送數據(雙向?主機狀態:主機將要發送的數據加入發送隊列;從機狀態:從機發送數據至發起請求的主機)。語法爲:
    Wire.write(value):value 要發送的數值(以單字節發送)
    Wire.write(string):string 字符組的指針(以一系列字節發送)
    Wire.write(data, length):data 一個字節數組(以字節形式發送數組);length 傳輸的字節數
    返回值:byte型值,返回輸入的字節數。

    6) Wire.available():返回接收到的字節數
    在主機中,一般用於主機發送數據請求後;在從機中,一般用於數據接收事件。語法爲:
    Wire.available()  無參數
    返回值:byte型值,返回輸入的字節數。

    7) Wire.read():讀取1B的數據
    在主機中,使用requestFrom()函數發送數據請求信號後,需要使用read()函數來獲取數據;在從機中需要使用read()讀取主機發送來的數據。語法爲:
    Wire.read()  無參數
    char c = Wire.read():以字符串形式接收數據(將數據作爲字符接收)
    int x = Wire.read():以整型形式接收數據
    返回值:讀到的字節數據

    8) Wire.onReceive():在從機端註冊一個事件,當從機收到主機發送的數據時即被觸發。語法爲:
    Wire.onReceive(handler):handler 當從機接收到數據時可被觸發的事件。該事件帶有一個int型參數(從主機讀到的字節數)且沒有返回值,如 void myHandler(int numBytes)
    返回值:none

    9) Wire.onRequest():註冊一個事件,當從機接收到主機數據請求時即被觸發
    Wire.onRequest(handler):handler  可被觸發的事件。該事件不帶參數和返回值,如 void myHandler() 。
    返回值:none

二、關於MPU6050:
1.關於輸出精度:
    以MPU6050加速度測量值爲例:量程是±8g時,測量精度是4096LSB/g,
    LSB的意思是最小有效位,爲數字輸出方式下使用;
    一般我們可以用mg/LSB來表示G-Sensor靈敏度,例如:mpu6050輸出的位數爲16位(2的16次方共65536個LSB)對應滿量程,當量程爲±2g時對應靈敏度就爲4g/65536LSB=0.06103515625mg/LSB,取倒數爲16384LSB/g。所以我們可以看到mpu605X寄存器手冊中的accelerometers' sensitivity per LSB in ACCEL_xOUT:

    因爲mpu6050只能16位輸出,所以測量範圍越大,對應精度就越低。上面表格的數據存在一個規律,即:
    Full Scalse Range * LSB Sensitivity = 32768

三、基礎使用:
以下實例實現 Arduino uno 與 MPU6050 的 IIC 通信,並通過 Arduino 與 PC 機的串口通訊將 MPU6050 的測量值打印在Arduino IDE 的串口監視器上。實例中未使用中斷功能。讀取的數據只經過單位的轉換,未做其他數據處理(如果要應用在項目上,可能要對原始數據進行濾波處理、數學演算等,才能給程序使用。)
//連線方法
//MPU-UNO
//VCC-5V
//GND-GND
//SCL-A5
//SDA-A4
//ADO-GND
//未使用中斷功能,即沒有做 INT-digital pin 2 (interrupt pin 0) 這樣的接線

//參考手冊:MPU-6000 and MPU-6050 Register Map and Descriptions Revision 4.2

#include <Wire.h>

long accelX, accelY, accelZ;      // 定義爲全局變量,可直接在函數內部使用
float gForceX, gForceY, gForceZ;

long gyroX, gyroY, gyroZ;
float rotX, rotY, rotZ;

void setup() {
  Serial.begin(9600);
  Wire.begin();
  setupMPU();
}

void loop() {
  recordAccelRegisters();
  recordGyroRegisters();
  printData();
  delay(100);
}

void setupMPU(){
  // REGISTER 0x6B/REGISTER 107:Power Management 1
  Wire.beginTransmission(0b1101000); //This is the I2C address of the MPU (b1101000/b1101001 for AC0 low/high datasheet Sec. 9.2)
  Wire.write(0x6B); //Accessing the register 6B/107 - Power Management (Sec. 4.30) 
  Wire.write(0b00000000); //Setting SLEEP register to 0, using the internal 8 Mhz oscillator
  Wire.endTransmission();

  // REGISTER 0x1b/REGISTER 27:Gyroscope Configuration
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x1B); //Accessing the register 1B - Gyroscope Configuration (Sec. 4.4) 
  Wire.write(0x00000000); //Setting the gyro to full scale +/- 250deg./s (轉化爲rpm:250/360 * 60 = 41.67rpm) 最高可以轉化爲2000deg./s 
  Wire.endTransmission();
  
  // REGISTER 0x1C/REGISTER 28:ACCELEROMETER CONFIGURATION
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x1C); //Accessing the register 1C - Acccelerometer Configuration (Sec. 4.5) 
  Wire.write(0b00000000); //Setting the accel to +/- 2g(if choose +/- 16g,the value would be 0b00011000)
  Wire.endTransmission(); 
}

void recordAccelRegisters() {
  // REGISTER 0x3B~0x40/REGISTER 59~64
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x3B); //Starting register for Accel Readings
  Wire.endTransmission();
  Wire.requestFrom(0b1101000,6); //Request Accel Registers (3B - 40)

  // 使用了左移<<和位運算|。Wire.read()一次讀取1bytes,並在下一次調用時自動讀取下一個地址的數據
  while(Wire.available() < 6);  // Waiting for all the 6 bytes data to be sent from the slave machine (必須等待所有數據存儲到緩衝區後才能讀取) 
  accelX = Wire.read()<<8|Wire.read(); //Store first two bytes into accelX (自動存儲爲定義的long型值)
  accelY = Wire.read()<<8|Wire.read(); //Store middle two bytes into accelY
  accelZ = Wire.read()<<8|Wire.read(); //Store last two bytes into accelZ
  processAccelData();
}

void processAccelData(){
  gForceX = accelX / 16384.0;     //float = long / float
  gForceY = accelY / 16384.0; 
  gForceZ = accelZ / 16384.0;
}

void recordGyroRegisters() {
  // REGISTER 0x43~0x48/REGISTER 67~72
  Wire.beginTransmission(0b1101000); //I2C address of the MPU
  Wire.write(0x43); //Starting register for Gyro Readings
  Wire.endTransmission();
  Wire.requestFrom(0b1101000,6); //Request Gyro Registers (43 ~ 48)
  while(Wire.available() < 6);
  gyroX = Wire.read()<<8|Wire.read(); //Store first two bytes into accelX
  gyroY = Wire.read()<<8|Wire.read(); //Store middle two bytes into accelY
  gyroZ = Wire.read()<<8|Wire.read(); //Store last two bytes into accelZ
  processGyroData();
}

void processGyroData() {
  rotX = gyroX / 131.0;
  rotY = gyroY / 131.0; 
  rotZ = gyroZ / 131.0;
}

void printData() {
  Serial.print("Gyro (deg)");
  Serial.print(" X=");
  Serial.print(rotX);
  Serial.print(" Y=");
  Serial.print(rotY);
  Serial.print(" Z=");
  Serial.print(rotZ);
  Serial.print(" Accel (g)");
  Serial.print(" X=");
  Serial.print(gForceX);
  Serial.print(" Y=");
  Serial.print(gForceY);
  Serial.print(" Z=");
  Serial.println(gForceZ);
}
代碼中相關設置的依據以及使用的寄存器: 
1)MPU6050的IIC地址:

2)電源管理寄存器:

3)陀螺儀配置:

4)加速度計配置:

5)加速度計測量值:

6)陀螺儀測量值:

三、簡單應用:


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章