> 技术文档 > STM32硬件I2C的注意事项_stm32 硬件i2c 读取ml90640数据始终为0x00

STM32硬件I2C的注意事项_stm32 硬件i2c 读取ml90640数据始终为0x00


文章目录

  • 软件模拟I2C
  • 硬件的实现方式

最近在研究I2C的屏幕使用。
有两种使用方式,软件模拟I2C、硬件HAL使用I2C。

软件模拟I2C

发送数据是通过设置引脚的高低电平实现的。

/*引脚配置*/#define OLED_W_SCL(x)GPIO_WriteBit(GPIOB, GPIO_Pin_6, (BitAction)(x))#define OLED_W_SDA(x)GPIO_WriteBit(GPIOB, GPIO_Pin_7, (BitAction)(x))/*引脚初始化*/void OLED_I2C_Init(void){// 先关闭 I2C1 避免 PB6/PB7 被干扰 // RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE); RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_OD;GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6; GPIO_Init(GPIOB, &GPIO_InitStructure);GPIO_InitStructure.GPIO_Pin = GPIO_Pin_7; GPIO_Init(GPIOB, &GPIO_InitStructure);OLED_W_SCL(1);OLED_W_SDA(1);}/** * @brief I2C发送一个字节 * @param Byte 要发送的一个字节 * @retval 无 */void OLED_I2C_SendByte(uint8_t Byte){uint8_t i;for (i = 0; i < 8; i++){OLED_W_SDA(Byte & (0x80 >> i));OLED_W_SCL(1);OLED_W_SCL(0);}OLED_W_SCL(1);//额外的一个时钟,不处理应答信号OLED_W_SCL(0);}

硬件的实现方式

/** * @brief 向OLED发送指令 */void OLED_SendCmd(uint8_t cmd) { static uint8_t sendBuffer[2] = {0}; sendBuffer[1] = cmd; OLED_Send(sendBuffer, 2);}/** * @brief 向OLED发送数据的函数 * @param data 要发送的数据 * @param len 要发送的数据长度 * @return None * @note 此函数是移植本驱动时的重要函数 将本驱动库移植到其他平台时应根据实际情况修改此函数 */#define I2C_TIMEOUT 100 // 超时时间(单位:ms)uint8_t OLED_Send(uint8_t *data, uint8_t len) {// HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, data, len, HAL_MAX_DELAY);HAL_StatusTypeDef status = HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, data, len, I2C_TIMEOUT); if (status != HAL_OK) { // 打印错误(如果你有串口) // printf(\"I2C Error: %d\\n\", status); // 重置 I2C I2C_Reset(&hi2c1); // 尝试重发一次 status = HAL_I2C_Master_Transmit(&hi2c1, OLED_ADDRESS, data, len, I2C_TIMEOUT); // 如果还是不行,返回失败 if (status != HAL_OK) { return 0; // 失败 } } return 1; // 成功}

HAL_I2C_Master_Transmit 会引起卡死的操作,所以要设置一下超时时间为100ms。
也不知道底层是怎么配置的。

驱动 IC 为 SSD1306,程序重启的时候需要重新配置一下I2C,不然对应的硬件端口会卡死。