1.串口USART
1.常见的通信方式
1.串行通信和并行通信
串行通信:速度较并行慢,但是占用的硬件资源少,通常只需要时钟线,一两根数据线还 有片选线即可。

并行通信:速度快,但是需要很多根数据线、地址线等。

2.全双工,半双工和单工通信
全双工:同一时刻双方可以互相发送数据、接收数据

半双工:同一时刻只能有一方可以给另外一方发送数据,即此发彼收,此收彼发

单工:只能由发送方数据发送给接收方

3.同步通信和异步通信
同步通信和异步通信都是针对串行通信而言
异步通信
- 数据是以字符为单位组成字符帧传输的。(一个字符,一个字节,八个二进制位)
- 字符帧由发送端一帧一帧的发送,每帧数据均是低位在前,高位在后,通过传输线被接收端一帧一帧的接收。
- 发送端和接收端可以有各自独立的时钟来控制数据的发送和接收,这两个时钟各自独立,互不同步。
- 接收端依靠字符帧格式来判断发送端是何时开始和结束发送的。
- 字符帧也叫做数据帧,由起始位,数据位,奇偶校验位,停止位等部分组成, 是异步通信的一个重要指标。
- 同步通信的另一个重要指标是波特率。
同步通信
- 同步是指在约定的通信速率下,发送端和接收端的时钟信号和相位始终保持一 致,保证通信双方在发送和接收数据时具有完全一致的定时关系。
- 同步通信把许多字符组成一个信息帧,每帧的开始用同步字符来表示。
- 在绝大多数场合下,发送端和接收端,采用的都是同一个时钟,所以在传送数据的同时还要发送时钟信号,以便接收端可以使用时钟信号来确定每一个信息 位。
- 同步通信一次通信只能传送一帧信息。
4.通信速率
对于同步通信,通信速率由时钟信号决定,时钟信号越快,传输速度越快。
对于异步通信来说,需要收发双方提前统一通信速率,这也就是我们串口调试时,波特率不对显示乱码的原因。
- 比特率:系统在单位时间内传输的比特率(二进制0或1)个数,通常用Rb表示,单位是比特(bit/s),缩写为bps。
- 波特率:系统在单位时间内传输的码元个数,通常用RB来表示,单位是波特(Bd)
- 码元有N个状态时,比特率与波特率的关系式:RB=Rb x log2N
5.常见的通信协议
在嵌入式中,有众多的通信协议,往往从性能,成本,稳定性,易用性等角度考虑选择合 适的协议。

2.串口基础知识
1.电平特性



2.串口传输协议
串口设备连接示意图:

参数概念:
- 波特率:一般选波特率都会有9600,19200,115200等选项,其实意思就是每秒传输这么多个比码元。
- 起始位:先发出一个逻辑 '0'的信号,表示传输数据的开始。
- 数据位:可以是5~8位逻辑 "0" 或"1",先传输Bit0,再传输Bit1,以此类推。(先传输低地址位,后传输高地址位)
- 校验位:数据位加上这一位之后,使得"1"的位数应为偶数(偶校验)或者奇数(奇校验),以此来校验数据传送的正确性,校验位是可选的,可以不传输。
- 停止位:它是一个字符数据的结束标志,数据线变回逻辑"1"。
3.STM32F103的USART资源
- STM32103有三个通用同步异步收发器USART,两个通用异步收发器UART,USART 也可以当作UART使用。
- 通常使用的是UART功能,USART在某些场合会使用到,选择通信方式使用场合决定。
- 可以通过电平转化芯片变为RS232/RS485电平。

4.STM32F103的UART框图

端口引脚



