计算机通信: 将计算机技术和通信技术相结合,完成计算机与外部设备或计算机与计算机之间的信息交换。按照数据传输方式的不同,可以分为串行通信和并行通信两类。
串行通信: 数据逐位传输,传输线少,长距离传输时成本低,但数据的传输控制较复杂。按照实现数据同步的方式,可以分为同步串行和异步串行两种。
并行通信: 多位数据同时传输,传输控制简单,传输速度快,但是在长距离传输时硬件成本较高。
异步通信的两个关键点是字符格式和 波特率 ,字符格式决定了数据的传输形式,波特率决定了字符中每一位数据的持续时间。
字符格式
❑ 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个时钟周期;
⑥ 重复此过程,直到所有数据位都被采样和存储;
⑦ 由停止位的上升沿使数据线返回到空闲状态。
串口通信的数据传输方向
错误校验方式
串口收发单元主要利用数据寄存器DR,发送引脚TX,接收引脚RX,以及三个通信状态位TXE、TC和RXNE来完成数据的接收和发送。
数据寄存器DR在硬件上分为TDR和RDR两个寄存器,通过数据的流向进行区分,在结构设计上采用了双缓冲结构;
发送时,数据通过数据总线送入TDR寄存器,然后传送到发送移位寄存器完成数据转换,从并行数据转为串行数据,最后通过TX引脚发送;
接收时,数据通过RX引脚逐位送入接收移位寄存器,8位数据接收完成后,送入RDR寄存器,供用户读取。
USB转TTL串口模块
①外设句柄的定义:
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倍 |
①串口初始化过程:
抽象—串口初始化函数MX_USART2_UART_Init
: 将与MCU无关的通信参数存入句柄结构 + 使用HAL_UART_Init
执行串口初始化操作,将句柄参数写入寄存器。
HAL_UART_Init
干了哪些事?
- 调用
HAL_UART_MspInit
- 修改状态忙
- 配置寄存器
- 清除标志位
承载—与MCU相关的初始化函数HAL_UART_MspInit
:时钟初始化 + 引脚初始化
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.该函数由用户调用 |
在PC上利用串口调试助手发送数据到MCU,MCU调用scanf函数读取数据,然后调用printf函数发送应答信息到PC。
串口外设配置
在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 */
实验现象
全部0条评论
快来发表一下你的评论吧 !