【单片机通讯协议】—— 常用的UART/I2C/SPI等通讯协议的基本原理与时序分析

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

在嵌入式系统开发中,通信协议扮演着至关重要的角色。UART、I2C、SPI是三种常用的串行通信协议,各自具有独特的特点和应用场景。本教程将深入解析这些协议的基本原理与时序。

一、通信基本知识

1.1 MCU的参见外设

存储设备(SD卡)、显示设备(屏幕)、传感器设备(GPS、温湿度传感器)等等

在这里插入图片描述

1.2 通信的分类

按基本的类型

串行通信:串行通信是一种通过一条数据线逐位发送数据的通信方式。数据按照顺序一位接一位地传输,这使得串行通信只需要较少的信号线,通常包括数据线、地线以及可能的时钟线和控制线。

并行通信
并行通信是一种通过多条数据线同时传输多位数据的通信方式。在同一时钟周期内,多个比特并行传输到目标设备。通常用于需要高传输速率的短距离通信。

从传输方向上来分

单工通信:单工通信就是公路上只允许车辆单向行驶,但数据只能从发送机发送给接收机,不能反向发送
在这里插入图片描述

半双工通信:半双工通信就是公路上允许车辆双向行驶,数据可以在发送机和接收机之间相互传输,但是不能同时发送
在这里插入图片描述
全双工通信:全双工通信就是公路上允许车辆同时双向行驶,数据可以在发送机和接收机之间同时相互传输
在这里插入图片描述

波特率
波特率是发送二进制数据位的速率,单位是bps(即每秒传输二进制位的数量)

二、UART(串口通讯)

2.1 简介

简介:
通用异步收发器,是一种通用串行、异步通信总线,该总线有两条数据线,可以实现全双工的发送和接收,常用于单片机与单片机或外部辅助设备之间的通信,
在这里插入图片描述

2.2 时序图分析

在这里插入图片描述
注意
UART从低位开始发送数据,一次只能发送8位数据,加上起始位和停止位,实际上一共是发送了10位
UART应用的场景
RS232 9针串行接口:一般用于计算机和单片机之间的通信
USB转串口:这个是目前计算机和单片机之间通信最常见的方式
整体来说UART多用于板间通信,比如单片机与单片机,单片机与计算机,一个设备与另一个设备之间的通讯。

2.3 UART的局限性

1.不能远距离传输信号
因为串口通讯使用的是TTL电平,只能在很短的距离进行通讯,不然信号很容易受到干扰,如果需要远离的通信,则需要在中间加入抗干扰的芯片,因此,衍生出了RS232(最大支持30米)、RS485(最大距离可以超过1000米),同时RS485还增加了一对多的通信功能。
在这里插入图片描述
2.通信速递慢
大部分的情况下,我们使用的最高串口的波特率为115200(11.25KB/s),按照这个速度,一个小时都写不满一张64M的SD卡。究其原因,是UART的通信需要双方约定好特定的波特率,由于早期的单片机的频率低,时钟精度低的问题,双方不可能保持严格的一致,传输的速度太快很容易出现误码的情况。
解决这个问题的爆发就是,加入一个CLOCK的信号,双方不需要约定具体的通信速度,因此衍生出了SPI(最高的传输速度,可突破10M)
在这里插入图片描述
3.不能一对多通信(原则上只支持一对一的方式)
当系统有很多个传感器时进行数据传输时,MCU就需要多个串口来连接这些设备,会导致接口资源的浪费。
在这里插入图片描述
因此,衍生出了I2C通讯,它的最大的优势就是支持一对多的通讯方式,
I2C通讯有两根线,一个是时钟线CLOCK,一个是数据线DATA,每个设备都挂在在这两根线上,故称为总线。每个设备都有自己的独立的ID号(地址)。当单片机想要和任意的设备通讯时,只需要按照特定的通讯协议,找到相应的设备进行通讯即可。
在这里插入图片描述

三、I2C

3.1简介

简介
(1) I2C:是PHILIPS公司开发的一种两线式、串行、半双工同步通信总线,可以挂载多个参与通信的器件,常用于板内通信,比如单片机与外围芯片之间短距离、低速的信号传输

(2) I2C协议主要是解决了单片机一对多的通信问题,通过构建一条信息通道,只需两个IO口,两条线,就可以把电路板上的所有芯片串起来,利用这个信息通道相互传输数据,相比于UART的通讯方式,大大节约了单片机的宝贵的IO资源,也降低了PCB的布线成本

3.1 硬件部分的知识

