I2C 总线精要
(→参考) |
(→参考) |
||
(未显示1个用户的50个中间版本) | |||
第1行: | 第1行: | ||
+ | |||
+ | |||
== 概述 == | == 概述 == | ||
− | + | 由 Philips (现 NXP) 于 80 年代开发,是一种很可靠的低速外设总线,广泛应用于 PC 和嵌入式系统:各种 I2C 接口的传感器、OLED 显示屏、SMBus (System Management Bus, )、PMBus (Power Management Bus)、IPMI (Intelligent Platform Management Interface)、DDC (Display Data Channel)、ATCA (Advanced Telecom Computing Architecture)...... | |
− | |||
− | + | 两根线: SDA, SCL,皆拉高 (pull-up),总线空闲时,两线皆为高电平 | |
− | + | * SDA : Serial Data Line, holds Data or address signal | |
+ | * SCL : Serial Clock Line, holds Clock signal | ||
+ | * IO must be open drain (or open collector in TTL) | ||
− | |||
− | + | [[文件:I2C data transfer 640.png]] | |
− | + | ||
− | + | ||
− | + | [[文件:I2c com.png]] | |
− | + | ||
− | + | ||
+ | |||
+ | * 7bit 地址,保留 16 个,可用 112;标准模式 (100 Kbit/s)、低速模式 (10 Kbit/s) | ||
+ | * 10bit 地址;快速模式 (400 Kbit/s)、高速模式 (3.4 Mbit/s) | ||
+ | |||
+ | |||
+ | '''数据传输:''' | ||
+ | |||
+ | * 7bit mode: 发送 7bit 的address (MSB) 及一位的 W(0) / R(1) 后,该 address 的 slave 端会发送一个 Ack (acknowledge) 位,ACK = 0 表设定成功 (Slave 把 SDA 拉到 LOW),开始数据传送 | ||
+ | * 每次传一个字节,每个字节都跟著一个 ACK bit,由 Slave 端发送(把 SDA 拉 LOW),否则 Master 认为字节写失败,发出 STOP 信号或是重新发送 START 信号 | ||
+ | |||
+ | * 在每个 byte 之间 Slave 端可以把 SCL 拉低来强制传输暂停 | ||
+ | * SDA 只能在 SCL 为 LOW 时改变 | ||
+ | * 在 SCL 为 HIGH 时,SDA 必须是 stable 的,除非 Start/Stop condition | ||
+ | |||
+ | |||
+ | '''10bit mode:''' | ||
+ | |||
+ | 用两个 byte 来传送 address。第一个 byte 的前五位需为 “1111 0” 来表示要使用 10-bit addressing | ||
+ | |||
+ | [[文件:I2c-10bit-addr.gif]] | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == 开始位 == | ||
+ | |||
+ | Start Condition | ||
+ | |||
+ | SDA,SCL 皆为高电平时,拉低 SDA | ||
+ | |||
+ | <source lang=cpp> | ||
void i2c_start(void) | void i2c_start(void) | ||
{ | { | ||
SDA = 1; // i2c start bit sequence | SDA = 1; // i2c start bit sequence | ||
− | |||
SCL = 1; | SCL = 1; | ||
− | + | i2c_delay(); | |
+ | |||
SDA = 0; | SDA = 0; | ||
− | + | i2c_delay(); | |
+ | |||
SCL = 0; | SCL = 0; | ||
− | + | i2c_delay(); | |
} | } | ||
+ | </source> | ||
− | void i2c_stop( | + | <br> |
+ | |||
+ | == 结束位 == | ||
+ | |||
+ | Stop Condition | ||
+ | |||
+ | SCL 上升沿后, SDA 从 0 拉到 1 | ||
+ | |||
+ | <source lang=cpp> | ||
+ | void i2c_stop() | ||
{ | { | ||
SDA = 0; // i2c stop bit sequence | SDA = 0; // i2c stop bit sequence | ||
− | + | i2c_delay(); | |
SCL = 1; | SCL = 1; | ||
− | + | i2c_delay(); | |
SDA = 1; | SDA = 1; | ||
− | + | i2c_delay(); | |
} | } | ||
+ | </source> | ||
− | + | <br> | |
+ | |||
+ | == 状态图 == | ||
+ | |||
+ | === 主发从收 === | ||
+ | |||
+ | * 开始位后,发 7 位地址,随后读写位为 0 (Write) | ||
+ | * 收到 slave 反馈的 ACK 位后,开始写字节 | ||
+ | * 每写一个字节,需要收到 slave 反馈的 ACK (SDA = 0) 后才开始下一个字节传输,否则传输中止,抛出出错异常 | ||
+ | * 写完所有字节,则发送 Stop condition,Slave 收到 Stop condition 后,才会中止数据接收。。。 | ||
+ | |||
+ | |||
+ | [[文件:I2c flow chart master tx slave rx.jpg | 950px]] | ||
+ | |||
+ | <br> | ||
+ | |||
+ | === 主收从发 === | ||
+ | |||
+ | * 开始位后,发 7 位地址,随后读写位为 1 (Read) | ||
+ | * 收到 slave 反馈的 ACK 位后,<b>立即</b>开始读取数据 <------ | ||
+ | * 每读一个字节,需要给一个 ACK (SDA = 0),如果是最后一个字节,则需给一个 NACK (SDA = 1) | ||
+ | |||
+ | |||
+ | [[文件:I2c flow chart master rx slave tx.jpg | 950px]] | ||
+ | |||
+ | <br> | ||
+ | |||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == 实例 == | ||
+ | |||
+ | Touch the head, send i2c data (No other device): | ||
+ | |||
+ | * Write 0x00 (no ack) | ||
+ | * Write 0x28 (no ack) 0x44 (no ack) | ||
+ | * Write 0x28 (no ack) 0x44 (no ack) | ||
+ | |||
+ | [[文件:Touch-iKair-head-then-send-data.png]] | ||
+ | |||
+ | <br> | ||
+ | |||
+ | Send i2c data (with pm2.5 sensor): | ||
+ | |||
+ | 0x00 0x12 0x1E 0x03 0x02 0x00 0x00 0x1A | ||
+ | |||
+ | [[文件:Touch-iKair-head-then-send-data2.png]] | ||
+ | |||
+ | |||
+ | 第一个字节 0x00 是目标传感部件环灯广播地址,改为 0x60 就只点亮 PM2.5 的环灯 (i2c addr = 0x30), 0x50 就只点亮甲醛传感部件上的环灯 (i2c addr = 0x28) | ||
+ | |||
+ | <br><br> | ||
+ | |||
+ | == 版本 == | ||
+ | |||
+ | The history of I²C specification releases: | ||
+ | |||
+ | * In 1982, the original 100 kHz I²C system was created as a simple internal bus system for building control electronics with various Philips chips. | ||
+ | * In 1992, Version 1 added 400 kHz Fast-mode (Fm) and a 10-bit addressing mode to increase capacity to 1008 nodes. This was the first standardized version. | ||
+ | * In 1998, Version 2 added 3.4 MHz High-speed mode (Hs) with power-saving requirements for electric voltage and current. | ||
+ | * In 2000, Version 2.1 clarified version 2, without significant functional changes. | ||
+ | * In 2007, Version 3 added 1 MHz Fast-mode plus (Fm+) (using 20 mA drivers), and a device ID mechanism. | ||
+ | * In 2012, Version 4 added 5 MHz Ultra Fast-mode (UFm) for new USDA (data) and USCL (clock) lines using push-pull logic without pull-up resistors, and added an assigned manufacturer ID table. It is only a unidirectional bus. | ||
+ | * In 2012, Version 5 corrected mistakes. | ||
+ | * In 2014, Version 6 corrected two graphs. This is the most recent standard | ||
+ | |||
+ | <br> | ||
+ | |||
+ | == 软件模拟 == | ||
+ | |||
+ | To initialize the ports set the output resisters to 0 and the tristate registers to 1 which disables the outputs and allows them to be pulled high by the resistors. | ||
+ | |||
+ | The following 4 functions provide the primitive start, stop, read and write sequences. All I2C transactions can be built up from these. | ||
+ | |||
+ | <source lang=cpp> | ||
+ | |||
+ | #define I2C_DELAY 4 /* us delay */ | ||
+ | #define I2C_MAXWAIT 5000 | ||
+ | |||
+ | #define TWI_SDA 11 /* PIN14_PD7 */ | ||
+ | #define TWI_SCL 16 /* PIN21_PF2 */ | ||
+ | |||
+ | #define SDA_LOW() digitalWrite(TWI_SDA, LOW) | ||
+ | #define SDA_HIGH() digitalWrite(TWI_SDA, HIGH) | ||
+ | #define SCL_LOW() digitalWrite(TWI_SCL, LOW) | ||
+ | #define SCL_HIGH() digitalWrite(TWI_SCL, HIGH) | ||
+ | |||
+ | #define SDA_READ() digitalRead(TWI_SDA) | ||
+ | #define SCL_READ() digitalRead(TWI_SCL) | ||
+ | |||
+ | #define i2c_delay() delayMicroseconds(4) | ||
+ | |||
+ | void i2c_start(void) | ||
{ | { | ||
− | + | SDA_HIGH(); // i2c start bit sequence | |
− | + | i2c_delay(); | |
− | + | ||
− | + | SCL_HIGH(); | |
− | + | i2c_delay(); | |
− | + | ||
− | + | SDA_LOW(); | |
− | + | i2c_delay(); | |
− | + | ||
− | + | SCL_LOW(); | |
− | + | i2c_delay(); | |
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
− | + | ||
} | } | ||
− | + | void i2c_stop(void) | |
{ | { | ||
− | + | SDA_LOW(); // i2c stop bit sequence | |
− | + | i2c_delay(); | |
− | + | ||
− | + | SCL_HIGH(); | |
− | + | i2c_delay(); | |
− | + | ||
− | + | SDA_HIGH(); | |
− | + | i2c_delay(); | |
− | + | } | |
− | + | ||
− | + | uint8_t i2c_rx(uint8_t ack) | |
− | + | { | |
− | + | uint8_t x, d = 0; | |
− | + | ||
− | + | SDA_HIGH(); | |
+ | |||
+ | for (x = 0; x < 8; x++) { | ||
+ | |||
+ | d <<= 1; | ||
+ | |||
+ | do { | ||
+ | SCL_HIGH(); | ||
+ | } while (SCL_IN == 0); // wait for any SCL clock stretching | ||
+ | |||
+ | i2c_delay(); | ||
+ | |||
+ | if (SDA_READ()) | ||
+ | d |= 1; | ||
+ | SCL_LOW(); | ||
+ | } | ||
+ | |||
+ | if (ack) | ||
+ | SDA_LOW(); | ||
+ | else | ||
+ | SDA_HIGH(); | ||
+ | |||
+ | SCL_HIGH(); | ||
+ | i2c_delay(); // send (N)ACK bit | ||
+ | SCL_LOW(); | ||
+ | SDA_HIGH(); | ||
+ | |||
+ | return d; | ||
+ | } | ||
+ | |||
+ | uint8_t i2c_tx(unsigned uint8_t d) | ||
+ | { | ||
+ | uint8_t x; | ||
+ | static uint8_t b; | ||
+ | |||
+ | for (x = 8; x; x--) { | ||
+ | if (d & 0x80) | ||
+ | SDA_HIGH(); | ||
+ | else | ||
+ | SDA_LOW(); | ||
+ | SCL_HIGH(); | ||
+ | d <<= 1; | ||
+ | SCL_LOW(); | ||
+ | } | ||
+ | |||
+ | SDA_HIGH(); | ||
+ | SCL_HIGH(); | ||
+ | |||
+ | i2c_delay(); | ||
+ | |||
+ | b = SDA_READ(); // possible ACK bit | ||
+ | |||
+ | SCL_LOW(); | ||
+ | return b; | ||
} | } | ||
</source> | </source> | ||
第114行: | 第291行: | ||
<br><br> | <br><br> | ||
− | == | + | == 传输距离 == |
+ | I2C 的总线长度,只要硬件参数合适,可以做到 5~8 米,如何延长 I2C 通信线缆长度,以下几条经验可以参考: | ||
+ | (1)实验测试中,我们发现,在通信正常的情况下,I2C 总线的上拉电阻与线缆长度是有比例关系的: | ||
− | + | 通信线缆越长,上拉电阻要越小。而通信线缆越短,上拉电阻要越大。比如: | |
+ | |||
+ | ① 通信线缆小于 0.2 米,一般可以采用 10K 的上拉电阻,这个也是很多I2C芯片的说明书中推荐的上拉电阻。 | ||
+ | |||
+ | ② 通信线缆在 0.2 到 2 米之间,一般可以采用 4.7K 上拉电阻。 | ||
+ | |||
+ | ③ 通信线缆在 2 米以上,一般可以采用 1~2.2K 上拉电阻。 | ||
+ | |||
+ | 上拉电阻的范围一般在 1K~10k 之间,之所以有这个范围,可以简单的认为,电阻过小,功耗比较大,而且容易烧毁 I2C 接口,而电阻过大,会影响 信号的上升沿时间,也就是影响到了 时钟频率,会出现误码。 | ||
+ | |||
+ | (2)远距离通信时,尽量使用 屏蔽 线缆,这个确实是有用的,能够很好的抗干扰。 | ||
+ | |||
+ | (3)如果不考虑成本,可以采用 I2C 总线中继芯片,如 P82B715、P82B96 等,这些中继芯片的基本原理是,将 I2C 总线接口转为差分信号,所以主机和从机之间,需要一对芯片,这样主机和从机之间是差分信号传输,也就克服了 I2C 总线的线缆长度限制了。一对芯片约 30元。 | ||
+ | |||
+ | (4)通信速率,在各种通信中,有一个共同的规律,通信速率与误码率成正比,通信速率越低,误码率也越低,所以我们在与 I2C 设备通信的时候,尤其是距离比较远的,可以考虑降低通信速率。 | ||
+ | |||
+ | <br> | ||
== 参考 == | == 参考 == | ||
第128行: | 第323行: | ||
* http://wiki.csie.ncku.edu.tw/embedded/I2C | * http://wiki.csie.ncku.edu.tw/embedded/I2C | ||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
− | |||
<br><br> | <br><br> | ||
<br><br> | <br><br> |
2020年6月24日 (三) 15:01的最后版本
目录 |
[编辑] 1 概述
由 Philips (现 NXP) 于 80 年代开发,是一种很可靠的低速外设总线,广泛应用于 PC 和嵌入式系统:各种 I2C 接口的传感器、OLED 显示屏、SMBus (System Management Bus, )、PMBus (Power Management Bus)、IPMI (Intelligent Platform Management Interface)、DDC (Display Data Channel)、ATCA (Advanced Telecom Computing Architecture)......
两根线: SDA, SCL,皆拉高 (pull-up),总线空闲时,两线皆为高电平
- SDA : Serial Data Line, holds Data or address signal
- SCL : Serial Clock Line, holds Clock signal
- IO must be open drain (or open collector in TTL)
- 7bit 地址,保留 16 个,可用 112;标准模式 (100 Kbit/s)、低速模式 (10 Kbit/s)
- 10bit 地址;快速模式 (400 Kbit/s)、高速模式 (3.4 Mbit/s)
数据传输:
- 7bit mode: 发送 7bit 的address (MSB) 及一位的 W(0) / R(1) 后,该 address 的 slave 端会发送一个 Ack (acknowledge) 位,ACK = 0 表设定成功 (Slave 把 SDA 拉到 LOW),开始数据传送
- 每次传一个字节,每个字节都跟著一个 ACK bit,由 Slave 端发送(把 SDA 拉 LOW),否则 Master 认为字节写失败,发出 STOP 信号或是重新发送 START 信号
- 在每个 byte 之间 Slave 端可以把 SCL 拉低来强制传输暂停
- SDA 只能在 SCL 为 LOW 时改变
- 在 SCL 为 HIGH 时,SDA 必须是 stable 的,除非 Start/Stop condition
10bit mode:
用两个 byte 来传送 address。第一个 byte 的前五位需为 “1111 0” 来表示要使用 10-bit addressing
[编辑] 2 开始位
Start Condition
SDA,SCL 皆为高电平时,拉低 SDA
void i2c_start(void) { SDA = 1; // i2c start bit sequence SCL = 1; i2c_delay(); SDA = 0; i2c_delay(); SCL = 0; i2c_delay(); }
[编辑] 3 结束位
Stop Condition
SCL 上升沿后, SDA 从 0 拉到 1
void i2c_stop() { SDA = 0; // i2c stop bit sequence i2c_delay(); SCL = 1; i2c_delay(); SDA = 1; i2c_delay(); }
[编辑] 4 状态图
[编辑] 4.1 主发从收
- 开始位后,发 7 位地址,随后读写位为 0 (Write)
- 收到 slave 反馈的 ACK 位后,开始写字节
- 每写一个字节,需要收到 slave 反馈的 ACK (SDA = 0) 后才开始下一个字节传输,否则传输中止,抛出出错异常
- 写完所有字节,则发送 Stop condition,Slave 收到 Stop condition 后,才会中止数据接收。。。
[编辑] 4.2 主收从发
- 开始位后,发 7 位地址,随后读写位为 1 (Read)
- 收到 slave 反馈的 ACK 位后,立即开始读取数据 <------
- 每读一个字节,需要给一个 ACK (SDA = 0),如果是最后一个字节,则需给一个 NACK (SDA = 1)
[编辑] 5 实例
Touch the head, send i2c data (No other device):
- Write 0x00 (no ack)
- Write 0x28 (no ack) 0x44 (no ack)
- Write 0x28 (no ack) 0x44 (no ack)
Send i2c data (with pm2.5 sensor):
0x00 0x12 0x1E 0x03 0x02 0x00 0x00 0x1A
第一个字节 0x00 是目标传感部件环灯广播地址,改为 0x60 就只点亮 PM2.5 的环灯 (i2c addr = 0x30), 0x50 就只点亮甲醛传感部件上的环灯 (i2c addr = 0x28)
[编辑] 6 版本
The history of I²C specification releases:
- In 1982, the original 100 kHz I²C system was created as a simple internal bus system for building control electronics with various Philips chips.
- In 1992, Version 1 added 400 kHz Fast-mode (Fm) and a 10-bit addressing mode to increase capacity to 1008 nodes. This was the first standardized version.
- In 1998, Version 2 added 3.4 MHz High-speed mode (Hs) with power-saving requirements for electric voltage and current.
- In 2000, Version 2.1 clarified version 2, without significant functional changes.
- In 2007, Version 3 added 1 MHz Fast-mode plus (Fm+) (using 20 mA drivers), and a device ID mechanism.
- In 2012, Version 4 added 5 MHz Ultra Fast-mode (UFm) for new USDA (data) and USCL (clock) lines using push-pull logic without pull-up resistors, and added an assigned manufacturer ID table. It is only a unidirectional bus.
- In 2012, Version 5 corrected mistakes.
- In 2014, Version 6 corrected two graphs. This is the most recent standard
[编辑] 7 软件模拟
To initialize the ports set the output resisters to 0 and the tristate registers to 1 which disables the outputs and allows them to be pulled high by the resistors.
The following 4 functions provide the primitive start, stop, read and write sequences. All I2C transactions can be built up from these.
#define I2C_DELAY 4 /* us delay */ #define I2C_MAXWAIT 5000 #define TWI_SDA 11 /* PIN14_PD7 */ #define TWI_SCL 16 /* PIN21_PF2 */ #define SDA_LOW() digitalWrite(TWI_SDA, LOW) #define SDA_HIGH() digitalWrite(TWI_SDA, HIGH) #define SCL_LOW() digitalWrite(TWI_SCL, LOW) #define SCL_HIGH() digitalWrite(TWI_SCL, HIGH) #define SDA_READ() digitalRead(TWI_SDA) #define SCL_READ() digitalRead(TWI_SCL) #define i2c_delay() delayMicroseconds(4) void i2c_start(void) { SDA_HIGH(); // i2c start bit sequence i2c_delay(); SCL_HIGH(); i2c_delay(); SDA_LOW(); i2c_delay(); SCL_LOW(); i2c_delay(); } void i2c_stop(void) { SDA_LOW(); // i2c stop bit sequence i2c_delay(); SCL_HIGH(); i2c_delay(); SDA_HIGH(); i2c_delay(); } uint8_t i2c_rx(uint8_t ack) { uint8_t x, d = 0; SDA_HIGH(); for (x = 0; x < 8; x++) { d <<= 1; do { SCL_HIGH(); } while (SCL_IN == 0); // wait for any SCL clock stretching i2c_delay(); if (SDA_READ()) d |= 1; SCL_LOW(); } if (ack) SDA_LOW(); else SDA_HIGH(); SCL_HIGH(); i2c_delay(); // send (N)ACK bit SCL_LOW(); SDA_HIGH(); return d; } uint8_t i2c_tx(unsigned uint8_t d) { uint8_t x; static uint8_t b; for (x = 8; x; x--) { if (d & 0x80) SDA_HIGH(); else SDA_LOW(); SCL_HIGH(); d <<= 1; SCL_LOW(); } SDA_HIGH(); SCL_HIGH(); i2c_delay(); b = SDA_READ(); // possible ACK bit SCL_LOW(); return b; }
- 使用示例:
The 4 primitive functions above can easily be put together to form complete I2C transactions. Here's and example to start an SRF08 ranging in cm:
i2c_start(); // send start sequence i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear i2c_tx(0x00); // SRF08 command register address i2c_tx(0x51); // command to start ranging in cm i2c_stop(); // send stop sequence
Now after waiting 65mS for the ranging to complete (I've left that to you) the following example shows how to read the light sensor value from register 1 and the range result from registers 2 & 3.
i2c_start(); // send start sequence i2c_tx(0xE0); // SRF08 I2C address with R/W bit clear i2c_tx(0x01); // SRF08 light sensor register address i2c_start(); // send a restart sequence i2c_tx(0xE1); // SRF08 I2C address with R/W bit set lightsensor = i2c_rx(1); // get light sensor and send acknowledge. Internal register address will increment automatically. rangehigh = i2c_rx(1); // get the high byte of the range and send acknowledge. rangelow = i2c_rx(0); // get low byte of the range - note we don't acknowledge the last byte. i2c_stop(); // send stop sequence
[编辑] 8 传输距离
I2C 的总线长度,只要硬件参数合适,可以做到 5~8 米,如何延长 I2C 通信线缆长度,以下几条经验可以参考:
(1)实验测试中,我们发现,在通信正常的情况下,I2C 总线的上拉电阻与线缆长度是有比例关系的:
通信线缆越长,上拉电阻要越小。而通信线缆越短,上拉电阻要越大。比如:
① 通信线缆小于 0.2 米,一般可以采用 10K 的上拉电阻,这个也是很多I2C芯片的说明书中推荐的上拉电阻。
② 通信线缆在 0.2 到 2 米之间,一般可以采用 4.7K 上拉电阻。
③ 通信线缆在 2 米以上,一般可以采用 1~2.2K 上拉电阻。
上拉电阻的范围一般在 1K~10k 之间,之所以有这个范围,可以简单的认为,电阻过小,功耗比较大,而且容易烧毁 I2C 接口,而电阻过大,会影响 信号的上升沿时间,也就是影响到了 时钟频率,会出现误码。
(2)远距离通信时,尽量使用 屏蔽 线缆,这个确实是有用的,能够很好的抗干扰。
(3)如果不考虑成本,可以采用 I2C 总线中继芯片,如 P82B715、P82B96 等,这些中继芯片的基本原理是,将 I2C 总线接口转为差分信号,所以主机和从机之间,需要一对芯片,这样主机和从机之间是差分信号传输,也就克服了 I2C 总线的线缆长度限制了。一对芯片约 30元。
(4)通信速率,在各种通信中,有一个共同的规律,通信速率与误码率成正比,通信速率越低,误码率也越低,所以我们在与 I2C 设备通信的时候,尤其是距离比较远的,可以考虑降低通信速率。
[编辑] 9 参考
- I2C-bus specification and user manual
- https://en.wikipedia.org/wiki/I%C2%B2C
- http://www.robot-electronics.co.uk/i2c-tutorial
- https://learn.sparkfun.com/tutorials/i2c
- http://wiki.csie.ncku.edu.tw/embedded/I2C