目录

零、软件I2C配置

一、MPU6050硬件部分

二、MPU6050软件部分。

👉👉👉完整程序编写步骤:

0、MPU6050.h文件内容:

1、新建MPU6050.c和MPU6050.h文件:

2、写MPU6050寄存器函数

2、1写单个字节:

2、2连续写多个字节:

3、读MPU6050寄存器函数

3、1读单个字节:

3、2连续读多个字节:

4、将2个字节转换成1个有符号半字,用来处理寄存器的高低位数据函数:

5、读取MPU6050设备ID函数(不要这个函数也是可以的):

6、读取加速度计原始数值函数:

7、读取陀螺仪原始数值函数:

8、线性标度变换函数(用来将原始数据转换成我们需要的):

 8.1推荐用原始数据除灵敏度来求加速度角速度。公式: 加(角)速度值 = 原始数据 / 灵敏度

9、读取转换后加速度计数值函数:

10、读取转换后的陀螺仪数值函数:

11、初始化MPU6050函数:

12、最后在主程序中调用两个读取函数:

👉最后观察现象:

👉也可通过串口发送到VOFA+,可以更加直观的观察数据的变化:



零、软件I2C配置

一、MPU6050硬件部分

二、MPU6050软件部分。

👉👉👉完整程序编写步骤:

0、MPU6050.h文件内容:

#ifndef __MPU6050_H
#define __MPU6050_H


#define MPU6050_ADDRESS		    0xD0     //MPU6050的I2C从机地址

#define	MPU6050_SMPLRT_DIV		0x19     //采样频率分频器
#define	MPU6050_CONFIG			0x1A     //配置
#define	MPU6050_GYRO_CONFIG		0x1B     //陀螺仪配置
#define	MPU6050_ACCEL_CONFIG	0x1C     //加速度计配置

#define	MPU6050_ACCEL_XOUT_H	0x3B     //加速度计X轴高位
#define	MPU6050_ACCEL_XOUT_L	0x3C     //加速度计X轴底位
#define	MPU6050_ACCEL_YOUT_H	0x3D     //加速度计Y轴高位
#define	MPU6050_ACCEL_YOUT_L	0x3E     //加速度计Y轴底位
#define	MPU6050_ACCEL_ZOUT_H	0x3F     //加速度计Z轴高位
#define	MPU6050_ACCEL_ZOUT_L	0x40     //加速度计Z轴底位
#define	MPU6050_TEMP_OUT_H		0x41     //温度测量值高位     
#define	MPU6050_TEMP_OUT_L		0x42     //温度测量值低位
#define	MPU6050_GYRO_XOUT_H		0x43     //陀螺仪X轴高位
#define	MPU6050_GYRO_XOUT_L		0x44     //陀螺仪X轴低位
#define	MPU6050_GYRO_YOUT_H		0x45     //陀螺仪Y轴高位
#define	MPU6050_GYRO_YOUT_L		0x46     //陀螺仪Y轴低位
#define	MPU6050_GYRO_ZOUT_H		0x47     //陀螺仪Z轴高位
#define	MPU6050_GYRO_ZOUT_L		0x48     //陀螺仪Z轴低位

#define	MPU6050_PWR_MGMT_1		0x6B     //电源管理1
#define	MPU6050_PWR_MGMT_2		0x6C     //电源管理2
#define	MPU6050_WHO_AM_I		0x75     //设备ID



void MPU6050_Init(void);                       //初始化
uint8_t MPU6050_GetID(void);                   //读取ID

void MPU6050_GetACCEL(int16_t *ACCEL_Array);   //读取加速度计原始数据
void MPU6050_GetGYRO(int16_t *GYRO_Array);     //读取陀螺仪原始数据

void MPU6050_GetAccel_Value(float *Accel_Value);  //读取转换后的加速度计数值
void MPU6050_GetGyro_Value(float *Gyro_Value);    //读取转换后的陀螺仪数值


#endif

1、新建MPU6050.c和MPU6050.h文件:

