stm32 硬件I2C

在stm32f103上解决硬件I2C总是busy的问题

问题

在使用stm32f103的硬件I2C的时候,读写I2C总线总是busy,即下面的代码总是无法退出:

    while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)) 
    {
        ;
    }

解决方法

在将io管脚复用成I2C之前,先作为输出GPIO管脚,然后拉高,即下面代码里的i2c_pin_init,并且在每次读写的时候都调用一次i2c_pin_init,代码如下:

#include "stm32f10x.h"
#include <stdint.h>
#include <stdio.h>

#define I2C1_ADDR   0x74

#define I2C_OK       0
#define I2C_FAIL    -1

/* Maximum Timeout values for flags and events waiting loops. These timeouts are
   not based on accurate values, they just guarantee that the application will 
   not remain stuck if the I2C communication is corrupted.
   You may modify these timeout values depending on CPU frequency and application
   conditions (interrupts routines ...). */   
#define I2C_FLAG_TIMEOUT         ((uint32_t)0x1000)
#define I2C_LONG_TIMEOUT         ((uint32_t)(10 * I2C_FLAG_TIMEOUT))    

static i2c_pin_init()
{
  GPIO_InitTypeDef  GPIO_InitStructure;

  RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
  GPIO_Init(GPIOB, &GPIO_InitStructure);

  GPIO_SetBits(GPIOB, GPIO_Pin_6 | GPIO_Pin_7);
  
  /*!< Configure pins: SCL/SDL */
  GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7;
  GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_OD;
  GPIO_Init(GPIOB, &GPIO_InitStructure);    
}

void i2c_Init(void)
{
  I2C_InitTypeDef   I2C_InitStructure;

  RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);

  i2c_pin_init();
  I2C_DeInit(I2C1);

  /*!< I2C1 Init */
  I2C_InitStructure.I2C_Mode = I2C_Mode_I2C;
  I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2;
  I2C_InitStructure.I2C_OwnAddress1 = I2C1_ADDR<<1;
  I2C_InitStructure.I2C_Ack = I2C_Ack_Enable;
  I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
  I2C_InitStructure.I2C_ClockSpeed = 100000;
  
  I2C_Init(I2C1, &I2C_InitStructure);

  /*!< I2C1 Init */
  I2C_Cmd(I2C1, ENABLE);
}

int8_t i2c_read(uint8_t devaddr, uint8_t RegName, uint8_t *buf, uint8_t len)
{   
    uint16_t tmp = 0;    
    uint32_t i2c_timeout;
    uint8_t loop;
    int8_t ret;
    
    devaddr <<= 1;

    i2c_pin_init();

    /* Test on BUSY Flag */
    i2c_timeout = I2C_LONG_TIMEOUT;
    while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)) 
    {
        if((i2c_timeout--) == 0) return -1;
    }

    /* Enable the I2C peripheral */
    I2C_GenerateSTART(I2C1, ENABLE);
    /* EV5 */
    i2c_timeout = I2C_FLAG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
    {
        if((i2c_timeout--) == 0)
        {
            ret = -2;
            goto I2CR_ERR;
        }
    }

    /* Transmit the slave address and enable writing operation */
    I2C_Send7bitAddress(I2C1, devaddr, I2C_Direction_Transmitter);
    /* EV6 */
    i2c_timeout = I2C_FLAG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
    {
        if((i2c_timeout--) == 0)
        {
            ret = -3;
            goto I2CR_ERR;
        }
    }

    /* Transmit the register address */
    I2C_SendData(I2C1, RegName);
    /* EV8 */
    i2c_timeout = I2C_FLAG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))  
    {
        if((i2c_timeout--) == 0)
        {
            ret = -4;
            goto I2CR_ERR;
        }
    }
    
    /* Enable the I2C peripheral */
    I2C_GenerateSTART(I2C1, ENABLE);
    /* EV5 */
    i2c_timeout = I2C_FLAG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
    {
        if((i2c_timeout--) == 0)
        {
            ret = -5;
            goto I2CR_ERR;
        }
    }

    /* Send address for read */
    I2C_Send7bitAddress(I2C1, devaddr, I2C_Direction_Receiver);
    /* EV6 */
    i2c_timeout = I2C_FLAG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED))   
    {
        if((i2c_timeout--) == 0)
        {
            ret = -6;
            goto I2CR_ERR;
        }
    }

    for (loop=0; loop<len; loop++)
    {
        if (loop == (len-1))
        {
            I2C_AcknowledgeConfig(I2C1, DISABLE);
            /* Send STOP Condition */
            I2C_GenerateSTOP(I2C1, ENABLE);            
        }

        i2c_timeout = I2C_FLAG_TIMEOUT;
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_RECEIVED))  
        {
            if((i2c_timeout--) == 0)
            {
                ret = -7;
                goto I2CR_ERR;
            }
        }

        buf[loop] = I2C_ReceiveData(I2C1);
    }

    I2C_AcknowledgeConfig(I2C1, ENABLE);
  
    /* return a Reg value */
    return I2C_OK;  

