([HAL库]STM32F1系列使用MPU6050(初级使用))

您所在的位置:网站首页 mpu6050寄存器手册 ([HAL库]STM32F1系列使用MPU6050(初级使用))

([HAL库]STM32F1系列使用MPU6050(初级使用))

#([HAL库]STM32F1系列使用MPU6050(初级使用))| 来源: 网络整理| 查看: 265

@([HAL库]STM32F1系列使用MPU6050(初级使用))

简介

最近开始使用了6轴姿态传感器MPU6050,准备学习一下姿态融合,于是打算写下了这篇博客。使用MPU6050之前,建议先阅读一遍他的寄存器手册,这样初学者能够更进一步了解MPU6050的地址,能够更快速理解配置代码。废话不多说,先看MPU6050的寄存器。

MPU6050主要寄存器

在这里插入图片描述 这个寄存器是指定陀螺仪输出速率的除法器,用于生成MPU-6050的采样速率。这个寄存器的地址是0x19 采样率公式:Sample Rate = Gyroscope Output Rate / (1 + SMPLRT_DIV) Sample Rate :采样频率 Gyroscope Output Rate:陀螺仪输出频率 SMPLRT_DIV:8位无符号值。 采样速率由陀螺仪输出速率除以该值确定。 对于陀螺仪输出频率需要主要一点:当DLPF低通滤波器禁用时(即DLPF_CF为0或7)陀螺仪输出频率为8KHz,当其使能使,陀螺仪输出频率为1KHz。

在这里插入图片描述 这个寄存器是用于配置陀螺仪和加速度计的外部帧同步(FSYNC)引脚采样和数字低通滤波器(DLPF)设置。0x1A是这个寄存器的地址,EXT_SYNC_SET是3位无符号值。 配置FSYNC引脚采样,一般情况下是给000(即禁止输入),DLPF_CF是设置低通滤波器的频率。这个频率一般情况下是带宽的 1/2 即可。(具体详细内容可以见寄存器手册)

在这里插入图片描述 该寄存器用于触发陀螺仪自检和配置陀螺仪的满量程范围。这个寄存器的地址是0x1B。这个寄存器的通过FS_SEL[1:0]设置了陀螺仪的的量程范围。同时XG_ST,YG_ST,ZG_ST这三个位是用于设置是否开启陀螺仪的XYZ三轴自检查(一般设置0,不进行自检)。 FS_SEL[1:0]有四种量程选择如下图: 在这里插入图片描述 通常选用±2000°/S这个量程范围。

在这里插入图片描述 该寄存器用于触发加速度计自检和配置加速度计满量程范围。 该寄存器还配置数字高通滤波器(DHPF)(一般都是不适用关闭,给0即可)。寄存器的地址是0x1X。这个寄存器的通过AFS_SEL[1:0]设置了加速度计的的量程范围。同时XA_ST,YA_ST,ZA_ST这三个位是用于设置是否开启加速度计的XYZ三轴自检查(一般设置0,不进行自检)。 AFS_SEL[1:0]有四种量程选择如下图: 在这里插入图片描述 通常选用±2g这个量程范围。

在这里插入图片描述 该寄存器决定哪些传感器测量值被加载到FIFO缓冲器中。寄存器的地址位0x23,因为本章节是初级使用,因此是禁用这个的给0就行。

在这里插入图片描述 此寄存器配置INT引脚中断信号的行为。寄存器地址是0x37。本次没有使用中断,于是这个寄存器也设置为0。

在这里插入图片描述 该寄存器允许中断源产生中断。寄存器地址0x38,但是没有使用中断,本章节并不使用中断因此也给0即可。如果使用中断根据寄存器手册配置即可。

在这里插入图片描述这些寄存器存储最近的加速度计测量值。 ACCEL_XOUT:16位2的补码值。 存储最近的X轴加速度计测量值。 ACCEL_YOUT:16位2的补码值。 存储最近的Y轴加速度计测量值。 ACCEL_ZOUT:16位2的补码值。 存储最近的Z轴加速度计测量值。

在这里插入图片描述 这些寄存器存储最新的温度传感器测量值。 TEMP_OUT:16位有符号值。 存储最近的温度传感器测量值。

