STM32 串口通信①:USART 全面理解 + 代码详解

一 前言

本篇文章并不会系统的从零开始讲起,适合大家对USART有一定的学习,再看本篇文章会有一定的收获,祝大家在本文中,吸收到新的知识。

二 通信方式

1)按数据传输的方式分(这就是"串行 vs 并行")

(1)串行通信

串行通信:是指数据一位一位地按顺序传输,比如我们常见的 UART、USART、SPI、I2C 等都是串行通信。这种方式的优点是连线少,成本低,尤其适合远距离传输和资源受限的场合。

特点:速度较慢,硬件连接简单,数据线只有一根,

(2)并行通信

并行通信:是同时传输多个位,比如计算机内部的总线、老式的并口打印机接口等。这种方式的数据吞吐量大,但需要更多的连线和同步机制,通常用于短距离和高速数据传输。

特点:速度较快,需要更多的数据线

不知道大家有没有这样一个疑问:

大家再看串行通信这里的举例,USART、UART他不是连接了四根线,其中两根数据线吗,分别是Rx、Tx吗,你怎么就能说他们俩是串行通信呢?

答:大家想的确实没错,但是在实际的硬件连接中,像 UART 或 USART 这样的串行通信确实会有四根线:VCC(电源)、GND(地线)、TX(发送)、RX(接收)。其中 TX 和 RX 是用于数据传输的两根线。

我之前说的"串行通信只有一根数据线"其实是指数据在一根线上按位串行传输,而不是像并行通信那样同时在多条线上并行传输多个位。TX 和 RX 是串行通信中用于发送和接收的两根数据线,数据是按位依次传输的。 所以,串行通信的"串"是指数据在一条数据线上按顺序传输,而并不是指有多少根物理线。

2)按通信方向分(这就是"单工/半双工/全双工")

类型 特点 举例
单工 只能单向通信 收音机(只能接收)
半双工 双向通信但不能同时进行 对讲机(你说我听,不能同时)
全双工 双向通信可同时进行 电话、UART串口

3)按时钟控制方式分(这就是"同步 vs 异步")

类型 特点 举例
同步通信 依靠共享时钟信号,时序精确 SPI、USART 同步模式
异步通信 没有时钟线,靠起始位/停止位来同步 UART、USART 异步模式

在这里就要引出我们本文的主角了,USART

三 USART

大家有没有经常搞混USART和UART呢,我简单的给大家找一下相关的数据和分类,

UART 是一种"异步串行通信协议";
USART 是 STM32 中的"通用同步/异步串口外设",它能实现 UART,也能实现更多。

UART能干的,USART就给他干完了,所以USART我们更常用。我们平常说的UART说的应该就是USART下的UART模式,他叫异步串行通信。

下两张表是他们所对应的模式

USART:

模式名称 描述
UART 模式 异步串行通信,最常用的方式,用 TX/RX 就行
同步模式 增加了一个时钟引脚(CK),用于同步通信(类似 SPI)
单线半双工模式 只有一根数据线,TX 和 RX 复用(比如红外通信)
智能卡模式 主要用来对接智能卡协议(ISO 7816),包含特定帧结构和校验要求
IrDA 模式 红外通信协议,STM32 USART 支持内建调制和解调
LIN 模式 本地互连网络(Local Interconnect Network),汽车中常用的低速通信协议
DMX 模式(高级型号) 灯光控制系统协议(部分高级芯片才有)

UART:

功能 有/无
异步通信(TX/RX)
同步通信(带时钟)
IrDA / LIN / Smartcard

大家观看上面这两张表,大家也能发现,USART要比UART的功能更加的强大,而我们更常用USART下的UART模式,也就是我们最经常接触的有Rx、Tx引脚的串口器件,USB转TTL电平的模块,如图:

在这里要特别说明一点:如果用异步的通信就一定会包含起始位、停止位、校验位、数据位,如果想要保证异步通信的准确性,就需要这些去判断,而不像同步通信,同步通信靠的是标准的时钟信号CLK

四 基础概念

1)波特率和比特率

比特率Bit Rate:每秒传输了多少个 0 或 1,传输了几位二进制的数

波特率 Baud Rate:传输的是码元,码元是用来承载比特的容器

