模拟I2C驱动

2023-02-05  本文已影响0人  WilliamChou

基于具体平台实现基础接口

void delay(void)
{
    // TO-DO: delay
    // volatile uint32_t count = 5U;
    // while(count > 0)
    // {
    //     count--;
    // }
}

#define SW_I2C_DELAY()          delay()

#define SW_SW_I2C_SCL_INIT()    //TO-DO: scl pin init
#define SW_I2C_SCL_IN()         //TO-DO: set scl pin as input
#define SW_I2C_SCL_OUT()        //TO-DO: set scl pin as output
#define SW_I2C_SCL_H()          //TO-DO: set scl pin to high
#define SW_I2C_SCL_L()          //TO-DO: set scl pin to low

#define SW_SW_I2C_SDA_INIT()    //TO-DO: sda pin init
#define SW_I2C_SDA_IN()         //TO-DO: set sda pin as input
#define SW_I2C_SDA_OUT()        //TO-DO: set sda pin as output
#define SW_I2C_SDA_H()          //TO-DO: set sda pin to high
#define SW_I2C_SDA_L()          //TO-DO: set sda pin to low
#define SW_I2C_SDA_IS_H()       //TO-DO: get sda pin level

I2C基础时序实现

void sw_i2c_init(void)
{
    SW_SW_I2C_SDA_INIT();
    SW_SW_I2C_SCL_INIT();

    SW_I2C_SCL_OUT();
    SW_I2C_SDA_OUT();

    SW_I2C_SCL_H();
    SW_I2C_SDA_H(); 
}

void sw_i2c_start(void)
{
    SW_I2C_SDA_OUT(); 
    SW_I2C_SCL_OUT();

    SW_I2C_SDA_H(); 
    SW_I2C_SCL_H();
    SW_I2C_DELAY();

    SW_I2C_SDA_L();
    SW_I2C_DELAY();
    SW_I2C_SCL_L();
}

void sw_i2c_stop(void)
{
    SW_I2C_SDA_OUT();

    SW_I2C_SDA_L();
    SW_I2C_DELAY();

    SW_I2C_SCL_H();
    SW_I2C_DELAY();

    SW_I2C_SDA_H();
}

void sw_i2c_tx_ack(void)
{
    SW_I2C_SDA_OUT();

    SW_I2C_SDA_L();
    SW_I2C_DELAY();

    SW_I2C_SCL_H();
    SW_I2C_DELAY();

    SW_I2C_SCL_L();
}

void sw_i2c_tx_nack(void)
{
    SW_I2C_SDA_OUT();

    SW_I2C_SDA_H();
    SW_I2C_DELAY();

    SW_I2C_SCL_H();
    SW_I2C_DELAY();

    SW_I2C_SCL_L();
}

uint8_t sw_i2c_rx_ack(void)
{
    uint8_t ret = 0;

    SW_I2C_SDA_IN();    
    SW_I2C_DELAY();

    SW_I2C_SCL_H();
    SW_I2C_DELAY();

    if (!SW_I2C_SDA_IS_H()) {
        ret = 1;
    }

    SW_I2C_SCL_L();

    return ret;
}

void sw_i2c_tx_byte(uint8_t dat)
{
    uint8_t i = 0;
    uint8_t temp = dat;

    SW_I2C_SDA_OUT();

    for (i = 0; i < 8; i++) 
    {
        if (temp & 0x80) 
        {
            SW_I2C_SDA_H();
        } 
        else 
        {
            SW_I2C_SDA_L();
        }
        SW_I2C_DELAY();

        SW_I2C_SCL_H();
        SW_I2C_DELAY();

        SW_I2C_SCL_L();
        temp <<= 1;
    }
}

uint8_t sw_i2c_rx_byte(void)
{
    uint8_t i = 0;
    uint8_t dat = 0;

    SW_I2C_SDA_IN();

    for (i = 0; i < 8; i++) 
    {
        SW_I2C_DELAY();

        SW_I2C_SCL_H();
        SW_I2C_DELAY();
        dat <<= 1;
        if (SW_I2C_SDA_IS_H()) 
        {
            dat |= 0x01;
        }

        SW_I2C_SCL_L();
    }

    return dat;
}

示例

根据slave的i2c时序要求,实现读写接口示例如下:

void sw_i2c_write(uint8_t device_addr, uint16_t reg_addr, uint8_t dat[], uint8_t len)
{
    uint8_t i = 0;

    sw_i2c_start();
    sw_i2c_tx_byte(device_addr & 0xFE);
    sw_i2c_rx_ack();
    sw_i2c_tx_byte((uint8_t)(reg_addr >> 8));
    sw_i2c_rx_ack();
    sw_i2c_tx_byte((uint8_t)(reg_addr & 0xff));
    sw_i2c_rx_ack();
    for(i = 0; i < len; i++)
    {
        sw_i2c_tx_byte(dat[i]);
        sw_i2c_rx_ack();
    }
    sw_i2c_stop();
}

void sw_i2c_read(uint8_t device_addr, uint16_t reg_addr, uint8_t dat[], uint8_t len)
{
    uint8_t i = 0;

    sw_i2c_start();
    sw_i2c_tx_byte(device_addr & 0xFE);
    sw_i2c_rx_ack();
    sw_i2c_tx_byte((uint8_t)(reg_addr >> 8));
    sw_i2c_rx_ack();
    sw_i2c_tx_byte((uint8_t)(reg_addr & 0xff));
    sw_i2c_rx_ack();

    sw_i2c_start();
    sw_i2c_tx_byte(device_addr | 0x01);
    sw_i2c_rx_ack();
    for(i = 0; i < len; i++)
    {
        dat[i] = sw_i2c_rx_byte();
        if(i == (len-1))
        {
            sw_i2c_tx_nack();
        }
        else
        {
            sw_i2c_tx_ack();
        }
    }
    sw_i2c_stop();
}
上一篇下一篇

猜你喜欢

热点阅读