USART串口协议

首先我们来了解一下通信接口啊,先看一下第一条,我们为什么需要通信?也就是通信的目的,它是将一个设备的数据传送到另一个设备,扩展硬件系统。比如这是我们的 STM32 芯片,它里面集成了很多功能模块,什么定时器计数啊, PWM 输出啊, AD 采集等等,这些都是芯片内部的电路,这些电路的配置寄存器啊,数据寄存器都在芯片里面,操作这些寄存器非常简单,直接读写就行了。但是也有些功能是 STM32 内部没有的,比如我们想蓝牙无线遥控的功能,想要陀螺仪加速度计测量姿态的功能。 STM32 没有,所以就只能外挂芯片来完成。那外挂的芯片它的数据都在 STM32 外面, STM32 如何才能获取到这些数据呢?这就需要我们在这两个设备之间连接上一根或多根通信线。通通过通信线路发送或者接收数据,完成数据交换,从而实现控制外挂模块和读取外挂模块数据的目的。所以在这里通信的目的是将一个设备的数据传送到另一个设备。单片机有了通信的功能,就能与众多别的模块互联,极大的扩展了硬件系统。
接着第二条就是通信协议。通信协议的作用是制定通信的规则,通信双方按照协议规则进行数据收发。比如说你考试的时候想给别人传答案,那你就可以和对方约定一个通信协议,比如先咳嗽一声代表重新开始,然后竖一个手指代表发送 A, 竖两个手指代表发送 B, 竖三个手指代表发送 C, 然后挥一挥手代表通信结束。这样来进行是吧?这里面就是一种通信方式。通信的目的是进行信息传递,双方约定的规则就是通信协议。
那最后,在 STM32 里面就有下表这么多的通信协议。这个表大家先提前了解一下哈,我们之后学到的时候还会再深入分析的。另外这个表我只是列了一个最典型的参数啊。因为各种通信协议应用都非常广泛,参数也很多。所以这里我列出的仅是它最常用最简单的配置,这个说明一下啊。
那我们来看一下第一个 USART 串口,它的引脚是 TX 和 RX,有的地方也叫 TXD 和 RXD 啊,这两种名称是一个意思啊。 TX 是数据发送角, RX 是数据接收角。
然后是 I2C 通信,引脚是 SCL 和 SDA, SCL 是时钟, SDA 是数据。
SPI 通信件是 SCLK、 MOSI、 MISO、 CS。SCLK 是时钟啊, MOSI 是主机输出数据角, MISO 是主机输入数据角, CS 是片选,用于指定通信的对象。
can通信,引脚是can_ H 和 L,这两个是差分数据角啊,用两个引脚表示一个差分数据。 USB 通信,引脚是 DP 和 DM,或者叫 D 正和 D 负啊,也是一对差分数据角。这就是这些通信协议规定的引脚。数据按照协议的规定在这些引脚上进行输入和输出,从而实现通信。
接着看一下后面它们的特性。首先是双工模式,这里全双工就是指通信双方能够同时进行双向通信。一般来说,全双工的通信都有两根通信线啊,比如串口,一根 TX 发送,一根 RX 接收。 SPI 一根 MOSI 发送,一根 MISO 接收。发送线路和接收线路互不影响,全双工。剩下的这些 I2C、 CAN 和 USB 都只只有一根数据线,can和 USB 两根差分线也是组合成一根数据线哈,所以都是半双工。当然还有一种方式就是单工。单工是指数据只能从一个设备到另一个设备,而不能反着来。比如把串口的 X 引脚去掉,那串口就退化成单工了。
然后是时钟特性,比如你发送个波形,高电平,然后低电平。接收方怎么知道你是一零,还是一一零零呢?这就需要有一个时钟信号来告诉接收方,你什么时候需要采集数据。时钟特性分为同步和异步啊,这里 I2C 和 SPI 有单独的时钟线,所以它们是同步的。接收方可以在时钟信号的指引下进行采样。剩下的串口 CAN 和 USB 没有时钟线,所以需要双方约定一个采样频率,这就是异步通信,并且还需要加一些针头针尾等啊,进行采样位置的对齐。
之后是电平特性,上面三个都是单端信号,也就是它们引脚的高低电平都是对 GND 的电压差,所以单端信号通信的双方必须要共地,就是把 GND 接在一起,所以说这里通信的引脚前三个还应该加一个 GND 引脚,不接 GND 是没法通信的哈。之后can和 USB 是差分信号,它是靠两个差分引脚的电压差来传输信号的,是差分信号。在通信的时候可以不需要接地哈,不过 USB 协议里面也有一些地方需要单端信号啊,所以 USB 还是需要供地的。使用差分信号可以极大的提高抗干扰特性,所以差分信号一般传输速度和距离都会非常高哈,性能也是很不错的。
最后看下设备特性。串口和 USB 属于点对点的通信,中间三个是可以在总线上挂载多个设备的。点对点通信就相当于老师找你去办公室谈话,只有两个人,直接传输数据就可以了。多设备就相当于老师在教室里面对所有同学谈话,需要有一个寻址的过程,以确定通信的对象。