---------------------------------------------------------------------------------------------------------------------------------

2、写MPU6050寄存器函数

2、1写单个字节:

#include "stm32f10x.h"                  // Device header
#include "MyI2C.h"
#include "MPU6050.h"


/**
  * 函数功能:MPU6050写1个寄存器
  * 入口参数:Reg: 需要操作的MPU6050地址
  * 入口参数:Data:需要写入的数据
  * 返 回 值:无
  */
void MPU6050_WriteReg(uint8_t Reg, uint8_t Data)
{
    /*发送从机地址*/
    MyI2C_Start();                    //I2C起始
    MyI2C_SendByte(MPU6050_ADDRESS);  //发送MPU6050地址 0xD0  第0位为0是写操作,1是读操作
    MyI2C_ReceiveAck();               //接收应答,我这里只接收,不作处理。
    
    /*发送需要写操作的寄存器*/
    MyI2C_SendByte(Reg);              
    MyI2C_ReceiveAck();
    
    /*发送需要写入的数据*/
    MyI2C_SendByte(Data);
    MyI2C_ReceiveAck();
    
    MyI2C_Stop();                      //I2C终止
}
2、2连续写多个字节:

/**
  * 函数功能:MPU6050写多个字节
  * 入口参数:BufAddress:寄存器首地址
  * 入口参数:BufData   :数据首地址
  * 入口参数:Length    :写入的字节数量
  * 返 回 值:无
  */
void MPU6050_WriteBuf(uint8_t BufAddress, uint8_t *BufData, uint8_t Length)
{
    uint8_t i;                               //for循环次数变量
    
    MyI2C_Start();                           //起始
    MyI2C_SendByte(MPU6050_ADDRESS | 0x00);  //发送从机地址  | 写模式
    MyI2C_ReceiveAck();                      //接收应答
    MyI2C_SendByte(BufAddress);              //发送寄存器首地址
    MyI2C_ReceiveAck();                      //接收应答
    
    for (i = 0; i < Length; i++) 
    {
        MyI2C_SendByte(BufData[i]);          //连续写入数据
        MyI2C_ReceiveAck();                  //接收应答
    }
    MyI2C_Stop();                            //停止
}

3、读MPU6050寄存器函数

3、1读单个字节:

/**
  * 函数功能:读取MPU6050寄存器里的数据
  * 入口参数:Reg:需要读取的寄存器地址
  * 返 回 值:读取到的数据
  */
uint8_t MPU6050_ReadReg(uint8_t Reg)
{
    uint8_t Reg_Data;                      //定义保存读取到的数据变量
    
    /*发送从机地址*/
    MyI2C_Start();                         //I2C起始
    MyI2C_SendByte(MPU6050_ADDRESS);       //MPU6050默认地址:0xD0 
    MyI2C_ReceiveAck();                    //接收MPU6050应答位
    
    /*发送需要读取的寄存器地址*/
    MyI2C_SendByte(Reg);                   
    MyI2C_ReceiveAck();
    
    /*发送读取模式*/
    MyI2C_Start();                           //I2C起始
    MyI2C_SendByte(MPU6050_ADDRESS | 0x01);  //发送MPU6050地址0xD0 | 0x01 (第0位为0是写操作,1是读操作)
    MyI2C_ReceiveAck();
    
    /*开始读取从机数据*/
    Reg_Data = MyI2C_ReceiveByte();          //读取MPU6050的数据
    MyI2C_SendAck(1);                        //读取完成后,应答位给1(非应答)
    MyI2C_Stop();                            //I2C终止
    
    return Reg_Data;                         //返回读取到的数据
}
3、2连续读多个字节:

/**
  * 函数功能:连续读MPU6050寄存器
  * 入口参数:BufAddress:寄存器首地址
  * 入口参数:BufData   :接收数据首地址
  * 入口参数:Length    :读取寄存器的数量
  */
