STM32F401 MPU6050实验(二)测加速度

 

目录

一、硬件资源

二、实验原理

初识MPU6050

MPU6050内的寄存器

1.SMPLRT_DIV 分频寄存器

2.CONFIG 配置寄存器

3.GYRO_CONFIG 陀螺仪配置寄存器

4.ACCEL_CONFIG 加速度计配置寄存器

5.PWR_MGMT_1

6.PWR_MGMT_2

7.WHO_AM_I

8.ACCEL_XOUT_H和ACCEL_XOUT_L

结果分析

三、代码部分

MPU6050.c

MPU605.h

main.c


本文是在上一篇文章的基础上进行的,对于IIC通信协议不懂的可以看上一篇博文MPU6050实验(一)IIC原理

由于要用到MPU6050的寄存器,所以要参考MPU6050的寄存器手册。

一、硬件资源

STM32F401,MPU6050,OLED显示屏

二、实验原理

初识MPU6050

MPU6050内部整合了三轴陀螺仪、三轴加速度计,而且还可以连接一个第三方数字传感器(如磁力
计),这样的话,就可以通过IIC接口输出一个9轴信号。陀螺仪的数据和加速度计的数据经过数据融合(互补滤波、卡尔曼滤波等等)才可以得到正确的⻆速度、加速度。

 

各轴采集到的数据经过ADC模数转换之后变为电平信号存入寄存器。

各方向确定如下:

MPU6050内的寄存器

 寄存器的地址可以在MPU6050的说明书Register Map找到,下面对Map进行说明:

Addr(Hex)十六进制地址,Addr(Dec)十进制地址,Serial属性,R/W为可读可写,R为只读

在对寄存器进行写操作之前要解除芯片的睡眠模式,由PWR_MGMT_1电源管理寄存器的sleep位控制,写0解除睡眠。如下图

1.SMPLRT_DIV 分频寄存器

分频越小内部AD转换越快,数据寄存器刷新越快

Sample Rate = Gyroscope Output Rate陀螺仪时钟/(1+SMPLRT_DIV)

不使用低通滤波器时,陀螺仪时钟为8KHz,使用时为1KHz

2.CONFIG 配置寄存器

外部同步设置和低通滤波器配置,配置滤波器参数越大,输出数据抖动越小。

3.GYRO_CONFIG 陀螺仪配置寄存器

高3位是XYZ轴的自测使能位,
Self-test response = Sensor output with self-test enabled - Sensor output without self-
test enabled(自测响应=使能-失能)

中间两位是满量程选择位。

4.ACCEL_CONFIG 加速度计配置寄存器

高3位是XYZ轴的自测使能位,中间两位是满量程选择位,最后三位配置高通滤波器

ACCEL_XOUT高位左移8位,或上低位数据,存入一个int16_t的变量

5.PWR_MGMT_1

第一位设备复位,写1所有寄存器恢复到默认值

第二位,睡眠模式,3循环模式,唤醒频率由PWR_MGMT_2的高2位确定

Bit3温度传感器的使能和失能,最后三位选择系统时钟来源

6.PWR_MGMT_2

用来控制6个轴进入待机模式

7.WHO_AM_I

属性为只读,内容为ID号,默认值为0x68

8.ACCEL_XOUT_H和ACCEL_XOUT_L

每个寄存器只有八位,所以读到的数据分为高八位和低八位存放,最后将高八位进行移位操作或上低八位得到十六位的数据。

其他轴的和GYRO的寄存器也是同样的道理。

结果分析

x为测得的数据,y为实际加速度,由x计算得到y的公式为x/32768=y/16(g)
 

三、代码部分

MPU6050.c

这部分要包含头文件,其中有寄存器对应的地址。

由于函数MPU6050_GetData要返回6个轴的传感器数据,本实验用指针传递。

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

#define MPU6050_ADDRESS 0xD0 //为了方便修改参数,突出是从机