-
TX:数据发送端口
-
RX:数据接收端口
-
SW_RX:在单线和智能卡模式下接收数据,属于内部端口,没有实际的外部引脚
-
RTS( (n) Request To Send):在硬件流控制下用于指示设备准备好可以接收数据了,低电平表示可以接收数据。
-
CTS((n) Clear To Send):在硬件流控制下用于指示设备以及发送完数据了,如果是高电平那么在本次数据发送完成后会阻塞下一次的传输,只有在低电平的时候才允许下一次传输。
-
CK:同步时钟端口,在同步通信模式下使用,用于输出同步时钟信号。
数据寄存器单元

- TDR:发送数据寄存器
- RDR:接收数据寄存器
- 在UART外设中只有一个寄存器USART_DR,是一个双向寄存器,取决于CPU是读这个寄存器还是写这个寄存器;如果是读,就是RDR;如果是写,就是TDR。
发送接收控制单元

CR1/CR2/CR3:控制寄存器,控制各种使能,比如UART使能、收发中断使能、DMA 使能等等。
SR:状态寄存器:用来表明UART的收发状态和错误状态等等。
GTPR:Smartcard和IrDA模式下专用的寄存器
波特率发生器

- fPCLK( frequency of the Peripheral Clock):外设总线时钟,USART1在APB1,最高可取72MHZ,剩下四个在APB2,最高可取36MHZ
- USARTDIV( USART Divider):USART/UART时钟分频器
- DIV_Mantissa:BBR寄存器的高12bit,用于存放波特率设置的整数部分
- DIV_Fraction:BRR寄存器的低4bit.用于存放波特率设置值的小数部分,每一位对应 的精度是1/2的四次方 = 0.0625
- 波特率计算公式:baudrate = fPCLK / USARTDIV * 16
1.假设fPCLK = 72MHZ,baudrate = 115200,那么USARTDIV=72MHZ/16/115200 = 39.0625,则DIV_Mantissa = 39<<4 = 0x270,DIV_Fraction=0.0625/0.0625=1,因此 BRR= 0X271
2.假设fPCLK = 72MHZ,baudrate=9600,那么USARTDIV=72MHZ/9600 = 468.75,则 DIV_Mantissa = 468<<4=0x1D40,DIV_Fraction=0.75/0.0625=12=0xC,因而 BRR=0X1D4C
UART框图配置步骤
- 选择需要使用的USART/UART(根据地址映射表得到地址)
- 根据需要的波特率设置BRR寄存器(波特率寄存器)
- 根据需求配置控制寄存器中的停止位和校验位
- 根据需求配置同步时钟使能位
- 使能USART的发送和接收位
- 根据需求使能发送和接收的中断位
- 使能RCC中的选中的USART/UART的时钟
- 使能USART/UART 写USART_DR寄存器发送数据,读USART_DR寄存器接收数据
5.实现串口发送
库函数实现串口发送
串口USART结构体:
typedef struct
{
uint32_t USART_BaudRate;
uint16_t USART_WordLength;
uint16_t USART_StopBits;
uint16_t USART_Parity;
uint16_t USART_Mode;
uint16_t USART_HardwareFlowControl;
} USART_InitTypeDef;
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);void USART_Cmd(USART_TypeDef* USARTx, FunctionalState NewState);
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);
5.软件流程设计
初始化系统
- 初始化GPIO、串口外设时钟
- 初始化串口引脚
- 初始化串口外设
- 使能串口外设
串口发送
cs
//usart.c
#include "stm32f10x.h"
#include "usart.h"
void my_usart_init(void)
{
GPIO_InitTypeDef GPIO_Initstructure;
USART_InitTypeDef USART_Initstructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA,ENABLE);
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_9;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Initstructure.GPIO_Speed = GPIO_Speed_10MHz;
GPIO_Init(GPIOA,&GPIO_Initstructure);
GPIO_Initstructure.GPIO_Pin = GPIO_Pin_10;
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init(GPIOA,&GPIO_Initstructure);
USART_Initstructure.USART_BaudRate = 115200;
USART_Initstructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
USART_Initstructure.USART_Mode = USART_Mode_Tx;
USART_Initstructure.USART_Parity = USART_Parity_No;
USART_Initstructure.USART_StopBits = USART_StopBits_1;
USART_Initstructure.USART_WordLength = USART_WordLength_8b;
USART_Init(USART1,&USART_Initstructure);
USART_Cmd(USART1,ENABLE);
}
cs
//main.c
#include "stm32f10x.h"
#include "main.h"
#include "led.h"
#include "buzzer.h"
#include "key.h"
#include "Relay.h"
#include "Shake.h"
#include "Exti.h"
#include "usart.h"
void delay(uint16_t time)
{
uint16_t i = 0;
while(time --)
{
i = 12000;
while(i --);
}
}
int main()
{
my_usart_init();
while(1)
{
USART_SendData(USART1,'h');
delay(1000);
USART_SendData(USART1,'e');
delay(1000);
USART_SendData(USART1,'l');
delay(1000);
USART_SendData(USART1,'l');
delay(1000);
USART_SendData(USART1,'0');
delay(1000);
}
}

