IIC通讯协议
一、什么是IIC
IIC(Inter-Integrated Circuit)其实是IICBus简称,所以中文应该叫集成电路总线,它是一种串行通信总线,使用多主从架构,由飞利浦公司在1980年代为了让主板、嵌入式系统或手机用以连接低速周边设备而发展。
二、IIC协议简介
I2C串行总线一般有两根信号线,一根是双向的数据线SDA,另一根是时钟线SCL。所有接到I2C总线设备上的串行数据SDA都接到总线的SDA上,各设备的时钟线SCL接到总线的SCL上。
为了避免总线信号的混乱,要求各设备连接到总线的输出端时必须是漏极开路(OD)输出或集电极开路(OC)输出。设备上的串行数据线SDA接口电路应该是双向的,输出电路用于向总线上发送数据,输入电路用于接收总线上的数据。而串行时钟线也应是双向的,作为控制总线数据传送的主机,一方面要通过SCL输出电路发送时钟信号,另一方面还要检测总线上的SCL电平,以决定什么时候发送下一个时钟脉冲电平;作为接受主机命令的从机,要按总线上的SCL信号发出或接收SDA上的信号,也可以向SCL线发出低电平信号以延长总线时钟信号周期。总线空闲时,因各设备都是开漏输出,上拉电阻Rp使SDA和SCL线都保持高电平。任一设备输出的低电平都将使相应的总线信号线变低,也就是说:各设备的SDA是“与”关系,SCL也是“与”关系。
总线对设备接口电路的制造工艺和电平都没有特殊的要求(NMOS、CMOS都可以兼容)。在I2C总线上的数据传送率可高达每秒十万位,高速方式时在每秒四十万位以上。另外,总线上允许连接的设备数以其电容量不超过400pF为限。
三、通讯过程
总线接口 MCU 通过 SDA 和 SCL 端口与 ET6934 进行数据传输。
1、数据有效性
当 SCL 信号处于高电平时,SDA 端口上的数据都是有效稳定的。
只有当 SCL 信号处于低电平时, 才能改变 SDA 端口上的电平高低。
2、开始(重新开始)和停止工作条件
当 SCL 信号为高电平,SDA 信号由高电平转为低电平开始工作或者重新开始工作, 而 SCL 信号为高电平,SDA 信号由低电平转为高电平时停止工作。
3、字节格式
数据线的每个字节由 8 位组成。每个字节包含一个应答位。传输第一个数据是 MSB。
4、应答
在应答时钟期间,主机使 SDA 端口处于高电平,在写模式期间,ET6934 会发出应答信号使 SDA 端 口在应答期间处于低电平。
注:ACK=应答信号 MSB=字节的最高位
S=起始信号 RS=重新开始信号 P=停止信号
最大时钟速度=400KBITS/S
Restart: 此时 SDA 电平翻转如波形中虚线所表示
四、代码实现
#define I2C_SDA1 P27//
#define I2C_SCL1 P26//
/*****************************************************
*函数名称:void I2cStart()
*函数功能:启动i2c
*入口参数:void
*出口参数:void
*****************************************************/
void I2cStart(void)
{
I2C_SCL1=1; //总线空闲时,SCL,SDA为高电平
I2C_SDA1=1;
_nop_(); //SCL高电平保持 4.7US,拉低SDA,产生起始信号
_nop_();
_nop_();
_nop_();
I2C_SDA1=0;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL1=0;
_nop_();
}
/*****************************************************
*函数名称:bit I2cRecAck()
*函数功能:检查应答信号
*入口参数:void
*出口参数:ask
*****************************************************/
void I2cRecAck(void)
{
I2C_SDA1=1; //主机主动释放SDA,为读ASK做准备
P2CON &=0x7F; //0b1111 0111
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL1=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL1=0;
P2CON |=0x80; //0b0000 0000
}
/*****************************************************
*函数名称:I2cStop(void)
*函数功能:停止I2C
*入口参数:void
*出口参数:void
*****************************************************/
void I2cStop(void)
{
I2C_SDA1=0;
I2C_SCL1=0;
_nop_();
_nop_();
I2C_SCL1=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SDA1=1;
_nop_();
}
/*****************************************************
*函数名称:I2cWriteByte(uchar dat)
*函数功能:写入一个字节
*入口参数:void
*出口参数:void
*****************************************************/
void I2cWriteByte(unsigned char dat)
{
unsigned char temp;
for(temp=0;temp<8;temp++)
{
if((dat&0X80)==0)
I2C_SDA1=0;
else
I2C_SDA1=1;
dat=dat<<1;
_nop_();
I2C_SCL1=1;
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
_nop_();
I2C_SCL1=0; //SCL低电平时,数据允许变化
_nop_();
}
}
/******************写入所有数据***********************/
void I2cWrAllData(unsigned char *p,unsigned char lengh)
{
unsigned char i;
for (i=0;i<lengh;i++) //发送最多16字节的显存数据
{
I2cWriteByte(*p); //写入数据
p++;
I2cRecAck();
}
}
/******************写完整数据***********************/
void I2cWrStruct(unsigned char *p,unsigned char length)
{
I2cStart();
I2cWriteByte(device_addr);
I2cRecAck();
I2cWrAllData(p,length);
I2cStop();
}