void MPU6050_ReadBuf(uint8_t BufAddress, uint8_t *BufData, uint8_t Length)
{
    uint8_t i;                              //for循环次数变量
    
    MyI2C_Start();                          //起始
    MyI2C_SendByte(MPU6050_ADDRESS | 0x00); //发送从机地址 | 写模式
    MyI2C_ReceiveAck();                     //接收应答
    MyI2C_SendByte(BufAddress);             //发送寄存器地址
    MyI2C_ReceiveAck();                     //接收应答
    
    MyI2C_Start();                          //起始
    MyI2C_SendByte(MPU6050_ADDRESS | 0x01); //发送从机地址 | 读模式
    MyI2C_ReceiveAck();                     //接收应答
    
    /*连续读取数据*/
    for (i = 0; i < Length; i++) 
    {
        BufData[i] = MyI2C_ReceiveByte();   //把数据存放在i指向的变量
        if( i < (Length - 1) )              
        {
            MyI2C_SendAck(0);               //发送应答
        }
        else                                
        {
            MyI2C_SendAck(1);               //最后一个要发送非应答
        }
    }
    MyI2C_Stop();                           //停止
}

4、将2个字节转换成1个有符号半字,用来处理寄存器的高低位数据函数:

/**
  * 函数功能:将2个字节转换成1个有符号半字,用来处理寄存器的高低位数据。
  * 入口参数:DataL:低位字节
  * 入口参数:DataH: 高位字节
  * 返 回 值:转换完成后的有符号数据
  */
int16_t MPU6050_Byte_to_HalfWord(uint8_t DataL, uint8_t DataH)
{
    int16_t Data;
    
    Data = (DataH << 8) | DataL;  //DataL放到低8位, DataH放到高8位
    
    return Data;                                //返回转换后的数据
}

5、读取MPU6050设备ID函数(不要这个函数也是可以的):

/**
  * 函数功能:读取MPU6050设备ID
  * 入口参数:无
  * 返 回 值:设备ID
  */
uint8_t MPU6050_GetID(void)
{
    uint8_t ID = 0;
    ID = MPU6050_ReadReg(MPU6050_WHO_AM_I);  //读取设备ID   寄存器:0x75
    
    return ID;
}

6、读取加速度计原始数值函数:

/**
  * 函数功能:读取加速度计原始数值
  * 入口参数:ACCEL_Array: X轴保存到外部的第0个元素
                           Y轴保存到外部的第1个元素
                           Z轴保存到外部的第2个元素
  * 返 回 值:无
  */
void MPU6050_GetACCEL(int16_t *ACCEL_Array)
{
    uint8_t DataL;     //定义保存数据低位变量
    uint8_t DataH;     //定义保存数据高位变量

    /*读取加速度计原始数值,寄存器地址含义需要翻手册的描述*/
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_L);           //读取X轴低位数据到DataL
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_XOUT_H);           //读取X轴高位数据到DataH
    ACCEL_Array[0] = MPU6050_Byte_to_HalfWord(DataL, DataH); //调用转换函数,将X轴转换结果存放到ACCEL_Array[0]
    
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_L);           //读取Y轴低位数据到DataL
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_YOUT_H);           //读取Y轴高位数据到DataH
    ACCEL_Array[1] = MPU6050_Byte_to_HalfWord(DataL, DataH); //调用转换函数,将Y轴转换结果存放到ACCEL_Array[1]
    
    DataL = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_L);           //读取Z轴低位数据到DataL
    DataH = MPU6050_ReadReg(MPU6050_ACCEL_ZOUT_H);           //读取Z轴高位数据到DataH
    ACCEL_Array[2] = MPU6050_Byte_to_HalfWord(DataL, DataH); //调用转换函数,将Z轴转换结果存放到ACCEL_Array[2]
}

7、读取陀螺仪原始数值函数:

/**
  * 函数功能: 读取陀螺仪原始数值
  * 入口参数:ACCEL_Array: X轴保存到第0个元素
                           Z轴保存到第2个元素
                           Y轴保存到第1个元素
  * 返 回 值:无           
  */
