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;
}

评论 2
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

如之

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

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

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

打赏作者

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

抵扣说明:

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

余额充值