zoukankan      html  css  js  c++  java
  • STM32-软件模拟I2C

    一、SCL和SDA引脚说明

      I2C的两个引脚(SCL引脚和SDA引脚)需要既能输出又能输入,为了避免复杂的配置操作需要把该引脚配置为开漏输出模式,该模式的说明如下图所示:

       当单片机的SDA引脚配置为低电平时,SDA线被拉低;当单片机的SDA引脚配置为高电平时,引脚端口为高阻态,SDA线通过上拉电阻被VCC拉高。因此一定要注意在进行I2C通讯时确保SDA线和SCL线外接上拉电阻。

    三、代码实现

      1、I2C软件延时

    /**
     * @brief 模拟I2C延时
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    static void analog_i2c_delay(void)
    {
        volatile uint8_t i;
    
        for (i = 0; i < 10; i++);
    }

      2、I2C引脚初始化

    /**
     * @brief 软件模拟I2C初始化
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    void bsp_analog_i2c_init(void)
    {
        GPIO_InitTypeDef GPIO_InitStruct = {0};
    
        __HAL_RCC_GPIOB_CLK_ENABLE();
    
        /*Configure GPIO pins : PB6 PB7 */
        GPIO_InitStruct.Pin = GPIO_PIN_6|GPIO_PIN_7;
        GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_OD;
        GPIO_InitStruct.Pull = GPIO_NOPULL;
        GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
        HAL_GPIO_Init(GPIOB, &GPIO_InitStruct);
        bsp_analog_i2c_stop();
    }

      3、I2C开始

    /**
     * @brief I2C 开始,SCL为高电平的时候SDA产生一个下降沿信号
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    void bsp_analog_i2c_start(void)
    {
        /*    _____
         *SDA      \_____________
         *    __________
         *SCL           \________
         */
        i2c_sda_high();
        i2c_scl_high();
        analog_i2c_delay();
        i2c_sda_low();
        analog_i2c_delay();
        i2c_scl_low();
        analog_i2c_delay();
    }

      4、I2C停止

    /**
     * @brief I2C 停止,SCL为高电平的时候SDA产生一个上升沿信号
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    void bsp_analog_i2c_stop(void)
    {
        /*               _______
         *SDA __________/
         *          ____________
         *SCL _____/
         */
        i2c_sda_low();
        i2c_scl_high();
        analog_i2c_delay();
        i2c_sda_high();
        analog_i2c_delay();
    }

      5、I2C等待响应

    /**
     * @brief I2C 等待响应
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    uint8_t bsp_analog_i2c_wait_ack(void)
    {
        uint32_t timeout = 0;
    
        i2c_sda_high();
        analog_i2c_delay();
        i2c_scl_high();
        analog_i2c_delay();
        while(i2c_read_sda())
        {
            timeout++;
            if(timeout > 2000)
            {
                return 0;
            }
        }
        i2c_scl_low();
        analog_i2c_delay();
        return 1;
    }

      6、I2C响应

    /**
     * @brief I2C 响应
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    void bsp_analog_i2c_ack(void)
    {
        /*           ____
         *SCL ______/    \______
         *    ____         _____
         *SDA     \_______/
         */
        i2c_sda_low();
        analog_i2c_delay();
        i2c_scl_high();
        analog_i2c_delay();
        i2c_scl_low();
        analog_i2c_delay();
        i2c_sda_high();
    }

      7、I2C不响应

    /**
     * @brief I2C 不响应
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    void bsp_analog_i2c_nack(void)
    {
        /*           ____
         *SCL ______/    \______
         *    __________________
         *SDA
         */
        i2c_sda_high();
        analog_i2c_delay();
        i2c_scl_high();
        analog_i2c_delay();
        i2c_scl_low();
        analog_i2c_delay();
    }

      8、I2C发送一个字节数据

    /**
     * @brief I2C 发送一个字节数据
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    void bsp_analog_i2c_send_byte(uint8_t data)
    {
        uint8_t i;
    
        for(i = 0; i < 8; i++)
        {
            if(data & 0x80)
            {
               i2c_sda_high();
            }
            else
            {
                i2c_sda_low();
            }
    
            analog_i2c_delay();
            i2c_scl_high();
            analog_i2c_delay();
            i2c_scl_low();
            if(i == 7)
            {
                i2c_sda_high();
            }
            data <<= 1;
            analog_i2c_delay();
        }
    }

      9、I2C接收一个字节数据

    /**
     * @brief I2C 读一个字节数据
     * @retval none
     * @author Mr.W
     * @date 2020-10-12
     */
    uint8_t bsp_analog_i2c_read_byte(void)
    {
        uint8_t i, data = 0;
    
        for(i = 0; i < 8; i++ )
        {
            data <<= 1;
            i2c_scl_high();
            analog_i2c_delay();
            if(i2c_read_sda())
            {
                data++;
            }
            i2c_scl_low();
            analog_i2c_delay();
        }
    
        return data;
    }

    #endif

  • 相关阅读:
    PHP 使用命名空间(namespace),实现自动加载
    快捷方式不能使用的解决方法
    Python学习案例
    Linux下Tomcat的安装和部署
    关于Linux下的环境变量
    关于Linux下安装Oracle
    Linux下安装MySQLdb模块(Python)
    交换机VLAN的定义、意义以及划分方式
    让java程序在后台一直执行(例如putty关闭后后台程序继续运行)
    基于FTP服务器搭建yum源
  • 原文地址:https://www.cnblogs.com/wenhao-Web/p/14151229.html
Copyright © 2011-2022 走看看