目录
一.I2C简介
1.什么是I2C
I2C是串行总线的一种,属于半双工通信(数据的发送和接收不能同时进行),由两线组成(时钟线SCL和数据线SDA),采用主从通信模式(支持多主机模式)。
2.I2C帧格式
S | ADDR | W/R | A | DATA | A/Ā | P |
S:起始位;由主机发起,表示此次通信的开始。
ADDR:从机地址位,为7bit。
W/R:数据方向位,主机是读数据还是写数据;
A:应答位。
DATA:数据位;要发送的数据,为8bit;在第一个字节中,其中7-1bit为要通信的从机地址,第0bit为通信的方向。
A/Ā:应答/非应答;主机读或写数据后,都需要有对应 的应答位,表示是否继续接收或发送数据。
P:停止位;由主机发起,表示此次通信的结束。
综上,每帧数据共有9bit。
3.I2C时序
数据位的有效性规定:
在时钟线为高电平期间不允许数据的改变,此时进行数据传输,在时钟线为低电平期间才允许数据信号的改变。
1.起始信号和停止信号
当SCL=1,SDA由高电平变为低电平表示起始信号;
当SCL=1,SDA由低电平变为高电平表示停止信号;
2.应答信号
在数据线为低电平期间,时钟线发送一个持续时间不低于4us的高电平脉冲信号。
3.非应答信号
在数据线为高电平期间,时钟线发送一个持续时间不低于4us的高电平脉冲信号。
4. 字节传输
在进行字节传输时,需保证数据为8bit,采用先传输高位,后传输低位的方式进行,在每传输字节后需跟一位应答位。
二.代码实现
//起始信号
void I2C_Start(void)
{
I2C_SDA_OUT();//数据线通信方向
I2C_SDA_H;//拉高数据线
I2C_SCL_H;//拉低时钟线
Delay_us(5);//延时5us
I2C_SDA_L;//拉低数据线
Delay_us(5);
I2C_SCL_L;//拉低时钟线
}
//停止信号
void I2C_Stop(void)
{
I2C_SDA_OUT();
I2C_SCL_L;
I2C_SDA_L;
Delay_us(5);
I2C_SCL_H;
I2C_SDA_H;
Delay_us(5);
}
//应答信号
void I2C_Ack(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_L;
Delay_us(2);
I2C_SCL_H;
Delay_us(5);
I2C_SCL_L;
}
//非应答信号
void I2C_Nack(void)
{
I2C_SCL_L;
I2C_SDA_OUT();
I2C_SDA_H;
Delay_us(2);
I2C_SCL_H;
Delay_us(5);
I2C_SCL_L;
}
//主机等待从机应答
u8 I2C_Wait_Ack(void)
{
int num=0;
int ack_flag;
I2C_SDA_IN();
I2C_SDA_H;
Delay_us(2);
I2C_SCL_H;
Delay_us(2);
while(I2C_READ)
{
num++;
if(num>250)
{
I2C_Stop();
ack_flag=1;
}
}
I2C_SCL_L;
ack_flag=0;
return ack_flag;
}
//主机发送一个字节
void I2C_Send_Byte(u8 data)
{
u8 t;
I2C_SDA_OUT();
I2C_SCL_L;
for(t=0;t<8;t++)
{
I2C_SDA=(data&0x80)>>7;
data<<=1;
I2C_SCL_H;
Delay_us(2);
I2C_SCL_L;
Delay_us(2);
}
}
//主机接收一个字节
u8 I2C_Recive_Byte(unsigned char ack)
{
unsigned char i,receive=0;
I2C_SDA_IN();
for(i=0;i<8;i++ )
{
I2C_SCL_L;
Delay_us(2);
I2C_SCL_H;
receive<<=1;
if(I2C_READ)receive++;
Delay_us(2);
}
if (!ack) I2C_Nack();
else I2C_Ack();
return receive;
}
三.时序实现过程中遇到的问题
1.延时时间需参考时序,看是否达到要求的最低延时时间。
2.在写完时序后,发现通信错误或无法通信,看是否是先钳住总线,因为在本人实现过程中,没有先钳住总线,导致通信数据错误,如读取MPU6050的地址应为0x68,而实际读取到不是此值,当先钳住总线后通信正常。