正点stm32f407探索者开发板使用HAL库通过I2C协议配置并读取MPU6050(基础向)

此文图片均链自CSDN

参考资料:[1][2]正点原子资料下载中心->stm32f407探索者开发板:资料A盘:Explorer STM32F4_V2.2_SCH.pdf,探索者IO引脚分配表.xlsx,5,MPU6050资料.rar

文章内容仅供参考;


通过STM32f07ZG芯片通过i2c协议向MPU6050的寄存器写数据来配置传感器,并通过该协议读取传感器读数;

MPU6050简述

在这篇文章中,主要用到了MPU6050集成的3轴MEMS陀螺仪和3轴MEMS加速度计;
其中陀螺仪的测量值是正比于角速度,不难理解,也可以方便地直接转换为国际单位制(如何转换下文详述);
对于加速度传感器的测量值,我们可以引入如下模型
在这里插入图片描述
在这里插入图片描述
若我使传感器在地表以1g的加速度竖直向上加速,那么传感器的示数应为Z=-2g
其测量值即为墙壁对小球造成的加速度,具体表现为小球所受重力加速度与小球与地面加速度的矢量和。同样,测量值与SI(国际单位制)也需要正比换算;

MPU6050的封装

在这里插入图片描述
我们可以观察到AD0针脚接地,根据AD0电平与传感器Slave地址的关系
在这里插入图片描述
我们可以得知传感器的从机地址为0x68;
我们结合在这里插入图片描述
可知I2C的两条线连接到了芯片的PB8和PB9引脚,我们可以将这两条引脚设置为I2C1;
在这里插入图片描述

I2C的函数操作

在这里插入图片描述
在这里我们用到的是这两个函数,内容是以阻塞模式将一定量的数据写入特定的内存地址/以阻塞模式从特定的内存地址读取一定量的数据;
函数参数如下(以读从机函数为例):
在这里插入图片描述
第一个值是指向包含指定 I2C 的配置信息的 I2C_HandleTypeDef 结构的指针,这部分是配置完.ioc文件后CubeMAX自动生成的,具体取决于使用的I2C编号,此处即为&hi2c1
在这里插入图片描述
第二个值为七位目标设备地址,注意使用时还需要左移一位,也就是上面提到的0x68;
第三个值为内存地址,即从机上的寄存器地址,地址的值需要查询寄存器分配表;
第四个值为内存地址长度,每8位二进制数为1,在这篇文章中均为1;
第五个值为接收数据的地址,指向要发送的数据;
第六个值为要接收的数据量,每8位二进制数为1;
第七个值为超时时间,如果超时未收到应答信号,则会在返回值中体现出来,单位毫秒(1000ms=1s);
返回值定义如下(自动生成):
在这里插入图片描述
写从机函数的第五、六个值变成了指向要发送数据的指针和要发送的数据量,和读从机函数细节相同;

配置过程寄存器操作内容

代码会在最后附上
在这里插入图片描述

上图的一些名称不是标准命名,仅供参考

重置MPU6050

在这里插入图片描述
MPU_PWR_MGMT1_REG(0x6B)寄存器Bit7写为1,并延时适当时间等待复位;

1
2
3
valu=0x80;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_PWR_MGMT1_REG,1,&valu,1,100);// Reset MPU6050
HAL_Delay(100);

唤醒MPU6050并配置时钟源

MPU_PWR_MGMT1_REG(0x6B)寄存器Bit6位写为0,Bit210设置为001,即将时钟源定位X轴角速度计;;

1
2
valu=0x01;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_PWR_MGMT1_REG,1,&valu,1,100);// Awaken MPU6050 &Set clock as PLL X

关闭所有中断

在这里插入图片描述
在这个简单实验中不需要配置这部分;
MPU_INT_EN_REG(0x38)寄存器Bit0347均置为1;

1
2
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_INT_EN_REG,1,&valu,1,100);// Close all interrupts

失能FIFO并关闭传感器i2c主机模式

在这里插入图片描述
MPU_USER_CTRL_REG(0x6A)寄存器Bit654写0;

1
2
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_USER_CTRL_REG,1,&valu,1,100);// Turn off IIC host mode and FIFO

无数据需要写入FIFO

在这里插入图片描述
在这里插入图片描述

使MPU_FIFO_EN_REG(0x23)寄存器均为0即可;

1
2
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_FIFO_EN_REG,1,&valu,1,100);// No sensors were added to the FIFO

关闭传感器待机模式

在这里插入图片描述

MPU_PWR_MGMT2_REG(0x6C)寄存器Bit543210位均置0;

1
2
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_PWR_MGMT2_REG,1,&valu,1,100);// Awaken sensor

配置陀螺仪和加速度计

在这里插入图片描述
在这里插入图片描述
本次简单实验不需要自检,选择量程即可;
MPU_ACCEL_CFG(0x1C)寄存器和MPU_GYRO_CFG(0X1B)寄存器的Bit43均设置为1(选择最大量程);

1
2
3
valu=0x18;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_ACCEL_CFG,1,&valu,1,100);// Accelerometer configuration
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_GYRO_CFG,1,&valu,1,100);// Gyroscope configuration

