11、串口通信

1、串口通信原理

  串口通信的概念非常简单,串口按位(bit)发送和接收字节。尽管比按字节(byte)的并行通信慢,但是串口可以在使用一根线发送数据的同时用另一根线接收数据。它很简单并且能够实现远距离通信。比如IEEE488定义并行通行状态时,规定设备线总长不得超过20米,并且任意两个设备间的长度不得超过2米;而对于串口而言,长度可达1200米。典型地,串口用于ASCII码字符的传输。通信使用3根线完成:(1)地线,(2)发送,(3)接收。由于串口通信是异步的,端口能够在一根线上发送数据同时在另一根线上接收数据。其他线用于握手,但是不是必须的。串口通信最重要的参数是波特率、数据位、停止位和奇偶校验。对于两个进行通信的端口,这些参数必须匹配:   

  1. 波特率(Baud Rate):波特率是串口通信中非常重要的参数,它表示每秒钟传送的比特数。例如,波特率为9600表示每秒钟传送9600个比特(或960个字节)。波特率的选择需要发送和接收双方协商一致,以确保数据的正确传输。不同的设备通常支持不同的波特率选项。
  2. 数据位(Data Bits):数据位确定每个字节中实际数据位的数量。通常使用的数据位有5、6、7和8位,表示一个字节可以包含的数据位数。例如,8位数据位意味着每个字节有8个比特用于传输数据。数据位的选择通常取决于所传输的数据的范围和类型。
  3. 停止位(Stop Bits):停止位用于表示一个字节的结束。它通常可以是1位、1.5位或2位。通信中的每个字节之后都会包含停止位,以便接收设备能够确定何时一个字节的传输结束。停止位的选择也可以根据具体需求进行调整。
  4. 奇偶校验位(Parity Bit):奇偶校验位用于检测传输中的错误。它可以是奇校验或偶校验。在每个字节的数据位之后,可以包含一个校验位,用于确保数据位中的比特数是奇数或偶数,具体取决于所选择的校验模式。这有助于检测传输中的错误,但也会增加数据传输的复杂性。
  5. 起始位(Start Bit):起始位用于指示一个字节的开始。它是在每个字节的前面,并且通常是1位。起始位的存在帮助接收设备确定何时开始接收一个字节的数据。

一、RS232通信协议

1、概念  

  个人计算机上的通讯接口之一,由电子工业协会(Electronic Industries Association,EIA) 所制定的异步传输标准接口。     

2、电气特性

  逻辑1(MARK):  -3V~-15V

  逻辑0(SPACE):  +3~+15V

3、接口

  实现全双工异步通信只需要三根线:RX、TX和GND。

二、常见COMS电平转RS232电平的芯片—MAX3232

img

1、逻辑输入与逻辑输出特性

img

2、RS232接口端输入特性

img

3、RS232接口端输出特性

img

三、STM32串口硬件电路

1、芯片内部串口电路

img

2、开发板串口硬件电路

img

四、STM32串口编程

1、整体流程

① 开启GPIO时钟和USARTX时钟

② 配置TX和RX引脚

③ 初始化USART控制器

2、细节实现

① 开启GPIO时钟和USARTX时钟

1
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);

② 配置TX和RX引脚

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* Configure USART1 Tx (PA.09) as alternate function push-pull */
/* 配置 USART1 的传输引脚 Tx (PA.09) 为复用推挽输出模式 */

// 创建 GPIO_InitTypeDef 结构体变量,用于配置 GPIO 引脚
GPIO_InitTypeDef GPIO_InitStructure;

// 配置引脚 PA.09 为 USART1 的传输引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
// 设置引脚模式为复用推挽输出
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
// 设置引脚输出速度为 50MHz
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
// 将上述配置应用到 GPIOA 引脚上,使其成为 USART1 的传输引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure USART1 Rx (PA.10) as input floating */
/* 配置 USART1 的接收引脚 Rx (PA.10) 为浮空输入模式 */

// 重新配置 GPIO_InitTypeDef 结构体变量,用于配置 GPIO 引脚
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
// 设置引脚模式为浮空输入
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
// 将上述配置应用到 GPIOA 引脚上,使其成为 USART1 的接收引脚
GPIO_Init(GPIOA, &GPIO_InitStructure);

③ 初始化USART控制器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/* USART1 mode config */
/* USART1 模式配置 */

// 创建 USART_InitTypeDef 结构体变量,用于配置 USART1 模块
USART_InitTypeDef USART_InitStructure;

// 设置 USART1 波特率为 115200
USART_InitStructure.USART_BaudRate = 115200;
// 设置数据帧长度为 8 位
USART_InitStructure.USART_WordLength = USART_WordLength_8b;
// 设置停止位为 1 位
USART_InitStructure.USART_StopBits = USART_StopBits_1;
// 禁用奇偶校验位
USART_InitStructure.USART_Parity = USART_Parity_No;
// 禁用硬件流控制
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
// 启用接收和发送模式
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;

// 将上述配置应用到 USART1 模块
USART_Init(USART1, &USART_InitStructure);

// 启用 USART1 模块
USART_Cmd(USART1, ENABLE);

五、STM32串口疑惑

1、串口时钟使能与控制器使能的关系

  为何USART时钟使能了,还需要在配置USART控制器的时候再使能一次?

1
2
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, 		ENABLE);
USART_Cmd(USART1, ENABLE);

1> USART的时钟使能

  APB2 peripheral clock enable register (RCC_APB2ENR)

img

2、 USART控制器使能

  USART Control register 1(USART_CR1)

img

3、原因

  img

RCC_APB2ENR:  控制APB2时钟是否供应给USART控制器

USART_CR1:   控制USART控制器的分频器和输出是否工作

4、TDR与RDR共用一个特殊功能寄存器地址

USART_DR功能描述:

  包含了发送或接收的数据。由于它是由两个寄存器组成的,一个给发送用(TDR) ,一个给接收用(RDR) ,该寄存器兼具读和写的功能。TDR寄存器提供了内部总线和输出移位寄存器之间的并行接口(参见图236 )。RDR寄存器提供了输入移位寄存器和内部总线之间的并行接口。(摘自《STM32参考手册》)

  笔者的理解是:当对USART_DR进行读操作的时候,访问的是RDR;当对USART_DR进行写操作的时候,访问的是TDR。

六、串口调试时需要注意的地方

1、通过MDK结合一些调试器可以单步、任意断点等等方式进行代码的调试。可是,这种调试方法对于调试操作系统,比如uCOS-II,还有那些必须要全速运行才能进行调试的情况,就显得力不从心。串口调试正是用于这些地方,可以在程序全速运行的情况下,实时的打印系统的运行信息。

2、串口调试也有它的局限性,由于串口的波特率相对于STM32这样高速运行的单片机显得迟钝,很多情况下不能及时的打印系统的运行信息。甚至有些情况下,我们原本那些串口调试的代码会成为影响我们系统实时性最主要的因素。