I2C笔记
物理层
(1)一个主机可以连接多个从机。
(2)每个连接到总线上的设备都有一个独立的地址,主机可以通过利用这个地址进行不同设备之间的访问
(3)一个I2C总线使用两条总线线路,一条SDA(数据线),一条SCL(时钟线)
(4)总线通过上拉电阻接到电源,当I2C空闲时,会输出高阻态,而当所有设备都空闲时,都输出高阻态,由上拉电阻把总线拉成高电平
(5)多个主机同时使用总线时,为防止数据冲突,会采用仲裁方式决定由哪个设备占用总线。
(6)具有3种传输模式:标准模式(100kbps),快速模式(400kbps),高速模式(可达3.4Mbps),目前大多I2C设备不支持高速模式
协议层
- 基本读写流程
一般常用的是复合格式的流程
主机先发送起始信号—>发送从机地址(一般7位或10位)---->发送传输方向位R/W(1为读,0为写)—>等待应答信号-ACK—>发送从设备内部的寄存器或存储器的地址—>发送传输方向位R/W(1为读,0为写)—>等待应答信号-ACK—>发送数据—>等待应答信号—>发送数据—>等待应答信号······ 最后发送结束信号
- 起始信号
- 当SDA为高电平时,SDA从高电平向低电平转换
- 当SCL为低电平时,SCL从低电平向高电平转换
起始信号:
void i2c_Stop(void)
{
/* 当SCL高电平时,SDA出现一个上跳沿表示I2C总线停止信号 */
EEPROM_I2C_SDA_0();
EEPROM_I2C_SCL_1();
i2c_Delay();
EEPROM_I2C_SDA_1();
}
终止信号:
void i2c_Stop(void)
{
I2C_SDA_0();
I2C_SCL_1();
i2c_Delay();
I2C_SDA_1();//当SCL为高时,SDA拉高
}
- 数据传输
-
当SCL为高电平的时候SDA表示的数据有效
-
此时SDA为高电平表示数据1,为低电平表示数据0
-
当SCL为低电平时,数据无效
- 地址及数据方向
-
读数据时,主机释放对SDA的控制,由从机控制SDA信号线
-
写数据时,从机释放对SDA的控制,由主机控制SDA信号线
void i2c_SendByte(uint8_t _ucByte)
{
uint8_t i;
/* 先发送字节的高位bit7 */
for (i = 0; i < 8; i++)
{
if (_ucByte & 0x80)//当_ucByte最高位1时,SDA=1
{
I2C_SDA_1();
}
else当_ucByte最高位0时,SDA=0
{
I2C_SDA_0();
}
i2c_Delay();
I2C_SCL_1();
i2c_Delay();
I2C_SCL_0();
if (i == 7)
{
I2C_SDA_1(); // 释放总线
}
_ucByte <<= 1; /* 左移一个bit */
i2c_Delay();
}
}
5.响应
- 每次设备(无论主从机)发送发数据或者地址时,对方都会发送一个应答ACK或者非应答信号NACK
- 若设备收到的信号为ACK,发送端继续发送数据,
- 若设备收到的信号为NACK,发送端接收到后会产生一个终止信号,结束信号通讯
ACK:
void i2c_Ack(void)
{
I2C_SDA_0(); /* CPU驱动SDA = 0 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
I2C_SDA_1(); /* CPU释放SDA总线 */
}
NACK:
void i2c_NAck(void)
{
I2C_SDA_1(); /* CPU驱动SDA = 1 */
i2c_Delay();
I2C_SCL_1(); /* CPU产生1个时钟 */
i2c_Delay();
I2C_SCL_0();
i2c_Delay();
}
参考的是野火,《STM32开发实战指南》,十分感谢