stm32 IIC总线busy解决方法

参考博客:

https://blog.csdn.net/PP_hui/article/details/112229696

1------这是IIC的初始化代码:

c 复制代码
#include "i2c.h"

/* USER CODE BEGIN 0 */
// #define __HAL_AFIO_REMAP_I2C1_ENABLE()  AFIO_REMAP_ENABLE(AFIO_MAPR_I2C1_REMAP)
/* USER CODE END 0 */

I2C_HandleTypeDef hi2c1;

/* I2C1 init function */
void MX_I2C1_Init(void)
{

    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    // hi2c1.Init.OwnAddress1 = 0;
        hi2c1.Init.OwnAddress1 = 0xA0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
        Error_Handler();
    }

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(i2cHandle->Instance==I2C1)
    {
        /* USER CODE BEGIN I2C1_MspInit 0 */

        /* USER CODE END I2C1_MspInit 0 */

        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**I2C1 GPIO Configuration
        PB8     ------> I2C1_SCL
        PB9     ------> I2C1_SDA
        */
        GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Pull = GPIO_PULLUP;/
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        // __HAL_AFIO_REMAP_I2C1_ENABLE();

        /* I2C1 clock enable */
        __HAL_RCC_I2C1_CLK_ENABLE();
        /* USER CODE BEGIN I2C1_MspInit 1 */
    __I2C1_FORCE_RESET();                                   //通过总复位模块对I2C一次复位操作

      __I2C1_RELEASE_RESET();
        /* USER CODE END I2C1_MspInit 1 */
    }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{

    if(i2cHandle->Instance==I2C1)
    {
        /* USER CODE BEGIN I2C1_MspDeInit 0 */

        /* USER CODE END I2C1_MspDeInit 0 */
        /* Peripheral clock disable */
        __HAL_RCC_I2C1_CLK_DISABLE();

        /**I2C1 GPIO Configuration
        PB8     ------> I2C1_SCL
        PB9     ------> I2C1_SDA
        */
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8);

        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_9);

        /* USER CODE BEGIN I2C1_MspDeInit 1 */

        /* USER CODE END I2C1_MspDeInit 1 */
    }
}

/* USER CODE BEGIN 1 */

我根据参考的博客在 HAL_I2C_MspInit() 中添加了2行代码;

目的是进行一次IIC 总线的复位操作;

2---------除此之外还定义了一个接口:

作用:判断IIC总线是否busy,如果busy,则重新初始化IIC;

c 复制代码
void I2C_Busy_C(void)
{

    SET_BIT(hi2c1.Instance->CR1,I2C_CR1_SWRST);          

    CLEAR_BIT(hi2c1.Instance->CR1,I2C_CR1_SWRST);

    HAL_I2C_MspInit(&hi2c1);                      //自定义函数

    HAL_I2C_Init(&hi2c1);

}

3----在HAL_I2C_Mem_Write()时会busy,

解决方案:

调用HAL_I2C_Mem_Write()之前,先判断是否busy,如果busy则重新初始化,初始化结束后,再HAL_I2C_Mem_Write();

c 复制代码
EEPROM_RES EEProm_Write(uint8_t addr,uint8_t* data,uint8_t size)
{
    int ret = 0;

        if(READ_BIT(hi2c1.Instance->SR2,I2C_SR2_BUSY) || READ_BIT(hi2c1.Instance->CR1,I2C_CR1_PE) == 0)
        {
             I2C_Busy_C();
        }
        
        ret = HAL_I2C_Mem_Write(&hi2c1,EEPROM_ADDR,addr,I2C_MEMADD_SIZE_8BIT,data,size,1000);
        if(HAL_OK == ret)
        {
            HAL_UART_Transmit(&huart3,"EEPROM_OK\r\n", strlen("EEPROM_OK\r\n"),100);
            return EEPROM_OK;
        }
        else if(HAL_ERROR == ret)
        {
            HAL_UART_Transmit(&huart3,"EEPROM_ERROR\r\n", strlen("EEPROM_ERROR\r\n"),100);
            return EEPROM_ERROR;
        }
        else if(HAL_BUSY == ret)
        {
            HAL_UART_Transmit(&huart3,"HAL_BUSY\r\n", strlen("HAL_BUSY\r\n"),100);
            return HAL_BUSY;
        }
        else if(HAL_TIMEOUT == ret)
        {
            HAL_UART_Transmit(&huart3,"HAL_TIMEOUT\r\n", strlen("HAL_TIMEOUT\r\n"),100);
            return HAL_TIMEOUT;
        }


}