void MPU6050_GetGYRO(int16_t *GYRO_Array)
{
    uint8_t DataL;     //定义数据低位变量
    uint8_t DataH;     //定义数据高位变量

    DataL = MPU6050_ReadReg(MPU6050_GYRO_XOUT_L);           //读取X轴低位数据到DataL
    DataH = MPU6050_ReadReg(MPU6050_GYRO_XOUT_H);           //读取X轴高位数据到DataH
    GYRO_Array[0] = MPU6050_Byte_to_HalfWord(DataL, DataH); //调用转换函数,将X轴转换结果存放到GYRO_Array[0]
    
    DataL = MPU6050_ReadReg(MPU6050_GYRO_YOUT_L);           //读取Y轴低位数据到DataL
    DataH = MPU6050_ReadReg(MPU6050_GYRO_YOUT_H);           //读取Y轴高位数据到DataH
    GYRO_Array[1] = MPU6050_Byte_to_HalfWord(DataL, DataH); //调用转换函数,将Y轴转换结果存放到GYRO_Array[1]
    
    DataL = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_L);           //读取Z轴低位数据到DataL
    DataH = MPU6050_ReadReg(MPU6050_GYRO_ZOUT_H);           //读取Z轴高位数据到DataH
    GYRO_Array[2] = MPU6050_Byte_to_HalfWord(DataL, DataH); //调用转换函数,将Z轴转换结果存放到GYRO_Array[2]
}

8、线性标度变换函数(用来将原始数据转换成我们需要的):

 8.1推荐用原始数据除灵敏度来求加速度角速度。公式: 加(角)速度值 = 原始数据 / 灵敏度

                                               1、 角速度量程对应灵敏度:

                                                  2、 加速度计量程对应灵敏度:

/**
  * 函数功能:线性标度变换
  * 入口参数:Sample_Value: 采样回来的原始数值 
  * 入口参数:URV:         量程上限      
  * 入口参数:LRV:         量程下限
  * 返 回 值:变换后的数据
  */
float Scale_Transform(float Sample_Value, float URV, float LRV)
{
    float Data;             //定义用来保存变换后的数据变量
    float Value_L = -32767.0; //定义采样值下限变量   MPU6050寄存器是16位的,最高位是符号位,
    float Value_U = 32767.0;  //定义采样值上限变量   所以寄存器输出范围是-7FFF~7FFF,对应十进制-32767~32767
    
    /* 公式:当前数据 =(采样值 - 采样值下限)/(采样值上限 - 采样值下限)*(量程上限 - 量程下限)+ 量程下限     */
    Data = (Sample_Value - Value_L) / (Value_U - Value_L) * (URV - LRV) + LRV;
           
    return Data;
}

9、读取转换后加速度计数值函数:

/**
  * 函数功能:读取转换后加速度计数值
  * 入口参数:Accel_Value:加速度值转换后保存的变量
  * 返 回 值:无
  */
void MPU6050_GetAccel_Value(float *Accel_Value)
{
    int16_t ACCEL_Array[3];          //定义用来保存加速度计原始数值的变量
    
    /*读取加速度计原始数值*/
    MPU6050_GetACCEL(ACCEL_Array);   
    
    /*开始转换加速度值*/
    Accel_Value[0] = Scale_Transform( (float)ACCEL_Array[0], 16.0, -16.0);  //转换X轴
    Accel_Value[1] = Scale_Transform( (float)ACCEL_Array[1], 16.0, -16.0);  //转换Y轴
    Accel_Value[2] = Scale_Transform( (float)ACCEL_Array[2], 16.0, -16.0);  //转换Z轴
}

10、读取转换后的陀螺仪数值函数:

/**
  * 函数功能:读取转换后的陀螺仪数值
  * 入口参数:Gyro_Value:陀螺仪转换后保存的变量
  * 返 回 值:无
  */
