基本概述
I2C是一种串行总线,使用主从架构。
- 只需要SCL(串行时钟线)和SDA(串行数据线)两条总线,两条线都需要上拉电阻
- 所有组件之间都存在简单的主从关系,连接到总线的每个设备均可以通过唯一地址进行软件寻址
- 最大设备数无限制,最大从机数理论上是127(7位地址数据)
传输协议
开始信号、7个地址位、1个读写位、1个应答位、8个数据位、1个应答位、结束信号
开始条件和停止条件
- 开始条件:SCL为高时,拉低SDA
- 停止条件:SCL为高时,拉高SDA
当主设备发送开始条件信号之后,所有从机设备即使处于睡眠模式,也会变为活动状态,并等待接收地址位
数据传输
传输格式
- 传输的数据总共有8位,由发送方设置,先发送数据的高地址,发送完8位数据后,接收方在第9个时钟会紧跟一个ACK位,成功接收为0,否则保持为1。以此往复,直到数据完全传输为止。
- 谁发送数据谁就驱动SDA线,由于上拉电阻的存在,默认是高电平,谁驱动谁就拉低SDA的电平
- 发送数据时,SDA的电平在SCL的低电平处变化,在高电平时接接收方读取数据
- ACK为高时,会引起主设备发生重启或者停止
软件模拟I2C协议
Bool Panel_i2c_Start( void )
{
Set_Panel_I2C_SDA();
Set_Panel_I2C_SCL();
Panel_i2c_Delay();
if( Panel_I2C_SDALo() || Panel_I2C_SCLLo() )
return FALSE;
Clr_Panel_I2C_SDA();
Panel_i2c_Delay();
Clr_Panel_I2C_SCL();
Panel_i2c_Delay();
return TRUE;
}
Bool Panel_i2c_SendByte( BYTE value )
{
BYTE i;
Bool result;
for( i = 0; i < 8; i++ ) // Send data via i2c pin
{
if( value & BIT7 )
Set_Panel_I2C_SDA();
else
Clr_Panel_I2C_SDA();
Panel_i2c_Delay();
Set_Panel_I2C_SCL();
Panel_i2c_Delay();
value <<= 1;
Clr_Panel_I2C_SCL();
}
Set_Panel_I2C_SDA();
Panel_i2c_Delay();
result = Panel_Wait_i2C_Ack();
Set_Panel_I2C_SCL();
Panel_i2c_Delay();
Clr_Panel_I2C_SCL();
Panel_i2c_Delay();
Clr_Panel_I2C_SDA();
return result;
}
Bool Panel_Wait_i2C_Ack( void )
{
BYTE i;
for( i = 0; i < 5; i++ )
{
if( Panel_I2C_SDALo() )
return TRUE;
Panel_i2c_Delay();
}
if( Panel_I2C_SDALo() )
return TRUE;
else
return FALSE;
}
void Panel_i2c_Stop( void )
{
// SCL=L, SDA=L, Stop condition.
Clr_Panel_I2C_SCL();
Clr_Panel_I2C_SDA();
Panel_i2c_Delay();
Set_Panel_I2C_SCL();
Panel_i2c_Delay();
Set_Panel_I2C_SDA();
Panel_i2c_Delay();
}
Bool Panel_i2c_AccessStart(BYTE SlaveAdr, Panel_I2cIoTransType trans_t)
{
BYTE Dummy; // loop dummy
if (trans_t == PANEL_I2C_TRANS_READ) // check i2c read or write
SlaveAdr = PANEL_I2C_DEVICE_ADR_READ(SlaveAdr); // read
else
SlaveAdr = PANEL_I2C_DEVICE_ADR_WRITE(SlaveAdr); // write
Dummy = PANEL_I2C_ACCESS_DUMMY_TIME;
while (Dummy--)
{
if (Panel_i2c_Start() == FALSE)
{
Panel_i2c_Stop();
continue;
}
if (Panel_i2c_SendByte(SlaveAdr) == TRUE) // check acknowledge
return TRUE;
Panel_i2c_Stop();
ForceDelayNVRAM(1);
}
return FALSE;
}
void i2cBurstWriteBytes(BYTE SlaveAdr, BYTE *pBuf, BYTE bufLen)
{
BYTE Dummy; // loop dummy
Dummy = I2C_ACCESS_DUMMY_TIME;
whlie(Dummy--)
{
if(Panel_i2c_AccessStart(SlaveAdr, PANEL_I2C_TRANS_WRITE) == FALS)
continue;
whlie(buflen--)
{
Panel_i2c_SendByte(*pBuf); // send byte
pBuf++; // next byte pointer
}
break;
}
Panel_i2c_Stop();
}