1. 程式人生 > 實用技巧 >STM32_軟體模擬I2C

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
 */
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(); }

  2、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(); }

  3、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();
}

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

  5、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();
}

  6、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();
}

  7、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();
    }
}

  8、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