好,通信协议和特征我就讲这么多啊,大家先了解一下,我们之后还会再学习的。然后我们就来学习一下串口的知识点,接下来的内容主要分为两个部分啊。前半部分我们主要讲的是串口的通信协议,就是软硬件的规则。这部分内容与某个具体的硬件无关啊。在我之前五幺的视频也讲过串口的通信协议。如果这里讲完还没听懂,也可以参考一下五幺的串口通信啊,都是一样的。然后后半部分我们讲的就是 STM32 内部的 USART 外设,这个外设的作用就是按照串口协议来产生和接收高低电平信号,实现串口通信。
那我们先看一下第一部分,首先看一下串口通信。
首先看一下串口通信,串口是一种应用十分广泛的通信接口啊,串口成本低,容易使用,通信线路简单,可实现两个设备的互相通信,在我们这个单片机的领域啊,串口其实是一种最简单的通信接口啊,它的协议相比较 I2C、SPI 等已经是非常简单的了,而且一般单片机它里面都会有串口的硬件外设,使用也是非常方便的,一般串口都是点对点的通信,所以是两个设备之间的互相通信,那下面一句单片机的串口可以使单片机与单片机,单片机与电脑,单片机与各式各样的模块互相通信,其中单片机和电脑通信啊,是串口的一大优势,可以接电脑屏幕,非常适合调试程序,打印信息,像 I2C 和 SPI 这些一般都是芯片之间的通信啊,不会接在电脑上,那有了通信就是极大的扩展单片机的应用范围,增强了单片机系统的硬件实力,这个也不难理解啊。
然后看一下下面这几个串口的设备,第一个是 USB 转串口模块,上面有个芯片,型号是 CH340,这个芯片可以把串口协议转化为 USB 协议,它一边是 USB 口,可以插在电脑上,另一边是串口的引脚,可以和支持串口的芯片接在一起,这样就能实现串口和电脑的通信了,
中间这个图是一个陀螺仪传感器的模块啊,可以测量角速度,加速度这姿态参数,它左右各四个引脚,一边是串口的引脚,另一边是 I2C 的引脚,
右边这个图是蓝牙串口模块,下面四个角是串口通信的引脚,上面的芯片可以和手机互联,实现手机遥控单片机的功能,

那这些就是串口通信和一些使用串口通信的模块啊,好,现在模块有了,我们来看一下硬件电路如何来接这个串口的线,下面这个图就是串口的接线图啊,一般串口通信的模块都有四个引脚,VCC、TX、RX、GND,VCC 和 GND 是供电啊,TX 和 RX 是通信的引脚,TX 和 RX 是单端信号,它们的高低电平都是相对于 GND 的,所以严格上来说 GND 应该也算是通信线啊,所以串口通信的 TX、RX、GND 是必须要接的,上面的 VCC,如果两个设备都有独立供电,那 VCC 可以不接,

如果其中一个设备没有供电,比如这里设备一是 STM32,设备二是蓝牙串口模块,STM32 有独立供电,蓝牙串口没有独立供电,那就需要把蓝牙串口的 VCC 和 STM32 的 VCC 接在一起,STM32 通过这根线向右边的子模块供电,当然供电的电压也需要注意一下哈,要按照子模块的要求来,这就是供电要求。

然后看一下上面这里说明,简单双向串口通信有两根通信线,发送端 TX 和接收端 RX,这里是简单的串口通信啊,复杂一点的串口通信还有其他引脚,比如时钟引脚,硬件流控制的引脚,这些引脚 STM32 的串口也有哈,不过我们最常用的还是简单的串口通信,也就是 VCC 接 D、TX、RX 这四个引脚,然后下一条 TX 与 RX 要交叉连接,这个也好理解,TX 是发送,RX 是接收,那你肯定得是一个设备的发送接另一个设备的接收,一个设备的接收接另一个设备的发送,这样来接线是吧,这个注意一下,别接错了。之后是当只需单向的数据传输时,可以只接一根通信线,比如你只需要设备一向设备二的单向通信,那就可以只接这一根 TX 到 RX 的线,另一根就可以不接,

