发一个IO模拟I2C从机的代码吧

2019-12-11 18:14发布

本帖最后由 xiaob135 于 2014-5-11 16:22 编辑

今天下了一天雨,无聊写点代码吧。
发现网上都是io口模拟i2c主机的代码,很少有模拟i2c从机的。所以写一个贡献出来。对于学习i2c的时序还是挺有帮助的。
需要两个带中断的io口,必须支持上升沿和下降沿中断。


typedef enum
{
                I2C_SLAVE_IDLE,
                I2C_SLAVE_ADD,//write iic add
                I2C_SLAVE_REG,//write the register add
                I2C_SLAVE_WRITE,//master write and slave read
                I2C_SLAVE_READ,//master read and slave write
                I2C_SLAVE_BUSY
}e_I2C_SLAVE_MODE;

static e_I2C_SLAVE_MODE                i2c_slave_mode = I2C_SLAVE_IDLE;
static unsigned char I2C_DATA_TEMP = 0;
static unsigned char i2c_slave_reg_p = 0;//the register add
static unsigned char i2c_slave_data_p = 0;//


void i2c_slave_scl_h( void )
{
        I2C_SDA_INT_EN();
        switch( i2c_slave_mode )
        {
                case I2C_SLAVE_ADD:
                case I2C_SLAVE_REG:
                case I2C_SLAVE_WRITE:
                        I2C_DATA_TEMP <<= 1;
                        if( I2C_SDA_IN() )
                                I2C_DATA_TEMP ++;
                        i2c_slave_data_p++;
                        break;               
                default:break;
        }
}

void i2c_slave_scl_l( void )
{
        I2C_SDA_INT_DIS();
       
        if( i2c_slave_data_p > 8 )
        {
                i2c_slave_data_p = 0;
                I2C_SDA_H();//end ack;
                return;
        }
       
        I2C_SCL_L();//slow the i2c speed
        switch( i2c_slave_mode )
        {
                case I2C_SLAVE_ADD:
                        if( i2c_slave_data_p == 8 )
                        {
                                        if( I2C_DATA_TEMP >> 1 == I2C_ADD )
                                        {
                                                I2C_SDA_L();//ack
                                                if( I2C_DATA_TEMP & 0x01 )//read
                                                {
                                                        i2c_slave_mode = I2C_SLAVE_READ;
                                                }
                                                else
                                                        i2c_slave_mode = I2C_SLAVE_REG;//write regster add
                                        }
                                        else
                                                i2c_slave_mode = I2C_SLAVE_BUSY;//nack
                        }
                        break;
                case I2C_SLAVE_REG:
                        if( i2c_slave_data_p == 8 )
                        {
                                        I2C_SDA_L();//ack
                                        i2c_slave_reg_p = I2C_DATA_TEMP;
                                        i2c_slave_mode = I2C_SLAVE_WRITE;
                        }
                        break;
                case I2C_SLAVE_WRITE:
                        if( i2c_slave_data_p == 8 )
                        {//
                                        if( I2C_SLAVE_WRITE_BYTE( i2c_slave_reg_p++, I2C_DATA_TEMP ) )
                                        {
                                                        I2C_SDA_L();
                                        }
                                        else
                                        {
                                                        i2c_slave_mode = I2C_SLAVE_BUSY;
                                        }
                        }
                        break;
                case I2C_SLAVE_READ:
                        if( i2c_slave_data_p < 8 )
                        {
                                        if( I2C_DATA_TEMP & 0x80 )//output a bit
                                                I2C_SDA_H();
                                        else
                                                I2C_SDA_L();               
                                        I2C_DATA_TEMP <<= 1;
                                        i2c_slave_data_p++;
                        }
                        else if( i2c_slave_data_p == 8 )
                        {
                                        if( I2C_SLAVE_READ_BYTE(i2c_slave_reg_p++, &I2C_DATA_TEMP) )
                                        {
                                                        I2C_SDA_L();
                                        }
                                        else
                                        {
                                                        i2c_slave_mode = I2C_SLAVE_BUSY;
                                        }
                        }
                        break;
                        default:break;
        }
        I2C_SCL_H();
}

void i2c_slave_sda_h( void )
{
                if( I2C_SCL_IN() )
                {
                        I2C_SCL_INT_DIS();
                        i2c_slave_mode = I2C_SLAVE_IDLE;
                }
}

void i2c_slave_sda_l( void )
{
        switch( i2c_slave_mode )
        {
                case I2C_SLAVE_IDLE:
                        if( I2C_SCL_IN() )
                        {
                                I2C_SCL_INT_EN();
                                i2c_slave_mode = I2C_SLAVE_ADD;
                                i2c_slave_data_p = 0;
                        }
                        break;
                default:break;
        }
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。