注:
1.SUART的TX(输出引脚)是PA9,所以PA9根据查手册是推挽复用输出。
2.且由于没有校验位,wordlenth是八位。
3.usart需要函数单独使能!


6.功能实现的补充
1.CH340C的双向转换能力
USB协议 ←→ TTL串口协议
电脑语言 单片机语言
1.USB → TTL(电脑到单片机)
电脑发数据 → USB接口 → CH340C转换 → TTL电平 → 单片机接收
2.TTL → USB(单片机到电脑)
单片机发数据 → TTL电平 → CH340C转换 → USB接口 → 电脑接收
CH340C的工作方式:
USART协议有固定格式
CH340C持续监控RXD引脚:
检测到下降沿(3.3V→0V)→ "哦!起始位!开始接收"
按115200波特率采样后续8位
检测到上升沿(停止位)→ "一个字节收完了"
转换成USB数据包发送
2.完整的数据流路径
- 你的代码:
USART_SendData(USART1,'h')
// 这个函数做了两件事:
把字符'h'写入USART数据寄存器(DR)
USART硬件自动开始发送
- STM32内部:USART模块工作
USART硬件自动完成:
从DR寄存器读取'h'的ASCII码(0x68)
添加起始位(0)
按115200速率一位位从TX引脚(PA9)输出
添加停止位(1)
整个过程完全由硬件完成,CPU不用管
- 物理层:PA9引脚输出TTL信号
PA9引脚输出:
┌─┬───┬───┬───┬───┬───┬───┬───┬───┬─┐
│0│1 │0 │1 │1 │0 │0 │0 │0 │1 │ ← 'h'=0x68(二进制01101000)
└─┴───┴───┴───┴───┴───┴───┴───┴───┴─┘
↑起始位0 数据位(LSB在前) ↑停止位1
- CH340C转换:TTL → USB
CH340C实时监控PA9(TX)信号:
检测到起始位下降沿 → 开始接收
采样8个数据位 → 得到0x68
打包成USB数据包
通过USB发送给电脑
- 电脑接收:USB → 显示
电脑收到USB数据包:
CH340驱动解码 → 得到0x68
串口工具显示字符'h'
3. 数据传输的关键
GPIO_Initstructure.GPIO_Mode = GPIO_Mode_AF_PP;
让USART模块的控制信号能到达PA9引脚,而不是让GPIO模块控制。
关键:GPIO_Mode_AF_PP模式让多路选择器切换到USART通道!
当USART_SendData()时,是USART硬件在自动操纵PA9引脚,按串口协议输出标准波形,CH340C检测到这个标准波形就知道是串口数据了!
4.实际信号流
STM32内部:
你的代码 → USART模块 → 多路选择器(AF模式) → PA9引脚
(硬件自动控制波形)
外部电路:
PA9引脚 → 连接到 → CH340C的RXD引脚
(TTL电平信号)
CH340C:
持续监听RXD引脚 → 检测USART波形 → 转换USB