今日主要學習一款傾角傳感器——MPU6050,往后對單片機原理基礎講的會比較少,更傾向于簡單粗暴地貼代碼,因為經過前些日子對MSP432的學習,對原理方面也有些熟絡了,除了在新接觸它時會對其引腳、時鐘、總線等進行仔細一些的研究之外,其余驅動方面便是照搬經驗了~~
本文嘗試使用STM32 F103C8T6通過IIC通信驅動MPU6050,文章提供源碼、原理講解、實踐操作與結果截圖,測試工程下載。
目錄
MPU6050
使用注意點:
?程序設計目標:
移植IIC通信:
編寫IIC與MPU6050的通信:
向MPU6050寄存器寫數據:
讀取MPU6050寄存器數據:
MPU6050地址:
MPU6050初始化:
MPU6050數據讀取處理:
MPU6050濾波一階互補:
主函數代碼:
MPU6050
下圖為MPU6050:
?MPU6050是由三個陀螺儀和三個加速度傳感器組成的6軸運動處理組件,是一款六軸(三軸加速度+三軸角速度(陀螺儀))傳感器
1. VCC:構成8位的IIC地址模塊自帶了 3.3V 超低壓差穩壓芯片,給 MPU6050 供電,因此外部供電可以選擇:3.3V / 5V 都可以
2.GND:不多說
3.SCL、SDA:IIC通訊引腳
另外,IIC_SDA 和 IIC_SCL 帶了 4.7K上拉電阻,外部可以不用再加上拉電阻了
4.XDA、XCL:XDA 跟 XCl是用來外接電磁傳感器,即使模塊不動,數值也會有波動。而外加電磁傳感器就是更好的解決這一問題。
5.AD0:?AD0 是從 IIC 接口(接 MCU)的地址控制引腳,該引腳控制IIC 地址的最低位。如果接?GND,則 MPU6050 的 IIC 地址是:0X68,如果接 VDD,則是0X69。另外,MPU_AD0 自帶了 10K 下拉電阻,當 AD0懸空時,默認 IIC 地址為(0X68)。?
?6.INT:在MPU6050 中有個INT 引腳,每當MPU6050 有數據輸出時,引腳INT 有相應的電平變化。可以將其觸發外部中斷作為控制周期。當MPU6050 的讀取一次數據,就控制一次,可以很好地保持MPU6050 數據的實時性。
使用注意點:
1.不用觸碰MPU6050芯片的表面,實測會使其卡住,我遇到這問題是需要給單片機重新下載程序才能解決。
2.AD0腳可以懸空也可接VCC\GND,這三種接法情況會導致MPU6050的地址變化,我是懸空的。
3.本文用到include "math.h"的庫函數:?double atan2? (double y???? , double x);編譯報錯警告時注意添加頭文件~
?程序設計目標:
有關于MPU6050地址,寄存器讀取,寄存器寫入方面的一些知識,我們就在程序設計實踐中一起講了~~
此次程序設計目標簡單,是IIC 讀取MPU6050的角度值,用串口1每隔1S向上位機反饋:
移植IIC通信:
首先是移植IIC軟件模擬時序、IIC引腳初始化的代碼,這里直接貼出:此處我初始化了PA2 和 PA3為通信端口:該IIC代碼是從他處移植的~? IIC基本原理不多加介紹:
#include "bsp_i2c.h"/* 定義I2C總線連接的GPIO端口, 用戶只需要修改下面4行代碼即可任意改變SCL和SDA的引腳 */
#define GPIO_PORT_I2C GPIOA /* GPIO端口 */
#define RCC_I2C_PORT RCC_APB2Periph_GPIOA /* GPIO端口時鐘 */
#define I2C_SCL_PIN GPIO_Pin_2 /* 連接到SCL時鐘線的GPIO */
#define I2C_SDA_PIN GPIO_Pin_3 /* 連接到SDA數據線的GPIO *//* 定義讀寫SCL和SDA的宏,已增加代碼的可移植性和可閱讀性 */
#if 0 /* 條件編譯: 1 選擇GPIO的庫函數實現IO讀寫 */#define I2C_SCL_1() GPIO_SetBits(GPIO_PORT_I2C, I2C_SCL_PIN) /* SCL = 1 */#define I2C_SCL_0() GPIO_ResetBits(GPIO_PORT_I2C, I2C_SCL_PIN) /* SCL = 0 */#define I2C_SDA_1() GPIO_SetBits(GPIO_PORT_I2C, I2C_SDA_PIN) /* SDA = 1 */#define I2C_SDA_0() GPIO_ResetBits(GPIO_PORT_I2C, I2C_SDA_PIN) /* SDA = 0 */#define I2C_SDA_READ() GPIO_ReadInputDataBit(GPIO_PORT_I2C, I2C_SDA_PIN) /* 讀SDA口線狀態 */
#else /* 這個分支選擇直接寄存器操作實現IO讀寫 *//* 注意:如下寫法,在IAR最高級別優化時,會被編譯器錯誤優化 */#define I2C_SCL_1() GPIO_PORT_I2C->BSRR = I2C_SCL_PIN /* SCL = 1 */#define I2C_SCL_0() GPIO_PORT_I2C->BRR = I2C_SCL_PIN /* SCL = 0 */#define I2C_SDA_1() GPIO_PORT_I2C->BSRR = I2C_SDA_PIN /* SDA = 1 */#define I2C_SDA_0() GPIO_PORT_I2C->BRR = I2C_SDA_PIN /* SDA = 0 */#define I2C_SDA_READ() ((GPIO_PORT_I2C->IDR & I2C_SDA_PIN) != 0) /* 讀SDA口線狀態 */
#endifvoid i2c_GPIO_Config(void);/*
*********************************************************************************************************
* 函 數 名: i2c_Delay
* 功能說明: I2C總線位延遲,最快400KHz
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
static void i2c_Delay(void)
{uint8_t i;/* 下面的時間是通過安富萊AX-Pro邏輯分析儀測試得到的。CPU主頻72MHz時,在內部Flash運行, MDK工程不優化循環次數為10時,SCL頻率 = 205KHz 循環次數為7時,SCL頻率 = 347KHz, SCL高電平時間1.5us,SCL低電平時間2.87us 循環次數為5時,SCL頻率 = 421KHz, SCL高電平時間1.25us,SCL低電平時間2.375us IAR工程編譯效率高,不能設置為7*/for (i = 0; i < 10; i++);
}/*
*********************************************************************************************************
* 函 數 名: i2c_Start
* 功能說明: CPU發起I2C總線啟動信號
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void i2c_Start(void)
{/* 當SCL高電平時,SDA出現一個下跳沿表示I2C總線啟動信號 */I2C_SDA_1();I2C_SCL_1();i2c_Delay();I2C_SDA_0();i2c_Delay();I2C_SCL_0();i2c_Delay();
}/*
*********************************************************************************************************
* 函 數 名: i2c_Start
* 功能說明: CPU發起I2C總線停止信號
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void i2c_Stop(void)
{/* 當SCL高電平時,SDA出現一個上跳沿表示I2C總線停止信號 */I2C_SDA_0();I2C_SCL_1();i2c_Delay();I2C_SDA_1();
}/*
*********************************************************************************************************
* 函 數 名: i2c_SendByte
* 功能說明: CPU向I2C總線設備發送8bit數據
* 形 參:_ucByte : 等待發送的字節
* 返 回 值: 無
*********************************************************************************************************
*/
void i2c_SendByte(uint8_t _ucByte)
{uint8_t i;/* 先發送字節的高位bit7 */for (i = 0; i < 8; i++){ if (_ucByte & 0x80){I2C_SDA_1();}else{I2C_SDA_0();}i2c_Delay();I2C_SCL_1();i2c_Delay(); I2C_SCL_0();if (i == 7){I2C_SDA_1(); // 釋放總線}_ucByte <<= 1; /* 左移一個bit */i2c_Delay();}
}/*
*********************************************************************************************************
* 函 數 名: i2c_ReadByte
* 功能說明: CPU從I2C總線設備讀取8bit數據
* 形 參:無
* 返 回 值: 讀到的數據
*********************************************************************************************************
*/
uint8_t i2c_ReadByte(u8 ack)
{uint8_t i;uint8_t value;/* 讀到第1個bit為數據的bit7 */value = 0;for (i = 0; i < 8; i++){value <<= 1;I2C_SCL_1();i2c_Delay();if (I2C_SDA_READ()){value++;}I2C_SCL_0();i2c_Delay();}if(ack==0)i2c_NAck();elsei2c_Ack();return value;
}/*
*********************************************************************************************************
* 函 數 名: i2c_WaitAck
* 功能說明: CPU產生一個時鐘,并讀取器件的ACK應答信號
* 形 參:無
* 返 回 值: 返回0表示正確應答,1表示無器件響應
*********************************************************************************************************
*/
uint8_t i2c_WaitAck(void)
{uint8_t re;I2C_SDA_1(); /* CPU釋放SDA總線 */i2c_Delay();I2C_SCL_1(); /* CPU驅動SCL = 1, 此時器件會返回ACK應答 */i2c_Delay();if (I2C_SDA_READ()) /* CPU讀取SDA口線狀態 */{re = 1;}else{re = 0;}I2C_SCL_0();i2c_Delay();return re;
}/*
*********************************************************************************************************
* 函 數 名: i2c_Ack
* 功能說明: CPU產生一個ACK信號
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void i2c_Ack(void)
{I2C_SDA_0(); /* CPU驅動SDA = 0 */i2c_Delay();I2C_SCL_1(); /* CPU產生1個時鐘 */i2c_Delay();I2C_SCL_0();i2c_Delay();I2C_SDA_1(); /* CPU釋放SDA總線 */
}/*
*********************************************************************************************************
* 函 數 名: i2c_NAck
* 功能說明: CPU產生1個NACK信號
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void i2c_NAck(void)
{I2C_SDA_1(); /* CPU驅動SDA = 1 */i2c_Delay();I2C_SCL_1(); /* CPU產生1個時鐘 */i2c_Delay();I2C_SCL_0();i2c_Delay();
}/*
*********************************************************************************************************
* 函 數 名: i2c_GPIO_Config
* 功能說明: 配置I2C總線的GPIO,采用模擬IO的方式實現
* 形 參:無
* 返 回 值: 無
*********************************************************************************************************
*/
void i2c_GPIO_Config(void)
{GPIO_InitTypeDef GPIO_InitStructure;RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE); /* 打開GPIO時鐘 */GPIO_InitStructure.GPIO_Pin = I2C_SCL_PIN | I2C_SDA_PIN;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD; /* 開漏輸出 */GPIO_Init(GPIO_PORT_I2C, &GPIO_InitStructure);/* 給一個停止信號, 復位I2C總線上的所有設備到待機模式 */i2c_Stop();
}/*
*********************************************************************************************************
* 函 數 名: i2c_CheckDevice
* 功能說明: 檢測I2C總線設備,CPU向發送設備地址,然后讀取設備應答來判斷該設備是否存在
* 形 參:_Address:設備的I2C總線地址
* 返 回 值: 返回值 0 表示正確, 返回1表示未探測到
*********************************************************************************************************
*/
uint8_t i2c_CheckDevice(uint8_t _Address)
{uint8_t ucAck;i2c_GPIO_Config(); /* 配置GPIO */i2c_Start(); /* 發送啟動信號 *//* 發送設備地址+讀寫控制bit(0 = w, 1 = r) bit7 先傳 */i2c_SendByte(_Address|I2C_WR);ucAck = i2c_WaitAck(); /* 檢測設備的ACK應答 */i2c_Stop(); /* 發送停止信號 */return ucAck;
}
#ifndef _BSP_I2C_H
#define _BSP_I2C_H#include <inttypes.h>
#include "stm32f10x.h"#define I2C_WR 0 /* 寫控制bit */
#define I2C_RD 1 /* 讀控制bit */void i2c_Start(void);
void i2c_Stop(void);
void i2c_SendByte(uint8_t _ucByte);
uint8_t i2c_ReadByte(uint8_t ack);
uint8_t i2c_WaitAck(void);
void i2c_Ack(void);
void i2c_NAck(void);
uint8_t i2c_CheckDevice(uint8_t _Address);
void i2c_GPIO_Config(void);#endif
編寫IIC與MPU6050的通信:
向MPU6050寄存器寫數據:
//模塊的A0引腳接GND,IIC的7位地址為0x68,若接到VCC,需要改為0x69
#define MPU6050_SLAVE_ADDRESS (0x68<<1) //MPU6050器件讀地址//add 是地址
//dat 是數據
void MPU6050_WriteReg(u8 reg_add,u8 reg_dat)
{i2c_Start();i2c_SendByte(MPU6050_SLAVE_ADDRESS);i2c_WaitAck();i2c_SendByte(reg_add);i2c_WaitAck();i2c_SendByte(reg_dat);i2c_WaitAck();i2c_Stop();
}
讀取MPU6050寄存器數據:
//reg_add是地址
//char*Read 表示傳入一個定義好的數組去接收
//num表示接收的位數void MPU6050_ReadData(u8 reg_add,unsigned char*Read,u8 num)
{unsigned char i;i2c_Start();i2c_SendByte(MPU6050_SLAVE_ADDRESS);i2c_WaitAck();i2c_SendByte(reg_add);i2c_WaitAck();i2c_Start();i2c_SendByte(MPU6050_SLAVE_ADDRESS+1);i2c_WaitAck();for(i=0;i<(num-1);i++){*Read=i2c_ReadByte(1);Read++;}*Read=i2c_ReadByte(0);i2c_Stop();
}
MPU6050地址:
此處我翻譯了部分地址,進行宏定義
//模塊的A0引腳接GND,IIC的7位地址為0x68,若接到VCC,需要改為0x69
#define MPU6050_SLAVE_ADDRESS (0x68<<1) //MPU6050器件讀地址#define MPU6050_WHO_AM_I 0x75 //用于驗證設備是否正常連接。
#define MPU6050_SMPLRT_DIV 0 //是采樣率分頻器的寄存器。對其進行配置可以設置采樣率,這里設置為8000Hz。
#define MPU6050_DLPF_CFG 0 //數字低通濾波器的寄存器。對其進行配置可以設置陀螺儀和加速度計的濾波參數,這里設置為0表示不濾波。
#define MPU6050_GYRO_OUT 0x43 //MPU6050陀螺儀數據寄存器地址
#define MPU6050_ACC_OUT 0x3B //MPU6050加速度數據寄存器地址//MPU6050 的兩個可能的器件地址。AD0 引腳的狀態決定了使用哪個地址,低電平表示使用 `MPU6050_ADDRESS_AD0_LOW`。
#define MPU6050_ADDRESS_AD0_LOW 0x68 // address pin low (GND), default for InvenSense evaluation board
#define MPU6050_ADDRESS_AD0_HIGH 0x69 // address pin high (VCC)
#define MPU6050_DEFAULT_ADDRESS MPU6050_ADDRESS_AD0_LOW#define MPU6050_RA_XG_OFFS_TC 0x00 //[7] PWR_MODE, [6:1] XG_OFFS_TC, [0] OTP_BNK_VLD X軸陀螺儀偏移溫度補償寄存器
#define MPU6050_RA_YG_OFFS_TC 0x01 //[7] PWR_MODE, [6:1] YG_OFFS_TC, [0] OTP_BNK_VLD Y軸陀螺儀偏移溫度補償寄存器
#define MPU6050_RA_ZG_OFFS_TC 0x02 //[7] PWR_MODE, [6:1] ZG_OFFS_TC, [0] OTP_BNK_VLD Z軸陀螺儀偏移溫度補償寄存器#define MPU6050_RA_X_FINE_GAIN 0x03 //[7:0] X_FINE_GAIN X軸加速度計校準增益寄存器
#define MPU6050_RA_Y_FINE_GAIN 0x04 //[7:0] Y_FINE_GAIN Y軸加速度計校準增益寄存器
#define MPU6050_RA_Z_FINE_GAIN 0x05 //[7:0] Z_FINE_GAIN Z軸加速度計校準增益寄存器#define MPU6050_RA_XA_OFFS_H 0x06 //[15:0] XA_OFFS X軸加速度計偏移高位寄存器
#define MPU6050_RA_XA_OFFS_L_TC 0x07 //X軸加速度計偏移低位寄存器
#define MPU6050_RA_YA_OFFS_H 0x08 //[15:0] YA_OFFS Y軸加速度計偏移高位寄存器
#define MPU6050_RA_YA_OFFS_L_TC 0x09 //Y軸加速度計偏移低位寄存器
#define MPU6050_RA_ZA_OFFS_H 0x0A //[15:0] ZA_OFFS Z軸加速度計偏移高位寄存器
#define MPU6050_RA_ZA_OFFS_L_TC 0x0B //Z軸加速度計偏移低位寄存器#define MPU6050_RA_XG_OFFS_USRH 0x13 //[15:0] XG_OFFS_USR X軸陀螺儀用戶偏移高位寄存器
#define MPU6050_RA_XG_OFFS_USRL 0x14 //X軸陀螺儀用戶偏移低位寄存器
#define MPU6050_RA_YG_OFFS_USRH 0x15 //[15:0] YG_OFFS_USR Y軸陀螺儀用戶偏移高位寄存器
#define MPU6050_RA_YG_OFFS_USRL 0x16 //Y軸陀螺儀用戶偏移低位寄存器
#define MPU6050_RA_ZG_OFFS_USRH 0x17 //[15:0] ZG_OFFS_USR Z軸陀螺儀用戶偏移高位寄存器
#define MPU6050_RA_ZG_OFFS_USRL 0x18 //Z軸陀螺儀用戶偏移低位寄存器。#define MPU6050_RA_SMPLRT_DIV 0x19 //設置采樣率除數,用于控制采樣率的頻率。
#define MPU6050_RA_CONFIG 0x1A //配置加速度計和陀螺儀的低通濾波器和同步采樣率
#define MPU6050_RA_GYRO_CONFIG 0x1B //配置陀螺儀的測量范圍和自檢
#define MPU6050_RA_ACCEL_CONFIG 0x1C //配置加速度計的測量范圍和自檢
#define MPU6050_RA_FF_THR 0x1D //雙向運動檢測的自由落體閾值
#define MPU6050_RA_FF_DUR 0x1E //雙向運動檢測的自由落體持續時間
#define MPU6050_RA_MOT_THR 0x1F //單向運動檢測的運動閾值
#define MPU6050_RA_MOT_DUR 0x20 //單向運動檢測的運動持續時間
#define MPU6050_RA_ZRMOT_THR 0x21 //零運動檢測的運動閾值
#define MPU6050_RA_ZRMOT_DUR 0x22 //零運動檢測的運動持續時間
#define MPU6050_RA_FIFO_EN 0x23 //FIFO緩沖區的數據輸出使能#define MPU6050_RA_I2C_MST_CTRL 0x24 //I2C主控制器的配置
#define MPU6050_RA_I2C_SLV0_ADDR 0x25 //I2C從設備0的地址
#define MPU6050_RA_I2C_SLV0_REG 0x26 //I2C從設備0的寄存器地址
#define MPU6050_RA_I2C_SLV0_CTRL 0x27 //I2C從設備0的控制設置
#define MPU6050_RA_I2C_SLV1_ADDR 0x28 //I2C從設備1的地址
#define MPU6050_RA_I2C_SLV1_REG 0x29 //I2C從設備1的寄存器地址
#define MPU6050_RA_I2C_SLV1_CTRL 0x2A //I2C從設備1的控制設置
#define MPU6050_RA_I2C_SLV2_ADDR 0x2B //I2C從設備2的地址
#define MPU6050_RA_I2C_SLV2_REG 0x2C //I2C從設備2的寄存器地址
#define MPU6050_RA_I2C_SLV2_CTRL 0x2D //I2C從設備2的控制設置
#define MPU6050_RA_I2C_SLV3_ADDR 0x2E //I2C從設備3的地址
#define MPU6050_RA_I2C_SLV3_REG 0x2F //I2C從設備3的寄存器地址
#define MPU6050_RA_I2C_SLV3_CTRL 0x30 //I2C從設備3的控制設置
#define MPU6050_RA_I2C_SLV4_ADDR 0x31 //I2C從設備4的地址
#define MPU6050_RA_I2C_SLV4_REG 0x32 //I2C從設備4的寄存器地址
#define MPU6050_RA_I2C_SLV4_DO 0x33 //I2C從設備4的寫數據
#define MPU6050_RA_I2C_SLV4_CTRL 0x34 //I2C從設備4的控制設置
#define MPU6050_RA_I2C_SLV4_DI 0x35 //I2C從設備4的讀數據
#define MPU6050_RA_I2C_MST_STATUS 0x36 //I2C主機狀態寄存器#define MPU6050_RA_INT_PIN_CFG 0x37 //中斷引腳配置寄存器
#define MPU6050_RA_INT_ENABLE 0x38 //中斷使能寄存器
#define MPU6050_RA_DMP_INT_STATUS 0x39 //DMP中斷狀態寄存器
#define MPU6050_RA_INT_STATUS 0x3A //中斷狀態寄存器#define MPU6050_RA_ACCEL_XOUT_H 0x3B //X軸加速度輸出高位字節
#define MPU6050_RA_ACCEL_XOUT_L 0x3C //X軸加速度輸出低位字節
#define MPU6050_RA_ACCEL_YOUT_H 0x3D //Y軸加速度輸出高位字節
#define MPU6050_RA_ACCEL_YOUT_L 0x3E //Y軸加速度輸出低位字節
#define MPU6050_RA_ACCEL_ZOUT_H 0x3F //Z軸加速度輸出高位字節
#define MPU6050_RA_ACCEL_ZOUT_L 0x40 //Z軸加速度輸出低位字節
#define MPU6050_RA_TEMP_OUT_H 0x41 //溫度輸出高位字節
#define MPU6050_RA_TEMP_OUT_L 0x42 //溫度輸出低位字節
#define MPU6050_RA_GYRO_XOUT_H 0x43 //X軸陀螺儀輸出高位字節
#define MPU6050_RA_GYRO_XOUT_L 0x44 //X軸陀螺儀輸出低位字節
#define MPU6050_RA_GYRO_YOUT_H 0x45 //Y軸陀螺儀輸出高位字節
#define MPU6050_RA_GYRO_YOUT_L 0x46 //Y軸陀螺儀輸出低位字節
#define MPU6050_RA_GYRO_ZOUT_H 0x47 //Z軸陀螺儀輸出高位字節
#define MPU6050_RA_GYRO_ZOUT_L 0x48 //Z軸陀螺儀輸出低位字節//外部傳感器數據寄存器
#define MPU6050_RA_EXT_SENS_DATA_00 0x49 //
#define MPU6050_RA_EXT_SENS_DATA_01 0x4A //
#define MPU6050_RA_EXT_SENS_DATA_02 0x4B //
#define MPU6050_RA_EXT_SENS_DATA_03 0x4C //
#define MPU6050_RA_EXT_SENS_DATA_04 0x4D //
#define MPU6050_RA_EXT_SENS_DATA_05 0x4E //
#define MPU6050_RA_EXT_SENS_DATA_06 0x4F //
#define MPU6050_RA_EXT_SENS_DATA_07 0x50 //
#define MPU6050_RA_EXT_SENS_DATA_08 0x51 //
#define MPU6050_RA_EXT_SENS_DATA_09 0x52 //
#define MPU6050_RA_EXT_SENS_DATA_10 0x53 //
#define MPU6050_RA_EXT_SENS_DATA_11 0x54 //
#define MPU6050_RA_EXT_SENS_DATA_12 0x55 //
#define MPU6050_RA_EXT_SENS_DATA_13 0x56 //
#define MPU6050_RA_EXT_SENS_DATA_14 0x57 //
#define MPU6050_RA_EXT_SENS_DATA_15 0x58 //
#define MPU6050_RA_EXT_SENS_DATA_16 0x59 //
#define MPU6050_RA_EXT_SENS_DATA_17 0x5A //
#define MPU6050_RA_EXT_SENS_DATA_18 0x5B //
#define MPU6050_RA_EXT_SENS_DATA_19 0x5C //
#define MPU6050_RA_EXT_SENS_DATA_20 0x5D //
#define MPU6050_RA_EXT_SENS_DATA_21 0x5E //
#define MPU6050_RA_EXT_SENS_DATA_22 0x5F //
#define MPU6050_RA_EXT_SENS_DATA_23 0x60 //#define MPU6050_RA_MOT_DETECT_STATUS 0x61 //運動檢測狀態寄存器
#define MPU6050_RA_I2C_SLV0_DO 0x63 //I2C從機0數據輸出寄存器
#define MPU6050_RA_I2C_SLV1_DO 0x64 //I2C從機1數據輸出寄存器
#define MPU6050_RA_I2C_SLV2_DO 0x65 //I2C從機2數據輸出寄存器
#define MPU6050_RA_I2C_SLV3_DO 0x66 //I2C從設備3的數據寄存器地址
#define MPU6050_RA_I2C_MST_DELAY_CTRL 0x67 //信號路徑重置寄存器地址
#define MPU6050_RA_SIGNAL_PATH_RESET 0x68 //運動檢測控制寄存器地址
#define MPU6050_RA_MOT_DETECT_CTRL 0x69 //用戶控制寄存器地址
#define MPU6050_RA_USER_CTRL 0x6A //電源管理1寄存器地址
#define MPU6050_RA_PWR_MGMT_1 0x6B //電源管理2寄存器地址
#define MPU6050_RA_PWR_MGMT_2 0x6C //寄存器銀行選擇寄存器地址
#define MPU6050_RA_BANK_SEL 0x6D //內存起始地址寄存器地址
#define MPU6050_RA_MEM_START_ADDR 0x6E //內存讀/寫寄存器地址
#define MPU6050_RA_MEM_R_W 0x6F //DMP配置1寄存器地址
#define MPU6050_RA_DMP_CFG_1 0x70 //DMP配置2寄存器地址
#define MPU6050_RA_DMP_CFG_2 0x71 //FIFO計數高字節寄存器地址
#define MPU6050_RA_FIFO_COUNTH 0x72 //FIFO計數低字節寄存器地址
#define MPU6050_RA_FIFO_COUNTL 0x73 //FIFO讀/寫寄存器地址
#define MPU6050_RA_FIFO_R_W 0x74 //FIFO讀/寫寄存器地址
#define MPU6050_RA_WHO_AM_I 0x75 //器件ID寄存器地址#define MPU6050_TC_PWR_MODE_BIT 7 //TC_PWR_MODE位,用于選擇電源模式
#define MPU6050_TC_OFFSET_BIT 6 //TC_OFFSET位,用于設置溫度傳感器的偏移
#define MPU6050_TC_OFFSET_LENGTH 6 //TC_OFFSET字段的長度
#define MPU6050_TC_OTP_BNK_VLD_BIT 0 //TC_OTP_BNK_VLD位,用于驗證OTP存儲的攝氏度系數是否有效#define MPU6050_VDDIO_LEVEL_VLOGIC 0 //VDDIO電平模式,表示VLOGIC級別
#define MPU6050_VDDIO_LEVEL_VDD 1 //VDDIO電平模式,表示VDD級別#define MPU6050_CFG_EXT_SYNC_SET_BIT 5 //EXT_SYNC_SET位,用于選擇外部同步信號
#define MPU6050_CFG_EXT_SYNC_SET_LENGTH 3 //EXT_SYNC_SET字段的長度
#define MPU6050_CFG_DLPF_CFG_BIT 2 //DLPF_CFG位,用于選擇數字低通濾波器配置
#define MPU6050_CFG_DLPF_CFG_LENGTH 3 //DLPF_CFG字段的長度#define MPU6050_EXT_SYNC_DISABLED 0x0 //禁用外部同步信號
#define MPU6050_EXT_SYNC_TEMP_OUT_L 0x1 //外部同步信號為溫度輸出的低字節
#define MPU6050_EXT_SYNC_GYRO_XOUT_L 0x2 //外部同步信號為陀螺儀X軸輸出的低字節
#define MPU6050_EXT_SYNC_GYRO_YOUT_L 0x3 //外部同步信號為陀螺儀Y軸輸出的低字節
#define MPU6050_EXT_SYNC_GYRO_ZOUT_L 0x4 //外部同步信號為陀螺儀Z軸輸出的低字節
#define MPU6050_EXT_SYNC_ACCEL_XOUT_L 0x5 //外部同步信號為加速度計X軸輸出的低字節
#define MPU6050_EXT_SYNC_ACCEL_YOUT_L 0x6 //外部同步信號為加速度計Y軸輸出的低字節
#define MPU6050_EXT_SYNC_ACCEL_ZOUT_L 0x7 //外部同步信號為加速度計Z軸輸出的低字節#define MPU6050_DLPF_BW_256 0x00 //
#define MPU6050_DLPF_BW_188 0x01 //
#define MPU6050_DLPF_BW_98 0x02 //
#define MPU6050_DLPF_BW_42 0x03 //
#define MPU6050_DLPF_BW_20 0x04 //
#define MPU6050_DLPF_BW_10 0x05 //
#define MPU6050_DLPF_BW_5 0x06 //#define MPU6050_GCONFIG_FS_SEL_BIT 4
#define MPU6050_GCONFIG_FS_SEL_LENGTH 2#define MPU6050_GYRO_FS_250 0x00
#define MPU6050_GYRO_FS_500 0x01
#define MPU6050_GYRO_FS_1000 0x02
#define MPU6050_GYRO_FS_2000 0x03#define MPU6050_ACONFIG_XA_ST_BIT 7
#define MPU6050_ACONFIG_YA_ST_BIT 6
#define MPU6050_ACONFIG_ZA_ST_BIT 5
#define MPU6050_ACONFIG_AFS_SEL_BIT 4
#define MPU6050_ACONFIG_AFS_SEL_LENGTH 2
#define MPU6050_ACONFIG_ACCEL_HPF_BIT 2
#define MPU6050_ACONFIG_ACCEL_HPF_LENGTH 3#define MPU6050_ACCEL_FS_2 0x00
#define MPU6050_ACCEL_FS_4 0x01
#define MPU6050_ACCEL_FS_8 0x02
#define MPU6050_ACCEL_FS_16 0x03#define MPU6050_DHPF_RESET 0x00
#define MPU6050_DHPF_5 0x01
#define MPU6050_DHPF_2P5 0x02
#define MPU6050_DHPF_1P25 0x03
#define MPU6050_DHPF_0P63 0x04
#define MPU6050_DHPF_HOLD 0x07#define MPU6050_TEMP_FIFO_EN_BIT 7
#define MPU6050_XG_FIFO_EN_BIT 6
#define MPU6050_YG_FIFO_EN_BIT 5
#define MPU6050_ZG_FIFO_EN_BIT 4
#define MPU6050_ACCEL_FIFO_EN_BIT 3
#define MPU6050_SLV2_FIFO_EN_BIT 2
#define MPU6050_SLV1_FIFO_EN_BIT 1
#define MPU6050_SLV0_FIFO_EN_BIT 0#define MPU6050_MULT_MST_EN_BIT 7
#define MPU6050_WAIT_FOR_ES_BIT 6
#define MPU6050_SLV_3_FIFO_EN_BIT 5
#define MPU6050_I2C_MST_P_NSR_BIT 4
#define MPU6050_I2C_MST_CLK_BIT 3
#define MPU6050_I2C_MST_CLK_LENGTH 4#define MPU6050_CLOCK_DIV_348 0x0
#define MPU6050_CLOCK_DIV_333 0x1
#define MPU6050_CLOCK_DIV_320 0x2
#define MPU6050_CLOCK_DIV_308 0x3
#define MPU6050_CLOCK_DIV_296 0x4
#define MPU6050_CLOCK_DIV_286 0x5
#define MPU6050_CLOCK_DIV_276 0x6
#define MPU6050_CLOCK_DIV_267 0x7
#define MPU6050_CLOCK_DIV_258 0x8
#define MPU6050_CLOCK_DIV_500 0x9
#define MPU6050_CLOCK_DIV_471 0xA
#define MPU6050_CLOCK_DIV_444 0xB
#define MPU6050_CLOCK_DIV_421 0xC
#define MPU6050_CLOCK_DIV_400 0xD
#define MPU6050_CLOCK_DIV_381 0xE
#define MPU6050_CLOCK_DIV_364 0xF#define MPU6050_I2C_SLV_RW_BIT 7
#define MPU6050_I2C_SLV_ADDR_BIT 6
#define MPU6050_I2C_SLV_ADDR_LENGTH 7
#define MPU6050_I2C_SLV_EN_BIT 7
#define MPU6050_I2C_SLV_BYTE_SW_BIT 6
#define MPU6050_I2C_SLV_REG_DIS_BIT 5
#define MPU6050_I2C_SLV_GRP_BIT 4
#define MPU6050_I2C_SLV_LEN_BIT 3
#define MPU6050_I2C_SLV_LEN_LENGTH 4#define MPU6050_I2C_SLV4_RW_BIT 7
#define MPU6050_I2C_SLV4_ADDR_BIT 6
#define MPU6050_I2C_SLV4_ADDR_LENGTH 7
#define MPU6050_I2C_SLV4_EN_BIT 7
#define MPU6050_I2C_SLV4_INT_EN_BIT 6
#define MPU6050_I2C_SLV4_REG_DIS_BIT 5
#define MPU6050_I2C_SLV4_MST_DLY_BIT 4
#define MPU6050_I2C_SLV4_MST_DLY_LENGTH 5#define MPU6050_MST_PASS_THROUGH_BIT 7
#define MPU6050_MST_I2C_SLV4_DONE_BIT 6
#define MPU6050_MST_I2C_LOST_ARB_BIT 5
#define MPU6050_MST_I2C_SLV4_NACK_BIT 4
#define MPU6050_MST_I2C_SLV3_NACK_BIT 3
#define MPU6050_MST_I2C_SLV2_NACK_BIT 2
#define MPU6050_MST_I2C_SLV1_NACK_BIT 1
#define MPU6050_MST_I2C_SLV0_NACK_BIT 0#define MPU6050_INTCFG_INT_LEVEL_BIT 7
#define MPU6050_INTCFG_INT_OPEN_BIT 6
#define MPU6050_INTCFG_LATCH_INT_EN_BIT 5
#define MPU6050_INTCFG_INT_RD_CLEAR_BIT 4
#define MPU6050_INTCFG_FSYNC_INT_LEVEL_BIT 3
#define MPU6050_INTCFG_FSYNC_INT_EN_BIT 2
#define MPU6050_INTCFG_I2C_BYPASS_EN_BIT 1
#define MPU6050_INTCFG_CLKOUT_EN_BIT 0#define MPU6050_INTMODE_ACTIVEHIGH 0x00
#define MPU6050_INTMODE_ACTIVELOW 0x01#define MPU6050_INTDRV_PUSHPULL 0x00
#define MPU6050_INTDRV_OPENDRAIN 0x01#define MPU6050_INTLATCH_50USPULSE 0x00
#define MPU6050_INTLATCH_WAITCLEAR 0x01#define MPU6050_INTCLEAR_STATUSREAD 0x00
#define MPU6050_INTCLEAR_ANYREAD 0x01#define MPU6050_INTERRUPT_FF_BIT 7
#define MPU6050_INTERRUPT_MOT_BIT 6
#define MPU6050_INTERRUPT_ZMOT_BIT 5
#define MPU6050_INTERRUPT_FIFO_OFLOW_BIT 4
#define MPU6050_INTERRUPT_I2C_MST_INT_BIT 3
#define MPU6050_INTERRUPT_PLL_RDY_INT_BIT 2
#define MPU6050_INTERRUPT_DMP_INT_BIT 1
#define MPU6050_INTERRUPT_DATA_RDY_BIT 0// TODO: figure out what these actually do
// UMPL source code is not very obivous
#define MPU6050_DMPINT_5_BIT 5
#define MPU6050_DMPINT_4_BIT 4
#define MPU6050_DMPINT_3_BIT 3
#define MPU6050_DMPINT_2_BIT 2
#define MPU6050_DMPINT_1_BIT 1
#define MPU6050_DMPINT_0_BIT 0#define MPU6050_MOTION_MOT_XNEG_BIT 7
#define MPU6050_MOTION_MOT_XPOS_BIT 6
#define MPU6050_MOTION_MOT_YNEG_BIT 5
#define MPU6050_MOTION_MOT_YPOS_BIT 4
#define MPU6050_MOTION_MOT_ZNEG_BIT 3
#define MPU6050_MOTION_MOT_ZPOS_BIT 2
#define MPU6050_MOTION_MOT_ZRMOT_BIT 0#define MPU6050_DELAYCTRL_DELAY_ES_SHADOW_BIT 7
#define MPU6050_DELAYCTRL_I2C_SLV4_DLY_EN_BIT 4
#define MPU6050_DELAYCTRL_I2C_SLV3_DLY_EN_BIT 3
#define MPU6050_DELAYCTRL_I2C_SLV2_DLY_EN_BIT 2
#define MPU6050_DELAYCTRL_I2C_SLV1_DLY_EN_BIT 1
#define MPU6050_DELAYCTRL_I2C_SLV0_DLY_EN_BIT 0#define MPU6050_PATHRESET_GYRO_RESET_BIT 2
#define MPU6050_PATHRESET_ACCEL_RESET_BIT 1
#define MPU6050_PATHRESET_TEMP_RESET_BIT 0#define MPU6050_DETECT_ACCEL_ON_DELAY_BIT 5
#define MPU6050_DETECT_ACCEL_ON_DELAY_LENGTH 2
#define MPU6050_DETECT_FF_COUNT_BIT 3
#define MPU6050_DETECT_FF_COUNT_LENGTH 2
#define MPU6050_DETECT_MOT_COUNT_BIT 1
#define MPU6050_DETECT_MOT_COUNT_LENGTH 2#define MPU6050_DETECT_DECREMENT_RESET 0x0
#define MPU6050_DETECT_DECREMENT_1 0x1
#define MPU6050_DETECT_DECREMENT_2 0x2
#define MPU6050_DETECT_DECREMENT_4 0x3#define MPU6050_USERCTRL_DMP_EN_BIT 7
#define MPU6050_USERCTRL_FIFO_EN_BIT 6
#define MPU6050_USERCTRL_I2C_MST_EN_BIT 5
#define MPU6050_USERCTRL_I2C_IF_DIS_BIT 4
#define MPU6050_USERCTRL_DMP_RESET_BIT 3
#define MPU6050_USERCTRL_FIFO_RESET_BIT 2
#define MPU6050_USERCTRL_I2C_MST_RESET_BIT 1
#define MPU6050_USERCTRL_SIG_COND_RESET_BIT 0#define MPU6050_PWR1_DEVICE_RESET_BIT 7
#define MPU6050_PWR1_SLEEP_BIT 6
#define MPU6050_PWR1_CYCLE_BIT 5
#define MPU6050_PWR1_TEMP_DIS_BIT 3
#define MPU6050_PWR1_CLKSEL_BIT 2
#define MPU6050_PWR1_CLKSEL_LENGTH 3#define MPU6050_CLOCK_INTERNAL 0x00 // 內部振蕩器作為時鐘源
#define MPU6050_CLOCK_PLL_XGYRO 0x01 //X軸陀螺儀的相位鎖定環(PLL)作為時鐘源
#define MPU6050_CLOCK_PLL_YGYRO 0x02 //Y軸陀螺儀的相位鎖定環(PLL)作為時鐘源
#define MPU6050_CLOCK_PLL_ZGYRO 0x03 //Z軸陀螺儀的相位鎖定環(PLL)作為時鐘源
#define MPU6050_CLOCK_PLL_EXT32K 0x04 //外部32.768kHz晶振作為時鐘源
#define MPU6050_CLOCK_PLL_EXT19M 0x05 //外部19.2MHz晶振作為時鐘源
#define MPU6050_CLOCK_KEEP_RESET 0x07 //保持復位狀態#define MPU6050_PWR2_LP_WAKE_CTRL_BIT 7
#define MPU6050_PWR2_LP_WAKE_CTRL_LENGTH 2
#define MPU6050_PWR2_STBY_XA_BIT 5
#define MPU6050_PWR2_STBY_YA_BIT 4
#define MPU6050_PWR2_STBY_ZA_BIT 3
#define MPU6050_PWR2_STBY_XG_BIT 2
#define MPU6050_PWR2_STBY_YG_BIT 1
#define MPU6050_PWR2_STBY_ZG_BIT 0#define MPU6050_WAKE_FREQ_1P25 0x0
#define MPU6050_WAKE_FREQ_2P5 0x1
#define MPU6050_WAKE_FREQ_5 0x2
#define MPU6050_WAKE_FREQ_10 0x3#define MPU6050_BANKSEL_PRFTCH_EN_BIT 6
#define MPU6050_BANKSEL_CFG_USER_BANK_BIT 5
#define MPU6050_BANKSEL_MEM_SEL_BIT 4
#define MPU6050_BANKSEL_MEM_SEL_LENGTH 5#define MPU6050_WHO_AM_I_BIT 6
#define MPU6050_WHO_AM_I_LENGTH 6#define MPU6050_DMP_MEMORY_BANKS 8
#define MPU6050_DMP_MEMORY_BANK_SIZE 256
#define MPU6050_DMP_MEMORY_CHUNK_SIZE 16
MPU6050初始化:
//初始化MPU6050
void MPU6050_Init(void)
{delay_ms(100);MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x00); //解除休眠狀態MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV , 0x07); //陀螺儀采樣率,1KHzMPU6050_WriteReg(MPU6050_RA_CONFIG , 0x06); //低通濾波器的設置,截止頻率是1K,帶寬是5KMPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x00); //配置加速度傳感器工作在2G模式,不自檢MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18); //陀螺儀自檢及測量范圍,典型值:0x18(不自檢,2000deg/s)
}//讀取MPU6050的ID
uint8_t MPU6050ReadID(void)
{unsigned char Re = 0;MPU6050_ReadData(MPU6050_RA_WHO_AM_I,&Re,1); //讀器件地址if(Re != 0x68){printf("MPU6050 dectected error!\r\n");return 0;}else{printf("MPU6050 ID = %d\r\n",Re);return 1;}}
MPU6050數據讀取處理:
// 讀取MPU6050的加速度數據
void MPU6050ReadAcc(short *accData)
{u8 buf[6];MPU6050_ReadData(MPU6050_ACC_OUT, buf, 6);accData[0] = ((buf[0] << 8) | buf[1]);accData[1] = ((buf[2] << 8) | buf[3]);accData[2] = ((buf[4] << 8) | buf[5]);
}//讀取MPU6050的角加速度數據
void MPU6050ReadGyro(short *gyroData)
{u8 buf[6];MPU6050_ReadData(MPU6050_GYRO_OUT,buf,6);gyroData[0] = ((buf[0] << 8) | buf[1]);gyroData[1] = ((buf[2] << 8) | buf[3]);gyroData[2] = ((buf[4] << 8) | buf[5]);
}//讀取MPU6050的原始溫度數據
void MPU6050ReadTemp(short *tempData)
{u8 buf[2];MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); //讀取溫度值*tempData = (buf[0] << 8) | buf[1];
}//讀取MPU6050的溫度數據,轉化成攝氏度
void MPU6050_ReturnTemp(float *Temperature)
{short temp3;u8 buf[2];MPU6050_ReadData(MPU6050_RA_TEMP_OUT_H,buf,2); //讀取溫度值temp3= (buf[0] << 8) | buf[1]; *Temperature=((double) temp3/340.0)+36.53;
}
MPU6050濾波一階互補:
float yijiehubu_R(float angle_m, float gyro_m)//?????????????
{angle_R = K1 * angle_m+ (1-K1) * (angle_R + gyro_m * dt);return angle_R;
}
float yijiehubu_P(float angle_m, float gyro_m)//?????????????
{angle_P = K1 * angle_m+ (1-K1) * (angle_P + gyro_m * dt);return angle_P;
}
方位角計算? atan2(X,Y):
坐標方位角是指一個點相對于另一個參考點的方向角度。下面是計算坐標方位角的公式:
假設要計算從點 A 到點 B 的坐標方位角,點 A 的坐標為 (x1, y1),點 B 的坐標為 (x2, y2)。
1. 計算點 B 相對于點 A 的水平距離 dx = x2 - x1。
2. 計算點 B 相對于點 A 的豎直距離 dy = y2 - y1。
3. 計算坐標方位角 angle = atan2(dy, dx)。
4. 將 angle 的弧度值轉化為角度值。
其中, atan2(dy, dx) 是求取反正切值的函數,返回值區間是(-π, π]。需要注意,因為 atan2函數的取值范圍不包括負半軸,所以需要做特殊處理,即:
如果 atan2(dy, dx) < 0,則 angle = 360 + atan2(dy, dx)。
作者:知乎用戶
鏈接:https://www.zhihu.com/question/601596103/answer/3032838089
來源:知乎
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。
主函數代碼:
#include "main.h"//211uint16_t t1,t2,t3;short Accel[3];short Gyro[3];float Temp;float Angle_Y,Angle_X,Angle_Z;int pitch,roll,yaw;int main(void)
{ init_ALL(); //初始化所有函數while(1){ MPU6050ReadAcc(Accel);//獲取加速度原始值MPU6050ReadGyro(Gyro);//獲取角速度原始值MPU6050_ReturnTemp(&Temp);//獲取溫度值 Angle_X=atan2(Accel[0],Accel[2])*57.3-Gyro[0]/16.4*0.005;//換算Angle_Y=atan2(Accel[1],Accel[2])*57.3-Gyro[1]/16.4*0.005;pitch=(int)yijiehubu_P(Angle_X,Gyro[0]/16.4); //一階互補濾波roll=-(int)yijiehubu_R(Angle_Y,Gyro[1]/16.4); }
}//初始化所有函數:
void init_ALL(void)
{Usart1_Init(115200); //初始化串口1printf("HELLO \r\n"); //串口1 測試重定向PrintfSysTick_Init(72);Timer2_Init();
// Timer3_PWM_init(2000,719);i2c_GPIO_Config(); //IIC初始化MPU6050_Init(); //mpu6050初始化MPU6050ReadID(); //讀取器件ID
}void TIM2_IRQHandler(void)
{if (TIM_GetITStatus(TIM2, TIM_IT_Update) == SET){
// printf("Angle_X=%lf",Angle_X);
// printf("\r\n");
// printf("Angle_Y=%lf",Angle_Y);
// printf("\r\n");// printf("\r\n");
// printf("Temp=%lf",Temp);printf("pitch=%d",pitch);printf("\r\n");printf("roll=%d",roll); printf("\r\n");printf("yaw=%d",yaw);TIM_ClearITPendingBit(TIM2, TIM_IT_Update);//清出中斷寄存器標志位,用于退出中斷}
}
測試結果:
工程下載:
https://download.csdn.net/download/qq_64257614/88212554?spm=1001.2014.3001.5503