STM32 - 使用 HAL 库实现软件模拟 I2C

不要让自己太懒的个人空间

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

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

二、代码实现
(一)编写软件模拟 I2C 的一些函数

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

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();
}
  1. 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();
}
  1. 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();
}
  1. 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;
}
  1. 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();
}
  1. 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();
}
  1. 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();
    }
}
  1. 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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值