文章目录
串口通信回顾
在前面我们已经了解UART串口通信了,它是一种简单易用的通信方式。
但在嵌入式编程中光学习一个串口通信,显然无法满足我们的需求,现在我们再来回顾一下串口通信的特点,分析一下串口通信的局限性。
串口通信的特点
串口(USART)通信是一种点对点的、全双工的、异步串行通信方式,它只需要两根线(Tx 和 Rx)就可以实现数据的发送和接收。
在通信过程中,发送方和接收方需要事先约定好相同的波特率,以此来保证数据能够被正确解析。
除此之外,串口通信还需要约定数据帧格式,比如起始位、数据位以及停止位等。
由于串口通信结构简单、实现成本低,因此在 PC 与单片机通信、传感器数据采集、蓝牙 / Wi-Fi 模块通信 等场景中被广泛使用。
串口通信的局限性
在串口通信中,通信双方通常是一对一、点对点的关系。
虽然在实践中,确实也可以通过增加多组 TX / RX 引脚,勉强实现一对多通信,但这种方式存在明显的问题:
- 硬件接线会很复杂,复杂性高,可维护性差。
- 单片机的引脚资源有限,这导致可连接的串口设备数量受限。
- 以我们使用的STM32F103C8T6单片机为例
- 该款单片机一共有三个USART外设,分别是:USART1、USART2以及USART3
- 实际可用的Tx和Rx引脚只有四对,其中有两对都属于USART1外设
- 所以,即便不考虑引脚使用过多、接线复杂、软件实现繁琐等问题,使用串口通信在多设备通信数量上,也存在显著瓶颈。
- 串口通用无法真正做到一对多通信。在同一时刻,一个串口只能做到与一台设备进行通信。
在嵌入式系统中,一对多通信的需求并不少见。
尤其是在资源紧张、引脚数量有限的情况下,实现一对多通信是嵌入式开发者必然面临的场景。
为了解决这个问题,我们需要学习一种新的通信方式,也就是I2C通信。
I2C通信 VS 串口通信
虽然我们还没有学习I2C通信,但不妨碍我们先来比较一下I2C通信和串口通信的差异,大家权当先了解一下。
待到学完I2C通信后,相信大家会对下列表格的内容有更加深入的理解。
| 特性 | USART(串口通信) | I2C(I²C通信) |
|---|---|---|
| 连接方式 | 点对点 | 多设备总线连接 |
| 所需引脚 | 每一台设备都需要 2 个引脚(TX、RX) | 即便连接多台设备,也仅需 2 个引脚(SCL、SDA) |
| 可连接设备数量 | 受 USART 引脚数量限制(通常 2~3 个) | 理论支持多达 100+个设备 |
| 通信模式 | 一对一(点对点) | 一对多(支持主从模式) |
| 数据传输方式 | 异步串行传输 | 同步串行传输 |
| 数据传输速率 | 波特率9600 - 115200 bps | 标准模式 100 Kbps,高速模式 400 Kbps |
| 设备寻址 | 无设备寻址,发送端和接收端点对点通信 | 支持设备寻址(7-bit 或 10-bit 地址) |
| 全双工/半双工 | 全双工(可以同时发送和接收数据) | 半双工(同一时刻通信时只能单向传输) |
| 适用场景 | 单片机与PC调试通信、GPS、蓝牙Wi-Fi通信 | 传感器网络、EEPROM 存储、嵌入式设备之间通信 |
串口通信虽然简单易用,但由于 需要独立的 TX/RX 线、端口数量受限、缺乏寻址能力,在多设备通信场景下并不适用。
因此,在嵌入式开发中,我们更倾向于使用 I2C 或者其它通信方式来进行一对多的通信。
I2C 仅需 两根信号线(SCL 和 SDA),即可实现一对多个设备的通信,同时实现简单易用性强、灵活和扩展性也非常不错。
总的来讲,I2C是嵌入式环境下,多设备通信中的性价比之选
下面我们正式开始学习I2C通信!
I2C是什么?
按照老规矩,我们在学习一个新的技术模块时,还是先来了解一下与这个技术模块相关的一些概念。
比如一个很简单的问题:I2C是什么东西?
I2C通信最早由飞利浦(现恩智浦半导体)公司,在1982年左右开发提出。
I2C是英文词组Inter-Integrated Circuit的缩写,更准确的缩写是"I2C",其中的2表示"I"字母的平方,即两个I。
在中文语境下,不要把它读成"I 二 C",而是要读成"I 方 C",其中方表示平方的意思。
如何理解Inter-Integrated Circuit这个词组呢?
- Inter-:意为 "相互、互相",表示设备之间的交互通信。
- Integrated Circuit(IC):指 "集成电路",也就是各种芯片。
所以I2C通信就可以理解成:集成电路间的通信、芯片之间的通信。
I2C 正是为了解决 不同芯片、不同集成电路之间进行数据通信 这一需求而设计的一种通信协议。
直到今天,I2C 依然是嵌入式系统中最常见的通信协议之一。
I2C通信被广泛应用于 单片机与各类外设芯片(如OLED、传感器、EEPROM 等)之间的通信。
- I2C通信是芯片之间的通信,通信双方芯片按照各自的程序,基于I2C通信协议完成通信
- 不要把I2C通信理解成谁控制谁,双方都是芯片,都有烧录好的程序,双方基于同样的I2C通信协议
- 只要双方在约定好的时间,做约定好的事情,通信就完成
- 对于我们而言,单片机有我们控制,单片机的I2C通信程序也由程序员完成
- 而与单片机进行I2C通信的设备,它有烧录好的I2C通信程序,我们不需要关心它的程序实现
总线
经过上面的描述,再加上对串口通信的了解,你一定已经对 I2C 有了一个基本认识:
I2C 是一种引脚资源占用少,但却能够实现多台设备通信的通信方式。
那么问题就来了:
多台设备,是如何在只使用极少引脚的情况下,实现通信的呢?
最起码的,接线是如何接的呢?
要回答这个问题,就不得不先引入一个非常重要的概念------总线。
什么是总线呢?
其实前面讲单片机系统架构时,也提过这个概念。
总线(Bus)是计算机系统中,多个设备之间共享的,数据传输通道。
通过总线结构:
- 多台设备不再需要一对一单独连线实现通信,而是统一将自身"挂在"总线上。这样就大幅度减少了引脚数量的使用,降低了接线复杂度。
- 相同总线上连接的设备,可以共用同一套通信协议进行通信,进一步降低了系统的复杂性。
结合上面的描述,通俗一点,可以把总线理解成"高速公路":
一条公共道路,多辆车都能上路,拥有统一的交通规则,这样大家都能顺利抵达目的地。
I2C总线
I2C通信,正是一种典型的总线式通信手段,所以很多地方也会直接把I2C通信,叫做I2C总线。
I2C通信对引脚资源的占用很少,使用的接线也很少,只需要两条信号线就可以了。这是I2C通信的优势!
在I2C通信中:
- 所有设备,都将自身挂载在同一条I2C总线上。
- I2C总线,仅包含两条线,即SDA总线与SCL总线。
- 通信设备自身,也仅占用两个引脚,即SDA引脚和SCL引脚。
其总线结构,如下图所示:

这两条总线分别是:
- SCL,Serial Clock Line,串行时钟信号线:I2C是同步串行通信方式,由SCL时钟信号线控制产生统一的时钟信号。
- SDA,Serial Data Line,串行数据传输线:用于双向传输数据,总线上所有设备的数据通信,都通过这一条数据总线完成。
关于这两条总线的详细作用以及工作原理,这些内容比较复杂,且都涉及I2C通信协议,我们留到后续小节再讲。
现在,仅看I2C总线结构,以及这两条总线的大体作用,你能得出什么结论呢?
这里,希望大家能够记住以下结论:
- I2C仍然是一种串行通信,I2C总线就是"串行总线"。
- 数据以 bit 为单位进行传输,通信时是 1 bit、1 bit 地依次传输。
- 数字电平含义与串口通信一致:高电平代表1,低电平代表0。
- 这种总线设计使得,即便单片机需要与多台设备通信,也仅需要占用两个引脚,大大减少了通信引脚资源的占用。
- 这种总线设计使得,即便单片机需要与多台设备通信,其余设备也只需要将自身挂在总线上,大大降低电路设计复杂性。
- 通信双方,只能通过一条SDA总线进行传输数据,显然,I2C肯定不是一种全双工通信协议。
- I2C是典型的半双工通信协议,在同一时刻,I2C通信中,数据都只能单向传输。
- 比如单片机给设备1发数据时,设备1就只能接收,而不能发送。
- 当然数据通信是双向的,在下一个时刻,设备1可以给单片机发数据,单片机此时只能接收。
- 半双工,意味着数据不能同时双向传输,但仍然支持双向数据传输。
至此,我们已经对 I2C 的总线式通信结构有了一个整体认识。
那么就会产生这样的疑问:
总线式设计将所有的设备,都挂载在总线上。
这么多设备都在总线上,如果随便发数据,随意互相通信,势必乱了套。
所以,I2C通信中,通信的过程是怎么控制的呢?由谁来控制呢?
为了回答这个问题,我们就需要了解I2C通信中,最重要的、最核心的概念------主从模式。
主从模式(重点!)
在I2C通信中,最核心且最重要的特点就是:主从模式。
通过 I2C 总线连接的多台设备,具有 "主-从"(Master-Slave) 关系。
整个I2C总线上的设备,可以分为两大类:
- 主机(Master):负责控制时钟信号总线(SCL),生成时钟信号,控制通信时序,掌控整个通信的过程。
- 从机(Slave):响应主设备的请求,执行数据发送或接收,本身不参与任何通信过程的控制。
严格来说,I2C 通信协议支持的主从模式是:一主多从,并且支持主设备切换。
在学习阶段,为了便于理解和实现,在后续我们固定把单片机作为主机,其它通过 I2C 总线与单片机相连的设备,一律视为从机。
在实际工程应用中,为了避免多设备竞争总线控制权而引发冲突,主设备切换这一功能也并不常用。
绝大多数实际场景中,I2C都是采用固定主机,一主多从式的通信方式。
该如何理解主从模式呢?
其实上面已经写得非常清楚了------I2C通信过程中,任何通信的操作都是由主机发起并控制的。
比如:
- 主机可以主动将数据发给从机,从机被动接收数据。
- 这种操作,称之为**"I2C的写模式**"。
- 站在主机的视角,将数据输出传递,这就是写!
- 从机不可以主动擅自将数据发给主机!
- 从机只能在主机的要求下,被动地将数据发给主机。
- 这种操作,称之为"I2C的读模式"。
- 站在主机的视角,从机输入数据,这就是读。
或者我们举一个通俗的例子:
所谓主从模式,就是皇帝和太监。
皇上想做什么,就跟太监说,太监必须配合去做。
太监想做什么,那是不可能的,太监不能主动做事情。必须是皇上让他做,他才可以做。
总之:
在I2C通信中,任何数据交互都必须由主机发起,任何通信过程都由主机控制,从机只能被动配合!这是I2C通信协议最重要且最核心的概念!!
主从模式容易产生的误解
在理解了 I2C 的主从通信模式之后,有些同学可能会产生这样一种疑惑与误解:
既然主机完全控制通信过程,那么是不是意味着:
如果没有主机的控制,从机就什么也做不了?什么都不会做?
主机完全控制从机,如果没有主机控制,从机啥也做不了,啥也不会干。
是不是这样呢?
这显然是一种误解,主机虽然有"控制欲",但肯定不会这么强。
从机需要配合主机完成通信,基于I2C通信协议,在这个过程中,从机有自身应当完成的工作,不是所有事情都由主机控制。
当然主机完全控制从机,这种事情也不可能做得到。
还是举例皇帝和太监。
皇上饿了,跟太监说"我饿了,弄点吃的来。"
太监于是去准备吃的,并且端过来。
这个过程,太监必然具有一定主观能动性,根据自身对皇帝喜好的了解,准备一些吃的,端上来。
但这个过程肯定不会是:"我饿了,你去菜园子搞点西红柿,再去鸡窝里捡几颗鸡蛋,然后把西红柿洗好了,切好了,先炒好鸡蛋..."
总之:
在I2C通信的过程中,主机具有绝对控制权,但主机只负责控制通信的重要节点,比如通信的开始,结束等。
从机需要按照通信协议,自主完成一些工作,比如数据接收和发送。
实际上,I2C本身就是两颗芯片之间的通信。
既然双方都是芯片,那么芯片内部必然都存储了符合I2C通信协议的程序。
作为单片机开发者,我们负责开发单片机的内部程序,而与单片机通信的从机设备,它们芯片上的程序已经在生产制造时烧录完成了。
只要你编写的,单片机上的程序,完全符合I2C通信协议,那么通信就会成功实现。
从机地址
I²C 通信是一种 "一对多" 的主从式通信方式。
在一条 I2C 总线上,主机可以连接多个从机设备。那么主机如何在多个从机中,找到目标从机设备呢?
这时就需要了解一个"从机地址"的概念。
在 I²C 通信中,从机地址(Slave Address) 是 主机 用来选择通信对象的唯一标识。
整条I2C总线上挂载的多台从机设备,每一台都需要拥有一个唯一的从机地址。
主机在控制通信开始时,会在总线上发送目标从机地址,只有匹配该地址的从机才会响应,从而建立通信关系。
在I2C通信中,这个过程被指为"寻址"。寻址对于I2C的任何通信过程而言,总是第一步需要完成的行为。
从机地址的确定
如何确定一台从机的从机地址呢?
首先从机地址,从格式上来说,通常就是一个7位的二进制数。
而具体到设备,大多数I2C从机设备,其从机地址在设备生产制造时就已经设定好了。
所以,获取从机地址,最准确的做法是:查阅厂商提供的官方数据手册
除此之外,还可以:
- 咨询设备的销售商。
- 向有经验的同学 / 同事 / 工程师请教。
- 借助 AI 工具,根据设备型号查询相关资料
当然无论你从什么渠道获取了从机地址,最终都需要验证一下再相信。
从机数量的限制
在上面的表格中,我们提到:I2C通信,理论支持的最大设备数量是100+。
这个数据并不是胡编乱造的,而是根据从机地址计算得出。
既然 I2C 从机地址是一个 7 位的二进制数,那么理论上可表示的从机地址数量就是:27 = 128
I2C 通信协议中自保留了一部分特殊地址,不能分配给普通从设备,例如:
- 0000 000(7位0):通用呼叫地址,广播地址,即主机广播式的向每一台从机发数据。
- 1 1 1 1 1 1 1(7位1):无特殊含义用途,但协议自保留,从机不能使用
- ...等等
因此,在实际 I2C 系统中,可用的从机地址数量并不是 128,而是大约 100+ 个。
当然这个数量已经非常多了,在绝大多数嵌入式场景中,已经非常够用了。
从机地址冲突的问题
从机设备那么多,生产的厂商也很多,不可能都事先商量好。
如果两家生产的从机设备,出现了从机地址冲突,该怎么办?
这个问题非常好,有时候确实也会碰到。
而且这还涉及到一个非常重要的问题:
如果I2C总线上,挂载着两台相同从机地址的从设备,会出现什么情况呢?
答:
- I2C 总线上,不能同时存在两台地址完全相同的从机。
- 一旦寻址出现了多从机响应,后续通信一定会失败!
- 任何一个时刻,主机都只能与一台从机设备,进行正常的双向数据通信。
原因也很简单,I2C通信过程中,主机发送从机接收,从机发送主机接收。这个数据通信是双向,可切换的,只是不允许同时发生。
一旦通信过程允许超过1台从机参与,那么多台从机就会争抢同一条总线的使用权,就会出现总线冲突问题。
I2C通信是无法解决这种问题的,这在物理线路上就不可能实现。
所以切记,I2C通信,同一条总线上只允许挂载从机地址不同的,多台从机设备。
从机地址的出厂特殊设计
为了避免从机地址冲突,设备的生产厂商在设置从机地址时,都会进行一些特殊的设计。
大多数厂商生产的从机设备,其从机地址都不是绝对固定的7位二进制数。
最常见的情况是:7位从机地址的高几位固定不变,但低几位设置为可配置。
举一个例子:
厂商生产了一种支持I2C通信的从机设备A,其从机地址的高6位固定为:011 110
而最低的1位可以在使用时,自由配置:可以配置为0,也可以配置为1。
那么,该设备在实际使用时,就可以切换两种不同的从机地址:
- 011 1100
- 011 1101
这种设计就增强了从机地址的灵活性,降低了从机地址冲突的可能性。
除此之外,这种设计还有一个明显的好处:
如果我想在嵌入式系统中,接入两台A设备作为从机,可以实现吗?
答:当然是可以实现的。只需要在接入总线时,将A1设备的从机地址设置为011 1100,A2设备的从机地址设置为011 1101。
当然,如果你还是想问,两台从机地址一样的设备,就真的没有办法接入同一条I2C总线了吗?
答:确实是这样,这是 I2C 通信本身的局限性,或者说特性。
扩展:关于广播模式
部分同学在了解了从机地址冲突的问题之后,可能还会产生这样一个新的疑问:
I2C通信不是支持广播模式吗?
广播模式下,不就是一台主机与多台从机,同时进行通信吗?
这又是什么情况呢?
其实这个问题回答起来非常简单。
首先,我们要知道,I2C之所以不允许多台从机参与通信:
是因为在一般通信情况下,多台从机如果同时向主机发数据,会产生总线竞争,出现无法解决的冲突问题。
而广播模式,显然是没有这种烦恼的!
大家上中学的时候,教室里都有广播大喇叭。
这个大喇叭就是主机,所有学生都是从机。
这个过程中,大喇叭发声,学生只需要听着就行。
学生需要回复大喇叭吗?大喇叭关心学生的回复吗?
显然是不需要的。
在I2C的广播模式下,虽然允许多台从机同时参与通信。但这些从机只负责接收主机数据,而不会向主机发送数据。
这些从机不需要竞争总线,不会产生冲突,自然就没有问题了