(1) 问题一:在某一时刻,如果有两个设备同时发送数据,应该会发生什么?比如设备A要发送1,设备B 要发送0,如下图所示,最终数据总线上会是高电平还是低电平?
在这里插入图片描述
回答
为解决上述的问题,I2C做了一些阉割的处理(这也是I2C硬件设计最精髓的地方),
先介绍一下,一般芯片如何输出高低电平
在芯片10口的内部一般会有两颗MOS管,上面的MOS管导通就输出高电平,下面的MOS管导通就输出高电平
在这里插入图片描述
如果两个芯片都挂在在同一个数据的总线上,在某一时刻,芯片A输出高电平,芯片B输出低电平,此时,电流就直接从电源流入地,造成电路短路,必定元器件内烧毁
在这里插入图片描述
所以,为了避免这种情况的发生,I2C总线对于设备的IO口,做了一些阉割处理,去掉了上面的MOS管,这样就不可能存在短路的情况了。
在这里插入图片描述
不过这样也会带来另外的问题:设备只能输出低电平,无法输出高电平。
解决办法
在数据总线上,加一颗上拉电阻,那么数据总线就默认输出高电平了(也就是后面的通讯时,空闲状态为什么是高电平的原因
重新回到一开始的问题两个设备如果同时要发送信号,怎么办?
在这里插入图片描述
当设备A输出高电平,设备B输出低电平时,此时总线式处于低电平的,无法满足设备A的需求,此时就需要软件协议来解决这个问题(也就是发送数据前,要进行寻址的操作,确定通讯的设备

总结
I2C为了解决多设备共用总线,而步烧毁电路的问题,采用开漏输出的方案,配合上拉电阻,就可以输出完整的高低电平,这个上拉电阻的取值一般在几千欧姆(4.7k欧姆),如果总线设备多且通信速度要求高的话,电阻就选着小一些,反之,电阻大一些
在这里插入图片描述
注意
由于I2C采用开漏输出加上拉电阻的模式,所以I2C的抗干扰的能力比较弱,只适合用于同一块电路板上的芯片之间的通信,并不适合超过30cm电路板之间的通讯

3.2 通讯规则与时序分析:

SCL时钟线:SCL时钟线用于同步
SDA数据线:用于传输数据
在这里插入图片描述

I2C总线能挂载多个器件,且支持多主机模式,也就是说,线路上的任何一个器件都可以作为主机,但受限于只有一根信号线,同一也就是发起和结束一次通信的权利时刻只能有一个主机,主机拥有该时刻下总线的控制权,而从机只能被主机呼叫。
问题:那线路上有这么多器件,主机是怎么识别出自己要呼叫的从机?
回答
在I2C总线协议中,每个器件都有一个固定的号码,他是一个7位的地址 ,如上图所示,每个设备的地址。例如,主机要获取设备E2PROM的数据,会事先发一个0x31找到E2PROM设备
I2C的时序图
在这里插入图片描述
寻址流程
1.I2C协议发送数据是从高位到低位依次发送,当总线空闲时,SCL时钟线和SDA数据线均保持高电平,
2.当主机要开始传输数据时,会先将SDA电平拉低,而此时SDA数据线上这个从高到低的跳变沿,就是起始位
3.接下来就是进行期间寻址,在SCL低电平时依次发送七位地址位
4.地址发送完之后,紧接着主机会发送一个读写指示位,低电平表示要发送数据,高电平表示要请求数据
5.主机发送完以上数据从机如果成加接收,会发送一个应答位到总线上
注意:只有SCL处于低电平时,SDA可以变化,SCL高电平时,SDA需要保持,以方便数据接收方读取操作
数据发送
在这里插入图片描述
I2C通信一般流程:
1.主机发送起始位并进行从机寻址
2.得到应答后主机开始发送 / 读取数据位
3.数据发送 / 读取完成主机发送停止位结束此次通信
在这里插入图片描述

应用的设备:
1.温湿度传感器

四、SPI

4.1 简介

简介
串行外围设备接口,是一种高速、全双工、同步通信总线,常用于单片机和E2PROM、FLASH、实时时钟、数字信号处理器等器件的通信,它主要是主从方式通信,通常只有一个主机和数个从机。
在这里插入图片描述
SCLK:时钟信号,由主机产生(Must)
MOSl:主机给从机发送指令或数据的通道
MIS0:主机读取从机的状态或数据的通道
CS:从机片选使能信号

在同一时刻,主机只能跟一个从机进行通信,当总线存在多个从机时,需要进行片选,将从机的CS接口电平拉低或者拉低。
在这里插入图片描述

4.2 时序图

以SCLK时钟线空闲时时高电平为例:
1.当SCLK出现下降沿时(从高电平跳到低电平时),进行数据输出
2.当SCLK出现上升沿时(从低电平跳到高电平时),进行数据采样
在这里插入图片描述
注意
1.SPI发送数据也是从高位到低位依次发送数据
2.SPI的时钟线SCLK在空闲的时候可以是高电平也可是低电平(由时钟的极性决定)
3.和I2C相比,SPI没有开始位、结束位、应答位,故规则上简单很多

CPIOL时钟极性
a. CPOL=0时,SCLK空闲时状态为低电平
b. CPOL=1时,SCLK空闲时状态为高电平

CPHA时钟的相位:它决定了什么时候进行数据输出,什么时候进行数据采样
a. CPHA=0时,每个周期的第一个跳变沿采样
b. CPHA=1时,每个周期的第一个跳变沿输出

不管上述哪一种设置,输出和采样都是交替进行,以上的两两组合,就构成了SPI的四种工作模式

五、 总结

在这里插入图片描述
常见的问题:UART/I2C/SPI这三种通讯协议之间的异同点是什么?
回答
1.通讯模式上:
SPI和IIC是同步通信,依赖时钟信号;而UART是异步通信,使用起始位和停止位来界定数据包。
2.从通讯的管脚上来说:
UART:只使用数据线和地线。通信双方需要预先约定波特率
I2C:使用两条线进行通信:数据线(SDA)和时钟线(SCL)。
SPI:使用四条线进行通信:主设备输出数据线(MOSI)、主设备输入数据线(MISO)、时钟线(SCLK)和从设备选择线(CS)

3.通讯的速率上:
SPI通常提供最高的数据传输速度(可突破10M),其次是IIC,UART相对较慢.

4.多设备通信方面:
IIC和SPI都支持多设备通信,但SPI需要为每个设备提供单独的SS(片选)信号线,而IIC通过地址识别设备。而UART原则上只支持一对一的通讯方式。
5.从纠错的方面:
UART有奇偶检验的方式来纠错,I2C有应答的方式来纠错,SPI没有

### 关于RT-Thread操作系统中UART通信的时序图 在RT-Thread操作系统环境中,UART(通用异步收发传输器)作为常见的串行接口,在嵌入式系统中的应用非常广泛。尽管提供的参考资料未直接提及具体的UART时序图表[^1],基于对RT-Thread的理解以及其对于外设驱动的支持方式,可以描述典型的UART通信过程。 #### UART初始化阶段 当系统启动并进入`rtthread_startup()`之后,会调用`rt_hw_board_init()`来进行硬件初始化工作。在此期间,如果涉及到UART模块,则会在`board.c`文件内完成相应的配置初始化操作,包括但不限于波特率设置、数据位长度指定、停止位数目设定及校验模式的选择等[^2]。 #### 数据发送流程 一旦完成了上述初始化步骤,应用程序可以通过调用API函数向UART缓冲区写入待发送的数据字节序列。此时,内部状态机将遵循下述逻辑: 1. **等待空闲**:检测线路是否处于空闲状态; 2. **起始位生成**:产生一个低电平持续一段时间(通常是一个比特周期),标志着一帧新消息的到来; 3. **数据位传送**:按照预先定义好的格式依次发出每一位数据,最低有效位先行; 4. **奇偶校验位(可选)**:如果有启用此功能的话,则计算并附加额外的一位用于错误检测目的; 5. **停止位发射**:最后送出高电平信号维持若干个比特宽度以结束当前字符流。 #### 接收端响应机制 接收方同样经历类似的同步化处理程序,区别在于它负责监听来自外部源传来的脉冲变化情况,并据此解析出原始的信息内容。具体而言就是识别起始条件触发采样动作,随后逐一对齐各个组成部分直至整个报文被完整捕获为止。 虽然这里未能提供确切的图形化展示形式,但是通过以上文字叙述应该能够帮助理解RT-Thread环境下UART交互的基本原理和时间节点安排。 ```c // 示例代码片段展示了如何利用RT-Thread API进行简单的UART数据交换 #include <rtdevice.h> #include "uart.h" static struct serial_device *serial; int main(void) { char send_data[] = "Hello, RT-Thread!"; // 获取指向已注册名为"uart1"设备实例的指针 serial = (struct serial_device *)rt_device_find("uart1"); if (!serial) { rt_kprintf("Find uart device failed!\n"); return -1; } // 打开该串口资源准备就绪 rt_device_open((rt_device_t)serial, RT_DEVICE_OFLAG_RDWR); // 发送字符串给对方节点 rt_device_write((rt_device_t)serial, 0, send_data, sizeof(send_data)); while (1) { /* 主循环体 */ } return 0; } ```
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2401_82458959

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值