总结:

1)修改MX_I2C1_Init();

2)创建重新初始化的接口I2C_Busy_C();

  1. 在HAL_I2C_Mem_Write()之前,先判断是否busy,如果busy就调用I2C_Busy_C();复位总线;-------------->再调用HAL_I2C_Mem_Write();

没了;

下面的代码是AT24C02的所有相关代码:

1)iic初始化

c 复制代码
#include "i2c.h"

/* USER CODE BEGIN 0 */
// #define __HAL_AFIO_REMAP_I2C1_ENABLE()  AFIO_REMAP_ENABLE(AFIO_MAPR_I2C1_REMAP)
/* USER CODE END 0 */

I2C_HandleTypeDef hi2c1;

/* I2C1 init function */
void MX_I2C1_Init(void)
{

    hi2c1.Instance = I2C1;
    hi2c1.Init.ClockSpeed = 100000;
    hi2c1.Init.DutyCycle = I2C_DUTYCYCLE_2;
    // hi2c1.Init.OwnAddress1 = 0;
        hi2c1.Init.OwnAddress1 = 0xA0;
    hi2c1.Init.AddressingMode = I2C_ADDRESSINGMODE_7BIT;
    hi2c1.Init.DualAddressMode = I2C_DUALADDRESS_DISABLE;
    hi2c1.Init.OwnAddress2 = 0;
    hi2c1.Init.GeneralCallMode = I2C_GENERALCALL_DISABLE;
    hi2c1.Init.NoStretchMode = I2C_NOSTRETCH_DISABLE;
    if (HAL_I2C_Init(&hi2c1) != HAL_OK)
    {
        Error_Handler();
    }

}

void HAL_I2C_MspInit(I2C_HandleTypeDef* i2cHandle)
{

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    if(i2cHandle->Instance==I2C1)
    {
        /* USER CODE BEGIN I2C1_MspInit 0 */

        /* USER CODE END I2C1_MspInit 0 */

        __HAL_RCC_GPIOB_CLK_ENABLE();
        /**I2C1 GPIO Configuration
        PB8     ------> I2C1_SCL
        PB9     ------> I2C1_SDA
        */
        GPIO_InitStruct.Pin = GPIO_PIN_8|GPIO_PIN_9;
        GPIO_InitStruct.Mode = GPIO_MODE_AF_OD;
        GPIO_InitStruct.Pull = GPIO_PULLUP;/
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        GPIO_InitStruct.Alternate = GPIO_AF4_I2C1;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);

        // __HAL_AFIO_REMAP_I2C1_ENABLE();

        /* I2C1 clock enable */
        __HAL_RCC_I2C1_CLK_ENABLE();
        /* USER CODE BEGIN I2C1_MspInit 1 */
    __I2C1_FORCE_RESET();                                   //通过总复位模块对I2C一次复位操作

      __I2C1_RELEASE_RESET();
        /* USER CODE END I2C1_MspInit 1 */
    }
}

void HAL_I2C_MspDeInit(I2C_HandleTypeDef* i2cHandle)
{

    if(i2cHandle->Instance==I2C1)
    {
        /* USER CODE BEGIN I2C1_MspDeInit 0 */

        /* USER CODE END I2C1_MspDeInit 0 */
        /* Peripheral clock disable */
        __HAL_RCC_I2C1_CLK_DISABLE();

        /**I2C1 GPIO Configuration
        PB8     ------> I2C1_SCL
        PB9     ------> I2C1_SDA
        */
        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_8);

        HAL_GPIO_DeInit(GPIOB, GPIO_PIN_9);

        /* USER CODE BEGIN I2C1_MspDeInit 1 */

        /* USER CODE END I2C1_MspDeInit 1 */
    }
}

/* USER CODE BEGIN 1 */

2)main函数调用MX_I2C1_Init();

3)at24c02.h