这就变成了单工的通信方式。最后,当电平标准不一致时,需要加电平转换芯片,串口也是有很多电平标准的哈,像我们这种直接从控制器里出来的信号一般都是 TTL 电平,相同的电平才能互相通信,不同的电平信号需要加一个电平转换芯片转接一下。
那说到电平标准,我们就来看一下串口常用的几种电平标准哈,

看下第一条电平标准是数据一和数据零的表达方式,是传输线缆中人为规定的电压与数据的对应关系,我们在单片机电路中最常见的是 TTL 电平啊,也就是五伏或者三点三伏表示逻辑一,零伏表示逻辑零,这是我们最多遇到的电平标准啊,但是串口还有些其他的电平标准,这里了解一下啊,串口常用的电平标准有如下三种,
第一种就是最常见的 TTL 电平,正三点三伏或者正五伏表示一,零伏表示零,这里一的电压如果你是五伏的器件就是正五伏,如果是三点三伏的器件就是正三点三伏,逻辑一啊,就是高电平的电压,就是 VCC 的电压,除了 TTL 电平,
串口还有 RS232 电平和 RS485 电平,其中 RS232 电平的规定是负 3 到负 15 伏表示一,正 3 到正 15 伏表示零。RS232 电平一般在大型的机器上使用啊,由于环境可能比较恶劣,静电干扰比较大,所以这里电瓶的电压都比较大,而且允许波动的范围也很大,
另外还有 RS485 电平,它的规定是两线压差,正 2 到正 6 伏表示一,负 2 到负 6 伏表示零,这里电瓶参考是两线压差,所以 RS4485 的电平是差分信号,差分信号抗干扰能力非常强啊,使用 RS485 电平标准,通信距离可以达到上千米,而上面这两种电平最远只能达到几十米啊,再远就传不了了,这就是串口常用的这几种电平标准啊,
像单片机这种低压小型设备使用的都是 TTL 电平啊,我们之后的内容也都是基于 TTL 电平来讲解的,如果你做设备需要其他的电平,那就再加电平转换芯片就行了,在软件层面它们都属于串口啊,所以程序并不会有什么变化,好到这里,串口协议的硬件部分我们就清楚了,
在硬件电路上,协议规定是一个设备使用 TX 发送高电平,另一个设备使用 RX 接收低电平,在线路中使用 TTL 电平,因为 STM32 是三点三伏的器件,所以如果线路对地是三点三伏,就代表发送了逻辑一,如果线路对地是零伏就代表发送了逻辑零,那现在如何接线,如何发送一和零我们就知道了。

接下来我们来看一下串口协议的软件部分如何。
如何用一和零来组成我们想要发送的一个字节数据?我们看下下面的这两个时序图哈,这就是串口发送一个字节的格式。这个格式是串口协议规定的哈。

