本文章针对于STM32F401RET6来学习串口知识。
UART简介
说到串口,我们一般会想到串口通信,而串口用于单片机与PC机之间进行通信,而两者之间进行数据交流遵循串口通信协议。
什么是通信协议?
两个设备或者芯片之间进行数据交流的一种规则。
有线通信:网线 USB HDMI DB9 IIS 电话线
特点:布线麻烦 稳定性较稳 抗干扰能力比较强 距离取决线长
无线通信:WiFi 蓝牙 NFC 红外 2/3/4/5G NB-Iot Lora Zigbee……
特点:信号稳定性比较不稳定 容易收到干扰 距离较短
串口通信协议
UART:通用异步收发传输器(Universal Asynchronous Receiver/Transmitter)
UART在STM32钟是作为一个片上外设的存在,而它则被用来与其他设备之间进行信息交流的一个器件,而通信之间则需要协议。
那么为什么需要协议呢?
在整个通信过程中,有可能是多设备,多种通道复杂的通信交流,比如:各国之间的语言交流,两个人进行讲话交流需要同一种语言,这就是一种规范。
同步通信:两个设备之间进行信息交换时,既有一根数据线还有一根同步时钟线(时钟线调节两个设备的收发数据的同步)
异步通信:两个设备指甲剪进行信息传输时,只有一根数据线,没有时钟线,位与位之间的传输几乎同步
接收器:接受信息的一端
发送器:发送信息的一端
单工:两个设备之间做通信时、一台设备只能做接收器或者发送器(一根数据线)
半双工:两个设备之间做通信时、同一时刻一台设备只能做接收器或者发送器(一根数据线)
全双工:两个设备之间做通信时、同一时刻一台设备既能做接收器也能做发送器(两根数据线)
并行通信:
并行通信传输中有多个数据位,同时在两个设备之间传输。发送设备将这些数据位通过对应的数据线传送给接收设备,还可附加移位数据校验位。接受设备可同时接收到这些数据,不需要做任何变换就可直接使用。并行方式主要用于近距离通信。
例:计算机内的总线结构
优点:传输速度快,处理简单
缺点:各数据位传输速率有差异会妨碍数据对齐,一个数据位完成发送还要等待其他数据发送完成
串行通信:
串行数据传输时,数据是一位一位地在通信线上传输的,先由具有几位总线的计算机内的发送设备,将几位并行数据经并–串转换硬件转换成串行方式,再逐位经传输线到达接收站的设备中,并在接收端将数据从串行方式重新转换成并行方式,以供接收方使用。串行数据传输的速度要比并行传输慢得多,但对于覆盖面极其广阔的公用电话系统来说具有更大的现实意义
常见的串行通信:直接相连、232、DB9、USB转串口
直接相连:一台设备的发送端口(Tx)直接连接另一台设备的接受端口(Rx)
232:电平协议 负逻辑电平
485:电平协议 差分传输(A B两线) AB线之间的压差决定逻辑0/1
抗干扰能力强
红色的线A向B发送数据 蓝牙的线是B向A发送数据
DB9:
USB转串口:
电脑与芯片(MCU)通信
USB线一端接到电脑、一端接MCU接IO口
转换芯片:CH340 CP2102……
USB信号:UD+/UD-
UD+:直接连接到USB总线的D+数据线
UD-:直接连接到USB总线的D-数据线
物理层面
USART1_TXD与CP2102_RXD短接
USART1_RXD与CP2102_TXD短接
数据帧格式
空闲电平:高
起始位:拉低 1位
数据位:5~8位(上位机) ST芯片8~9位 只能选8位进行通信
校验位:奇偶校验 奇校验 偶校验 数据位的0/1个数
例如:原始数据1010 1010
传输数据1010 1000(校验错误)
传输数据1010 0000(校验正确)
校验正确率不高、一般不使用的
停止位:0.5~2位 拉高
空闲位到起始位拉低电平表示传输数据开始,到停止位拉高电平表示数据传输结束。
UART四要素
异步通信时,上位机与芯片保持一致
波特率:传输速率 例如115200 1s传输115200位数据
STM32的UART
TM32F401RET6有三个USART
USART1/USART6挂靠在APB2上、时钟大小84MHz
USART2挂靠在APB1上、时钟大小42MHz
STM32的UART介绍(STM32f401参考手册)
通用同步异步收发器 (USART) 能够灵活地与外部设备进行全双工数据交换,满足外部设备对工业标准 NRZ 异步串行数据格式的要求。 USART 通过小数波特率发生器提供了多种波特率
STM32的串口模块工作流程
IO口与PC之间由转换芯片连接
STM32的UART特征
全双工异步通信
16倍/8倍的过采样
1位/2位的停止位
8/9位的数据位
框架分析
收发原理
想要数据的正常收发必须保证接收移位寄存器与发送移位寄存器正常工作
想要接收移位寄存器与发送移位寄存器正常工作必须保证接收器与发送器控制正常工作
寄存器控制描述
想要接收器与发送器控制正常工作需要保证寄存器正常工作
波特率控制原理
波特率计算:
BRR寄存器中需要填入DIV的值、计算DIV的整数与小数部分
USARTDIV=Fck/(8*(2-OVER8))/BRR
以USART1为例
FCK:84MHz
OVER8:在16倍过采样下等于0、在8倍过采样下等于1
BRR:与上位机保存一致
USARTDIV本质就是一个分频比
如84MHz的频率要想得到波特率为115200,分频比为浮点数
void boud(u32 brr)
{
float div; //分频比
u32 div_m,div_f; //div_m:DIV整数部分,div_f:DIV小数部分
div = 84000000.0/16/brr;
div_m = (u32)div;
div_f = (div-div_m)*16+0.5 //小数放不进BRR寄存器,则将之乘上过采样倍数,再进行四舍五入
USART1->BRR |= div_m | div_f;
}
STM32的UART寄存器
STM32的UART实验
USART1_TX:PA9 复用推挽输出
USART1_RX:PA10 复用模式
需要在GPIO复用寄存器中写入AF0~15
写入的具体值参考7.3.2IO引脚复用器与映射
UART功能初始化流程
- 打开时钟(PA USART1)
- 配置IO模式
- 计算波特率
- 接收器使能/发送器使能
- 不需要奇偶校验
- 字长
- 过采样
- 停止位
- 使能
void Uart_Config(u32 brr)
{
float div;
u32 div_m,div_f; //div_m 分频整数部分 div_f分频比小数部分
RCC->AHB1ENR |= (1<<0); //打开GPIOA时钟
RCC->APB2ENR |= (1<<4); //打开USART1时钟
GPIOA->MODER &= ~(0xf<<18); //清零PA9/PA10
GPIOA->MODER |= (0xa<<18); //GPIOA复用功能模式
GPIOA->OTYPER &= ~(3<<9); //输出推挽模式
GPIOA->AFR[1] |= (7<<4); //PA9 复用功能高位寄存器(UART1 AF7)
GPIOA->AFR[1] |= (7<<8); //PA10 复用功能高位寄存器(UART1 AF7)
div = 84000000.0/16/brr; //84MHz 16倍过采样
div_m = (u32)div;
div_f = (div-div_m)*16+0.5;
USART1->BRR |= (div_m<<4)|div_f;
//CR1寄存器配置
USART1->CR1 |= (1<<2); //接收器使能
USART1->CR1 |= (1<<3); //发送器使能
USART1->CR1 &= ~(1<<10); //禁止奇偶校验
USART1->CR1 &= ~(1<<12); //字长 8数据位
USART1->CR1 &= ~(1<<15); //16倍过采样
//CR2寄存器配置
USART1->CR2 &= ~(3<<12); //1个停止位
USART1->CR1 |= (1<<13); //USART1使能
}
取消半主机状态代码:
#pragma import(__use_no_semihosting_swi) //取消半主机状态
struct __FILE { int handle; /* Add whatever you need here */ };
FILE __stdout;
int fputc(int ch, FILE *f)
{
while((USART1->SR &(0X01<<7))==0); //等待之前的数据发送完毕
USART1->DR=ch;
return (ch);
}
int ferror(FILE *f) {
/* Your implementation of ferror */
return EOF;
}
void _ttywrch(int ch) {
while((USART1->SR &(0X01<<7))==0);
USART1->DR=ch;
}
void _sys_exit(int return_code) {
label: goto label; /* endless loop */
}
若不想写取消半主机状态代码
可再keil软件中勾选