情况 每个码元代表多少比特 举例说明
简单二进制通信 1 bit 一个码元只有两种状态(0 或 1)
QPSK(四相移键控) 2 bits 一个码元表示 00、01、10、11

这里说的码元,并不是固定死的,他是人为可以规定的,在今天的串口和未来几天关于蓝牙HC-05的讲解,都是将一个码元表示成 1 个比特,也就是说,最近我写的博客中,都是比特率=波特率。

2)通信接口

前文提到的USB转TTL电平模块,要简单说一下,USB是电脑的接口,TTL是单片机引脚的电平,但是电脑和单片机之间是没法进行交流的。

🧑‍💻【电脑】 ---(USB)→ ❓ →(TX/RX)---【单片机】

中间得来个"翻译官"------这就是我们说的 USB转TTL模块

关于通信接口,还有两个分别是RS232\RS485,这里我并没有研究太深,大家感兴趣的,自己研究就行。

3)复用功能、重映射

说实话这两个我是经常搞混,我给大家进行一个总结,希望大家不要重走我的苦

复用功能;也总说成复用引脚,他就是可以实现同一个引脚可以干很多事情,给大家举个例子,大家可以翻开"stm32f10x中文参考手册"的第118页、120页,在PA9这个引脚上,不仅可以是定时器1通道2还可以是USART1_Tx

如果出现了这个复用引脚,那么我们在配置GPIO结构体的时候,就要选择AF,例如:GPIO_Mode_AF_PP。大家能明白为什么要有复用推挽复用开漏的功能了吧?

接下来讲重映射:

重映射是将外设的某个功能换个引脚来使用。

你原本以为串口只能走 PA9/PA10 ,结果它说:"不,我还能走 PB6/PB7,只要你设置一下重映射就行!"

这样不就能解决引脚冲突,让资源分配更灵活了嘛。

REMAP=0是默认,REMAP=1是重映射到对应的引脚。一旦要有重映射我们就要在代码中配置一个复用时钟函数,如下图:

重映射中还有部分重映射、完全重映射,给大家总结好表格,大家自行阅读。

类型 说明
默认映射 比如 USART1 默认映射在 PA9 / PA10
部分重映射 比如 TIM2 可以从 PA0/PA1 映射成 PA15/PB3(只改部分)
完全重映射 所有引脚全部换一组,比如 TIM3 从 PA6/PA7/PC6 映射成 PC8/PC9/PB0

五 代码讲解

以上关于知识点就到此为止了,代码相关的知识便会很简单,usart.c代码

关于USART中UART模式的硬件代码配置如下,我是利用了中断,大家如果不想用中断也可以,只需将相应的代码删除即可~

PA9--Tx发送,在这里的发送可就用到了第四部分的复用功能哦,AF_PP,翻阅前文即可

PA10--Rx接收

cs 复制代码
	usart_structure.USART_BaudRate = 115200;
	usart_structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	usart_structure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	usart_structure.USART_Parity = USART_Parity_No;
	usart_structure.USART_StopBits = USART_StopBits_1;
	usart_structure.USART_WordLength = USART_WordLength_8b;

波特率、校验位、模式等等,这里就是异步通信的标准了,需要把他们都配齐才可以。

为什么这里中断是RXNE呢?首先我们需要了解一下整个过程:

在这里说一下数据是怎么写进去的,首先发送一个数据,也就是库函数中的void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);这个意思就是将数据发送给数据寄存器TDR中,一旦数据写TDR中,TXE的标志位就会被清零,表示"发送数据寄存器"正在用。随后TDR中的数据转移到移位寄存器中(shift register),此时,TDR空了,也就代表着TXE重新置位,告诉数据可以发下一个数据给TDR了。

此时来到移位寄存器,移位寄存器要发送数据,这里发送是通过Tx引脚一位一位 的发送,包括了整个字节,起始位、数据位、校验位、停止位,等待发送完毕即可

常用三个东西,TXE、TC、RXNE

发送数据,需要用这个,TDR空,则用TXE(TXE=1)
判断数据整个过程(字符串)是否发送完成,则用TC
当你的设备需要从外部接收数据(RDR),中断处理,则用RXNE