串口中每一个字节都装载在一个数据帧里面,每个数据帧都由起始位、数据位和停止位组成。这里数据位有 8 个,代表一个字节的 8 位哈。在右边这个数据帧里面,还可以在数据位的最后加一个奇偶校验位,这样数据位总共就是 9 位。其中有效载荷是前 8 位代表一个字节,校验位跟在有效载荷后面占一位啊。这就是串口数据帧的整体结构。
那我们来看下串口的参数,第一个参数就是波特率,它的用途是规定串口通信的数据率啊。我们之前说了,串口一般是使用异步通信,所以需要双方约定一个通信速率,比如我每隔一秒发送一位,那你就也得每隔一秒接收一位。如果你接收快了,那就会重复接收某些位,如果你接收慢了,那就会漏掉某些位。所以说发送和接收必须要约定好速率,这个数据参数就是波特率。
波特率本来的意思是每秒传输码元的个数哈,单位是码元每秒,或者直接叫波特。另外还有个数率表示叫比特率,比特率的意思是每秒传输的比特数,单位是bit/s,或者叫 BPS, 在二进制调制的情况下,一个码元就是一个比特啊。此时波特率就等于比特率。像我们单片机的串口通信,基本都是二进制调制啊,也就是高电平表示一,低电平表示零,一位就是一比特。所以说这个串口的波特率经常会和比特率混用哈,不过这也没关系的,因为这两个说法的数值相等。如果是多进制调制,那波特率就和比特率不一样了,这个了解一下。
那反映到波形上,比如我们双方规定波特率为 1000BPS, 那就表示一秒要发 1000 位每一位的时间就是一毫秒,也就是这里,这一段时间是一毫秒。发送方每隔一毫秒发送一位,接收方每隔一毫秒接收一位,这就是波特率,它决定了每隔多久发送一位。
接下来是起始位,它是标志一个数据帧的开始,固定为低电平。我们看一下下面这个波形啊,首先串口的空闲状态是高电平,也就是没有数据传输的时候,引脚必须要置高电平作为空闲状态。然后需要传输的时候,必须要先发送一个起始位这个起始位必须是低电平来打破空闲状态的高电平产生一个下降沿,这个下降沿就告诉接收设备这一帧数据要开始了。如果没有起始位,那当我发送 8 个一的时候,是不是数据线就一直都是高电平啊?没有任何波动对吧?这样接收方怎么知道我发送数据了呢?所以这里必须要有一个固定为低电平的起始位,产生下降沿来告诉接收设备我要发送数据了。
同理,在一个字节数据发送完成后,必须要有个停止位,这个停止位的作用是用于数据帧间格固定为高电平,同时这个停止位啊也是为下一个起始位做准备的。如果没有停止位,那当我数据最后一位是 0 的时候,下次再发动新的一针,是不是就没法产生下降沿了?对吧。这就是起始位和停止位的作用。起始位固定为 0 产生下降沿表示传输开始,停止位固定为一,把引脚恢复成高电平,方便下一次的下降沿。如果没有数据了,正好引脚也为高电平,代表空闲状态。

然后继续看中间的数据位,这里数据位表示数据帧的有效载荷。1 为高电平,0 为低电平,低位先行啊。比如我要发送一个字节是 0X0F, 那就首先把 0F 转换为二进制,就是 0000111。然后低位先行,所以数据要从低位开始发送,也就是 11110000,像这样,依次放在发送引脚上,所以最终引脚的波形就是这样的。所以说如果你想发送 0X0F 这一个字节数据,那就按照波特率要求定时翻转引脚电瓶,产生一个这样的波形就行了。

好,最后看一下校验位,它的作用是用于数据验证,是根据数据位计算得来的。这里串口使用的是一种叫奇偶校验的数据验证方法,奇偶校验可以判断数据传输是不是出错了,如果数据出错了,可以选择丢弃或者要求重传。校验可以选择三种方式啊,无校验、奇校验和偶校验。无校验就是不需要校验位,波形就是左边这个,起始位、数据位、停止位,总共三个部分。奇校验和偶校验的波形就是右边这个,起始位、数据位、校验位位停止位总共四个部分啊。如果使用了奇校验,那么包括校验位在内的 9 个数据会出现奇数个一。比如如果你传输 00001111,目前总共 4 个一是偶数个,那么校验位就需要再补一个一,连同校验位就是 000011111,总共 5 个一,保证一为奇数。如果数据是 00001110,此时 3 个一是奇数个,那么校验位就补一个 0,连同校验位就是 0000011100 总共还是 3 个一,一的个数为奇数。发送方在发送数据后会补一个校验位,保证一的个数为奇数。接收方在接收数据后会验证数据位和校验位,如果一的个数还是奇数,就认为数据没有出错。如果在传输中因为干扰有一位由一变成零,或者由零变成一了,那么整个数据的奇偶特性就会变化。接收方一验证,发现一的个数不是奇数,那就认为传输出错,就可以选择丢弃或者要求重传,这就是奇校验的差错控制方法。如果选择双方约定偶校验,那就是保证一的个数是偶数。校验方法也是一样的道理哈。当然奇偶校验的检出率并不是很高哈。比如如果有两位数据同时出错,奇偶特性不变,那就校验不出来。所以奇偶校验只能保证一定程度上的数据校验。如果想要更高的检出率,可以了解下 CRC 校验哈,这个校验会更加好用,当然也会更复杂。我们这个 STM32 内部也有 CRC 的外设,可以了解一下。

