#include "iic.h" // 宏定义 #define SDA_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_SET) #define SDA_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_10, GPIO_PIN_RESET) #define SCL_HIGH() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_SET) #define SCL_LOW() HAL_GPIO_WritePin(GPIOA, GPIO_PIN_9, GPIO_PIN_RESET) #define SDA_READ() HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_10) void I2C_Delay(uint8_t us) { for (volatile int i = 0; i < 5 * us; i++); // MSI_16MHZ下1对应0.188us,5为0.93us } void I2C_Start(void) { SDA_HIGH(); SCL_HIGH(); I2C_Delay(3);// SDA_LOW();// 当SCL为高电平时,SDA从高变低表示开始信号 I2C_Delay(3);// SCL_LOW();// 开始信号传送完毕,拉低SCL准备数据传输 } void I2C_Stop(void) { SDA_LOW(); SCL_HIGH();// 当SCL为高电平时,SDA从低变高表示停止信号 I2C_Delay(2);// SDA_HIGH(); I2C_Delay(3);// } void I2C_SendByte(uint8_t byte) { for (uint8_t i = 0; i < 8; i++) { if (byte & 0x80) { SDA_HIGH(); } else { SDA_LOW(); } SCL_HIGH();// 在SCL上升沿时,数据稳定在SDA线上 I2C_Delay(2); SCL_LOW();// 在SCL下降沿时,SDA可以改变状态 I2C_Delay(3); byte <<= 1; } } uint8_t I2C_ReadByte(void) { uint8_t byte = 0; SDA_InputMode(); // 切换SDA为输入模式 for (uint8_t i = 0; i < 8; i++) { SCL_HIGH(); I2C_Delay(2); byte = (byte << 1) | SDA_READ();// 从MSB开始读取 SCL_LOW(); I2C_Delay(3); } SDA_OutputMode(); // 恢复SDA为输出模式 return byte; } uint8_t I2C_WaitAck(void) { uint8_t ack; SDA_HIGH(); // 释放 SDA 线,准备接收ACK SDA_InputMode(); // 切换为输入模式,接收ACK SCL_HIGH(); I2C_Delay(6);// ack = SDA_READ(); // 读取ACK信号 SCL_LOW(); SDA_OutputMode(); // 恢复 SDA 为输出模式 return (ack == GPIO_PIN_RESET); // 返回ACK状态 } void Soft_I2C_Write(uint8_t devAddr, uint8_t regAddr, uint8_t data) { I2C_Start(); I2C_SendByte(devAddr << 1); // 发送设备地址+写位 if (!I2C_WaitAck()) return; // 等待ACK I2C_SendByte(regAddr); // 发送寄存器地址 if (!I2C_WaitAck()) return; // 等待ACK I2C_SendByte(data); // 发送数据 if (!I2C_WaitAck()) return; // 等待ACK I2C_Stop(); } void Soft_I2C_Read(uint8_t devAddr, uint8_t regAddr, uint8_t *data) { I2C_Start(); I2C_SendByte(devAddr << 1); // 发送设备地址+写位 if (!I2C_WaitAck()) return; // 等待ACK I2C_SendByte(regAddr); // 发送寄存器地址 if (!I2C_WaitAck()) return; // 等待ACK I2C_Start(); // 重启总线 I2C_SendByte((devAddr << 1) | 1); // 发送设备地址+读位 if (!I2C_WaitAck()) return; // 等待ACK *data = I2C_ReadByte(); // 读取数据 I2C_Stop(); } void Soft_I2C_ReadMulti(uint8_t devAddr, uint8_t regAddr, uint8_t *data, uint16_t count) { I2C_Start(); I2C_SendByte(devAddr << 1); // 发送设备地址+写位 if (!I2C_WaitAck()) return; // 等待ACK I2C_SendByte(regAddr); // 发送寄存器地址 if (!I2C_WaitAck()) return; // 等待ACK I2C_Start(); // 重启总线 I2C_SendByte((devAddr << 1) | 1); // 发送设备地址+读位 if (!I2C_WaitAck()) return; // 等待ACK while (count--) { *data++ = I2C_ReadByte(); // 读取多字节数据 } I2C_Stop(); } void SDA_InputMode(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_INPUT; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); } void SDA_OutputMode(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; GPIO_InitStruct.Pin = GPIO_PIN_10; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD; GPIO_InitStruct.Pull = GPIO_NOPULL; HAL_GPIO_Init(GPIOA, &GPIO_InitStruct); }