c 复制代码
#ifndef AT24C02_H
#define AT24C02_H
#include "stm32f4xx_hal.h"
#include "usart.h"

typedef enum{
	EEPROM_OK,
	EEPROM_ERROR
}EEPROM_RES;

extern I2C_HandleTypeDef hi2c1;



//AT24C02一共32页,每页8字节,共256字节;
//不能跨页写数据[比如:1个2字节的数据占用0x07和0x08两个地址,可能导致数据错乱]

//第一页地址:0x00-0x07
//第二页地址:0x08-0x0F
//第三页地址:0x10-0x17
//第四页地址:0x18-0x1F
//第五页地址:0x20-0x27
//第六页地址:0x28-0x2F
//第七页地址:0x30-0x37
//第八页地址:0x38-0x3F
//第九页地址:0x40-0x47
//第十页地址:0x48-0x4F
//第十一页地址:0x50-0x57
//第十二页地址:0x58-0x5F
//第十三页地址:0x60-0x67
//第十四页地址:0x68-0x6F
//第十五页地址:0x70-0x77
//第十六页地址:0x78-0x7F
//第十七页地址:0x80-0x87
//第十八页地址:0x88-0x8F
//第十九页地址:0x90-0x97
//第二十页地址:0x98-0x9F
//第二十一页地址:0xA0-0xA7
//第二十二页地址:0xA8-0xAF
//第二十三页地址:0xB0-0xB7
//第二十四页地址:0xB8-0xBF
//第二十五页地址:0xC0-0xC7
//第二十六页地址:0xC8-0xCF
//第二十七页地址:0xD0-0xD7
//第二十八页地址:0xD8-0xDF
//第二十九页地址:0xE0-0xE7
//第三十页地址:0xE8-0xEF
//第三十一页地址:0xF0-0xF7
//第三十二页地址:0xF8-0xFF


//由于各个参数的实际大小是不确定的,领导每明确要求;所以统一把长度设置为4字节
typedef enum{
    E2ADDR_X_STEP=0x00,//X轴步进【0x00-0x03】
    E2ADDR_Y_STEP=0x04,//Y轴步进【0x04-0x07】
    E2ADDR_Z_STEP=0x08,//Z轴步进【0x08-0x0B】

    E2ADDR_X_POS=0x0C,//X轴位置【0x0C-0x0F】
    E2ADDR_Y_POS=0x10,//Y轴位置【0x10-0x13】
    E2ADDR_Z_POS=0x14,//Z轴位置【0x14-0x17】

    E2ADDR_X_SPEED=0x18,//X轴运行速度【0x18-0x1B】
    E2ADDR_Y_SPEED=0x1C,//Y轴运行速度【0x1C-0x1F】
    E2ADDR_Z_SPEED=0x20,//Z轴运行速度【0x20-0x23】

    E2ADDR_X_ACC=0x24,//X轴运行加速度【0x24-0x27】
    E2ADDR_Y_ACC=0x28,//Y轴运行加速度【0x28-0x2B】
    E2ADDR_Z_ACC=0x2C,//Z轴运行加速度【0x2C-0x2F】

	E2ADDR_X_CHECKSELF_SPEED = 0x30,//X轴自检速度【0x30-0x33】
	E2ADDR_Y_CHECKSELF_SPEED = 	0x34,//Y轴自检速度【0x34-0x37】
	E2ADDR_Z_CHECKSELF_SPEED = 	0x38,//Z轴自检速度【0x38-0x3B】

	E2ADDR_X_CHECKSELF_ACC = 0x3C,//X轴自检加速度【0x3C-0x3F】
	E2ADDR_Y_CHECKSELF_ACC = 	0x40,//Y轴自检加速度【0x40-0x43】
	E2ADDR_Z_CHECKSELF_ACC = 	0x44,//Z轴自检加速度【0x44-0x47】
}AT24C02_APP_ADDR;

#define PARAMNULL		0xFFFFFFFF
#define USER_PARAM_NULL(TYPE,PARAM,VALUE)   ((TYPE)PARAMNULL == PARAM)?(PARAM = VALUE):(PARAM);
#define EE_SIZE 256//bytes
#define EEPROM_ADDR		0xa0
struct Device_Param{
	int32_t step;
	int32_t pos;
	int32_t speed;
	int32_t acc;
	int32_t check_speed;
	int32_t check_acc;
};


