0%

IIC protocol

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
// SCL  --  PB8  输出模式
// SDA -- PB9 输出模式/输入模式

#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)
{
//1.设置SDA和SCL为输出模式
IIC_SCLConfig();
IIC_SDAConfig(GPIO_Mode_OUT);

//2.确保SDA和SCL处于空闲状态
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)
{
//1.设置SDA引脚为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);

//2.确保SDA和SCL处于空闲状态
SDA_SET(1);
SCL_SET(1);
delay_us(5);

//3.把SDA引脚电平拉低
SDA_SET(0);
delay_us(5);

//4.把SCL引脚电平拉低,此时准备数据
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
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void IIC_SendByte(uint8_t Byte)   
{
uint8_t i = 0;
//1.设置SDA引脚为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);

//2.把SCL引脚电平拉低,此时主机准备数据
SCL_SET(0);
delay_us(5);

//3.循环发送8bit,遵循MSB高位先出
for(i=7;i>=0;i--)
{
//4.判断待发送的字节的最高位
if( Byte & (i<<i) )
{
SDA_SET(1);
}
else
SDA_SET(0);

delay_us(5);

//5.把SCL电平拉高,此时从机读取bit
SCL_SET(1);
delay_us(5);

//6.把SCL引脚电平拉低,此时主机准备下一个bit
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;

//1.设置SDA引脚为输入模式
IIC_SDAConfig(GPIO_Mode_IN);

//2.把SCL引脚电平拉低,此时为第9个脉冲的低电平,从机准备bit
SCL_SET(0);
delay_us(5);

//3.把SCL引脚电平拉高,此时为第9个脉冲的高电平,主机读取状态
SCL_SET(1);
delay_us(5);

//4.主机读取状态 1 表示未应答 0 表示已应答
if(SDA_READ)
ack = false;
else
ack = true;

//5.把SCL引脚电平拉低
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;

//1.设置SDA引脚为输入模式
IIC_SDAConfig(GPIO_Mode_IN);

//2.把SCL引脚电平拉低,此时从机准备数据
SCL_SET(0);
delay_us(5);

//3.循环读取8bit,遵循MSB高位先出
for (i = 0; i < 8; ++i)
{
//4.把SCL电平拉高,此时主机读取bit
SCL_SET(1);
delay_us(5);

//5.主机读取bit
data <<= 1;
data |= SDA_READ;
//delay_us(5);

//6.把SCL引脚电平拉低,此时从机准备下一个bit数据
SCL_SET(0);
delay_us(5);
}

//7.返回结果
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)
{
//1.设置SDA引脚为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);

//2.把SCL引脚电平拉低,此时主机准备
SCL_SET(0);
delay_us(5);

//3.判断ack的状态,从而对SDA操作
if(ack)
SDA_SET(1);
else
SDA_SET(0);

delay_us(5);

//4.把SCL电平拉高,此时从机读取bit
SCL_SET(1);
delay_us(5);

//5.把SCL引脚电平拉低
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)
{
//1.设置SDA引脚为输出模式
IIC_SDAConfig(GPIO_Mode_OUT);

//2.设置SDA和SCL均为低电平
SDA_SET(0);
SCL_SET(0);
delay_us(5);

//3.把SCL电平拉高
SCL_SET(1);
delay_us(5);

//4.把SDA电平拉高
SDA_SET(1);
delay_us(5);
}

参考文章
STM32F4xx中文参考手册