串口通信-轮询方式
1 串口通信概述
1.1 计算机通信的基本概念
计算机通信: 将计算机技术和通信技术相结合,完成计算机与外部设备或计算机与计算机之间的信息交换。按照数据传输方式的不同,可以分为串行通信和并行通信两类。
串行通信: 数据逐位传输,传输线少,长距离传输时成本低,但数据的传输控制较复杂。按照实现数据同步的方式,可以分为同步串行和异步串行两种。
同步串行通信: 数据传输以数据块(一组字符)为单位,在一个数据块内,字符与字符间无间隔,收发双方依靠独立的时钟线进行信号的同步。
异步串行通信: 数据传输以单个字符为单位,字符和字符之间的间隙任意,字符内部每一位持续的时间相同。收发双方没有专门的时钟信号,而是依靠事先约定的字符格式和通信速率来完成通信适用于大批量的数据传输。
并行通信: 多位数据同时传输,传输控制简单,传输速度快,但是在长距离传输时硬件成本较高。
1.2 异步串行通信
异步通信的两个关键点是字符格式和 波特率 ,字符格式决定了数据的传输形式,波特率决定了字符中每一位数据的持续时间。
字符格式
❑ 1 位起始位,规定为低电平;
❑ 5~8 位数据位,即要传送的有效信息;
❑ 1 位奇偶校验位;
❑ 1~2 位停止位,规定为高电平。
常用字符格式:1位起始位,8位数据位,无奇偶校验,1位停止位
传输时低位在前,高位在后,上图发送数据为0xE9。
通信速率
波特率:每秒钟传送二进制数码的位数,以bit/s(bps)为单位。
常用的波特率有:9600、19200、38400、57600和115200;
波特率为115200,表示每秒传输115200位,且每一位数据在数据线上持续时间为Tbit= 1/115200 ≈ 8.68us
异步串行通信的数据接收过程
接收过程的本质是数据采样,假设接收端的采样时钟是波特率的16倍。
① 接收过程由起始位的下降沿启动;
② 接收端等待8个时钟周期,以便建立一个接近比特周期中间的采样点;
③ 接收端等待16个时钟周期,使其进入第一个数据位周期的中点;
④ 第一个数据位被采样并存储在接收寄存器中;
⑤ 串口模块在采样第二个数据位之前等待另外16个时钟周期;
⑥ 重复此过程,直到所有数据位都被采样和存储;
⑦ 由停止位的上升沿使数据线返回到空闲状态。
串口通信的数据传输方向
错误校验方式
奇偶校验:奇校验表示数据中“1”的个数与校验位“1”的个数之和为奇数;偶校验表示数据中“1”的个数与校验位“1”的个数之和为偶数。
代码和校验:发送方将所发数据块求和,产生一个字节的校验字符附加到数据块末尾。接收方采用同样方式进行检测。
循环冗余校验:通过某种数学运算实现有效信息与校验位之间的循环校验,常用于磁盘信息的传输、存储区的完整性校验等。
2 STM32串口通信
2.1 串口收发单元
串口收发单元主要利用数据寄存器DR,发送引脚TX,接收引脚RX,以及三个通信状态位TXE、TC和RXNE来完成数据的接收和发送。
TXE:发送数据寄存器空标志。当TDR寄存器的内容已经传送到发送移位寄存器 时,该位由硬件置1。如果串口控制寄存器CR1中的TXEIE位为1,将会触发发送数据寄存器空中断。注意:当TXE置1时,数据有可能还在发送。
TC:发送完成标志。当发送移位寄存器的内容发送完成,同时TDR寄存器也为 空时,该位由硬件置1,表示本次数据传输已经完成。如果串口控制寄存器CR1中的TCIE位为1,将会触发发送完成中断。注意:当TC置1时,数据才是真正地发送完成。
RXNE:接收数据寄存器不为空标志。当移位寄存器的内容已经传送到接收数据寄存器RDR时,该位由硬件置1。如果串口控制寄存器CR1中的RXNEIE位为1,将会触发接收数据寄存器不为空中断。
数据寄存器DR在硬件上分为TDR和RDR两个寄存器,通过数据的流向进行区分,在结构设计上采用了双缓冲结构;
发送时,数据通过数据总线送入TDR寄存器,然后传送到发送移位寄存器完成数据转换,从并行数据转为串行数据,最后通过TX引脚发送;
接收时,数据通过RX引脚逐位送入接收移位寄存器,8位数据接收完成后,送入RDR寄存器,供用户读取。
USB转TTL串口模块
2.2 串口的数据类型定义
①外设句柄的定义:
HAL库在结构上,对每个外设抽象成了一个称为ppp_HandleTypeDef的结构体,其中ppp就是每个外设的名字。所有的函数都是工作在ppp_HandleTypeDef指针之下。
例如,使用USART2时,可以定义USART初始化结构体变量(全局变量)huart2。
UART_HandleTypeDef huart2;
huart2就被称为串口的句柄,它被贯穿整个USART收发的流程。
②外设句柄数据类型的组成:
③串口初始化数据类型:
成员变量WordLength的取值范围
宏常量定义 | 含义 |
---|---|
UART_WORDLENGTH_8B | 数据位长度为8位 |
UART_WORDLENGTH_9B | 数据位长度为9位 |
成员变量StopBits的取值范围
宏常量定义 | 含义 |
---|---|
UART_STOPBITS_1 | 停止位长度为1位 |
UART_STOPBITS_2 | 停止位长度为2位 |
成员变量Parity的取值范围
宏常量定义 | 含义 |
---|---|
UART_PARITY_NONE | 无奇偶校验 |
UART_PARITY_EVEN | 偶校验 |
UART_PARITY_ODD | 奇校验 |
成员变量Mode的取值范围
宏常量定义 | 含义 |
---|---|
UART_MODE_RX | 串口仅处于接收模式,只能接收数据,不能发送数据 |
UART_MODE_TX | 串口仅处于发送模式,只能发送数据,不能接收数据 |
UART_MODE_TX_RX | 串口处于接收和发送模式,可以同时收发数据 |
成员变量HwFlowCtI的取值范围
宏常量定义 | 含义 |
---|---|
UART_HWCONTROL_NONE | 无硬件流控 |
UART_HWCONTROL_RTS | 使能“请求发送(RTS)”引脚 |
UART_HWCONTROL_CTS | 使能“允许发送(CTS)”引脚 |
UART_HWCONTROL_RTS_CTS | 使能“请求发送(RTS)”和“允许发送(CTS)引脚 |
成员变量OverSampling的取值范围
宏常量定义 | 含义 |
---|---|
UART_OVERSAMPLING_16 | 采样频率是信号传输频率的16倍 |
UART_OVERSAMPLING_8 | 采样频率是信号传输频率的8倍 |
2.3 外设初始化设计思想
①串口初始化过程:
抽象—串口初始化函数MX_USART2_UART_Init: 将与MCU无关的通信参数存入句柄结构 + 使用HAL_UART_Init执行串口初始化操作,将句柄参数写入寄存器。
HAL_UART_Init 干了哪些事?
调用 HAL_UART_MspInit
修改状态忙
配置寄存器
清除标志位
承载—与MCU相关的初始化函数HAL_UART_MspInit :时钟初始化 + 引脚初始化
3 串口通信方式
轮询方式:CPU不断检测串口的状态标志来判断数据收发的情况。特点:程序设计简单,但CPU在检测标志位期间,无法执行其他任务,CPU利用率较低。
中断方式:使能中断后,接收一字节数据或发送一字节后申请中断,在ISR中完成后续处理。在数据收发期间,CPU可以执行其他任务,CPU利用率较高。
DMA方式:初始化时设置相关参数,启动DMA传输后,数据传输过程不需要CPU的干预。传输完成后,再产生DMA中断,由CPU进行后续处理。传输效率最高。
4 轮询方式的串口通信 ##
-
串口初始化函数:HAL_UART_Init
函数原型 HAL StatusTypeDef HAL_UART_Init (UART_HandleTypeDef *huart) 功能描述 按照串口句柄中指定的参数初始化串口 入口参数 huart:串口句柄的地址 返回值 HAL状态值:HAL_OK表示初始化成功,HAL_ERROR表示初始化失败 注意事项 1.该函数将调用与MCU相关的初始化函数HAL_UART_Msplnit完成时钟、引脚和中断等底层硬件的初始化操作2.该函数由CubeMX自动生成 -
接口函数:HAL_UART_Transmit
函数原型 HAL_StatusTypeDef HAL_UART_Transmit(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size, uint 32_t Timeout) 功能描述 在轮询方式下发送一定数量的数据 入口参数1 huart:串口句柄的地址 入口参数 pData:待发送数据的首地址 入口参数3 Size:待发送数据的个数 入口参数4 Timeout:超时等待时间, 以ms为单位, HAL MAX DELAY表示无限等待 返回值 HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用;HAL_TIMEOUT表示发送超时 注意事项 1.该函数连续发送数据,发送过程中通过判断TXE标志来发送下一个数据,通过判断TC标志来结束数据的发送2.如果在等待时间内没有完成发送,则不再发送,返回超时标志3.该函数由用户调用 -
接口函数:HAL_UART_Receive
函数原型 HAL_StatusTypeDef HAL_UART_Receive(UART_Handle TypeDef *huart, uint 8_t *pData, uint 16_t Size, uint 32_t Timeout) 功能描述 在轮询方式下接收一定数量的数据 入口参数1 huart:串口句柄的地址 入口参数 pData:存放数据的首地址 入口参数3 Size:待接收数据的个数 入口参数4 Timeout:超时等待时间, 以ms为单位, HAL MAX DELAY表示无限等待 返回值 HAL状态值:HAL_OK表示发送成功;HAL_ERROR表示参数错误;HAL_BUSY表示串口被占用;HAL_TIMEOUT表示发送超时 注意事项 1.该函数连续接收数据,接收过程中通过判断RXNE标志来发送下一个数据2.如果在等待时间内没有完成接收,则不再接收,返回超时标志3.该函数由用户调用
5 任务实践1
在PC上利用串口调试助手发送数据到MCU,MCU调用scanf函数读取数据,然后调用printf函数发送应答信息到PC。
串口外设配置
异步模式,无硬件流控
设置通信参数:波特率115200,8位数据位,无奇偶校验,1位停止位,使能接收和发送,16倍过采样(CubeMX默认配置)
在Keil中勾选Use MicroLIB
编写代码
printf和scanf重定向
/* USER CODE BEGIN Includes */
#include < stdio.h >
/* USER CODE END Includes */
int fputc (int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, (uint8_t *)&ch, 1, HAL_MAX_DELAY);
return ch;
}
/* USER CODE END 4 */
用户应用代码——猜数游戏
/* USER CODE BEGIN 3 */
printf("Please guess a number between 0 to 9n");
if (scanf("%d", &guess_num) == 1)
{
if (guess_num == ans)
{
printf("You are right! It's %dn", ans);
}
else
{
printf("You are wrong! It is not %dn", guess_num);
}
}
}
/* USER CODE END 3 */
实验现象