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);
}
相关推荐
森焱森1 小时前
无人机三轴稳定控制(2)____根据目标俯仰角,实现俯仰稳定化控制,计算出升降舵输出
c语言·单片机·算法·架构·无人机
白鱼不小白1 小时前
stm32 USART串口协议与外设(程序)——江协教程踩坑经验分享
stm32·单片机·嵌入式硬件
S,D2 小时前
MCU引脚的漏电流、灌电流、拉电流区别是什么
驱动开发·stm32·单片机·嵌入式硬件·mcu·物联网·硬件工程
芯岭技术5 小时前
PY32F002A单片机 低成本控制器解决方案,提供多种封装
单片机·嵌入式硬件
youmdt5 小时前
Arduino IDE ESP8266连接0.96寸SSD1306 IIC单色屏显示北京时间
单片机·嵌入式硬件
嘿·嘘5 小时前
第七章 STM32内部FLASH读写
stm32·单片机·嵌入式硬件
Meraki.Zhang5 小时前
【STM32实践篇】:I2C驱动编写
stm32·单片机·iic·驱动·i2c
几个几个n8 小时前
STM32-第二节-GPIO输入(按键,传感器)
单片机·嵌入式硬件
Despacito0o11 小时前
ESP32-s3摄像头驱动开发实战:从零搭建实时图像显示系统
人工智能·驱动开发·嵌入式硬件·音视频·嵌入式实时数据库
门思科技11 小时前
设计可靠 LoRaWAN 设备时需要考虑的关键能力
运维·服务器·网络·嵌入式硬件·物联网