STM32驱动MPU6050时I2C可读但无法写入的故障排查
MPU6050 I2C可读但无法写入寄存器问题分析与解决
问题概述
基于STM32F767ZI开发MPU6050驱动时,出现读写异常:读取WHO_AM_I寄存器能正常返回设备地址,但写入SAMPLE_RATE_DIVIDER寄存器后,读取返回值始终为0x00。所有HAL库调用均返回HAL_OK,设备应答正常。
现有代码
I2C写入函数
static IOStatus_t Stm32f767zi_I2C_Write(uint8_t Address,uint32_t Size,uint8_t* DataPtr) { IOStatus_t Status = IO_SUCCESS; HAL_StatusTypeDef HAL_Status; uint8_t* WritePointer = (uint8_t*) malloc(Size+1); memcpy(WritePointer,&Address,1); memcpy(WritePointer+1,DataPtr,Size); HAL_Status = HAL_I2C_Master_Transmit(&hi2c2, MPU6050_I2C_ADDRESS<<1, WritePointer, Size+1, 100); free(WritePointer); if (HAL_Status != HAL_OK) { Status = IO_FAILURE; } return Status; }
I2C读取函数
static IOStatus_t Stm32f767zi_I2C_Read(uint8_t Address,uint32_t Size,uint8_t* DataPtr) { IOStatus_t Status = IO_SUCCESS; HAL_StatusTypeDef HAL_Status; HAL_Status = HAL_I2C_Master_Transmit(&hi2c2, MPU6050_I2C_ADDRESS<<1, &Address, 1, 100); HAL_Delay(1); if (HAL_Status == HAL_OK) { HAL_Status = HAL_I2C_Master_Receive(&hi2c2, MPU6050_I2C_ADDRESS<<1, DataPtr, Size, 100); if (HAL_Status != HAL_OK) { Status = IO_FAILURE; } } return Status; }
测试代码
uint8_t RxData; uint8_t ID; Stm32f767zi_I2C_Read(REG_WHO_AM_I,1,&ID); Stm32f767zi_I2C_Write(REG_SAMPLE_RATE_DIVIDER,1,&ID); Stm32f767zi_I2C_Read(REG_SAMPLE_RATE_DIVIDER,1,&RxData);
已排查项
- 确认
SAMPLE_RATE_DIVIDER寄存器为读写属性 - 拆分
HAL_I2C_Master_Transmit为两次单字节传输,无效 - UART验证写入数据指针正常
- 所有HAL调用返回
HAL_OK,设备应答正常
核心疑问
为何I2C读功能正常,但无法写入寄存器?是否设备被锁定写入?
参考单字节写入时序


解决建议
1. 检查MPU6050是否处于休眠状态
MPU6050上电默认进入休眠模式,此时大部分寄存器无法正常写入。必须先写入PWR_MGMT_1寄存器(地址0x6B),将SLEEP位(第0位)置0唤醒设备:
uint8_t wakeup_cmd = 0x00; Stm32f767zi_I2C_Write(0x6B, 1, &wakeup_cmd); HAL_Delay(100); // 等待设备完成唤醒
2. 替换写入函数为HAL_I2C_Mem_Write
手动拼接地址和数据的方式容易出现时序匹配问题,HAL库提供的HAL_I2C_Mem_Write专门针对“设备地址+寄存器地址+数据”的I2C写入场景,更贴合MPU6050的时序要求:
static IOStatus_t Stm32f767zi_I2C_Write(uint8_t Address,uint32_t Size,uint8_t* DataPtr) { IOStatus_t Status = IO_SUCCESS; HAL_StatusTypeDef HAL_Status; // 使用HAL专用内存写入函数,指定寄存器地址为8位 HAL_Status = HAL_I2C_Mem_Write(&hi2c2, MPU6050_I2C_ADDRESS<<1, Address, I2C_MEMADD_SIZE_8BIT, DataPtr, Size, 100); if (HAL_Status != HAL_OK) { Status = IO_FAILURE; } return Status; }
3. 确认I2C地址与硬件匹配
MPU6050的I2C地址由AD0引脚电平决定:
- AD0接GND:7位地址为0x68,左移1位后为0xD0
- AD0接VCC:7位地址为0x69,左移1位后为0xD2
确保代码中MPU6050_I2C_ADDRESS的定义与硬件连接一致。
4. 排查硬件问题
- 检查SDA/SCL引脚的上拉电阻(推荐4.7kΩ)是否存在、焊接正常
- 确认MPU6050供电电压为3.3V,电源纹波是否过大
- 排查SDA/SCL引脚是否有虚焊、短路情况
内容的提问来源于stack exchange,提问作者Hugo Pontes
相关产品推荐
相关产品推荐

