STM32F030与BQ25713 I²C寄存器读写异常问题求助
问题:BQ25713 与 STM32F030 I2C通信时寄存器读写异常
硬件与现象
- 主控:STM32F030,开发环境STM32CubeIDE(HAL库初始化完成,编译调试无报错)
- 外设:TI BQ25713充电芯片,I2C 8位写地址0xD6(对应7位地址0x6B)
- 异常现象:
- 读取ManufacturerID寄存器(地址0x2E)时,预期值为0x0040,实际得到0x2E41
- DeviceID、ChargeCurrent等寄存器读写结果均错误
- 仅AC_STAT寄存器的CHRG_OK位可正常识别输入状态
原代码
#define BQ25713_REG_I2C_ADDRESS 0xD6 // I2C 8位写地址(由7位地址0x6B转换) #define BQ25713_REG_MANUFACTURER_ID 0x2E // MANUFACTURER ID寄存器地址 checkBitsAndControlLEDs(BQ25713_REG_MANUFACTURER_ID); uint16_t SetI2CData(uint16_t regAddress, uint16_t regValue) { HAL_StatusTypeDef status; uint8_t regValSet8[2]; // 拆分LSB和MSB regValSet8[0] = regValue & 0xFF; // LSB regValSet8[1] = (regValue >> 8) & 0xFF; // MSB // 检查设备是否就绪 status = HAL_I2C_IsDeviceReady(&hi2c1, BQ25713_REG_I2C_ADDRESS, 3, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); HAL_Delay(300); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); } // 写入LSB status = HAL_I2C_Mem_Write(&hi2c1, BQ25713_REG_I2C_ADDRESS, regAddress, I2C_MEMADD_SIZE_16BIT, ®ValSet8[0], 1, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); HAL_Delay(300); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); } // 写入MSB status = HAL_I2C_Mem_Write(&hi2c1, BQ25713_REG_I2C_ADDRESS, regAddress + 1, I2C_MEMADD_SIZE_16BIT, ®ValSet8[1], 1, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); HAL_Delay(300); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); } return 0; } uint16_t ReadI2CData(uint16_t regAddress) { uint8_t readData[2]; HAL_StatusTypeDef status; // 检查设备是否就绪 status = HAL_I2C_IsDeviceReady(&hi2c1, BQ25713_REG_I2C_ADDRESS, 3, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(300); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); } // 读取寄存器数据 status = HAL_I2C_Mem_Read(&hi2c1, BQ25713_REG_I2C_ADDRESS | 0x01, regAddress, I2C_MEMADD_SIZE_16BIT, readData, 2, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(10000); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); HAL_Delay(10000); } // 组合LSB和MSB uint16_t readI2CData = (readData[0] << 8) | readData[1]; return readI2CData; } // 通过LED显示寄存器位状态 void checkBitsAndControlLEDs(uint16_t check_register) { uint16_t regData = ReadI2CData(check_register); for (int i = 15; i >= 0; i--) { if ((regData >> i) & 1) { // 位为1时点亮绿色LED(PA2) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); HAL_Delay(2500); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); } else { // 位为0时点亮红色LED(PA1) HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(2500); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); } HAL_Delay(1000); // 间隔1秒 } }
问题分析与修复方案
1. 寄存器地址长度错误(核心问题)
BQ25713的寄存器地址为8位宽度,但代码中使用I2C_MEMADD_SIZE_16BIT,导致STM32向芯片发送16位地址(如把0x2E当成0x002E发送),完全偏离目标寄存器。
- 修复:将所有
HAL_I2C_Mem_Read/HAL_I2C_Mem_Write中的地址长度参数改为I2C_MEMADD_SIZE_8BIT。
2. I2C读地址手动修改错误
HAL_I2C_Mem_Read函数会自动根据传入的8位写地址生成对应的读地址(写地址+1),无需手动对地址执行|0x01操作,否则会发送错误的设备地址。
- 修复:
HAL_I2C_Mem_Read的设备地址参数直接用BQ25713_REG_I2C_ADDRESS,去掉|0x01。
3. 数据字节序处理错误
BQ25713采用小端格式存储16位寄存器数据:LSB(低字节)在前,MSB(高字节)在后。原代码中组合数据时将LSB左移8位,导致字节序反转。
- 修复:读取后的数据组合逻辑改为:
uint16_t readI2CData = (readData[1] << 8) | readData[0];
4. 字写入方式错误
BQ25713支持单次字写入(2字节连续传输),无需分两次写入LSB和MSB,原代码中手动偏移寄存器地址regAddress +1会导致写入错误的寄存器位置。
- 修复:合并两次
HAL_I2C_Mem_Write为一次,直接写入2字节数据:status = HAL_I2C_Mem_Write(&hi2c1, BQ25713_REG_I2C_ADDRESS, regAddress, I2C_MEMADD_SIZE_8BIT, regValSet8, 2, HAL_MAX_DELAY);
修正后的关键代码片段
修正后的ReadI2CData函数
uint16_t ReadI2CData(uint16_t regAddress) { uint8_t readData[2]; HAL_StatusTypeDef status; status = HAL_I2C_IsDeviceReady(&hi2c1, BQ25713_REG_I2C_ADDRESS, 3, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(300); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); } // 修正地址长度为8位,移除手动修改的读地址 status = HAL_I2C_Mem_Read(&hi2c1, BQ25713_REG_I2C_ADDRESS, regAddress, I2C_MEMADD_SIZE_8BIT, readData, 2, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET); HAL_Delay(10000); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET); HAL_Delay(10000); } // 修正字节序组合逻辑 uint16_t readI2CData = (readData[1] << 8) | readData[0]; return readI2CData; }
修正后的SetI2CData函数
uint16_t SetI2CData(uint16_t regAddress, uint16_t regValue) { HAL_StatusTypeDef status; uint8_t regValSet8[2]; regValSet8[0] = regValue & 0xFF; // LSB regValSet8[1] = (regValue >> 8) & 0xFF; // MSB status = HAL_I2C_IsDeviceReady(&hi2c1, BQ25713_REG_I2C_ADDRESS, 3, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); HAL_Delay(300); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); } // 修正地址长度为8位,单次写入2字节数据 status = HAL_I2C_Mem_Write(&hi2c1, BQ25713_REG_I2C_ADDRESS, regAddress, I2C_MEMADD_SIZE_8BIT, regValSet8, 2, HAL_MAX_DELAY); if (status != HAL_OK) { HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_SET); HAL_Delay(300); HAL_GPIO_WritePin(GPIOA, GPIO_PIN_2, GPIO_PIN_RESET); } return 0; }
内容的提问来源于stack exchange,提问作者Melisa
相关产品推荐
相关产品推荐