cs 复制代码
#include "usart.h"
#include "stm32f10x.h"                  // Device header
#include "stdio.h"


//普通uart
void my_usart_Config(void)
{
	GPIO_InitTypeDef GPIO_structure;
	USART_InitTypeDef usart_structure;
	NVIC_InitTypeDef NVIC_structure;

  NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  RCC_APB2PeriphClockCmd( RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);

	//PA9--Tx,发送
	GPIO_structure.GPIO_Mode = GPIO_Mode_AF_PP;
	GPIO_structure.GPIO_Pin = GPIO_Pin_9;
	GPIO_structure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init( GPIOA, &GPIO_structure );
	
	//PA10--Rx,接收
	GPIO_structure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
	GPIO_structure.GPIO_Pin = GPIO_Pin_10;
	GPIO_structure.GPIO_Speed = GPIO_Speed_50MHz;
  GPIO_Init( GPIOA, &GPIO_structure );	
	
	usart_structure.USART_BaudRate = 9600;
	usart_structure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
	usart_structure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;
	usart_structure.USART_Parity = USART_Parity_No;
	usart_structure.USART_StopBits = USART_StopBits_1;
	usart_structure.USART_WordLength = USART_WordLength_8b;
  USART_Init(USART1, &usart_structure);
  USART_Cmd( USART1,ENABLE);
  USART_ITConfig( USART1,USART_IT_RXNE,ENABLE);	//RXNE,接收数据寄存器不空

	NVIC_structure.NVIC_IRQChannel = USART1_IRQn;
	NVIC_structure.NVIC_IRQChannelCmd = ENABLE;
	NVIC_structure.NVIC_IRQChannelPreemptionPriority = 1;
	NVIC_structure.NVIC_IRQChannelSubPriority = 0;
  NVIC_Init(&NVIC_structure);
	
	
}


//发送寄存器TDR,移位寄存器shift register
//发送一个字节ascii码的值
void My_Usart_Send_Byte(USART_TypeDef* USARTx, uint16_t Data)
{
	
  USART_SendData( USARTx,  Data);//写到TDR中
  while( USART_GetFlagStatus( USARTx,  USART_FLAG_TXE) == RESET);
	//txe,发送数据的寄存器空了,移位寄存器已经空了
}

//发送字符串
void My_Usart_Send_String(USART_TypeDef* USARTx, unsigned char *str)
{
	 uint16_t i =0;
	
	do
	{
			My_Usart_Send_Byte( USARTx,  *(str + i));
			i++;
		
	}while(*(str + i) != '\0');
	
  while( USART_GetFlagStatus( USARTx,  USART_FLAG_TC) == RESET);
	//tc,数据已经彻底全部发送完成了
	
	
}


//发送汉字
int putc(int ch, FILE *p)
{
	  USART_SendData( USART1,  (u8)ch);
	  while( USART_GetFlagStatus( USART1,  USART_FLAG_TXE) == RESET);
	
	return ch;

}
相关推荐
Invinciblenuonuo1 小时前
STM32八股【10】-----stm32启动流程
stm32·单片机·嵌入式硬件
hahaha60163 小时前
RK3588和FPGA桥片之间IO电平信号概率性不能通信原因
单片机·嵌入式硬件·fpga开发
茯苓gao6 小时前
STM32G4 电机外设篇(三) TIM1 发波 和 ADC COMP DAC级联
stm32·单片机·嵌入式硬件
君鼎6 小时前
STM32——CAN总线
stm32·单片机·嵌入式硬件
阿川!6 小时前
嵌入式软件--stm32 DAY 8.5 基础复习总结
stm32·单片机·嵌入式硬件
小猪写代码10 小时前
STM32中,如何理解看门狗
stm32·单片机·嵌入式硬件
Lester_110110 小时前
嵌入式学习笔记 - STM32 HAL库以及标准库内核以及外设头文件区别问题
笔记·stm32·单片机·学习
小智学长 | 嵌入式11 小时前
SOC-ESP32S3部分:23-文件系统
单片机·esp32
不脱发的程序猿12 小时前
MCU如何从向量表到中断服务
单片机·嵌入式硬件
仰泳之鹅15 小时前
【STM32F1标准库】理论——定时器/计数器中断
stm32·单片机·嵌入式硬件