配置数字低通滤波器


这里选择相对均衡的配置,即将MPU_CONFIGURATION(0x1A)的Bit210配置为011;

1
2
valu=0x03;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_CONFIGURATION,1,&valu,1,100);// Select sampling rate

配置输出率

在这里插入图片描述

根据上式,MPLRT写0即可,将MPU_RATE_DIVIDER(0x19)寄存器所有位写0;

1
2
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_RATE_DIVIDER,1,&valu,1,100);// Select output rate

配置部分代码一览

1
2
3
4
5
6
7
8
9
10
11
12
#define MPU_PWR_MGMT1_REG		0X6B
#define MPU_PWR_MGMT2_REG 0X6C
#define MPU_INT_EN_REG 0X38
#define MPU_USER_CTRL_REG 0X6A
#define MPU_FIFO_EN_REG 0X23
#define MPU_DEVICE_ID_REG 0X75
#define MPU_ACCEL_XOUTH_REG 0X3B
#define MPU_GYRO_XOUTH_REG 0X43
#define MPU_ACCEL_CFG 0X1C
#define MPU_GYRO_CFG 0X1B
#define MPU_RATE_DIVIDER 0X19
#define MPU_CONFIGURATION 0X1A
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
HAL_StatusTypeDef stat;
uint8_t valu=0x80;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_PWR_MGMT1_REG,1,&valu,1,100);// Reset MPU6050
HAL_Delay(100);
valu=0x01;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_PWR_MGMT1_REG,1,&valu,1,100);// Awaken MPU6050 &Set clock as PLL X
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_INT_EN_REG,1,&valu,1,100);// Close all interrupts
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_USER_CTRL_REG,1,&valu,1,100);// Turn off IIC host mode and FIFO
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_FIFO_EN_REG,1,&valu,1,100);// No sensors were added to the FIFO
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_PWR_MGMT2_REG,1,&valu,1,100);// Awaken sensor
valu=0x18;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_ACCEL_CFG,1,&valu,1,100);// Accelerometer configuration
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_GYRO_CFG,1,&valu,1,100);// Gyroscope configuration
valu=0x03;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_CONFIGURATION,1,&valu,1,100);// Select sampling rate
valu=0x00;
stat=HAL_I2C_Mem_Write(&hi2c1,0x68<<1,MPU_RATE_DIVIDER,1,&valu,1,100);// Select output rate

读取部分寄存器操作内容

在这里插入图片描述
在这里插入图片描述
按地址读取测量值即可;
接收之后需要把数据处理成16位有符号整数。

1
2
3
4
#define MPU_ACCEL_XOUTH_REG	0X3B
#define MPU_GYRO_XOUTH_REG 0X43
int16_t data16A[3],data16G[3];
uint8_t dataACCEL[6],dataGYRO[6];
1
2
3
4
5
stat=HAL_I2C_Mem_Read(&hi2c1, 0x68<<1,MPU_ACCEL_XOUTH_REG, 1, dataACCEL,6, 100);
stat=HAL_I2C_Mem_Read(&hi2c1, 0x68<<1,MPU_GYRO_XOUTH_REG, 1, dataGYRO,6, 100);
for(int8_t i=0;i<3;i++)
data16G[i]=(((uint16_t)dataGYRO[2*i])<<8)|dataGYRO[2*i+1],
data16A[i]=(((uint16_t)dataACCEL[2*i])<<8)|dataACCEL[2*i+1];

此时data16·[i]中存储的并不是SI下的数据:
对于陀螺仪,如果内存数字为X,则有X=wLSBACCELX=w\cdot \text{LSB}_{ACCEL},w的单位即为°/s;
对于加速度计,如果内存的数字为X,则有X=aLSBGYROX=a\cdot \text{LSB}_{GYRO},a的单位为g(约9.8m/s2),需要注意,加速度值并不是物体相对于地面的加速度值,而是该值与重力加速度的矢量和;
对于LSB的值可以依照所选量程对照上表可得;

一些数据验证

我在不同角度下静置开发板,并通过U5的调试模式下以10Hz左右读取了100组加速度计测量值(data16A[i])的平均值,定义函数

f([a1,a2,a3])=a12+a22+a32f([a_1,a_2,a_3])=\sqrt{a_1^2+a_2^2+a_3^2}

绘制下表:

组数 a1 a2 a3 f([a1,a2,a3])
1 -1.81 51.35 2039.58 2040.23
2 385.66 47.98 2004.43 2041.76
3 1385.47 168.05 1488.20 2040.22
4 -2068.78 39.14 10.00 2069.19
5 2.99 2084.68 -59.76 2085.54

可以观察到,在误差允许范围内,均接近所选量程下最低分辨率的1g(2048LSB/g);


正点stm32f407探索者开发板使用HAL库通过I2C协议配置并读取MPU6050(基础向)
https://tanyuu.github.io/2022.01-06/正点stm32f407探索者开发板使用HAL库通过I2C协议配置并读取MPU6050(基础向)/
作者
F Juny
发布于
2022年4月18日
许可协议