以下内容来源于抖音,作者工科男孙老师,读者根据文章内容以及相应论文添加自己的理解进行注释。
在一个单片机里面,总是有各种各样的外设,比如SD卡,加速度传感器,屏幕,GPS,温湿度传感器等等
单片机需要和他们通信,或者给他们写入数据
有的时候还需要和另一个单片机,或者电脑进行通信
常见的就有UART,I2C,SPI和RS232
UART(串口通信)
初始化之后:
物理层就是两根线,一根发送一根接收,双方约定好传输的速度
两根线是独立的,可以同时发送数据给对方
缺点
针对这些缺点,就衍生出来其他的通信机制
3.20补
以下内容来源于CSDN,作者小麦大叔,读者根据文章内容以及相应论文添加自己的理解进行注释。
UART没有时钟信号,无法控制何时发送数据,也无法保证双发按照完全相同的速度接收数据。
如果要解决这个问题,UART为每个字节添加额外的起始位和停止位,以帮助接收器在数据到达时进行同步;双方还必须事先就传输速度达成共识(设置相同的波特率,例如每秒9600位)
异步串行工作得很好,但是在每个字节发送的时候都需要额外的起始位和停止位以及在发送和接收数据所需的复杂硬件方面都有很多开销。
不难发现,如果接收端和发送端设置的速度都不一致,那么接收到的数据将是垃圾(乱码)。
RS232(不能远距离传输信号):
一般是在同一块电路板上的两个芯片
或者是两块距离很近的电路板之间
否则的话信号很容易受到干扰
那这就延伸出RS232和RS485,RS232最大通信距离可到30米左右,而RS485最大通信距离可到1000米
同时485还增加了一对多的功能
SPI(通信速度慢)
因为早期单片机频率比较低,时钟精度的问题,所以双方的精度不可能做到完全一致
那么最好的解决方法就是加入一个clock信号,双方不用约定传输速度
发送方在发送数据时,只需要同时给一个clock上升沿
像是sd卡,屏幕这种外设一般都会使用SPI接口
3.20补
以下内容来源于CSDN,作者小麦大叔,读者根据文章内容以及相应论文添加自己的理解进行注释。
SPI
是一个同步的数据总线,也就是说它是用单独的数据线和一个单独的时钟信号来保证发送端和接收端的完美同步。
时钟是一个振荡信号,它告诉接收端在确切的时机对数据线上的信号进行采样。
产生时钟的一侧称为主机,另一侧称为从机。总是只有一个主机(一般来说可以是微控制器/MCU),但是可以有多个从机(后面详细介绍);
数据的采集时机可能是时钟信号的上升沿(从低到高)或下降沿(从高到低)。具体要看对SPI的配置;
注意,SPI是“全双工”(具有单独的发送和接收线路),因此可以在同一时间发送和接收数据,另外SPI的接收硬件可以是一个简单的移位寄存器。这比异步串行通信所需的完整UART要简单得多,并且更加便宜;
数据在传输中,高位在先还是低位在先,SPI协议并无明确规定,但是数据要在主从机中正确传输,自然双方要先约定好,一般会采用高位在先(MSB)方式传输。
SPI特性
SPI总线包括4条逻辑线,定义如下:
MISO:
Master input slave output
主机输入,从机输出(数据来自从机);MOSI:
Master output slave input
主机输出,从机输入(数据来自主机);SCLK :
Serial Clock
串行时钟信号,由主机产生发送给从机;SS:
Slave Select
片选信号,由主机发送,以控制与哪个从机通信,通常是低电平有效信号。
其他制造商可能会遵循其他命名规则,但是最终他们指的相同的含义。以下是一些常用术语;
MISO也可以是
SIMO
,DOUT
,DO
,SDO
或SO
(在主机端);MOSI也可以是
SOMI
,DIN
,DI
,SDI
或SI
(在主机端);NSS也可以是
CE
,CS
或SSEL
;SCLK也可以是
SCK
;
本文将按照以下命名进行讲解[MISO, MOSI, SCK,NSS]
时钟极性 CKP/Clock Polarity
除了配置串行时钟速率(频率)外,SPI主设备还需要配置时钟极性。
根据硬件制造商的命名规则不同,时钟极性通常写为CKP或CPOL。时钟极性和相位共同决定读取数据的方式,比如信号上升沿读取数据还是信号下降沿读取数据;
CKP可以配置为1或0。这意味着您可以根据需要将时钟的默认状态(IDLE)设置为高或低。极性反转可以通过简单的逻辑逆变器实现。您必须参考设备的数据手册才能正确设置CKP和CKE。
CKP = 0
:时钟空闲IDLE
为低电平0
;CKP = 1
:时钟空闲IDLE
为高电平1
;
时钟相位 CKE /Clock Phase (Edge)
除配置串行时钟速率和极性外,SPI主设备还应配置时钟相位(或边沿)。根据硬件制造商的不同,时钟相位通常写为CKE或CPHA;
顾名思义,时钟相位/边沿,也就是采集数据时是在时钟信号的具体相位或者边沿;
CKE = 0
:在时钟信号SCK
的第一个跳变沿采样;CKE = 1
:在时钟信号SCK
的第二个跳变沿采样;
时钟配置总结
综上几种情况,下图总结了所有时钟配置组合,并突出显示了实际采样数据的时刻;
其中黑色线为采样数据的时刻;
蓝色线为SCK时钟信号;
具体如下图所示;
模式编号
SPI的时钟极性和相位的配置通常称为 SPI模式,所有可能的模式都遵循以下约定;具体如下表所示;
SPI Mode | CPOL | CPHA |
---|---|---|
0 [00] | 0 | 0 |
1 [01] | 0 | 1 |
2 [10] | 1 | 0 |
3 [11] | 1 | 1 |
除此之外,我们还应该仔细检查微控制器数据手册中包含的模式表,以确保一切正常。
多从机模式
前面说到SPI总线必须有一个主机,可以有多个从机,那么具体连接到SPI总线的方法有以下两种:
第一种方法:多NSS
- 通常,每个从机都需要一条单独的SS线。
- 如果要和特定的从机进行通讯,可以将相应的
NSS
信号线拉低,并保持其他NSS
信号线的状态为高电平;如果同时将两个NSS
信号线拉低,则可能会出现乱码,因为从机可能都试图在同一条MISO
线上传输数据,最终导致接收数据乱码。
具体连接方式如下图所示;
第二种方法:菊花链
在数字通信世界中,在设备信号(总线信号或中断信号)以串行的方式从一 个设备依次传到下一个设备,不断循环直到数据到达目标设备的方式被称为菊花链。
- 菊花链的最大缺点是因为是信号串行传输,所以一旦数据链路中的某设备发生故障的时候,它下面优先级较低的设备就不可能得到服务了;
- 另一方面,距离主机越远的从机,获得服务的优先级越低,所以需要安排好从机的优先级,并且设置总线检测器,如果某个从机超时,则对该从机进行短路,防止单个从机损坏造成整个链路崩溃的情况;
具体的连接如下图所示;
其中红线加粗为数据的流向;
所以最终的数据流向图可以表示为:
SCK为时钟信号,8clks表示8个边沿信号;
其中D为数据,X为无效数据;
所以不难发现,菊花链模式充分使用了SPI其移位寄存器的功能,整个链充当通信移位寄存器,每个从机在下一个时钟周期将输入数据复制到输出。
优缺点
SPI通讯的优势
使SPI作为串行通信接口脱颖而出的原因很多;
- 全双工串行通信;
- 高速数据传输速率。
- 简单的软件配置;
- 极其灵活的数据传输,不限于8位,它可以是任意大小的字;
- 非常简单的硬件结构。从站不需要唯一地址(与I2C不同)。从机使用主机时钟,不需要精密时钟振荡器/晶振(与UART不同)。不需要收发器(与CAN不同)。
SPI的缺点
- 没有硬件从机应答信号(主机可能在不知情的情况下无处发送);
- 通常仅支持一个主设备;
- 需要更多的引脚(与I2C不同);
- 没有定义硬件级别的错误检查协议;
- 与RS-232和CAN总线相比,只能支持非常短的距离;
I2C(不支持一对多)
很浪费资源
所以衍生出来I2C
单片机想要和任意的设备通信时,只需要按照特定的通信协议在总线上
为什么是I2C
如何控制电压
发送端在时钟的高电平发出数据,接收端会在时钟的高电平去取数据
但是如果同时有两个设备需要发送信息,会发生什么呢
我们需要搞清楚芯片是怎么发出高低电平的
在芯片IO口的内部一般会有两颗MOS管,
上面的MOS管导通就输出高电平,下面的MOS管导通就输出低电平
如果我们把两个IO口都挂在一根总线上
那么如果一个芯片输出高电平,一个芯片输出低电平,那么就会直接接地,短路了,后果就是必定会有一个元器件被烧毁
I2C为了解决这个问题,对IO口进行了阉割,去除上面的MOS管
但是这样子只能输出低电平,没办法输出高电平,于是:
加入上拉电阻之后,总线默认就处于高电平的状态
如果想要输出低电平,芯片只需要把MOS管打开,拉低店总线电平就可以
那么两个设备同时要发送信号怎么办?
两个设备都要输出高电平:
两个设备都要输出低电平:
一个输出高电平,一个输出低电平:
虽然说设备A没能得到满足,但是至少没有芯片被损坏,那么A怎么解决,就是软件协议的问题了
上拉电阻的取值
如果太小的话
当MOS拉低电平的时候,可能浪费能量,烧毁电路,而且没办法拉低电平
如果太大的话
每一个设备的IO口对地都会有一些寄生电容,从低电平往高电平转换的过程中,需要通过这颗电阻给电容充电,所以I2C信号上升时会有一个爬坡的过程
电阻越大,给电容充电的速度也就越慢,爬坡的速度也就越慢,严重的话就会导致信号失真
所以一般随着总线的设备增加,也会设当减少上拉电阻的电阻值
稳妥的话,可以用示波器看一下,波形有没有问题
总结
正是因为采用了开漏输出和上拉电阻的模式,I2C信号的抗干扰能力时比较弱的
只适用于同一块电路板上的芯片之间进行通信
并不适合超过30cm电路板之间的通信
I2C通信协议
温度传感器是如何传输数据到单片机,然后输出到串口打印出来呢?
使用一个示波器监测I2C总线的数据线和信号线
会捕捉到一闪而过的信息
于是我们需要I2C总线的协议,和传感器的数据总线
起始位
从机设备地址
然后在温度传感器的数据手册上:
读写检测
意思就是:
从机回复
单片机释放数据线,让I2C的数据线处于默认的高电平状态
当随后高电平被拉低,就是从机进行了回应
然后单片机再次接管总线,写入数据
从机应答
通信结束
全流程:

单片机:那个叫1000000的设备,我要给你写入一个数据了
温度传感器:好的
单片机:数据是11110011
温度传感器:收到
单片机:通信结束
读数据
随后数据部分,一共是24位,前面16位是温度数据,后面8位是校验部分
所以我们只需要关注前面的数据就可以了
得到二进制位,换算为十进制,再根据公式进行计算,就可以得到温度信息
总结
起始位,7位地址码,读写位,应答位,数据包,应答位,结束包组成
整个通信过程中,时钟线完全由主机掌控,数据线会在应答位和读数据的时候释放给从机使用
如果需要读写某个特定的寄存器,还会在地址和数据之间加入一个寄存器地址
3.20补
注:以下内容来自zhangduang_KHKW,读者根据文章内容以及相应论文添加自己的理解进行注释。
1、I2C总线简介
串行、半双工的总线;主要用于近距离、低速的芯片之间的通信;I2C总线有两根双向的信号线,一根数据线SDA用于收发数据,一根时钟线SCL用于通信双方时钟的同步;
I2C总线是一种多主机总线,连接在 I2C 总线上的器件分为主机和从机。
2、通信过程
- 主机发送起始信号启用总线
- 主机发送一个字节数据指明从机地址和后续字节的传送方向
- 被寻址的从机发送应答信号回应主机
- 发送器发送一个字节数据
- 接收器发送应答信号回应发送器
- ........ (循环步骤4、5)
- 通信完成后主机发送停止信号释放总线
第4步和第5步用的是发送器和接收器,不是主机和从机,这是由第一个字节的最后一位决定主给从发,还是从给主发。(有一个读写位,决定是读还是写)
第一个字节和最后的停止信号一定是主机发给从机,但中间就不一定了。
3、寻址方式
I2C总线上传送的数据是广义的,既包括地址,又包括真正的数据。
主机在发送起始信号后必须先发送一个字节的数据,该数据的高7位为从机地址,最低位表示后续字节的传送方向(读写位,1是读,0是写)
4、起始信号和停止信号
SCL(时钟线)为高电平时,SDA(数据线)由高变低表示起始信号;
SCL(时钟线)为高电平时,SDA(数据线)由低变高表示停止信号;
起始信号和停止信号都是由主机发出,起始信号产生后总线处于占用状态,停止信号产生后总线被释放,处于空闲状态。
空闲时,SCL与SDA都是高电平。
停止情况有两种:
- 主机不想发了,就发送停止信号;
- 从机不想接了,不应答,主机就发送停止信号结束此次通信。
5、 字节传送与应答
I2C总线通信时每个字节为8位长度,数据传送时,先传送最高位,后传送低位,发送器发送完一个字节数据后接收器必须发送1位应答位来回应发送器,即一帧共有9位。
I2C每次发送数据必须是8位。
MSB固定,先发高位,再发低位。
6、同步数据信号
I2C总线在进行数据传送时,时钟线SCL为低电平期间发送器向数据线上发送一位数据,在此期间数据线上的信号允许发生变化,时钟线SCL为高电平期间接收器从数据线上读取一位数据,在此期间数据线上的信号不允许发生变化,必须保持稳定。(SCL为低电平,写,数据线上的数据可以变化,SCL为高电平,读,数据线上的数据不许变化)
7、时钟同步与仲裁
(1)时钟同步
时钟同步是通过I2C总线上的SCL之间的线“与”(wire-AND)来完成的,即如果有多个主机同时产生时钟,那么只有所有master都发送高电平时,SCL上才表现为高电平,否则SCL都表现为低电平。(在上面有图,可以看上面的图加以理解)
线“与”特性由开漏电路实现。如果控制开漏输出INT为0,低电平,则VGS >0,N-MOS管导通,使输出接地,若控制开漏输出INT为1 (它无法直接输出高电平) 时,则N-MOS 管关闭,所以引脚既不输出高电平,也不输出低电平,为高阻态。正常使用时必须外部接上拉电阻。也就是说,若有很多个开漏模式引脚(C1、C2....)连接到一起时,只有当所有引脚都输出高阻态,才由上拉电阻提供高电平,此高电平的电压为外部上拉电阻所接的电源的电压。若其中一个引脚为低电平,那线路就相当于短路接地,使得整条线路都为低电平,0 伏。
(2)仲裁
总线仲裁与时钟同步类似,当所有主机在SDA上都写1时,SDA的数据才是1,只要有一个主机写0,那此时SDA上的数据就是0.
一个主机每发送一个bit数据,在SCL为高电平时,就检查SDA的电平是否和发送的数据一致,如果不一致,这个主机便知道自己输掉了仲裁,然后停止向SDA写数据。也就是说,如果主机一致检查到总线上数据和自己发送的数据一致,则继续传输,这样在仲裁过程中就保证了赢得仲裁的master不会丢失数据。
输掉仲裁的主机在检测到自己输了之后也就不再产生时钟脉冲,并且要在总线空闲时才能重新传输。
仲裁的过程可能要经过多个bit的发送和检查,实际上两个主机如果发送的时序和数据完全一样,则两个主机都能正常完成整个数据传输。
在第三个数据时,DATA1发现自己的想要传输的数据(1)和SDA数据线上的数据(0)不一样,他就知道自己输了仲裁,后面就不发消息了
注意:多个主机仲裁时,因为线“与”特性,谁低谁能强制SDA为低,也就是跟自己匹配,所以先高(高电平1)的那个就会仲裁失败。(因为高电平需要两个都输出高电平,假如有一个低电平,那么就会输出低电平)
8、典型I2C时序
(1)主机向从机发送数据
(2)从机向主机发送数据
(3)主机先向从机发送数据,然后从机再向主机发送数据
注:S:起始信号,A:应答信号,A非:表示非应答,P:终止信号,
阴影部分表示数据由主机向从机传送,无阴影部分表示从机向主机发送数据。
数据传输中间如果想转换发送方向,不用发P停止信号,就不会释放总线,直接再发起始信号。
怎么发起始信号,怎么发停止信号,这些都不用关心,由I2C控制器完成,我们使用的时候只需要正确配置控制器相应的寄存器就可以了。