void AT24C02_Read_Test(void);
void AT24C02_Write_Test(void);
void I2c_EraseChip(void);
#endif

4)at24c02.c

c 复制代码
#include "AT24C02.h"
void I2C_Busy_C(void)
{

    SET_BIT(hi2c1.Instance->CR1,I2C_CR1_SWRST);          

    CLEAR_BIT(hi2c1.Instance->CR1,I2C_CR1_SWRST);

    HAL_I2C_MspInit(&hi2c1);                      //自定义函数

    HAL_I2C_Init(&hi2c1);

}




// ------------------------------------------------

//                             版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
// 原文链接:https://blog.csdn.net/PP_hui/article/details/112229696



EEPROM_RES EEProm_Write(uint8_t addr,uint8_t* data,uint8_t size)
{
    int ret = 0;

        if(READ_BIT(hi2c1.Instance->SR2,I2C_SR2_BUSY) || READ_BIT(hi2c1.Instance->CR1,I2C_CR1_PE) == 0)
        {
             I2C_Busy_C();
        }

        ret = HAL_I2C_Mem_Write(&hi2c1,EEPROM_ADDR,addr,I2C_MEMADD_SIZE_8BIT,data,size,1000);
        if(HAL_OK == ret)
        {
            HAL_UART_Transmit(&huart3,"EEPROM_OK\r\n", strlen("EEPROM_OK\r\n"),100);
            return EEPROM_OK;
        }
        else if(HAL_ERROR == ret)
        {
            HAL_UART_Transmit(&huart3,"EEPROM_ERROR\r\n", strlen("EEPROM_ERROR\r\n"),100);
            return EEPROM_ERROR;
        }
        else if(HAL_BUSY == ret)
        {
            HAL_UART_Transmit(&huart3,"HAL_BUSY\r\n", strlen("HAL_BUSY\r\n"),100);
            return HAL_BUSY;
        }
        else if(HAL_TIMEOUT == ret)
        {
            HAL_UART_Transmit(&huart3,"HAL_TIMEOUT\r\n", strlen("HAL_TIMEOUT\r\n"),100);
            return HAL_TIMEOUT;
        }


}
EEPROM_RES EEProm_Read(uint8_t addr,uint8_t *buf,uint16_t size)
{
    if(HAL_OK != HAL_I2C_Mem_Read(&hi2c1,EEPROM_ADDR,addr,I2C_MEMADD_SIZE_8BIT,buf,size,1000))
    {
                HAL_UART_Transmit(&huart3,"EEPROM_ERROR\r\n", strlen("EEPROM_ERROR\r\n"),100);

        return EEPROM_ERROR;
    }
    HAL_Delay(10);
    HAL_UART_Transmit(&huart3,"EEPROM_OK\r\n", strlen("EEPROM_OK\r\n"),100);
    return EEPROM_OK;
}

void I2c_EraseChip(void)
{
    uint16_t i=0;
    uint8_t erase[8] = {0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF};
    HAL_UART_Transmit(&huart3,"will erase chip\r\n", strlen("will erase chip\r\n"),100);

    for( i=0; i<(EE_SIZE/8); i++)
    {
        if(HAL_OK != HAL_I2C_Mem_Write(&hi2c1, EEPROM_ADDR, i*8,I2C_MEMADD_SIZE_8BIT, erase, 8, 1000))
        {
            Error_Handler();
            HAL_UART_Transmit(&huart3,"EEPROM_ERROR\r\n", strlen("EEPROM_ERROR\r\n"),100);
        }
        else{
            HAL_UART_Transmit(&huart3,"EEPROM_OK\r\n", strlen("EEPROM_OK\r\n"),100);
        }
        HAL_Delay(10);
    }
}




// void Platform_Init(void)
// {
//     //读取EEPROM存储的数据
//     EEProm_Read(E2_JPB_LEFT,(uint8_t*)at24c02_data_4byte,4);
//     EEProm_Read(E2_JPB_RIGHT,(uint8_t*)at24c02_data_4byte,4);
//     EEProm_Read(E2_LIGHTSWITCH,(uint8_t*)&at24c02_data_1byte,1);
//     EEProm_Read(E2_LIGHTBRIGHTNESS,(uint8_t*)&at24c02_data_1byte,1);
//     EEProm_Read(E2_LIGHTBOOTVALUE,(uint8_t*)&at24c02_data_1byte,1);


