一、IIC基本特征
两线通讯:数据线(SDA)和时钟线(SCL)。
IIC可以挂多个设备,有主从机之分(主机访问从机)。IIC总线上的器件都有一个唯一器件地址,主机通过器件地址确定对应从机。
IIC采用半双工通讯,硬件上需要上拉电阻一般是4.7K~10K典型值为4.7K。总线上最大电容400pF限制。
二、IIC通讯时序
IIC空闲时为高电平。
主机写数据到从机
起始和停止信号
起始信号:SCL为高电平时,SDA从高变低
停止信号:SCL为高电平时,SDA从低变高
void I2C_Start(void) //起始信号函数
{
SDA_Out(1); //SDA输出高
SCL_Out(1); //SCL输出高
delay_us(5);
SDA_Out(0); //SDA输出低
delay_us(5);
SCL_Out(0);
delay_us(3);
}
void I2c_Stop(void) //停止信号函数
{
SDA_Out(0); //SDA输出低
SCL_Out(0); //SCL输出低
delay_us(5);
SCL_Out(1); //SCL输出高
delay_us(5);
SDA_Out(1);
delay_us(3);
}
数据变化只能在SCl为低电平时进行
****主机发送数据到从机****
阴影部分为主机发送给从机的数据,空白为从机返回的数据。
主机先发送 :起始信号 + 从机地址【高7bit 为地址,最低位为读写bit(0:对从机写操作;1:对从机读操作)】+读ACK(从机发送给主机)+写数据 + 读ACK +…+ 写数据 + 读ACK + 停止信号。
主机发送数据到从机的ACK都是从机发给主机的。
主机接收数据到从机
阴影部分为主机发送给从机的数据,空白为从机返回的数据。
主机先发送 :起始信号 + 从机地址【高7bit 为地址,最低位为读写bit(0:对从机写操作;1:对从机读操作)】+读ACK(从机发送给主机)+ 读数据 + 写ACK +…+ 读数据 + 写ACK + 停止信号。
ACK总结:ACK都是数据接收器件发给数据发送器件的。
void Ack(void) //主机读ACK
{
SCL_Out(0);
delay_us(2);
SDA_Out(1);
SDA_IN();
delay_us(2);
SCL_Out(1);
SDA_Out(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7));
delay_us(4);
SCL_Out(0);
SDA_OUT();
delay_us(2);
}
void Nack(uint8_t ack) //主机写ACK
{
SCL_Out(0);
delay_us(2);
if(ack == 1)
SDA_Out(1);
else
SDA_Out(0); //写应答信号
delay_us(2);
SCL_Out(1); //拉高时钟线
delay_us(4); //延时
SCL_Out(0); //拉低时钟线
delay_us(2); //延时
}
主机发送数据用Ack函数,主机接收数据时用Nack函数且最后一个Nack为高
void I2c_SendByte(uint8_t _ucByte) //主机发送8bit数据
{
uint8_t i;
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)
SDA_Out(1);
else
SDA_Out(0);
delay_us(2);
SCL_Out(1);
delay_us(2);
_ucByte <<= 1; //左移一个bit
SCL_Out(0);
}
SDA_Out(0);
delay_us(1);
SCL_Out(0);
delay_us(1);
}
uint8_t I2c_ReadByte(void) //主机接收8bit数据
{
uint8_t i;
uint8_t value;
/* 读到第1个bit为数据的bit7 */
value = 0;
for (i = 0; i < 8; i++)
{
value<<=1;
SCL_Out(0);
SDA_IN();
delay_us(2);
if(GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_7))
value |= 0x01 ;
else
value &= 0xfe;
SCL_Out(1);
delay_us(2);
}
SCL_Out(0);
SDA_OUT();
delay_us(2);
SDA_Out(0);
delay_us(2);
return value;
}
int I2C_Write(uint8_t addr , uint8_t* buff, uint8_t size) //主机发数据
{
uint8_t i;
I2C_Start();
I2c_SendByte(addr);
Ack();
for(i = 0; i < size; i++)
{
I2c_SendByte(buff[i]);
Ack();
}
I2c_Stop();
return 0;
}
int I2C_Read(uint8_t addr , uint8_t* buff, uint8_t size,uint8_t bus_bit) //主机接收数据
{
uint8_t i,busy;
I2C_Start();
I2c_SendByte(addr+1);
delay_us(2);
Ack();
for(i = 0; i< (size-1); i++)
{
buff[i] = I2c_ReadByte();
delay_us(2);
Nack(0);
}
buff[size-1] = I2c_ReadByte();
delay_us(2);
Nack(1);
delay_us(10);
I2c_Stop();
return 0;
}