Hướng dẫn đọc dữ liệu từ MPU6050 với Tiva C M4

Discussion in 'Sensors' started by AnNguyen, Jul 16, 2015.

  1. AnNguyen

    AnNguyen Thành Viên PIF

    Tạo 2 file có tên là mpu6050.h và mpu6050.c với nội dung như sau, rồi include nó vô project.

    Tóm tắt: Đọc dữ liệu từ cảm biến accelerometer và Gyro trên module MPU6050, qua giao thức I2C.
    Các hàm sẽ sử dụng được defined trong file .h

    mpu6050.h

    Code:
    #ifndef __i2c_h__
    #define __i2c_h__
     
    #ifdef __cplusplus
    extern "C" {
    #endif
     
    void initI2C(void);
    void i2cWrite(uint8_t addr, uint8_t regAddr, uint8_t data);
    void i2cWriteData(uint8_t addr, uint8_t regAddr, uint8_t *date, uint8_t length);
    uint8_t i2cRead(uint8_t addr, uint8_t regAddr);
    void i2cReadData(uint8_t addr, uint8_t regAddr, uint8_t *data, uint8_t length);
    void initMPU6050(void);
    void getMPU6050Data(void);
    #ifdef __cplusplus
    }
    #endif
     
    #endif
    
    mpu6050.c

    Code:
    #include <stdint.h>
    #include <stdbool.h>
     
    #include "I2C.h"
     
    #include "inc/hw_memmap.h"
    #include "driverlib/gpio.h"
    #include "driverlib/pin_map.h"
    #include "driverlib/i2c.h"
    #include "driverlib/sysctl.h"
     
    #define MPU6050_SMPLRT_DIV                  0x19
    #define MPU6050_INT_PIN_CFG                 0x37
    #define MPU6050_ACCEL_XOUT_H                0x3B
    #define MPU6050_GYRO_XOUT_H                 0x43
    #define MPU6050_PWR_MGMT_1                  0x6B
    #define MPU6050_WHO_AM_I                    0x75
     
    #define MPU6050_ADDRESS                     0x68
    #define MPU6050_WHO_AM_I_ID                 0x68
     
    // Scale factor for +-2000deg/s and +-8g - see datasheet: 
    #define MPU6050_GYRO_SCALE_FACTOR_2000      16.4f
    #define MPU6050_ACC_SCALE_FACTOR_8          4096.0f
     
    void initI2C(void) {
        SysCtlPeripheralEnable(SYSCTL_PERIPH_I2C1); // Enable I2C1 peripheral
        SysCtlDelay(2); // Insert a few cycles after enabling the peripheral to allow the clock to be fully activated
        SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); // Enable GPIOA peripheral
        SysCtlDelay(2); // Insert a few cycles after enabling the peripheral to allow the clock to be fully activated
     
        // Use alternate function
        GPIOPinConfigure(GPIO_PA6_I2C1SCL);
        GPIOPinConfigure(GPIO_PA7_I2C1SDA);
     
        GPIOPinTypeI2CSCL(GPIO_PORTA_BASE, GPIO_PIN_6); // Use pin with I2C SCL peripheral
        GPIOPinTypeI2C(GPIO_PORTA_BASE, GPIO_PIN_7); // Use pin with I2C peripheral
     
        I2CMasterInitExpClk(I2C1_BASE, SysCtlClockGet(), true); // Enable and set frequency to 400 kHz
     
        SysCtlDelay(2); // Insert a few cycles after enabling the I2C to allow the clock to be fully activated
    }
     
    void i2cWrite(uint8_t addr, uint8_t regAddr, uint8_t data) {
        i2cWriteData(addr, regAddr, &data, 1);
    }
     
    void i2cWriteData(uint8_t addr, uint8_t regAddr, uint8_t *data, uint8_t length) {
        I2CMasterSlaveAddrSet(I2C1_BASE, addr, false); // Set to write mode
     
        I2CMasterDataPut(I2C1_BASE, regAddr); // Place address into data register
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_START); // Send start condition
        while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
        uint8_t i = 0;
        for (i = 0; i < length - 1; i++) {
            I2CMasterDataPut(I2C1_BASE, data[i]); // Place data into data register
            I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_CONT); // Send continues condition
            while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
        }
     
        I2CMasterDataPut(I2C1_BASE, data[length - 1]); // Place data into data register
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_SEND_FINISH); // Send finish condition
        while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
    }
     
    uint8_t i2cRead(uint8_t addr, uint8_t regAddr) {
        I2CMasterSlaveAddrSet(I2C1_BASE, addr, false); // Set to write mode
     
        I2CMasterDataPut(I2C1_BASE, regAddr); // Place address into data register
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_SEND); // Send data
        while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
     
        I2CMasterSlaveAddrSet(I2C1_BASE, addr, true); // Set to read mode
     
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_RECEIVE); // Tell master to read data
        while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
        return I2CMasterDataGet(I2C1_BASE); // Read data
    }
     
    void i2cReadData(uint8_t addr, uint8_t regAddr, uint8_t *data, uint8_t length) {
        I2CMasterSlaveAddrSet(I2C1_BASE, addr, false); // Set to write mode
     
        I2CMasterDataPut(I2C1_BASE, regAddr); // Place address into data register
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_SINGLE_SEND); // Send data
        while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
     
        I2CMasterSlaveAddrSet(I2C1_BASE, addr, true); // Set to read mode
     
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_RECEIVE_START); // Send start condition
        while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
        data[0] = I2CMasterDataGet(I2C1_BASE); // Place data into data register
        uint8_t i = 1;
        for (i = 1; i < length - 1; i++) {
            I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_RECEIVE_CONT); // Send continues condition
            while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
            data[i] = I2CMasterDataGet(I2C1_BASE); // Place data into data register
        }
     
        I2CMasterControl(I2C1_BASE, I2C_MASTER_CMD_BURST_RECEIVE_FINISH); // Send finish condition
        while (I2CMasterBusy(I2C1_BASE)); // Wait until transfer is done
        data[length - 1] = I2CMasterDataGet(I2C1_BASE); // Place data into data register
    }
    void initMPU6050(void) {
    uint8_t i2cBuffer[5]; // Buffer for I2C data
    i2cBuffer[0] = i2cRead(MPU6050_ADDRESS, MPU6050_WHO_AM_I);
    i2cWrite(MPU6050_ADDRESS, MPU6050_PWR_MGMT_1, (1 << 7)); // Reset device, this resets all internal registers to their default values
    SysCtlDelay(SysCtlClockGet()/100);
    while (i2cRead(MPU6050_ADDRESS, MPU6050_PWR_MGMT_1) & (1 << 7)) {
    // Wait for the bit to clear
    };
    SysCtlDelay(SysCtlClockGet()/100);
    i2cWrite(MPU6050_ADDRESS, MPU6050_PWR_MGMT_1, (1 << 3) | (1 << 0)); // Disable sleep mode, disable temperature sensor and use PLL as clock reference
     
    i2cBuffer[0] = 0; // Set the sample rate to 1kHz - 1kHz/(1+0) = 1kHz
    i2cBuffer[1] = 0x03; // Disable FSYNC and set 41 Hz Gyro filtering, 1 KHz sampling
    i2cBuffer[2] = 3 << 3; // Set Gyro Full Scale Range to +-2000deg/s
    i2cBuffer[3] = 2 << 3; // Set Accelerometer Full Scale Range to +-8g
    i2cBuffer[4] = 0x03; // 41 Hz Acc filtering
    i2cWriteData(MPU6050_ADDRESS, MPU6050_SMPLRT_DIV, i2cBuffer, 5); // Write to all five registers at once
     
     
    /* Enable Raw Data Ready Interrupt on INT pin */
    i2cBuffer[0] = (1 << 5) | (1 << 4); // Enable LATCH_INT_EN and INT_ANYRD_2CLEAR
    // When this bit is equal to 1, the INT pin is held high until the interrupt is cleared
    // When this bit is equal to 1, interrupt status is cleared if any read operation is performed
    i2cBuffer[1] = (1 << 0);            // Enable RAW_RDY_EN - When set to 1, Enable Raw Sensor Data Ready interrupt to propagate to interrupt pin
    i2cWriteData(MPU6050_ADDRESS, MPU6050_INT_PIN_CFG, i2cBuffer, 2); // Write to both registers at once
     
    }
    void getMPU6050Data(void) {
    uint8_t buf[14];
    i2cReadData(MPU6050_ADDRESS, MPU6050_ACCEL_XOUT_H, buf, 14); // Note that we can't write directly into MPU6050_t, because of endian conflict. So it has to be done manually
     
    accaxisX = (buf[0] << 8) | buf[1];
    accaxisY = (buf[2] << 8) | buf[3];
    accaxisZ = (buf[4] << 8) | buf[5];
     
    gyroaxisX = (buf[8] << 8) | buf[9];
    gyroaxisY = (buf[10] << 8) | buf[11];
    gyroaxisZ = (buf[12] << 8) | buf[13];
    }
    
     
  2. TRẦN MINH QUANG

    TRẦN MINH QUANG Thành Viên PIF

    anh cho em hỏi, em dùng thư viện như hình rồi em vào kiểm tra giá trị các trục quay thì hiện tất cả các trục là 0, ko thay đổi gì hết, lúc đầu nó bị lỗi undefined các biến accaxisX,..., e có khai bào nó kiểu int mà không được, anh giúp em với :((
    aaaaaaa.png
     
  3. hoangthien94

    hoangthien94 Ban Chủ Nhiệm

    Chào bạn Quang,
    - Không biết kết nối phần cứng của bạn như thế nào? Bạn có chắc là I2C bạn đã config đúng ko?
    - Các biến accaxisX, accaxisY, accaxisZ, gyroaxisX, gyroaxisY, gyroaxisZ bạn khai báo ở file nào, có khai báo kiểu extern không?
    - Không rõ hình bạn up lên có phải code của bạn bị lỗi không, nhưng trong while(1) bạn làm gì?
     
    2death and TRẦN MINH QUANG like this.
  4. TRẦN MINH QUANG

    TRẦN MINH QUANG Thành Viên PIF

    -Minh đọc được r, do không để hàm getMPU trong while. Cám ơn hoangthien94 :).
    -Mình khai báo trong file MPU6050.c á, mà tại sao phải khai báo kiểu extern v hoangthien94? mình khai báo int dữ liệu thu được có sai ko?
     
  5. hoangthien94

    hoangthien94 Ban Chủ Nhiệm

    Bạn thử truy xuất các biến accaxisX, accaxisY, accaxisZ, gyroaxisX, gyroaxisY, gyroaxisZ trong hàm main.c xem, bạn sẽ tự thấy vấn đề thôi :1cool_byebye:
     
    2death and TRẦN MINH QUANG like this.
  6. TRẦN MINH QUANG

    TRẦN MINH QUANG Thành Viên PIF

    -Mình hiểu rồi, Cám ơn hoangthien94. :D
     
    2death likes this.
  7. anhdeptrai

    anhdeptrai Trứng gà

    có ai làm con MPU6050 nay với arm cortex M0 của NXP chưa cuk thể là kit LPC11U68
    XIN CHỈ GIÁO
     
  8. phamdangkhoa2911

    phamdangkhoa2911 Trứng gà

    Hi mọi người, mình đang nghiên cứu về mpu6050, mình có thử sử dụng thư viện trên nhưng các giá trị mình đọc được đều bằng 0.
    Phần cứng mình kết nối theo như code, mình sử dụng điện trở 4.7k nối nguồn 3.3v làm pull-up liệu không biết đúng ko?
    Trong hàm main mình khai báo giống trong hình không biết đã đúng chưa nữa? Mọi người chỉ giáo cho mình với :D thank mọi người
     
  9. phamdangkhoa2911

    phamdangkhoa2911 Trứng gà

    Xin lỗi mình quên kèm hình :gach
    [​IMG]
     
  10. thienbk14

    thienbk14 Thành Viên PIF

    muốn tính góc nghiêng thì tính thế nào vậy anh
     
  11. hoangphuoc

    hoangphuoc Thành Viên PIF

    Đang bị giống và chưa biết phải sửa thế nào @@
     
  12. trunghieu96nt

    trunghieu96nt Thành Viên PIF

    +Bạn/Anh thử thêm extern trước khai báo biến int32_t .... Với lại kiểm tra lại hàm initI2C với initMPU6050 đã đúng chưa
     
    hoangphuoc likes this.
  13. hoangphuoc

    hoangphuoc Thành Viên PIF

    Thanks nhé. Mình sửa được rồi
     
  14. Minh Vũ

    Minh Vũ Thành Viên PIF

    Code:
    i2cBuffer[2] = 3 << 3; // Set Gyro Full Scale Range to +-2000deg/s
    i2cBuffer[3] = 2 << 3; // Set Accelerometer Full Scale Range to +-8g 
    Anh cho em hỏi về 2 dòng trên, thường là em thấy là muốn đổi bit của thanh ghi là 1<<bit hay 0<<bit. Còn ghi kiểu như anh em chưa gặp. giờ em muốn config accel là 4g thì có phải là
    Code:
    i2cBuffer[3] = 1 <<3;  
    đúng không ạ?

    Trong datasheet của MPU6050 thì bit1 ứng với 4g; bit2 ứng với 8g
     
Loading...

Share This Page