那到这里串口的时序我们就了解了。最后再说明一下哈,我们这里的数据位有两种表示方法,一种是把校验位作为数据位的一部分,就像下面这个时序一样,分为 8 位数据和 9 位数据,其中 9 位数据就是 8 位有效载荷和一位校验位。另一种就是把数据位和校验位独立开,数据位就是有效载荷,校验位就是独立的一位。像我上面的描述啊,就是把数据位和校验位分开描述了。在串口助手软件里,也是用的这种分开描述的方法,数据位为 8 位,校验位一位,总总之无论是合在一起还是分开描述,描述的都是同一个东西啊,这个应该也好理解。

那最后我们来看几个串口通信的实际波形啊,看完这些波形,相信你就能理解串口是如何来传输数据的了。
相信你就能理解串口是如何来传输数据的了。这些波形我是用示波器实测的哈。操作方法是把探头的 GND 接在负极,探头接在发送设备的 TX 引脚,然后发送数据,就能捕捉到这些波形了。
那我们先看一下第一个波形。这个波形是发送一个字节数据 0x55 时,在 TX 引脚输出的波形。波特率是 9600,所以每一位的时间就是 1÷9600,大概是 104 微秒哈。可以看到这里一位就是 100 微秒多一点,就是 104 为秒,没发送数据的时候是空闲状态高电平,数据帧开始先发送起始位产生下降沿,代表数据帧开始啊,数据 0X55 转为二进制低位先行,就是依次发送 10101010,然后这个参数是 8 位数据,一位停停止无校验啊,没有校验位,所以之后就是停止位,把引脚置回高电平。这样一个数据帧就完成了。
在 STM32 中,这个根据字节数据翻转高低电平,是由 USART 外设自动完成的哈,不用我们操心。当然你也可以软件模拟产生这样的波形,那就是定时器定一个 104 微秒的时间,时间到之后,按照数据帧的要求调用 GPIO WriteBit 置高低电平,产生一个和这一模一样的波形,这样也是可以完成串口通信的。 TX 引脚发送就是置高低电平,那在 RX 引脚接收,显然就是读取高低电平了。这也可以由 USART 外设自动来完成,不用我们操心。如果想软件模拟的话,那就是定时调用 GPIO ReadInputDataBit 来读取每一位,最终拼接成一个字节。当然接收的时候应该还需要一个外部中断哈,在起始位的下降沿触发,进入接收状态,并且对其采样时钟,然后依次采样八次,这就是接收的逻辑。

接着看一下下面的波形,如果发发送 0XAA 波形就是这样的起始位,然后 01010101 停止位结束。

再下面,如果发送 0XFF 就是 8 个一,那波形就是这样,起始位 8 个一,停止位结束。在起始位下降沿之后的一个数据帧的时间内,这个高电平就是作为数据一来看的。当数据帧结束后,这里虽然还是一,没有任何变化,但此时的一已经是属于空闲状态了,它需要等待下一个下降沿来开启新的一帧数据。

之后再看下面,如果发送连字 00 就是 8 个 0,那波形就是起始位 8 个 0,停止位智慧高电平,这样来进行。

然后继续看右边的波形。这里如果把波特率改成 4800 呢,也就是波特率变为一半,那相应的波形时长就会变为原来的二倍。可以看到这里 10 位数据总共大概两毫秒多一点,具体应该在 2.08 毫秒对吧。那一位就是 208 微秒,是之前的二倍哈。数据波形的时间拉宽,波形的变化趋势是不变了哈。

之后看下面这个模型,这里加了一个偶校验位,数据是连字五五,数下一的个数是四个,已经是偶数了,所以输出的校验位是零。一点零。此时包括校验位在内的数据总共是偶数个一,总的波形就是这个样子。

最后看一下停止位的变化。串口的停止位是可以进行配置的哈,可以选择一位、一点五位、两位等。看一下啊,这上面的波形是一位停止位,连续发送两个 0x55,两个数据帧会接在一起,中间没有空闲状态。
下面这个波形是两位停止位,连续发送两个 0x55,可以看到这里停止位就是两位的宽度,中间也没有空闲状态。不过这样数据分隔的就更宽一些了。这就是不同长度停止位的现象。

好到这里有关串口协议的硬件和软件就介绍完了。总结一下就是, TX 引脚输出定时翻转的高低电平, RX 引脚定时读取引脚的高低电平。每个字节的数据加上起始位停止位可选的校验位,打包成数据帧,依次输出在 TX 引脚,另一端 RX 引脚依次接收,这样就完成了字节数据的传递,这就是串口通信。