STM32F4使用HAL函数与MLX90395 I2C通信如何实现重复起始条件?
解决STM32 HAL库I2C操作MLX90395时自动发送停止条件的问题
问题核心
STM32 HAL库的HAL_I2C_Mem_Write/Read、HAL_I2C_Master_Transmit/Receive系列函数,在完成单次传输后会自动发送I2C停止条件,但MLX90395磁力计要求使用重复起始条件(禁止中途发送停止,否则可能破坏寄存器状态或传感器工作模式)。
解决方案
1. 使用HAL的顺序传输函数(推荐)
HAL库提供了支持重复起始的顺序传输函数:HAL_I2C_Master_Seq_Transmit和HAL_I2C_Master_Seq_Receive,通过最后一个参数uint32_t Options控制是否发送停止条件:
I2C_FIRST_FRAME:发送起始条件,不发送停止(用于多帧传输的第一帧)I2C_NEXT_FRAME:发送重复起始条件,不发送停止(用于中间帧)I2C_LAST_FRAME:发送数据后发送停止条件(用于最后一帧)
以下是修改后的Enter_SM_Mode函数示例:
enumExit Enter_SM_Mode(uint8_t address, uint8_t cmd_reg){ HAL_StatusTypeDef ret; static uint8_t st_sm_mode = 0b00111010; // 单次测量模式命令字节 uint8_t tx_buffer[2] = {cmd_reg, st_sm_mode}; // 寄存器地址 + 命令数据 // 第一步:发送设备地址、寄存器地址、命令数据,不发送停止条件 ret = HAL_I2C_Master_Seq_Transmit(&hi2c1, (uint16_t)address, tx_buffer, 2, I2C_FIRST_FRAME, 100); if(ret != HAL_OK){ return EXIT_BAD_ERROR; } // 第二步:发送重复起始条件,读取状态字节,最后发送停止条件 uint8_t status_data; uint16_t read_address = (uint16_t)(address | 0x01); // 转换为读地址 ret = HAL_I2C_Master_Seq_Receive(&hi2c1, read_address, &status_data, 1, I2C_LAST_FRAME, 50); if(ret != HAL_OK){ return EXIT_BAD_ERROR; } return EXIT_OK; }
2. 直接操作I2C寄存器(底层可控)
如果顺序函数仍无法满足需求,可以直接操作I2C的控制寄存器(如I2C_CR1、I2C_DR),手动实现完整的I2C时序:
- 发送起始条件(置位
START位) - 发送设备写地址,等待ACK
- 发送寄存器地址,等待ACK
- 发送命令数据,等待ACK
- 发送重复起始条件(再次置位
START位) - 发送设备读地址,等待ACK
- 接收状态字节,发送NACK(或ACK,根据需求)
- 发送停止条件(置位
STOP位)
这种方式完全避免HAL库的自动停止逻辑,但需要熟悉STM32 I2C寄存器的操作细节。
关于带_IT后缀的函数
带_IT的是中断版本的I2C函数,原理和阻塞版一致,只是将传输过程放到中断中处理,适合需要非阻塞操作的场景。如果你不需要中断驱动,直接使用阻塞版的顺序传输函数即可。
内容的提问来源于stack exchange,提问作者g'pv
相关产品推荐
相关产品推荐

