STM32使用MPU6050姿态传感器的指南

文章目录

  • 特性
  • 引脚说明
  • 使用I2C软件,驱动mpu6050
  • 手册中寄存器描述
  • MPU6050初始化的步骤:
  • 数据读取
  • mpu6050输出的值
  • 特性

    MPU6050 ,能同时检测三轴加速度三轴陀螺仪(三轴角速度)的运动数据以及温度数据。利用其内部的 DMP 模块(Digital Motion Processor 数字运动处理器) ,可对传感器数据进行滤波、融合处理,直接通过 IIC 接口向主控器输出姿态解算后的数据,降低主控器的运算量。其姿态解算频率最高可达 200Hz

    参数 说明
    供电 3.3V-5V
    通讯接口 IIC 协议,支持的 IIC 时钟最高频率为 400KHz
    测量维度 加速度: 3 维 陀螺仪: 3 维
    ADC 分辨率 加速度: 16 位 陀螺仪: 16 位
    加速度测量范围 ±2g、 ±4g、 ±8g、 ±16g 其中 g 为重力加速度常数, g=9.8m/s ²
    加速度最高分辨率 16384 LSB/g
    加速度测量精度 0.1g
    加速度输出频率 最高 1000Hz
    陀螺仪测量范围 ±250 º/s 、 ±500 º/s 、 ±1000 º/s、 ±2000 º/s、
    陀螺仪最高分辨率 131 LSB/( º/s)
    陀螺仪测量精度 0.1 º/s
    陀螺仪输出频率 最高 8000Hz
    DMP 姿态解算频率 最高 200Hz
    温度传感器测量范围 -40~ +85℃
    温度传感器分辨率 340 LSB/℃
    温度传感器精度 ±1℃
    工作温度 -40~ +85℃
    功耗 500uA~3.9mA (工作电压 3.3V)

    引脚说明

    引脚名称 说明
    VCC 3.3/5V 电源输入
    GND 地线
    SCL I2C 从时钟信号线 SCL (模块上已接上拉电阻)
    SDA I2C 从数据信号线 SDA (模块上已接上拉电阻)
    XDA I2C 主串行数据信号线,用于外接传感器(模块上已接上拉电阻)
    XCL I2C 主串行时钟信号线,用于外接传感器(模块上已接上拉电阻)
    AD0 从机地址设置引脚接地或悬空时, 地址为: 0x68;接 VCC 时,地址为:0x69
    INT 中断输出引脚

    备注:SDA/SCL、 XDA/XCL 通讯引脚分别为两组 I2C 信号线;当模块与外部主机通讯时, 使用 SDA/SCL,如与 STM32 芯片通讯; 而 XDA/XCL 则用于 MPU6050 芯片与其它I2C 传感器通讯时使用,但一般不这样使用。

    模块引脚与单片机连接

    引脚名称 开发板连接
    VCC 接3.3或5V
    GND GND
    SCL PB6
    SDL PB7
    AD0 悬空或者接地
    INT PA11

    编程要点
    (1) 初始化 STM32 的 I2C(软件模拟);
    (2) 使用 I2C 向 MPU6050 写入控制参数;
    (3) 定时读取加速度、角速度及温度数据;

    使用I2C软件,驱动mpu6050

    #define GPIO_PORT_I2C	GPIOB			/* GPIO端口*/
    #define RCC_I2C_PORT 	RCC_APB2Periph_GPIOB		/* GPIO时钟*/
    #define I2C_SCL_PIN		GPIO_Pin_6			/* 连接SCL的GPIO */
    #define I2C_SDA_PIN		GPIO_Pin_7			/* 连接SDL的GPIO */
    
    #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数据 */
    
    static void i2c_Delay(void)
    {
    	uint8_t i;
    	for (i = 0; i < 10; i++);
    }
    
    //当SCL高电平时,SDA出现一个下跳沿表示I2C总线启动信号
    void i2c_Start(void)
    {
        /*    _____
         *SDA      \_____________
         *    __________
         *SCL           \________
         */
    	I2C_SDA_1();
    	I2C_SCL_1();
    	i2c_Delay();
    	I2C_SDA_0();
    	i2c_Delay();
    	I2C_SCL_0();
    	i2c_Delay();
    }
    
    //当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号
    void i2c_Stop(void)
    {
        /*               _______
         *SDA __________/
         *          ____________
         *SCL _____/
         */
    	I2C_SDA_0();
    	I2C_SCL_1();
    	i2c_Delay();
    	I2C_SDA_1();
    }
    
    /*CPU向I2C总线设备发送8bit数据
    
    */
    void i2c_SendByte(uint8_t _ucByte)
    {
    	uint8_t i;
    
    	/* 先发送高7位,*/
    	for (i = 0; i < 8; i++)
    	{		
    		if (_ucByte & 0x80)
    		{
    			I2C_SDA_1();//发送的1
    		}
    		else
    		{
    			I2C_SDA_0();//发送的0
    		}
    		i2c_Delay();
    		I2C_SCL_1();
    		i2c_Delay();	
    		I2C_SCL_0();
    		if (i == 7)
    		{
    			 I2C_SDA_1(); //释放总线
    		}
    		_ucByte <<= 1;	/*左移一个 bit */
    		i2c_Delay();
    	}
    }
    
    /*
    CPU从I2C设备读取8bit数据
    */
    uint8_t i2c_ReadByte(u8 ack)
    {
    	uint8_t i;
    	uint8_t value;
    
    	/* 读取到第一个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();
    	else
    		i2c_Ack();
    	return value;
    }
    
    /*
    CPU产生一个时钟,并读取器件的ACK应答信号
    */
    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;
    }
    
    /*
    CPU产生一个ACK信号
    
    */
    void i2c_Ack(void)
    {
    
        /*           ____
         *SCL ______/    \______
         *    ____         _____
         *SDA     \_______/
         */
    	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总线 */
    }
    
    /*
    CPU产生1个NACK信号
    */
    void i2c_NAck(void)
    {
        /*           ____
         *SCL ______/    \______
         *    __________________
         *SDA
         */
    	I2C_SDA_1();	/* CPU驱动SDA = 1 */
    	i2c_Delay();
    	I2C_SCL_1();	/* CPU产生一个时钟 */
    	i2c_Delay();
    	I2C_SCL_0();
    	i2c_Delay();	
    }
    
    /*
    配置I2C总线的GPIO
    */
    void i2c_GPIO_Config(void)
    {
    	GPIO_InitTypeDef GPIO_InitStructure;
    
    	RCC_APB2PeriphClockCmd(RCC_I2C_PORT, ENABLE);	//时钟
    
    	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();
    }
    
    /*
    CPU发送设备地址,然后读取设备应答是否有设备
    */
    uint8_t i2c_CheckDevice(uint8_t _Address)
    {
    	uint8_t ucAck;
    
    	i2c_GPIO_Config();		/* 配置GPIO */
    	
    	i2c_Start();		/*I2C开始信号*/
    
    	/* 发送设备地址和读写控制bit(0=写,1=读)bit7位先传 */
    	i2c_SendByte(_Address|I2C_WR);
    	ucAck = i2c_WaitAck();	/*检测设备应答 */
    
    	i2c_Stop();			/* I2C结束信号 */
    
    	return ucAck;
    }
    

    mp6050使用软件I2C读写数据

    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();
    }
    读
    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();
    }
    

    手册中寄存器描述

    1、电源管理寄存器

    描述:这个寄存器允许用户配置电源模式和时钟源。它也提供1位重置整个设备,和1位使能温度传感器
    SLEEP 设置1时,设备进入低功耗休眠模式;TEMP_DIS用于设置是否使能温度传感器,0 则使能

    CLKSEL[2:0]时钟源如下,

    内部8M RC晶振精度不高,一般选择X/Y/Z轴陀螺作为参考PLL的时钟源,设置CLKSEL=001

    2、陀螺仪寄存器
    该寄存器用于触发陀螺仪自检并配置陀螺仪的量程范围。

    FS_SEL[1:0]的取值:0,±250° /S; 1,±500° /S; 2,±1000° /S; 3,±2000° /S;
    一般设置为3,±2000dps,因为陀螺仪的ADC为16位分辨率,所以得到灵敏度为65536/4000 = 16.4LSB(°/S)

    3、加速度传感器
    该寄存器用于触发加速计自检并配置加速计满标度范围。该寄存器还配置数字高通滤波器(DHPF)。

    AFS_SEL[1:0]选择范围:0, ±2g; 1,±4g; 2,±8g; 3,±16g;
    一般设置为0,±2g ,灵敏度为65536/4=16384 LSB/g

    4、 采样率
    该寄存器指定用于生成MPU-60X0采样率的陀螺仪输出速率的除法器。

    传感器寄存器输出、FIFO输出和DMP采样均基于采样率。

    在这陀螺仪的输出频率是1Khz或者8Khz,与数字低通滤波器(DLPF)的设置有关。
    公式 采样频率 = 陀螺仪输出频率 / (1+SMPLRT_DIV)

    当 DLPF_CFG=0/7 的时候,频率为 8Khz,其他情况是 1Khz。而且 DLPF 滤波频率一般设置
    为采样率的一半。

    例如:采样率,假设为125HZ,那么 SMPLRT_DIV=1000/125 – 1 = 7

    5、 配置寄存器
    该寄存器配置陀螺仪和加速度计的外部帧同步(FSYNC)引脚采样和数字低通滤波器(DLPF)设置。

    其中,DLPF_CFG 配置低通滤波如下

    一般我们设置角速度传感器的带宽为其采样率的一半, 如前面所说的,如果设置采样率为 125Hz,那么带宽就应该设置为 62Hz,取近似值 44Hz, 就应该设置 DLPF_CFG=011

    MPU6050初始化的步骤:

  • 复位MPU6050,让MPU6050内部的所有寄存器恢复默认值
    必须设置该寄存器位0x00,以唤醒MPU6050,进入正常工作状态,一般选择x轴陀螺PLL作为时钟源,以获得更高精度的时钟。
  • 陀螺仪配置寄存器(0x1B)
  • 加速度传感器配置寄存器(0x1C)
  • 陀螺仪采样率,由采样率分频寄存器(0x19)控制;
  • 设置数字低通滤波器,由配置寄存器(0x1A)控制;
    DLPF位设置,即DLPF_CFG[2:0],加速度技和陀螺仪,都是根据这三个位的配置进行过滤的,
  • 初始化程序

    #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_PWR_MGMT_1       0x6B
    #define MPU6050_RA_PWR_MGMT_2       0x6C
    
    #define MPU6050_WHO_AM_I        0x75
    #define MPU6050_SMPLRT_DIV      0  //8000Hz  fix me
    #define MPU6050_DLPF_CFG        0  //fix me
    #define MPU6050_GYRO_OUT        0x43     //MPU6050陀螺仪数据寄存器地址
    #define MPU6050_ACC_OUT         0x3B     //MPU6050加速度数据寄存器地址
    
    void MPU6050_Init(void)
    {
      int i=0,j=0;
      for(i=0;i<1000;i++)
      {
        for(j=0;j<1000;j++);
      }
    	MPU6050_WriteReg(MPU6050_RA_PWR_MGMT_1, 0x01);
    	MPU6050_WriteReg(MPU6050_RA_SMPLRT_DIV , 0x07);	//值得设置
    	MPU6050_WriteReg(MPU6050_RA_CONFIG , 0x03);//值得设置
    	MPU6050_WriteReg(MPU6050_RA_ACCEL_CONFIG , 0x00);
    	MPU6050_WriteReg(MPU6050_RA_GYRO_CONFIG, 0x18);
    }
    

    数据读取

    1、 陀螺仪数据输出寄存器
    通过读取这6个寄存器,就可以读到陀螺仪 x/y/z 轴的值,比如 x 轴的数据,可以通过读取 0X43(高 8 位)和 0X44(低 8 位)寄存器得到,其他轴以此类推

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

    2、加速度传感器数据输出寄存器
    通过读取这6个寄存器,就可以读到加速度传感器 x/y/z 轴的值,比如读 x 轴的数据,可以通过读取0X3B(高 8 位)和0X3C(低8位)寄存器得到,其他轴以此类推

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

    3、 温度换算

    温度传感器的值,可以通过读取 0X41(高 8 位)和 0X42(低 8 位)寄存器得到,

    温度换算公式为:Temperature = 36.53 + regval/340

    其中, Temperature 为计算得到的温度值,单位为℃, regval 为从 0X41 和 0X42 读到的温度传感器值

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

    4、主程序

    uint8_t MPU6050ReadID(void)
    {
    	unsigned char Re = 0;
    	MPU6050_ReadData(MPU6050_RA_WHO_AM_I,&Re,1); //读器件地址
    	if (Re != 0x68) {
    		MPU_ERROR("检测不到 MPU6050 模块");
    		return 0;
     	} else {
    		 MPU_INFO("MPU6050 ID = %d\r\n",Re);
    	return 1;
    	}
    }
    int main(void)
    {
    	short Accel[3];
    	short Gyro[3];
    	float Temp;
    	SysTick_Init();
    	SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk;
    	USART_Config();
    	i2c_GPIO_Config();
    	MPU6050_Init();
    
    	//检测MPU6050
    	if (MPU6050ReadID() == 1)
    	{	
    		while(1)
    		{
    			if(Task_Delay[0]==TASK_ENABLE)
    			{
    				Task_Delay[0]=1000;
    			}	
    			if(Task_Delay[1]==0)
    			{
    				MPU6050ReadAcc(Accel);			
    				printf("\加速度 %8d%8d%8d    ",Accel[0],Accel[1],Accel[2]);
    				MPU6050ReadGyro(Gyro);
    				printf("陀螺仪 %8d%8d%8d    ",Gyro[0],Gyro[1],Gyro[2]);				
    				MPU6050_ReturnTemp(&Temp); 
    				printf("温度 %8.2f",Temp);				
    				Task_Delay[1]=500;//更新数据的频率
    			}
    		}   
    	}
    }
    

    mpu6050输出的值

    加速度: 2634 -2146 16238 陀螺仪: -63 -29 -33 温度: 21.51
    加速度: 2680 -2312 16044 陀螺仪: -53 -18 -36 温度: 21.53
    加速度: 2744 -2320 16196 陀螺仪: -48 -16 -36 温度: 21.66
    加速度: -1 -1 -1 陀螺仪: -1 -1 -1 温度: 36.53
    加速度: -1 -1 -1 陀螺仪: -1 -1 -1 温度: 36.53
    加速度: -9586 3804 12182 陀螺仪: -456 -594 -72 温度: 22.14
    加速度: -2452 -1740 15716 陀螺仪: -232 -436 -169 温度: 22.17
    加速度: -986 -1736 16178 陀螺仪: -64 -184 -56 温度: 22.20
    加速度: -194 -1790 16366 陀螺仪: -46 -9 -11 温度: 22.24

    参考

    MPU-6000.6050中文资料.pdf
    野火MPU6050模块用户手册.pdf
    MPU6050原始数据分析.pdf

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32使用MPU6050姿态传感器的指南

    发表评论