串行通信
USART通信是一种串行通信方式,即将数据一位一位的发送出去。
同步通信与异步通信
异步串行通信协议:
通信双方不需要使用同一个时钟信号来同步数据传输,工作双方的"工作效率"允许存在差异。
发送方和接收方各自有独立的时钟源,但要求发送端和接收端保持相同的**解析速率(波特率)**以使得接收端能够正常解析发送端的数据。
接收方通过检测数据中的起始位和停止位等特定标志来确定数据的开始和结束,从而实现数据的异步接收。
由于数据带有特定的起始位和停止位,所以接收端处理数据不需要严格与发送端保持同步,即便接收端处理较慢,一般也不会产生问题,因为发送端数据会缓存在接收端寄存器内部。
同步串行通信协议:
通信双方需要使用同一个时钟信号来同步数据传输。
通常由发送方提供时钟信号,接收方根据这个时钟信号来确定何时接收数据位,确保双方在数据传输过程中保持严格的同步。
通常由发送端发送起始信号、特殊信号标志等来告知接收端发送数据开始,当然传输结束也是一样的。
发送端和接收端必须实时同步处理数据,否则就会导致数据丢失。
USART在UART异步串行通信的基础上,还支持同步串行通信的外设/通信协议。
串口通信设备的连接方式
串口通信的连接方式非常简单,具有以下特点:
点对点通信:UART 通常用于两个设备之间的通信,一个设备作为发送方(TX),另一个设备作为接收方(RX)。
简单易用:UART 只需要两条信号线(TX 和 RX)即可实现全双工通信(可以同时发送和接收数据)。
串口通信的数据帧格式
UART通信采用的通信方式是串行通信,即数据按位(bit)顺序一位一位的传输,所以我们首先就需要了解UART数据帧格式。
一个经典的UART数据帧格式如下图所示:
引脚在发送数据和接受数据时,默认空闲电位是高电位,起始位低电平,停止位高电平。数据位8-9位,低电平(可以加校验位,但串行通信的稳定性好,不容易出错,所以不加校验位也行)
数字88转换成二进制补码形式,数据是:0101 1000
其数据帧格式如下图所示
字符串"abc"转换成二进制表示,即转换成各个字符的编码值表示,各个字符的编码值是:
‘a’:十进制97,0x61,即二进制0110 0001
‘b’:十进制98,0x62,即二进制0110 0010
‘c’:十进制99,0x63,即二进制0110 0011
在通信传输数据时,发送"abc"肯定是先发a再发b,最后发c,这样才能保证接收端也是先接收a再接到b,最后收到c,如此就能收到一个字符串"abc"。
所以其数据帧格式如下图所示:
波特率
UART串口通信是一种异步串行通信协议,不需要通信双方统一时钟信号,双方设备可以工作在不同的频率下。
这样就出现了一个显而易见的问题:
数据帧是依靠一定频率的高低电平变化来表示数据0和1,那么当发送端发送一个数据帧时,接收端如何才能准确识别每一个比特(bit)的时间间隔呢?
比如发送端发送了一个10位的数据帧,用时1秒钟,那么就是0.1秒发送1位,若接收端不知道0.1s这个间隔,接收端能够正确解析数据帧吗?
显然是不可以的。
为了解决这个问题,UART通信引入了波特率(Baud Rate)的概念。
波特率(Baud Rate) 是指 每秒传输的最大位数,单位是 bps(bits per second),即“每秒传输的比特数”。它用于衡量串行通信(如UART、RS-232、SPI、I2C等)的数据传输速率。
简单来说:
波特率 = 1秒内传输的bit数量
比如 波特率是9600 bps,意味着每秒传输 9600 个 bit。
在UART通信中,最常见的波特率是9600、115200、57600 等。
很显然,发送端和接收端必须使用相同波特率,否则会出现乱码或数据丢失等问题。
USART的工作原理
也就是说,假如我们想要使用USART模块发送数据,只需要将数据写入到发送数据寄存器中,这样USART模块通过内部电路就会自动将数据逐位的,通过Tx引脚发送出去.
接受数据时,通过Rx引脚接受,由于接收时时是反向接收的,所以可以靠电路设计反向接收,这样数据进入到寄存器中就是正常的了。
连接电路及设备
好的,我们搞清楚了原理,现在要连接硬件设备。
首先搞清楚双方通信的Tx,Rx引脚。
经过查表:
可以找到,即PA9,PA10的复用功能。
pc端则需要USB转TTL模块。
连USART外设模块
这里的硬件流控指的是:
RTS由接收端控制,决定是否允许对方发送数据,连接到发送端的CTS。
CTS由发送端控制,决定是否允许自己发送数据,连接到接收端的RTS。
常用于数据吞吐量大的数据传输,如蓝牙,wifi等模块。这里不需要。
引脚的工作模式
Tx端,选择挽输出高低电平。
Rx端,由于数据是低电平才是数据起始的标志,所以使用上拉输入模式,而下拉输入模式接收端默认是低电平模式,就会一直处于数据接收状态,浮空输入模式也行,因为浮空模式下默认不接收任何电平,所以不影响数据起始位的低电平接收。
注意:
引脚输出什么只能由一方来单独控制,所以输出模式有通用和复用的区别,用来确定控制权的归属。
但输入模式并不需要什么控制权,引脚的输入可以同时由GPIO外设读,也可以由USART1外设来读,所以输入模式并没有复用和通用的区别。
这就是为什么这个枚举类型里面只有输复用输出,而没有复用输入的原因。
代码实现外设初始化
void GPIO_init(void){
RCC_APB2PeriphResetCmd(RCC_APB2Periph_GPIOA, ENABLE);
GPIO_InitTypeDef GPIO_InitStruct;
//设置PA10使用上拉输入模式
GPIO_InitStruct.GPIO_Mode = GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10;