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

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];
}
 

TRẦN MINH QUANG

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];
}
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
 

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ì?
 

TRẦN MINH QUANG

Thành Viên PIF
Chào bạn Quang,
- 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ì?
-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?
 

hoangthien94

Ban Chủ Nhiệm
-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?
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:
 

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
 

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
 

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
 
Top