在这里插入图片描述 这些寄存器存储最新的陀螺仪测量值。 GYRO_XOUT:16位2的补码值。 存储最近的X轴陀螺仪测量。 GYRO_YOUT:16位2的补码值。 存储最近的Y轴陀螺仪测量。 GYRO_ZOUT:16位2的补码值。 存储最近的Z轴陀螺仪测量值。

在这里插入图片描述此寄存器允许用户启用和禁用FIFO缓冲器、I2C主模式和主I2C接口。寄存器的地址是0X1A,初级使用下FIFO禁用,并且也没有外接AUX IIC传感器,所以也禁用I2C主模式和接口,直接给0。 在这里插入图片描述 此寄存器允许用户配置电源模式和时钟源。 它还提供了一个用于重置整个设备的位,以及一个用于禁用温度传感器的位。该寄存器的地址是0x6B。上电初始化时得先使用这个寄存器进行一个重置整个设备,设置最高位DEVICE_RESET位1即重置。 SLEEP置1睡眠,一般0。 CYCLE当此位设置为1并且休眠被禁用时,MPU-60x0将在休眠模式和唤醒模式之间循环,以由LP_WAKE_CTRL(寄存器108)确定的速率从活动传感器获取单个数据样本。 TEMP_DIS当设置为1时,此位禁用温度传感器. CLKSEL[2:0]寄存器配置时钟源,如图:在这里插入图片描述 一般选者陀螺仪X轴的时钟源。 在这里插入图片描述 此寄存器允许用户在加速度计低功耗模式下配置唤醒频率。寄存器地址是0x6C,该寄存器主要目的就是为了启动MPU6050的陀螺仪和加速度计。 LP_WAKE_CTRL[1:0]使用在MPU-9050上,因此MPU6050设置为0。 STBY_XA :当设置为1时,此位使X轴加速度计进入待机模式 STBY_YA:当设置为1时,此位使Y轴加速度计进入待机模式 STBY_ZA:当设置为1时,此位使Z轴加速度计进入待机模式 STBY_XG:当设置为1时,此位使X轴陀螺仪进入待机模式。 STBY_YG:当设置为1时,此位使Y轴陀螺仪进入待机模式。 STBY_ZG:当设置为1时,此位使Z轴陀螺仪进入待机模式。 所以以上信号都要设置为0,启动陀螺仪。

到这里以上都是最基本最重要的MPU-6050得得寄存器。还有很多各种功能寄存器需要用在别的场合再进行配置。

STM32CUBE配置

采用STM32F103C8T6作为控制器,该芯片内部有两个硬件IIC,因此采用硬件IIC来控制MPU-6050,以下是配置过程。 配置外部高速晶振。

在这里插入图片描述

配置下载模式,我使用的是SWD下载模式。 在这里插入图片描述

选择I2C模式。默认引脚是SDA-PB7 SCL-PB6在这里插入图片描述

并且要将I2C时钟频率设置为400KHz。因为MPU-6050手册中写道需要使用400KHz的I2C执行与设备所有寄存器的通信。 在这里插入图片描述

配置串口通道1,默认设置即可。 在这里插入图片描述

KEIL代码编写 修改HAL库I2C的BUG