//     EEProm_Read(E2_ZOOM_POSLIMIT,(uint8_t*)&at24c02_data_4byte,4);
//     EEProm_Read(E2_ZOOM_POSZERO,(uint8_t*)&at24c02_data_4byte,4);
//     EEProm_Read(E2_ZOOM_SPEEDSELFTEST,(uint8_t*)&at24c02_data_2byte,2);
//     EEProm_Read(E2_ZOOM_SPEEDRUN,(uint8_t*)&at24c02_data_2byte,2);
//     EEProm_Read(E2_ZOOM_STEP,(uint8_t*)&at24c02_data_2byte,2);

//     EEProm_Read(E2_Z_POSLIMIT,(uint8_t*)&at24c02_data_4byte,4);
//     EEProm_Read(E2_Z_POSZERO,(uint8_t*)&at24c02_data_4byte,4);
//     EEProm_Read(E2_Z_SPEEDSELFTEST,(uint8_t*)&at24c02_data_2byte,2);
//     EEProm_Read(E2_Z_SPEEDRUN,(uint8_t*)&at24c02_data_2byte,2);
//     EEProm_Read(E2_Z_STEP,(uint8_t*)&at24c02_data_2byte,2);

// }


int32_t XPosition = 0;
void param_init(void)
{
        USER_PARAM_NULL(int32_t,XPosition,0);
}


struct Device_Param Device_XMotor = {
	 .step = 0,
	 .pos = 0,
	 .speed = 0,
	 .acc = 0,
	 .check_speed = 0,
	 .check_acc = 0
    

};
void AT24C02_Write_Test(void)
{
    ///E2ADDR_X_STEP
    int32_t ret=0;
    uint8_t debugData[30] = 0;
    Device_XMotor.step = 4;
    ret = EEProm_Write(E2ADDR_X_STEP,(uint8_t*)&Device_XMotor.step,4);

  sprintf(debugData,"\r\nSET E2ADDR_X_STEP=%d\r\n\r\n",ret);
   HAL_UART_Transmit(&huart3,debugData, strlen(debugData),100);
}


void AT24C02_Read_Test(void)
{
    int32_t ret=0;
    uint8_t debugData[30] = 0;
    EEProm_Read(E2ADDR_X_STEP,(uint8_t*)&ret,4);

      
  sprintf(debugData,"\r\nE2ADDR_X_STEP=%d\r\n\r\n",ret);
   HAL_UART_Transmit(&huart3,debugData, strlen(debugData),100);
}
相关推荐
BigShark8885 小时前
2025蓝桥杯(单片机)备赛--扩展外设之I2C的重要应用--PCF8591(八)
单片机·职场和发展·蓝桥杯
ID2024101322066 小时前
单电源运放
单片机·嵌入式硬件
Matlab程序猿小助手7 小时前
【MATLAB源码-第218期】基于matlab的北方苍鹰优化算法(NGO)无人机三维路径规划,输出做短路径图和适应度曲线.
开发语言·嵌入式硬件·算法·matlab·机器人·无人机
linux_carlos9 小时前
#lwIP 的 Raw API 使用指南
stm32·单片机·mcu·物联网·rtdbs
Graceful_scenery10 小时前
STM32F103系统时钟配置
stm32·单片机·嵌入式硬件
姓刘的哦10 小时前
MCU中的定时器
单片机·嵌入式硬件
xcx00311 小时前
应用于各种小家电的快充协议芯片
单片机·嵌入式硬件·物联网
what&&why12 小时前
stm32与ht7038的项目
stm32·单片机·嵌入式硬件
TeYiToKu12 小时前
笔记整理—linux驱动开发部分(13)块设备
linux·c语言·驱动开发·笔记·嵌入式硬件·arm
BigShark88813 小时前
2025蓝桥杯(单片机)备赛--扩展外设之NE555的使用及定时器1的详细讲解(十)
单片机·职场和发展·蓝桥杯