I2CR_ERR:
    I2C_GenerateSTOP(I2C1, ENABLE); 
    return ret;
}

int8_t i2c_write(uint8_t devaddr, uint8_t RegName, uint8_t *buf, uint8_t len)
{     
	uint32_t i2c_timeout;
	uint8_t loop;
	int8_t ret = I2C_OK;
	
	devaddr <<= 1;

	i2c_pin_init();
	
    /* Test on BUSY Flag */
    i2c_timeout = I2C_LONG_TIMEOUT;
    while (I2C_GetFlagStatus(I2C1,I2C_FLAG_BUSY)) 
    {
        if((i2c_timeout--) == 0) return -1;
    }

    /* Enable the I2C peripheral */
    I2C_GenerateSTART(I2C1, ENABLE);

    /* EV5 */
    i2c_timeout = I2C_FLAG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_MODE_SELECT))
    {
        if((i2c_timeout--) == 0)
        {
            ret = -2;
            goto I2CW_ERR;
        }
    }
  
    /* Transmit the slave address and enable writing operation */
    I2C_Send7bitAddress(I2C1, devaddr, I2C_Direction_Transmitter);
  
  /* EV6 */
    i2c_timeout = I2C_FLAG_TIMEOUT;
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED))
    {
        if((i2c_timeout--) == 0)
        {
            ret = -3;
            goto I2CW_ERR;
        }
    }
  
    /* Transmit the register address for r/w operations */
    I2C_SendData(I2C1, RegName);
    i2c_timeout = I2C_FLAG_TIMEOUT;
    /* EV8 */
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))  
    {
        if((i2c_timeout--) == 0)
        {
            ret = -4;
            goto I2CW_ERR;
        }
    }

    for (loop=0; loop<len-1; loop++)
    {
        I2C_SendData(I2C1, buf[loop]);
        /* EV8 */
        i2c_timeout = I2C_FLAG_TIMEOUT;
        while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTING))  
        {
            if((i2c_timeout--) == 0)
            {
                ret = -5;
                goto I2CW_ERR;
            }
        }        
    }

    I2C_SendData(I2C1, buf[loop]);
    i2c_timeout = I2C_FLAG_TIMEOUT;
    /* EV8-2 */
    while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED))  
    {
        if((i2c_timeout--) == 0)
        {
            ret = -6;
            goto I2CW_ERR;
        }
    } 

I2CW_ERR:  
    /* Send STOP Condition */
    I2C_GenerateSTOP(I2C1, ENABLE);

    return ret;
}

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论
STM32是一系列由意法半导体(STMicroelectronics)开发的32位微控制器产品线。STM32系列提供了丰富的硬件外设,其中包括硬件I2C(Inter-Integrated Circuit)接口。 硬件I2C是一种用于在微控制器和其他外设之间进行通信的串行通信协议。它使用两根线路,即SDA(数据线)和SCL(时钟线),允许多个设备在同一总线上进行通信。 在STM32上使用硬件I2C,您需要首先配置和初始化相关的GPIO引脚,并设置I2C的时钟频率、地址等参数。然后,您可以使用STM32提供的I2C库函数来发送和接收数据。 以下是一个示例代码,用于在STM32上使用硬件I2C发送数据: ```c #include "stm32f4xx.h" void I2C_Init(void) { // 配置相关GPIO引脚为I2C功能 RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_InitStructure.GPIO_OType = GPIO_OType_OD; GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; GPIO_Init(GPIOB, &GPIO_InitStructure); // 配置I2C时钟和地址 RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); I2C_InitTypeDef I2C_InitStructure; I2C_InitStructure.I2C_Mode = I2C_Mode_I2C; I2C_InitStructure.I2C_DutyCycle = I2C_DutyCycle_2; I2C_InitStructure.I2C_OwnAddress1 = 0x00; I2C_InitStructure.I2C_Ack = I2C_Ack_Enable; I2C_InitStructure.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit; I2C_InitStructure.I2C_ClockSpeed = 100000; I2C_Init(I2C1, &I2C_InitStructure); // 使能I2C I2C_Cmd(I2C1, ENABLE); } void I2C_SendData(uint8_t data) { // 等待I2C准备就绪 while (I2C_GetFlagStatus(I2C1, I2C_FLAG_BUSY)); // 设置要发送的数据 I2C_SendData(I2C1, data); // 等待数据发送完成 while (!I2C_CheckEvent(I2C1, I2C_EVENT_MASTER_BYTE_TRANSMITTED)); } int main(void) { // 初始化I2C I2C_Init(); // 发送数据 uint8_t data = 0xAA; I2C_SendData(data); while (1) { // 保持程序运行 } } ``` 这只是一个简单的示例代码,具体的实现方式可能会因为所使用的STM32型号和开发工具不同而有所差异。在实际开发中,您可能还需要处理其他I2C事件、配置中断等。建议您查阅相关的STM32参考手册和开发文档,以获取更详细的信息和示例代码。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

如之

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值