在STM32F103C8T6的单条I2C总线上控制多个地址相同的VL53L0X传感器,可通过以下方案实现:
问题核心
VL53L0X的默认I2C地址为0x29
,若所有传感器地址相同且无法修改,直接连接会导致总线冲突。解决方案需通过硬件或软件手段分时复用或物理隔离传感器。
解决方案
1. 利用XSHUT引脚分时初始化并修改地址(推荐)
原理:通过控制VL53L0X的XSHUT(复位/关断)引脚,逐个唤醒传感器并修改其I2C地址。
步骤:
硬件连接:
- 将每个VL53L0X的XSHUT引脚连接到STM32的不同GPIO(如PA0-PA3)。
- 所有传感器的I2C SDA/SCL并联到STM32的I2C总线(如PB6/PB7)。
VL53L0X_1: XSHUT → PA0
VL53L0X_2: XSHUT → PA1
VL53L0X_3: XSHUT → PA2
VL53L0X_4: XSHUT → PA3
初始化代码逻辑:
// 关闭所有传感器
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_RESET);
HAL_Delay(10);
// 逐个初始化并修改地址
for (int i = 0; i < 4; i++) {
// 唤醒当前传感器
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 << i, GPIO_PIN_SET);
HAL_Delay(10);
// 初始化VL53L0X并修改地址(例如0x29 → 0x30+i)
VL53L0X_Init(&h_i2c1, 0x29); // 初始默认地址
VL53L0X_SetDeviceAddress(&h_i2c1, 0x29, 0x30 + i);
HAL_Delay(10);
}
后续操作:
- 通过新地址(0x30-0x33)分别访问各传感器。
2. 使用I2C多路复用器(TCA9548A)
原理:通过多路复用器扩展I2C通道,每个通道连接一个传感器。
步骤:
硬件连接:
- TCA9548A的SCL/SDA接STM32的I2C总线。
- 每个VL53L0X连接到TCA9548A的不同通道(CH0-CH3)。
代码逻辑:
// 选择通道0
uint8_t channel = 0;
HAL_I2C_Mem_Write(&h_i2c1, 0x70, 0, I2C_MEMADD_SIZE_8BIT, &channel, 1, 100);
VL53L0X_ReadDistance(&h_i2c1, 0x29); // 读取通道0的传感器
// 切换通道后重复操作
3. 分时复用(无硬件修改)
原理:同一时间仅使能一个传感器,其他保持复位状态。
步骤:
- 硬件连接:同方案1。
代码逻辑:
// 读取传感器1
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_RESET);
VL53L0X_ReadDistance(&h_i2c1, 0x29);
// 依次切换使能其他传感器
关键注意事项
- XSHUT引脚控制:确保亚博智能模块的XSHUT未被固定拉高。若已拉高,需切断PCB走线并飞线到GPIO。
- 地址修改验证:修改地址后,通过读取设备ID(寄存器0xC0)确认是否成功。
- 时序延迟:每次唤醒或复位后需等待至少1ms(VL53L0X启动时间)。
示例代码片段(STM32 HAL库)
// 初始化GPIO和I2C
void Init_GPIO() {
GPIO_InitTypeDef GPIO_InitStruct = {0};
__HAL_RCC_GPIOA_CLK_ENABLE();
// 配置PA0-PA3为输出
GPIO_InitStruct.Pin = GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
}
// 修改传感器地址
void SetSensorAddress(I2C_HandleTypeDef *hi2c, uint8_t old_addr, uint8_t new_addr) {
uint8_t cmd[2] = {0x8A, new_addr << 1}; // 地址左移1位(I2C协议)
HAL_I2C_Master_Transmit(hi2c, old_addr, cmd, 2, 100);
}
// 主函数初始化
int main() {
Init_GPIO();
// 关闭所有传感器
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 | GPIO_PIN_1 | GPIO_PIN_2 | GPIO_PIN_3, GPIO_PIN_RESET);
HAL_Delay(10);
for (int i = 0; i < 4; i++) {
// 唤醒第i个传感器
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0 << i, GPIO_PIN_SET);
HAL_Delay(10);
// 初始化并修改地址
VL53L0X_Init(&h_i2c1, 0x29);
SetSensorAddress(&h_i2c1, 0x29, 0x30 + i);
HAL_Delay(10);
}
while (1) {
// 通过新地址0x30-0x33读取各传感器
}
}
调试建议
- 使用逻辑分析仪监控I2C总线,确认地址修改是否成功。
- 若无法修改地址,检查亚博智能模块的XSHUT引脚是否可控。
- 确保I2C上拉电阻(通常4.7kΩ)已正确连接。
通过上述方案,可低成本实现单I2C总线控制多路VL53L0X传感器。