I2C的总结
I2C优点:
接口线少只有两根线,控制方式简单,通信速率较高;
I2C 是飞利浦公司开发的两线式串行总线;
I2C缺点:
硬件比较复杂,稳定性不太好,程序移植有点麻烦,用软件模拟I2C比较方便
物理层特点:
(1)支持多设备的总线
(2)一个总线只使用两根线,数据线SDA,时钟线SCL
(3)每个连接总线都设备都有一个独立的地址,查询设备都是靠这个地址
(4)总线通过上拉电阻,空闲的时候就输出高阻态,所有设备空间的时候,会拉成高电平
(5)多个主机同时使用总线的时候,就会使用仲裁
(6)总线传输模式,标准100kbits/s,快速模式400kbit.s
I2C协议有什么?
I2C 里面定义了通信的 6 个方面
1、起始和停止信号
2、数据有效性、
3、响应
4、仲裁
5、时钟同步
6、地址广播
(1)数据有效性
I2C传输数据,SCL时钟要为高电平期间,SDA传输数据的线必须稳定;
时钟为低电平的期间,数据线上的高电平或者低电平数据允许发生变化;
传输数据以字节为单位,每次传输的字节数不受限制;
(2)起始和停止信号
时钟SCL为高电平期间,SDA数据线由高电平向低电平变化表示起始信号;
时钟SCL为高电平期间,SDA数据线由低电平向高电平变化表示停止信号;
起始和停止信号都是由主机发出,发送起始信号后,总线就处于被占用的状态,主机发送停止信号后,总线就处于空闲状态;
(3)应答和响应
发送端传输完一个字节的数据后,后面必须要跟一个校验位,这个校验位是 从机 通过控制SDA(数据线)来实现的,主机可以继续发送数据,这个校验位就是数据或地址传输过程中的响应。
响应分为(应答ACK)和(非应答NACK)
作为从机 当 主机接收到I2C传输的一个字节数据或地址后,若让主机继续发送需要向对方发送应答ACk信号低电平脉冲,主机就会继续发送下一个数据;
若从机希望结束数据传输,则会向主机发送 非应答NACK信号高电平脉冲,主机收到非应答信号,就会产生停止信号,结束信号传输;
每个字节必须保证8位,先传送高位MSB ,在传输地位LSB,传送的字节要跟一位应答位 (一帧 9 位 )
(4)总线的寻址方式
分为两种,7位和10位的
D7~D1 是 从机的地址,D0位是数据传送方向位;
为0表示主机向从机写数据,为1 主机向 从机读数据;
主机发送一个地址,总线上每个器件都将头7位于自己的地址比较,一样,就会被主机选址
四位是固定的,3个可编程
(5)数据传输模式
主机发送起始信号,发送从机地址+使能位写数据,从机发送应答,主机发送数据,从机应答主机发送数据,非应答,主机 发送结束信号;
软件模拟:
#include "iic.h"
// at 芯片读写操作的
// 起始信号
void iic_start(void)
{
IIC_SCL = 1;
IIC_SDA = 1;
delay_10us(1);
IIC_SDA = 0;
delay_10us(1);
IIC_SCL = 0;
// 处于占用
}
// 停止信号
void iic_stop(void)
{
IIC_SCL = 1;
IIC_SDA = 0;
delay_10us(1);
IIC_SDA = 1;
delay_10us(1);
}
// 应答信号
void iic_ack(void)
{
IIC_SCL = 0;
IIC_SDA = 0;
delay_10us(1);
IIC_SCL = 1;
delay_10us(1);
IIC_SCL = 0;
}
// 非应答信号
void iic_nack(void)
{
IIC_SCL = 0;
IIC_SDA = 1;
delay_10us(1);
IIC_SCL = 1;
delay_10us(1);
IIC_SCL = 0;
}
u8 iic_wait_ack(void)
{
u8 time_temp =0;
IIC_SDA = 1;
delay_10us(1);
while(IIC_SDA)
{
time_temp++;
if(time_temp>100)
{
iic_stop();
return 1; // 返回1 停止应答
}
}
IIC_SDA = 0;
return 0;
}
// IIC写字节的操作
void iic_write_byte( u8 dat) // 入参 传入字节
{
//
u8 i =0;
IIC_SCL=0;
for(i=0;i<8;i++) //从高位 在地位 写入
{
if( (dat&0x80) > 1) // 0x80 1000 0000 从最高位 判断最高位为1 如果大于0
IIC_SDA = 1;
else
IIC_SDA = 0;
dat <<= 1; // 左移一位
IIC_SDA = 0;
delay_10us(1);
IIC_SCL=0;
delay_10us(1);
}
}
// IIC 读字节操作
u8 iic_read_byte(u8 ack)
{
u8 i =0;
u8 receive =0;
for(i=0;i<8;i++)
{
IIC_SCL = 0;
delay_10us(1);
IIC_SCL=1;
delay_10us(1);
receive<<=1;
if(IIC_SDA)receive++;
}
if(!ack)iic_nack();
else iic_ack();
return receive;
}