✅作者简介:热爱科研的嵌入式开发者,修心和技术同步精进
❤欢迎关注我的知乎:对error视而不见
代码获取、问题探讨及文章转载可私信。
☁ 愿你的生命中有够多的云翳,来造就一个美丽的黄昏。
🍎获取更多嵌入式资料可点击链接进群领取,谢谢支持!👇
一、MPU6050简介
MPU6050是一款集成了三轴加速度计和三轴陀螺仪的6轴运动处理传感器,内部还集成了数字运动处理器(DMP),可以通过I2C接口输出处理后的姿态数据。它广泛应用于无人机、智能手环、机器人等领域,能够为设备提供精确的运动和姿态信息。
主要特性
- 三轴加速度计和三轴陀螺仪,可测量三个方向的加速度和角速度。
- 数字运动处理器(DMP),可直接输出四元数,方便进行姿态解算。
- 可编程的采样率和量程。
- 低功耗模式,适合电池供电设备。
- I2C接口,方便与微控制器连接。
二、硬件连接
将MPU6050与STM32进行连接,一般需要连接以下几根线:
- VCC:连接到STM32的电源正极(通常为3.3V)。
- GND:连接到STM32的地。
- SCL:连接到STM32的I2C时钟线。
- SDA:连接到STM32的I2C数据线。
- INT:中断输出引脚,可用于触发STM32的外部中断(可选)。
假设使用STM32的I2C1接口与MPU6050连接,硬件连接如下:
MPU6050 | STM32 |
---|---|
VCC | 3.3V |
GND | GND |
SCL | PB6 |
SDA | PB7 |
INT | PA0(可选) |
三、STM32代码实现
1. I2C初始化
首先需要初始化STM32的I2C接口,以下是基于STM32 HAL库的初始化代码:
#include "stm32f1xx_hal.h"
I2C_HandleTypeDef hi2c1;
void I2C1_Init(void)
{
hi2c1.Instance = I2C1;
hi2c1.Init.ClockSpeed = 400000;
hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c1.Init.OwnAddress1 = 0;
hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c1.Init.OwnAddress2 = 0;
hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c1) != HAL_OK)
{
Error_Handler();
}
}
void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{
GPIO_InitTypeDef GPIO_InitStruct = {0};
if (i2cHandle->Instance == I2C1)
{
__HAL_RCC_GPIOB_CLK_ENABLE();
__HAL_RCC_I2C1_CLK_ENABLE();
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);
}
}
2. MPU6050初始化
在使用MPU6050之前,需要对其进行初始化,设置采样率、量程等参数:
#define MPU6050_ADDR 0xD0
void MPU6050_Init(void)
{
// 唤醒MPU6050
uint8_t data = 0x00;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x6B, 1, &data, 1, 100);
// 设置采样率
data = 0x07;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x19, 1, &data, 1, 100);
// 设置陀螺仪量程
data = 0x00;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x1B, 1, &data, 1, 100);
// 设置加速度计量程
data = 0x00;
HAL_I2C_Mem_Write(&hi2c1, MPU6050_ADDR, 0x1C, 1, &data, 1, 100);
}
3. 读取MPU6050数据
编写函数来读取MPU6050的加速度和陀螺仪数据:
void MPU6050_ReadData(int16_t* accel, int16_t* gyro)
{
uint8_t buffer[14];
HAL_I2C_Mem_Read(&hi2c1, MPU6050_ADDR, 0x3B, 1, buffer, 14, 100);
accel[0] = (buffer[0] << 8) | buffer[1];
accel[1] = (buffer[2] << 8) | buffer[3];
accel[2] = (buffer[4] << 8) | buffer[5];
gyro[0] = (buffer[8] << 8) | buffer[9];
gyro[1] = (buffer[10] << 8) | buffer[11];
gyro[2] = (buffer[12] << 8) | buffer[13];
}
4. 主函数
在主函数中,初始化I2C和MPU6050,然后不断读取MPU6050的数据并进行处理:
int main(void)
{
HAL_Init();
I2C1_Init();
MPU6050_Init();
int16_t accel[3];
int16_t gyro[3];
while (1)
{
MPU6050_ReadData(accel, gyro);
// 处理数据,例如打印输出
printf("Accel: %d, %d, %d\n", accel[0], accel[1], accel[2]);
printf("Gyro: %d, %d, %d\n", gyro[0], gyro[1], gyro[2]);
HAL_Delay(100);
}
}
四、代码解释
- I2C初始化:
I2C1_Init
函数用于初始化STM32的I2C1接口,设置时钟速度、占空比等参数。HAL_I2C_MspInit
函数用于初始化I2C相关的GPIO引脚。 - MPU6050初始化:
MPU6050_Init
函数用于唤醒MPU6050,并设置采样率、陀螺仪量程和加速度计量程。 - 读取MPU6050数据:
MPU6050_ReadData
函数通过I2C接口读取MPU6050的加速度和陀螺仪数据,并将其存储在数组中。 - 主函数:在主函数中,首先初始化I2C和MPU6050,然后在循环中不断读取MPU6050的数据,并将其打印输出。
五、姿态解算
通过读取MPU6050的加速度和陀螺仪数据,可以进行姿态解算,得到设备的欧拉角(俯仰角、横滚角、偏航角)。常用的姿态解算算法有互补滤波、卡尔曼滤波等。以下是一个简单的互补滤波示例:
#define PI 3.14159265358979323846
float accel_angle[2];
float gyro_angle[2];
float complementary_angle[2];
void ComplementaryFilter(int16_t* accel, int16_t* gyro, float dt)
{
// 计算加速度计的角度
accel_angle[0] = atan2(accel[1], accel[2]) * 180 / PI;
accel_angle[1] = atan2(-accel[0], sqrt(accel[1] * accel[1] + accel[2] * accel[2])) * 180 / PI;
// 计算陀螺仪的角度
gyro_angle[0] += gyro[0] * dt / 131.0;
gyro_angle[1] += gyro[1] * dt / 131.0;
// 互补滤波
complementary_angle[0] = 0.98 * (complementary_angle[0] + gyro[0] * dt / 131.0) + 0.02 * accel_angle[0];
complementary_angle[1] = 0.98 * (complementary_angle[1] + gyro[1] * dt / 131.0) + 0.02 * accel_angle[1];
}
在主函数中调用ComplementaryFilter
函数进行姿态解算:
int main(void)
{
HAL_Init();
I2C1_Init();
MPU6050_Init();
int16_t accel[3];
int16_t gyro[3];
float dt = 0.1; // 采样时间
while (1)
{
MPU6050_ReadData(accel, gyro);
ComplementaryFilter(accel, gyro, dt);
// 打印姿态角
printf("Pitch: %f, Roll: %f\n", complementary_angle[0], complementary_angle[1]);
HAL_Delay(100);
}
}