STM32 HAL驱动MPU6050传感器
项目概述
本项目实现了基于STM32 HAL库的MPU6050传感器驱动,可以读取加速度计和陀螺仪数据。项目使用I2C接口与MPU6050通信,并通过UART接口输出数据。
项目仓库地址:STM32_Sensor_Drives
硬件连接
MPU6050 I2C接口
PB10 ------> I2C2_SCL
PB11 ------> I2C2_SDA
UART调试接口
PA2 ------> USART2_TX
PA3 ------> USART2_RX
代码结构
项目主要包含以下文件:
main.c
: 主程序入口,初始化外设并循环读取MPU6050数据i2c.c/h
: I2C配置和MPU6050驱动函数usart.c/h
: UART配置和printf重定向gpio.c/h
: GPIO配置
MPU6050驱动实现
数据结构定义
在i2c.h
中定义了MPU6050数据结构:
typedef struct _mpu6050_data{
double ACCEL_X ,ACCEL_Y ,ACCEL_Z;
double GYRO_X ,GYRO_Y ,GYRO_Z;
}mpu6050_data;
初始化函数
在i2c.c
中实现了MPU6050初始化函数:
void MPU6050_start(void)
{
uint8_t SendAddress = 0x6b;
uint8_t SendData = 0x00; //解除休眠状态
HAL_I2C_Mem_Write(&hi2c2,0xD1,SendAddress,1,&SendData,1,0xff);
SendAddress = 0x19;//采样率分频器
SendData = 0x07;
HAL_I2C_Mem_Write(&hi2c2,0xD1,SendAddress,1,&SendData,1,0xff);
SendAddress = 0x1A;//低通滤波器
SendData = 0x06;
HAL_I2C_Mem_Write(&hi2c2,0xD1,SendAddress,1,&SendData,1,0xff);
SendAddress = 0x1B;//陀螺仪
SendData = 0x08; //± 500 °/s
HAL_I2C_Mem_Write(&hi2c2,0xD1,SendAddress,1,&SendData,1,0xff);
SendAddress = 0x1C;//加速度计
SendData = 0x00; //± 2g
HAL_I2C_Mem_Write(&hi2c2,0xD1,SendAddress,1,&SendData,1,0xff);
}
初始化步骤:
- 解除MPU6050休眠状态(寄存器0x6B)
- 设置采样率分频器(寄存器0x19)
- 配置低通滤波器(寄存器0x1A)
- 配置陀螺仪量程为±500°/s(寄存器0x1B)
- 配置加速度计量程为±2g(寄存器0x1C)
数据读取函数
在i2c.c
中实现了MPU6050数据读取函数:
void get_i2c_mpu6050(mpu6050_data *data){
uint8_t MPU_Data[] = {0X00, 0X00,0X00, 0X00,0X00, 0X00,0X00, 0X00,0X00, 0X00,0X00, 0X00,0X00, 0X00};
uint8_t preg1_Data = 0x3B;
HAL_I2C_Mem_Read(&hi2c2, 0xD1,preg1_Data,I2C_MEMADD_SIZE_8BIT,MPU_Data,14,50);
float Temp = (MPU_Data[6]<<8)|MPU_Data[7];
if(Temp>32768) Temp-=65536;
Temp=(36.53+Temp/340);
short int ACCEL_XOUT1 = ((MPU_Data[0]<<8)|MPU_Data[1]);
data->ACCEL_X = (double)ACCEL_XOUT1/16384;
short int ACCEL_YOUT1 = ((MPU_Data[2]<<8)|MPU_Data[3]);
data->ACCEL_Y = (double)ACCEL_YOUT1/16384;
short int ACCEL_ZOUT1 = ((MPU_Data[4]<<8)|MPU_Data[5]);
data->ACCEL_Z = (double)ACCEL_ZOUT1/16384;
short int GYRO_XOUT1 = ((MPU_Data[8]<<8)|MPU_Data[9]);
data->GYRO_X = (double)GYRO_XOUT1/65.5;
short int GYRO_YOUT1 = ((MPU_Data[10]<<8)|MPU_Data[11]);
data->GYRO_Y = (double)GYRO_YOUT1/65.5;
short int GYRO_ZOUT1 = ((MPU_Data[12]<<8)|MPU_Data[13]);
data->GYRO_Z = (double)GYRO_ZOUT1/65.5;
}
数据读取步骤:
- 从寄存器0x3B开始,连续读取14个字节的数据
- 处理温度数据(虽然在本例中未使用)
- 处理加速度数据(前6个字节)
- X轴加速度:字节0-1
- Y轴加速度:字节2-3
- Z轴加速度:字节4-5
- 除以16384转换为g单位(±2g量程下)
- 处理陀螺仪数据(后6个字节)
- X轴角速度:字节8-9
- Y轴角速度:字节10-11
- Z轴角速度:字节12-13
- 除以65.5转换为°/s单位(±500°/s量程下)
I2C配置
I2C配置在i2c.c
中实现:
void MX_I2C2_Init(void)
{
hi2c2.Instance = I2C2;
hi2c2.Init.ClockSpeed = 100000;
hi2c2.Init.DutyCycle = I2C_DUTYCYCLE_2;
hi2c2.Init.OwnAddress1 = 0;
hi2c2.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
hi2c2.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
hi2c2.Init.OwnAddress2 = 0;
hi2c2.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
hi2c2.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
if (HAL_I2C_Init(&hi2c2) != HAL_OK)
{
Error_Handler();
}
}
主要配置:
- 时钟速度:100kHz
- 7位地址模式
- 禁用时钟拉伸
UART配置与printf重定向
UART配置在usart.c
中实现:
void MX_USART2_UART_Init(void)
{
huart2.Instance = USART2;
huart2.Init.BaudRate = 115200;
huart2.Init.WordLength = UART_WORDLENGTH_8B;
huart2.Init.StopBits = UART_STOPBITS_1;
huart2.Init.Parity = UART_PARITY_NONE;
huart2.Init.Mode = UART_MODE_TX_RX;
huart2.Init.HwFlowCtl = UART_HWCONTROL_NONE;
huart2.Init.OverSampling = UART_OVERSAMPLING_16;
if (HAL_UART_Init(&huart2) != HAL_OK)
{
Error_Handler();
}
}
为了支持printf函数,重定向了fputc函数:
int fputc(int ch, FILE *f)
{
if (f == stdout) // 仅处理标准输出
{
HAL_UART_Transmit(&huart2, (uint8_t *)&ch, 1, 100); // 阻塞发送
if (ch == '\n') // 发送\n时自动补充\r
HAL_UART_Transmit(&huart2, (uint8_t *)"\r", 1, 100);
}
return ch;
}
主程序
主程序在main.c
中实现:
int main(void)
{
/* 初始化代码省略 */
MX_GPIO_Init();
MX_USART2_UART_Init();
MX_I2C2_Init();
/* USER CODE BEGIN 2 */
MPU6050_start();
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
printf("System will start while\n");
while (1)
{
mpu6050_data data = {0};
get_i2c_mpu6050(&data);
printf("ax: %.3f--ay: %.3f--az: %.3f--gx: %.3f--gy: %.3f--gz: %.3f\n", data.ACCEL_X, data.ACCEL_Y, data.ACCEL_Z, data.GYRO_X, data.GYRO_Y, data.GYRO_Z);
HAL_Delay(200);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
主程序流程:
- 初始化GPIO、UART和I2C外设
- 初始化MPU6050传感器
- 进入主循环
- 读取MPU6050数据
- 通过UART打印数据
- 延时200ms
MPU6050寄存器说明
寄存器地址 | 名称 | 功能 |
---|---|---|
0x6B | PWR_MGMT_1 | 电源管理1,用于设备复位、睡眠模式、时钟源等 |
0x19 | SMPLRT_DIV | 采样率分频器 |
0x1A | CONFIG | 配置寄存器,主要用于配置DLPF(数字低通滤波器) |
0x1B | GYRO_CONFIG | 陀螺仪配置,设置量程等 |
0x1C | ACCEL_CONFIG | 加速度计配置,设置量程等 |
0x3B-0x40 | ACCEL_XOUT_H至ACCEL_ZOUT_L | 加速度计输出数据 |
0x41-0x42 | TEMP_OUT_H和TEMP_OUT_L | 温度传感器输出数据 |
0x43-0x48 | GYRO_XOUT_H至GYRO_ZOUT_L | 陀螺仪输出数据 |
注意事项
MPU6050的I2C地址为0x68(二进制:1101000),但在代码中使用的是0xD1(二进制:11010001)。这是因为HAL库的I2C函数需要在7位地址后添加读/写位(0表示写,1表示读)。
加速度计和陀螺仪的原始数据都是16位有符号整数,需要进行转换才能得到实际的物理量:
- 加速度计:在±2g量程下,除以16384得到以g为单位的加速度
- 陀螺仪:在±500°/s量程下,除以65.5得到以°/s为单位的角速度
温度传感器的数据转换公式为:温度(°C) = 36.53 + (原始数据/340)