发一个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;
        }
}

友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
该问题目前已经被作者或者管理员关闭, 无法添加新回复
60条回答
xiaob135
1楼-- · 2019-12-13 17:24
fengyunyu 发表于 2014-5-12 06:10
串口是字符型的通信,i2c是数据块型的通信,这个如何理解?

就是说从应用层的角度来讲,串口是一个字节一个字节的传送,需要自己编写一个通信协议。
i2c每次读取、写入都是先写地址,再写数据。这样应用层就可以直接进行数据交流,而不需要自己再写通信协议。
huaohui666666
2楼-- · 2019-12-13 23:00
思路不错,MARK!
craigtao
3楼-- · 2019-12-14 03:16
 精彩回答 2  元偷偷看……
xiaob135
4楼-- · 2019-12-14 07:51
BUG修正版。在单片机上实际测试通过。
mhw
5楼-- · 2019-12-14 12:41
不错。用在什么单片机上,主频多少,有没有测试过主机SCK最高速率多少?
去年做过一个产品,51单片机,处理起来很费时。最后没办法,检测到起始位后,关闭中断,直接用nop的方式来延时,直到通信结束退出。
主机SCK速率不能超过30K。
zhang3lu
6楼-- · 2019-12-14 17:00
先顶了,楼主能不能发个应用方面的程序看看

一周热门 更多>