void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data){//指定地址写寄存器
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReceiveAck();//从机收到后应答
	MyI2C_SendByte(RegAddress);//指定寄存器
	MyI2C_ReceiveAck();
	MyI2C_SendByte(Data);//数据
	MyI2C_ReceiveAck();
	MyI2C_Stop();
}
uint8_t MPU6050_ReadReg(uint8_t RegAddress){//指定地址读寄存器
	uint8_t Data;
	MyI2C_Start();
	MyI2C_SendByte(MPU6050_ADDRESS);
	MyI2C_ReceiveAck();//从机收到后应答
	MyI2C_SendByte(RegAddress);//指定寄存器
	MyI2C_ReceiveAck();
	MyI2C_Start();//重新指定读写位
	MyI2C_SendByte(MPU6050_ADDRESS |0x01);
	MyI2C_ReceiveAck();
	Data = MyI2C_ReceiveByte();//数据
	MyI2C_SendAck(1);//不给从机应答
	MyI2C_Stop();
	return Data;
}

void MPU6050_Init(){
	MyI2C_Init();
	MPU6050_WriteReg(PWR_MGMT_1,0X01);//解除睡眠,选择陀螺仪时钟
	MPU6050_WriteReg(PWR_MGMT_2,0X00);//6轴均不待机
	MPU6050_WriteReg(SMPLRT_DIV,0X09);//陀螺仪采样率为1K/(1+0x09)=100Hz
	MPU6050_WriteReg(CONFIG,0X06);//对应外部同步和低通滤波设置
	MPU6050_WriteReg(GYRO_CONFIG,0X18);//自测使能,满量程选择
	MPU6050_WriteReg(ACCEL_CONFIG,0X18);//自测使能,满量程选择,高通滤波器
	
}
uint8_t MPU6050_GetID(){//返回MPU6050的ID
	return MPU6050_ReadReg(WHO_AM_I);
}
//用指针,进行变量的地址传递,实现多返回值
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
						int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ)
{
	uint8_t DataH,DataL;//分别接收高八位和低八位的数据
	DataH = MPU6050_ReadReg(ACCEL_XOUT_H);
	DataL = MPU6050_ReadReg(ACCEL_XOUT_L);
	*AccX = (DataH << 8) | DataL;//高八位左移八位或低八位得到十六位的数据
	
	DataH = MPU6050_ReadReg(ACCEL_YOUT_H);
	DataL = MPU6050_ReadReg(ACCEL_YOUT_L);
	*AccY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(ACCEL_ZOUT_H);
	DataL = MPU6050_ReadReg(ACCEL_ZOUT_L);
	*AccZ = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(GYRO_XOUT_L);
	*GyroX = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(GYRO_XOUT_L);
	*GyroY = (DataH << 8) | DataL;
	
	DataH = MPU6050_ReadReg(GYRO_XOUT_H);
	DataL = MPU6050_ReadReg(GYRO_XOUT_L);
	*GyroZ = (DataH << 8) | DataL;
}


MPU605.h

其中有寄存器的地址宏定义,对寄存器用途不清楚可以参考手册

#ifndef MPU6050_H
#define MPU6050_H

#define SMPLRT_DIV	0x19
#define CONFIG		0x1A
#define GYRO_CONFIG	0x1B
#define ACCEL_CONFIG	0x1C

#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 TEMP_OUT_H	0x41
#define TEMP_OUT_L	0x42
#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

#define PWR_MGMT_1	0x6B
#define PWR_MGMT_2	0x6C
#define WHO_AM_I	0x75


void MPU6050_WriteReg(uint8_t RegAddress,uint8_t Data);
uint8_t MPU6050_ReadReg(uint8_t RegAddress);
void MPU6050_Init(void);
uint8_t MPU6050_GetID();
void MPU6050_GetData(int16_t *AccX,int16_t *AccY,int16_t *AccZ,
						int16_t *GyroX,int16_t *GyroY,int16_t *GyroZ);