在i2c.c文件下 将__HAL_RCC_I2C1_CLK_ENABLE();提前

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle) { GPIO_InitTypeDef GPIO_InitStruct = {0}; if(i2cHandle->Instance==I2C1) { /* USER CODE BEGIN I2C1_MspInit 0 */ //I2CBug 将这个使能提前 __HAL_RCC_I2C1_CLK_ENABLE(); /* USER CODE END I2C1_MspInit 0 */ __HAL_RCC_GPIOB_CLK_ENABLE(); /**I2C1 GPIO Configuration PB6 ------> I2C1_SCL PB7 ------> I2C1_SDA */ GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7; GPIO_InitStruct.Mode = GPIO_MODE_AF_OD; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(GPIOB, &GPIO_InitStruct); /* I2C1 clock enable */ __HAL_RCC_I2C1_CLK_ENABLE(); /* USER CODE BEGIN I2C1_MspInit 1 */ /* USER CODE END I2C1_MspInit 1 */ } } 设置串口printf重定义

在usart.c的文件底部的/* USER CODE BEGIN 1 /和/ USER CODE END 1 */中间添加以下代码: 报错就是没有添加#include "stdio.h"头文件。

#ifdef __GNUC__ #define PUTCHAR_PROTOTYPE int __io_putchar(int ch) #else #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) #endif /* __GNUC__ */ PUTCHAR_PROTOTYPE { HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xFFFF); return ch; } MPU-6050配置代码

mpu-6050.h文件

#ifndef __MPU6050_H #define __MPU6050_H #include "main.h" #include "i2c.h" #define MPU6050_Write_Addr 0xD0 //默认状态 地址为0X69 只有六位数据 使用IC7位寻址 ,第七位根据MPU6050引脚AD0在判断 AD0=0 第七位0 AD0=1 第七位1 第八位I2C读1 写0 我这里使用AD0=0低电平 #define MPU6050_Read_Addr 0xD1 #define MPU_Out_Fre_DIV_Addr 0x19 //采样频率地址 默认8Khz 如果开了低通滤波器 则变为1Khz #define MPU_Dlpf_Addr 0x1A //低通滤波器地址 #define MPU_Gyro_Addr 0x1B //陀螺仪数据地址 第八七六位 XYZ轴自检给1 不自检给0 第五四两位 用于给陀螺仪量程范围 00-0~250 01-0~500 10-0~1000 11-0~2000 其余位0 #define MPU_Accel_Addr 0x1C //加速计数据地址 第八七六位 XYZ轴自检给1 不自检给0 第五四两位 用于给陀螺仪量程范围 00-±2G 01-±4G 10-±8G 11-±16G 其余位0 #define MPU_Id_Addr 0x75 //MPU ID的地址 #define MPU_Int_Addr 0X38 //mpu中断使能地址 #define MPU_User_Addr 0x6A //MPU用户控制地址 用于控制FIFO I2C主模式 #define MPU_Fifo_En_Addr 0x23 //MPU的FIFO使能地址 #define MPU_Int_Pin_Addr 0x37 //INT中断地址 #define PowerMem_Register1_Addr 0x6B //电源管理1的地址 #define PowerMem_Register2_Addr 0x6C //电源管理2的地址 #define Set_PowerMen_Reset 0x80 //在电源管理 输入 这个数据 为MPU 复位 #define Set_PowerMen_Start_XPPL 0x01 //在电源管理 输入 这个数据 为MPU唤醒 且使用X轴的时钟源 #define Set_Smplrt_Div 0x00 //采样分频 #define Set_Dlpf_Div 0x00 //低通滤波器模式 #define Set_Gyro_Range 0x11 //设置陀螺仪的量程范围 #define Set_Accel_Range 0x00 //设置加速计的量程范围 #define Set_Int_Enable 0x00 //设置关闭全部中断 #define Set_User_I2c 0x00 //禁止FIFO I2C主模式 #define Set_Fifo_Enable 0x00 //禁止FIFO模式 #define Set_Int_Pin_L 0x80 //INT脚低电平有效 #define Sat_Start_Mpu 0x00 //设置启动MPU陀螺仪 //加速度计 数据寄存器地址 #define ACCEL_Xout_H 0x3B #define ACCEL_Xout_L 0x3C #define ACCEL_Yout_H 0x3D #define ACCEL_Yout_L 0x3E #define ACCEL_Zout_H 0x3F #define ACCEL_Zout_L 0x40 //陀螺仪 数据寄存器地址 #define GYRO_Xout_H 0x43 #define GYRO_Xout_L 0x44 #define GYRO_Yout_H 0x45 #define GYRO_Yout_L 0x46 #define GYRO_Zout_H 0x47 #define GYRO_Zout_L 0x48 extern signed short ax; extern signed short ay; extern signed short az; extern signed short gx; extern signed short gy; extern signed short gz; extern signed short ax_l; extern signed short ay_l; extern signed short az_l; extern signed short gx_l; extern signed short gy_l; extern signed short gz_l; void I2C_Write(unsigned char dev_addr,unsigned char mem_addr , unsigned char data); void I2C_Read(unsigned char dev_addr,unsigned char mem_addr , unsigned char *buf,unsigned char len); void MPU_Set_LPF(uint16_t lpf); void Set_Mpu_Rate(uint16_t rata); void MPU_6050_Init(void); void Read_Mpu_Gyro(void); void Read_Mpu_Accel(void); void MPU6050_calibrate(void);

mpu-6050.c文件

#include "mpu6050.h" #include "stdio.h" unsigned char I2C_Accel_Buf[6]; unsigned char I2C_Gyro_Buf[6]; //加速度计 signed short ax; signed short ay; signed short az; //陀螺仪 signed short gx; signed short gy; signed short gz; //校准 signed short ax_l=0; signed short ay_l=0; signed short az_l=0; signed short gx_l=0; signed short gy_l=0; signed short gz_l=0; //编写I2C写入 void I2C_Write(unsigned char dev_addr,unsigned char mem_addr , unsigned char data) { HAL_I2C_Mem_Write(&hi2c1,dev_addr,mem_addr,I2C_MEMADD_SIZE_8BIT,&data,1,2); } //编写I2C读出 void I2C_Read(unsigned char dev_addr,unsigned char mem_addr , unsigned char *buf,unsigned char len) { HAL_I2C_Mem_Read(&hi2c1,dev_addr,mem_addr,I2C_MEMADD_SIZE_8BIT,buf,len,2); } //初始化MPU6050 void MPU_6050_Init(void) { unsigned char temp=0; reset_MPU6050: I2C_Write(MPU6050_Write_Addr,PowerMem_Register1_Addr,Set_PowerMen_Reset); //MPU复位 HAL_Delay(50); I2C_Write(MPU6050_Write_Addr,PowerMem_Register1_Addr,Set_PowerMen_Start_XPPL); //MPU唤醒 使用X轴作为时钟源 I2C_Read(MPU6050_Write_Addr,MPU_Id_Addr,&temp,1); //读器件ID if(temp != 0x68) { goto reset_MPU6050; } I2C_Write(MPU6050_Write_Addr,MPU_Gyro_Addr,(Set_Gyro_Range I2C_Read(MPU6050_Write_Addr,ACCEL_Xout_H,I2C_Accel_Buf,6); ax= (I2C_Accel_Buf[0] uint8_t data=0; if(lpf>=188)data=1; else if(lpf>=98)data=2; else if(lpf>=42)data=3; else if(lpf>=20)data=4; else if(lpf>=10)data=5; else data=6; I2C_Write(MPU6050_Write_Addr,MPU_Dlpf_Addr,data); } /*自校准模式 MPU6050校准函数 将IMU水平放置,z轴向上时,启动校准 思路是计算N个周期的平均值,得到校准参数 */ #define CL_cnt 128 void MPU6050_calibrate(void) { unsigned short i; signed int temp[6] = {0}; for(i=0; i /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ printf("----------------------------------\r\n"); HAL_Delay(500); Read_Mpu_Gyro(); Read_Mpu_Accel(); printf("ax:%1.3f g,\tgx:%f deg/s\r\n",(float)ax/(0xffff/4),(float)gx/(0xffff/500)); //输出加速度计和陀螺仪的初始数据 } 串口打印

在这里插入图片描述 在读取过程中,我摇晃了MPU_6050因此读到的数据有偏差。并且这个是最原始的数据,还未做任何处理。到这里已经完成了本章的所有功能。初级使用MPU-6050读到了原始数据。后续将会使用DMP姿态计算获得俯仰角,翻滚角和偏航角,更进一步姿态解算后使用卡尔曼滤波,令其解算出的角度更加准确。

使用过程中遇到的问题

在使用过程中遇到了极其奇葩的问题,有个型号的MPU-6050模块读到的器件地址不是0x68而是0x98。然后百度了一下发现还真有人遇到了这种神奇的问题,而且还是同一种模块。(有些人能读到数据,有些人读不到,也有些人不确定读到的对不对。。)但是没有任何资料更够解释这个现象。总之还是避免买下面这个模块吧。 在这里插入图片描述 在这里插入图片描述



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3