void MPU6050_GetGyro_Value(float *Gyro_Value)
{
    /*定义用来保存陀螺仪原始数值的数组*/
    int16_t GYRO_Array[3];        
   
    /*读取陀螺仪的原始数值,保存到GYRO_Array[]数组中*/
    MPU6050_GetGYRO(GYRO_Array);  
    
    /*开始转换陀螺仪值*/
    Gyro_Value[0] = Scale_Transform( (float)GYRO_Array[0], 2000.0, -2000.0);  //转换X轴
    Gyro_Value[1] = Scale_Transform( (float)GYRO_Array[1], 2000.0, -2000.0);  //转换Y轴
    Gyro_Value[2] = Scale_Transform( (float)GYRO_Array[2], 2000.0, -2000.0);  //转换Z轴
    
}

11、初始化MPU6050函数:

/**
  * 函数功能:初始化MPU6050
  * 入口参数:无
  * 返 回 值:无
  */
void MPU6050_Init(void)
{
    /*调用软件I2C初始化函数*/
    MyI2c_Init();
    
    /*MPU6050寄存器初始化, 需要对照手册描述来配置*/
    MPU6050_WriteReg(MPU6050_PWR_MGMT_1, 0x01);   //电源管理1寄存器,取消睡眠模式,选择时钟源为X轴陀螺仪
    MPU6050_WriteReg(MPU6050_PWR_MGMT_2, 0x00);   //电源管理2寄存器,保持默认值,所有轴不休眠。
    MPU6050_WriteReg(MPU6050_SMPLRT_DIV, 0x09);   //采样率分频寄存器,
    MPU6050_WriteReg(MPU6050_CONFIG, 0x06);       //配置寄存器
    MPU6050_WriteReg(MPU6050_GYRO_CONFIG, 0x18);  //陀螺仪配置寄存器,选择满量程 ±2000°/s
    MPU6050_WriteReg(MPU6050_ACCEL_CONFIG, 0x18); //加速度计配置寄存器,选择满量程 ±16g
    
}

12、最后在主程序中调用两个读取函数:

#include "stm32f10x.h"                  // Device header
#include "MPU6050.h"
#include "OLED.h"


uint8_t MPU6050_Who = 0;       //定义保存MPU6050 设备ID变量
float MPU6050_ACCEL_Value[3];  //定义保存MPU6050加速度计数据数组
float MPU6050_GYRO_Value[3];   //定义保存MPU6050陀螺仪数据数组



int main(void)
{
    OLED_Init();          //OLED初始化
    MPU6050_Init();       //MPU6050初始化

    MPU6050_Who = MPU6050_GetID();  //读取MPU6050 ID
    OLED_Printf(0, 0, OLED_8X16, "ID:%X", MPU6050_Who);      //显示ID
    OLED_Update();


    while(1)
   {
        /*读取MPU6050数据*/
        
        MPU6050_GetAccel_Value(MPU6050_ACCEL_Value); //读取加速度计的值
        MPU6050_GetGyro_Value(MPU6050_GYRO_Value);   //读取陀螺仪的值
        
        /*在0.96寸OLED屏幕上显示数据*/
        OLED_ShowFloatNum(0, 16, MPU6050_ACCEL_Value[0], 2, 2, OLED_8X16);  //加速度X轴
        OLED_ShowFloatNum(0, 32, MPU6050_ACCEL_Value[1], 2, 2, OLED_8X16);  //加速度Y轴
        OLED_ShowFloatNum(0, 48, MPU6050_ACCEL_Value[2], 2, 2, OLED_8X16);  //加速度Z轴
        
        OLED_ShowFloatNum(64, 16, MPU6050_GYRO_Value[0], 2, 2, OLED_8X16);  //陀螺仪X轴
        OLED_ShowFloatNum(64, 32, MPU6050_GYRO_Value[1], 2, 2, OLED_8X16);  //陀螺仪Y轴
        OLED_ShowFloatNum(64, 48, MPU6050_GYRO_Value[2], 2, 2, OLED_8X16);  //陀螺仪Z轴
        
        OLED_Update();
   }

}

👉最后观察现象:

👉也可通过串口发送到VOFA+,可以更加直观的观察数据的变化:

Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