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
mpu6050.c
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
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];
}