#endif
main.c

将测得的数据分两列输出左边为加速度,右边为角速度

#include "stm32f4xx.h"                  // Device header
#include "oled.h"
#include "MPU6050.h"

int16_t AX,AY,AZ,GX,GY,GZ;

int main(void){
	OLED_Init();
	MPU6050_Init();
	OLED_ShowString(1,1,"ID");
	uint8_t ID;
	OLED_ShowHexNum(1,4,ID,2);//显示MPU6050地址
	
	while(1){
		MPU6050_GetData(&AX,&AY,&AZ,&GX,&GY,&GZ);
		OLED_ShowSignedNum(2,1,AX,5);
		OLED_ShowSignedNum(3,1,AY,5);
		OLED_ShowSignedNum(4,1,AZ,5);
		OLED_ShowSignedNum(2,8,GX,5);
		OLED_ShowSignedNum(3,8,GY,5);
		OLED_ShowSignedNum(4,8,GZ,5);
	}
}
  • 40
    点赞
  • 52
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
以下是一个基于标准库函数的STM32F407 MPU6050陀螺仪姿态解算的示例代码: ```c #include "stm32f4xx.h" #include "math.h" #define PI 3.14159265 int16_t AccX, AccY, AccZ, GyroX, GyroY, GyroZ; float pitch = 0, roll = 0, yaw = 0; float AccAngleX, AccAngleY, GyroAngleX, GyroAngleY, GyroAngleZ; void Delay(__IO uint32_t nCount) { while(nCount--) { } } void MPU6050_Init() { // 初始化I2C ... // 初始化MPU6050 I2C_WriteByte(MPU6050_ADDR, MPU6050_RA_PWR_MGMT_1, 0x00); I2C_WriteByte(MPU6050_ADDR, MPU6050_RA_SMPLRT_DIV, 0x07); I2C_WriteByte(MPU6050_ADDR, MPU6050_RA_CONFIG, 0x06); I2C_WriteByte(MPU6050_ADDR, MPU6050_RA_GYRO_CONFIG, 0x18); I2C_WriteByte(MPU6050_ADDR, MPU6050_RA_ACCEL_CONFIG, 0x01); } void MPU6050_GetData() { uint8_t buf[14]; I2C_ReadBytes(MPU6050_ADDR, MPU6050_RA_ACCEL_XOUT_H, 14, buf); AccX = (buf[0] << 8) | buf[1]; AccY = (buf[2] << 8) | buf[3]; AccZ = (buf[4] << 8) | buf[5]; GyroX = (buf[8] << 8) | buf[9]; GyroY = (buf[10] << 8) | buf[11]; GyroZ = (buf[12] << 8) | buf[13]; } void MPU6050_CalcAngle() { AccAngleX = atan(AccY / sqrt(AccX * AccX + AccZ * AccZ)) * 180 / PI; AccAngleY = atan(-AccX / sqrt(AccY * AccY + AccZ * AccZ)) * 180 / PI; GyroAngleX = GyroX / 131.0; GyroAngleY = GyroY / 131.0; GyroAngleZ = GyroZ / 131.0; pitch = 0.98 * (pitch + GyroAngleX * 0.01) + 0.02 * AccAngleX; roll = 0.98 * (roll + GyroAngleY * 0.01) + 0.02 * AccAngleY; yaw += GyroAngleZ * 0.01; } int main(void) { MPU6050_Init(); while(1) { MPU6050_GetData(); MPU6050_CalcAngle(); Delay(100); } } ``` 需要注意的是,以上代码中的 `I2C_ReadBytes` 和 `I2C_WriteByte` 函数需要根据实际情况进行实现。另外,MPU6050的数据采样率可以通过 `MPU6050_RA_SMPLRT_DIV` 寄存器进行配置,根据具体要求进行设置。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值