IIC协议
IIC简介
内部集成电路 I2C(IIC,Inter-Integrated Circuit) 总线是由Philips公司开发的是一种简单的、半双工同步通信的串行通信接口。它只需要两根线即可在连接于总线上的器件之间传送信息。
IIC 主要特性
- 并行总线/I2C 协议转换器
- 多主模式功能:同一接口既可用作主模式也可用作从模式
- IIC 主模式特性:
- IIC从模式特性:
- 可编程 I2C 地址检测
- 双寻址模式,可对 2 个从地址应答
- 停止位检测
- 7 位/10 位寻址以及广播呼叫的生成和检测
- 支持不同的通信速度:
- 标准速度(高达 100 kHz)
- 快速速度(高达 400 kHz)
引脚定义
IIC总线只需要两根引脚就可以实现通信,一根是数据线(SDA Serial Data),另一根是时钟线(SCL Serial Clock),所有通过IIC接口通信的外围器件都挂载在IIC总线上,通过这种机制就可以实现多机通信。

可以看到,外围器件的时钟线和数据线都是挂载在IIC总线(由主控芯片提供),并且在空闲状态下所有器件的时钟线(SCL)和数据线(SDA)都被总线的上拉电阻拉高,这样就可以把SDA引脚和SCL引脚设置为开漏模式即可,可以防止短路,也能节约功耗。
通信流程
在主模式下,I2C 接口会启动数据传输并生成时钟信号。串行数据传输始终是在出现起始位时开始,在出现停止位时结束。起始位和停止位均在主模式下由软件生成。
在从模式下,该接口能够识别其自身地址(7 或 10 位)以及广播呼叫地址。广播呼叫地址检测可由软件使能或禁止。
数据和地址均以 8 位字节传输,MSB 在前。起始位后紧随地址字节(7 位地址占据一个字节;10 位地址占据两个字节)。地址始终在主模式下传送。
在字节传输 8 个时钟周期后是第 9 个时钟脉冲,在此期间接收器必须向发送器发送一个应答位。

- 空闲状态:SDA引脚和SCL引脚空闲时均为高电平。
- 开始信号: 在SCL引脚保持高电平期间,SDA引脚的电平被拉低。
- 数据传输:
- 主机发送开始信号后,需要发送从器件的地址(1byte = 7bit+1bit),遵循MSB高位先出
- 在脉冲信号的低电平期间,数据线SDA的电平是正在修改的,此时不允许收发
- 在脉冲信号的高电平期间,数据线SDA的电平是保持锁存的,此时允许收发
- 应答信号:在第九个脉冲信号的高电平期间接收方才可以应答,SDA=0 表示应答 SDA=1 表示未应答。
- 停止信号:在SCL引脚保持高电平期间,把SDA引脚的电平拉高。
主器件和从器件建立联系的顺序:
- 主器件发送开始信号
- 主器件向从器件发送器件地址
- 主器件等待识别到其自身地址的器件应答
模拟IIC时序
1 2 3 4 5 6 7
|
#define SDA_SET(n) (n) ? GPIO_SetBits(GPIOB,GPIO_Pin_9) : GPIO_ResetBits(GPIOB,GPIO_Pin_9) #define SCL_SET(n) (n) ? GPIO_SetBits(GPIOB,GPIO_Pin_8) : GPIO_ResetBits(GPIOB,GPIO_Pin_8)
#define SDA_READ GPIO_ReadInputDataBit(GPIOB,GPIO_Pin_9)
|
IIC初始化
1 2 3 4 5 6 7 8 9 10 11
| void IIC_Config(void) { IIC_SCLConfig(); IIC_SDAConfig(GPIO_Mode_OUT);
SDA_SET(1); SCL_SET(1); delay_us(5); }
|
IIC开始信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void IIC_Start(void) { IIC_SDAConfig(GPIO_Mode_OUT);
SDA_SET(1); SCL_SET(1); delay_us(5);
SDA_SET(0); delay_us(5);
SCL_SET(0); }
|
IIC发送字节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| void IIC_SendByte(uint8_t Byte) { uint8_t i = 0; IIC_SDAConfig(GPIO_Mode_OUT);
SCL_SET(0); delay_us(5);
for(i=7;i>=0;i--) { if( Byte & (i<<i) ) { SDA_SET(1); } else SDA_SET(0);
delay_us(5);
SCL_SET(1); delay_us(5);
SCL_SET(0); delay_us(5); } }
|
判断从机是否应答
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| bool IIC_IsSlaveACK(void) { bool ack; IIC_SDAConfig(GPIO_Mode_IN);
SCL_SET(0); delay_us(5);
SCL_SET(1); delay_us(5);
if(SDA_READ) ack = false; else ack = true; SCL_SET(0); delay_us(5); return ack; }
|
IIC读取字节
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| uint8_t IIC_ReadByte(void) { uint8_t i = 0,data = 0;
IIC_SDAConfig(GPIO_Mode_IN);
SCL_SET(0); delay_us(5);
for (i = 0; i < 8; ++i) { SCL_SET(1); delay_us(5);
data <<= 1; data |= SDA_READ;
SCL_SET(0); delay_us(5); }
return data; }
|
接收器向 发送器发送一个应答位(ack=1 表示不应答 ack=0 表示应答)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| void IIC_MasterACK(uint8_t ack) { IIC_SDAConfig(GPIO_Mode_OUT);
SCL_SET(0); delay_us(5);
if(ack) SDA_SET(1); else SDA_SET(0);
delay_us(5);
SCL_SET(1); delay_us(5); SCL_SET(0); delay_us(5); }
|
IIC停止信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| void IIC_Stop(void) { IIC_SDAConfig(GPIO_Mode_OUT);
SDA_SET(0); SCL_SET(0); delay_us(5);
SCL_SET(1); delay_us(5);
SDA_SET(1); delay_us(5); }
|
参考文章
STM32F4xx中文参考手册