持续关注阿杰在线更新保姆式笔记~~坚持日更

参考资料:

《STM32F1开发指南-库函数版本》- 5.3 usart串口文件夹介绍

                                                            -第9章 串口实验

《STM32中文参考手册V10》-第25章通用同步异步收发器(USART)

 片上外设GPIO配置 --《STM32中文参考手册V10》-8.1.11 外设的GPIO配置

 片上外设对应的GPIO可查询对应的数据手册,如正点原子的精英板可用《STM32F103ZET6

串口通讯(Serial Communication)是一种设备间非常常用的串行通讯方式,因为它简单便捷,因此大部分电子设备都支持该通讯方式,其通讯协议可分层为协议层和物理层。物理层规定通信协议中具有机械、电子功能的特性,从而确保原始数据在物理媒体的传播;协议层主要规定通讯逻辑,统一双方的数据打包、解包标准。通俗的讲物理层规定我们用嘴巴还是肢体交流,协议层规定我们用中文还是英文交流。下面分析一下串口通讯协议的物理层和协议层。

USART(Universal Synchronous/Asynchronous Receiver/Transmitter):通用同步/异步串行接收/发送器

UART(Universal Asynchronous Receiver/Transmitter):通用异步收发传输器

一、串行通信接口背景知识

处理器与外部设备通信的两种方式:

并行通信
   -传输原理:数据各个位同时传输。

   -优点:速度快

   -缺点:占用引脚资源多

串行通信
   -传输原理:数据按位顺序传输。

   -优点:占用引脚资源少

   -缺点:速度相对较慢

串行通信按照数据传送方向,分为:


单工:
           数据传输只支持数据在一个方向上传输

半双工:
           允许数据在两个方向上传输,但是,在某一时刻,只允许数据在一个方向上传输,它实际上是一种切换方向的单工通信;

全双工:
           允许数据同时在两个方向上传输,因此,全双工通信是两个单工通信方式的结合,它要求发送设备和接收设备都有独立的接收和发送能力。

串行通信的通信方式:


同步通信 : 带时钟同步信号传输。
    -SPI,IIC通信接口

异步通信:不带时钟同步信号。

    -UART(通用异步收发器),单总线

常见的串行通信接口:

STM32的串口通信接口:

UART: 通用异步收发器
USART: 通用同步异步收发器

大容量STM32F10x系列芯片,包含3USART2UART

串口通信的三种方式:

1、中断方式进行串口通信

中断方式可以在接收到信息或需要发送数据时产生中断,在中断服务程序中完成数据的接收与发送。相对于查询方式,中断方式的CPU利用率要高。在CPU任务简单的系统中,使用中断方式确实是一种好方法。但是在复杂的系统中,比如移动机器人,处理器需要处理串行口通信,多个传感器数据的采集以及处理,实时轨迹的生成,运动轨迹插补以及位置闭环控制等等任务,牵扯到多个中断的优先级分配问题。为了保证数据发送与接收的可靠性,需要把UART的中断优先级设计较高,但是系统可能还有其他的需要更高优先级的中断,必须保证其定时的准确,这样就有可能造成串行通讯的中断不能及时响应,从而造成数据丢失。

2、DMA方式进行串口通信

DMA是 Direct Memory Access的缩写,意思是“存储器直接访问”,它是一种高速的数据传输操作,允许在外部设备和存储器之间直接读/写数据,即不通过CPU,也不需要 CPU干预。整个数据传输操作是在一个称作DMA控制器的控制下进行的。CPU除了在数据传输开始和结束时做一点处理外,在传输过程中可以进行其他的工作。这样,在大部分时间里,CPU和输入/输出设备都处于并行的操作状态。其基本原理可以查阅教科书,此处不赘述。

3、查询式进行串口通信

查询方式下CPU的负担较重,浪费了处理器的能力,不能够很好的处理其他的事件

UART异步通信方式引脚

-RXD:数据输入引脚。数据接受。

-TXD:数据发送引脚。数据发送。

UART异步通信方式特点: 

l 全双工异步通信。
l 分数波特率发生器系统,提供精确的波特率。
     -发送和接受共用的可编程波特率,最高可达4.5Mbits/s

l 可编程的数据字长度( 8 位或者 9 位);
l 可配置的停止位(支持 1 或者 2 位停止位);
l 可配置的使用 DMA 多缓冲器通信。
l 单独的发送器和接收器使能位。
l 检测标志:① 接受缓冲器  ②发送缓冲器空 ③传输结束标志
l 多个带标志的中断源。触发中断。
l 其他:校验控制,四个错误检测标志。

串口通信过程

STM32串口异步通信需要定义的参数: 

 二、物理层

1.通讯结构
串口通讯的物理层的主要标准是RS-232标准,其规定了信号的用途、通讯接口及信号的电平标准,其通讯结构如下:

在这里插入图片描述

在设备内部信号是以TTL电平标准传输的,设备之间是通过RS-232电平标准传输的,而且TTL电平需要经过电平转换芯片才能转化为RS-232电平,RS-232电平转TTL电平也是如此。

2.电平标准
根据使用的电平标准不同,串口通讯可分为 RS-232标准 及TTL标准,具体标准如下:
在这里插入图片描述

 在电子电路中常使用TTL的电平标准,但其抗干扰能力较弱,为了增加串口的通讯距离及抗干扰能力,使用RS-232电平标准在设备之间传输信息,经常使用MA3232芯片对TTL电平及RS-232电平进行相互转换。

 三、 协议层

1.数据包
串口通讯的数据包由发送设备通过自身的TXD接口传输到接收设备得RXD接口,在协议层中规定了数据包的内容,具体包括起始位、主体数据(8位或9位)、校验位以及停止位,通讯的双方必须将数据包的格式约定一致才能正常收发数据。

在串行通信中,数据在1位宽的单条线路上进行传输,一个字节的数据要分为8次,由低位到高位按顺序一位一位的进行传送。

串口收发数据的单位:字节 (Byte) ,   1Byte = 8 bits , 串口收发数据格式一般为  :1bit 起始位(一般为0)  +  8bits 数据位(一字节)  + 1bit 校验位(可有可无)  + 1bit结束位(一般为1)
在这里插入图片描述

 2.波特率
由于异步通信中没有时钟信号,所以接收双方要约定好波特率,即每秒传输的码元个数,以便对信号进行解码,常见的波特率有4800、9600、115200等。STM32中波特率的设置通过串口初始化结构体来实现。
3.起始和停止信号
数据包的首尾分别是起始位和停止位,数据包的起始信号由一个逻辑0的数据位表示,停止位信号可由0.5、1、1.5、2个逻辑1的数据位表示,双方需约定一致。STM32中起始和停止信号的设置也是通过串口初始化结构体来实现。
4.有效数据
有效数据规定了主题数据的长度,一般为8或9位,其在STM32中也是通过串口初始化结构体来实现的。
5.数据校验
在有效数据之后,有一个可选的数据校验位。由于数据通信相对更容易受到外部干扰导致传输数据出现偏差,可以在传输过程加上校验位来解决这个问题。校验方法有奇校验(odd)、偶校(even)、 0 校验(space)、 1 校验(mark)以及无(noparity)。这些也都可以在串口初始化结构体中实现的。

四、STM32的USART简介

USART(通用同步异步收发器)是一个串行通信设备,可以灵活地与外部设备进行全双工数据交换。有别于 USART 还有一个UART,它是在 USART 基础上裁剪掉了同步通信功能,只有异步通信。简单区分同步和异步就是看通信时需不需要对外提供时钟输出,我们平时用的串口通信基本都是 UART。USART 在 STM32 应用最多莫过于“打印”程序信息,一般在硬件设计时都会预留一USART 通信接口连接电脑,用于在调试程序是可以把一些调试信息“打印”在电脑端的串口调试助手工具上,从而了解程序运行是否正确、如果出错哪具体哪里出错等等。
STM32中一共有5个USART,如示:
在这里插入图片描述

 USART的USB转串口原理图如下:

在这里插入图片描述

USART1的发送和接收端口是事先连接好的,如果要使用其他USART只需要将相应的发送接收端口按图连接好即可。
USART有多个中断请求事件:

在这里插入图片描述

 五、USART功能框图剖析

 下文结合图片看加深理解。
1、功能引脚
TX:发送数据输出引脚。
RX:接收。
SW_RX:数据接收引脚,属于内部引脚。
nRTS:请求以发送,n表示低电平有效。如果使能 RTS 流控制,当USART接收器准备好接收新数据时就会将nRTS变成低电平;当接收寄存器已满时,nRTS将被设置为高电平。该引脚只适用于硬件流控制。
nCTS:清除以发送(Clear To Send),n表示低电平有效。如果使能 CTS流控制,发送器在发送下一帧数据之前会检测 nCTS 引脚,如果为低电平,表示可以发送数据,如果为高电平则在发送完当前数据帧之后停止发送。该引脚只适用于硬件流控制。
SCLK:发送器时钟输出引脚。这个引脚仅适用于同步模式。
USART:下图是STM32F103VET6芯片的USART引脚

USART1的时钟来源于APB2总线时钟,最大频率为72MHZ,其他4个时钟来源于APB1总线时钟,最大频率36MHZ。UART只有异步传输功能,没有SCLK、nCTS和nRTS功能引脚。

2.数据寄存器
USART说数据寄存器(USART_DR)只有低 9 位有效,并且第 9 位数据是否有效要取决于USART 控制寄存器 1(USART_CR1)的 M 位设置,当 M 位为 0 时表示 8 位数据字长,当 M位为 1 表示 9 位数据字长,我们一般使用 8位数据字长。
USART_DR包含了已发送的数据或者接收到的数据。USART_DR实际是包含了两个寄存器,一个专门用于发送的可写 TDR,一个专门用于接收的可读 RDR。当进行发送操作时,往 USART_DR写入数据会自动存储在 TDR内;当进行读取操作时,向 USART_DR读取数据会自动提取 RDR 数据。
TDR和RDR都是介于系统总线和移位寄存器之间。串行通信是一个位一个位传输的,发送时把 TDR 内容转移到发送移位寄存器,然后把移位寄存器数据每一位发送出去,接时把接收到的每一位顺序保存在接收移位寄存器内然后才转移到 RDR。
USART 支持 DMA 传输,可以实现高速数据传输。

3.控制器
USART有专门控制发送的发送器、控制接收的接收器,还有唤醒单元、中断控制等。
使用USART之前需要向USART_CR1寄存器的UE位置1使能USART,UE位用于开启供给串口的时钟。发送或者接收数据字长可选8或9位,由USARTT_CR1的M位控制。
1)发送器
当USART_CR1寄存器的发送使能位TE置1时,启动数据发送,发送移位寄存器的数据会在TX引脚输出,低位在前,高位在后。如果是同步模式SCLK也输出时钟信号。
一个字符帧发送需要3部分:起始位、数据帧、停止位。起始位是一个位周期的低电平,位周期就是每一位占用的时间 ;数据帧就是我们要发送的8或9位数据,数据是最低位开始传输的;停止位是一定时间周期的高电平。
停止位的时间长短可以通过USART控制寄存器2(USART_CR2)的STOP[1:0]位控制,可选0.5个、1个、1.5个、2个停止位。默认使用1个停止位。2个停止位适用于正常USART模式、单线模式和调制解调器模式。0.5和1.5个停止位用于智能卡模式。
当发使能位TE置1之后,发送器开始会发送一个空闲帧(一个数据帧长度的高电平),接下来就可以往USART_DR寄存器写入要发送的数据。在写入最后一个数据后,需等待USART状态寄存器(USART_SR)的TC位为1,表示数据传输完成。USART_CR1寄存器的TCIE位置1,则产生中断。
发送数据时,几个重要的标志位如下:
TE:发送使能。
TXE:发送寄存器为空,发送单个字节时使用。
TC:发送完成,发送多个字节数据时候使用。
TXIE:发送完成中断使能。
2)接收器
将CR1寄存器的RE位置1,使能USART接收,使得接收器在RX线开始搜索起始位。在确定起始位后,就根据RX线电平状态把数据存放在接收移位寄存器内。接收完成后就把接收移位寄存器的数据移到PDR内,并把USART_SR寄存器的RXNE位置。如果USART_CR2寄存器的RXNEIE置1可以产生中断。
接收数据时,几个重要的标志位如下:
RE: 接收使能。
RXNE:读数据寄存器非空。
RXNEIE:发送完成中断使能。

4.小数波特率生成
USART 的发送器和接收器使用相同的波特率。计算公式如下:

其中,f PLCK 为 USART 时钟, USARTDIV 是一个存放在波特率寄存器(USART_BRR)的一个无符号定点数。其中 DIV_Mantissa[11:0]位定义 USARTDIV 的整数部分,DIV_Fraction[3:0]位定义 USARTDIV 的小数部分。
例如:DIV_Mantissa=24(0x18),DIV_Fraction=10(0x0A),此时 USART_BRR 值为0x18A;那么USARTDIV的小数位10/16=0.625;整数位24,最终USARTDIV的值为24.625。
如果知道 USARTDIV 值为 27.68,那么 DIV_Fraction=16*0.68=10.88,最接近的正整数为 11,所以 DIV_Fraction[3:0]为 0xB;DIV_Mantissa=整数(27.68)=27,即为 0x1B。
波特率的常用值有 2400、9600、19200、115200。下面以实例讲解如何设定寄存器值得到波特率的值。
我们知道 USART1 使用 APB2 总线时钟,最高可达 72MHz,其他 USART 的最高频率为 36MHz。我们选取 USART1 作为实例讲解,即 f PLCK =72MHz。为得到 115200bps 的波特率,此时:

115200 =72000000/(16 ∗ USARTDIV)

解 得 USARTDIV=39.0625 , 可 算 得 DIV_Fraction=0.0625*16=1=0x01 ,DIV_Mantissa=39=0x27,即应该设置 USART_BRR 的值为 0x171。

5.校验控制
STM32F103系列控制器USART支持奇偶校验。使用校验位时,串口传输的长度将在8位数据帧上加上1位的校验位,总共9位,此时USART_CR1寄存器的M位需要设置位1,即9数据位。将USART_CR1寄存器的PCE位置1就可以启动奇偶校验控制,奇偶校验由硬件自动完成。启动了奇偶校验控制之后,发送数据帧时会自动添加校验位,接收数据自动验证校验位。接收数据时如果出现奇偶校验位验证失败,会将USART_SR寄存器的PE置1,并可以产生奇偶校验中断。
使用了奇偶校验控制位后,每个字符帧的格式变成了:起始位+数据帧+校验位+停止位。

6.中断控制

六、开发板与上位机的连接

开发板与上位机之间通过USB线连接,所以在上位机上要配置一个USB转串口 的驱动,以便把USB传输过来的电平转换为TTL电平,TTL电平才能与串口调试助手建立联系。一般使用CH341驱动作为win10下的USB转串口,驱动安装成功的情况下接入USB会在计算机的设备管理器的端口中发现串口:
在这里插入图片描述

七、STM32串口常用寄存器和库函数

 八、串口配置一般步骤

①  串口时钟使能,GPIO时钟使能:  RCC_APB2PeriphClockCmd(); rcc.h->693
②   串口复位:USART_DeInit(); 这一步不是必须的
③  GPIO端口模式设置: GPIO_Init(); gpio.h->351
      模式设置为GPIO_Mode_AF_PP--》具体模式设置查看手册
④  串口参数初始化: USART_Init();  _usart.h->366
⑤  使能串口: USART_Cmd();            _usart.h->370
⑥  开启中断:USART_ITConfig();  _usart.h->371

⑦  初始化NVIC(如果需要开启中断才需要这个步骤)

      NVIC_Init();                                misc.h->197

      -->凡是使用中断都要开启NVIC

》编写中断处理函数:USARTx_IRQHandler();startup_stm32f10x_hd.s->117

》串口数据收发:

void USART_SendData();//发送数据到串口,DR 

uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据

》串口传输状态获取:

FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);

_usart.h->371

void USART_ClearITPendingBit(USART_TypeDef* USARTx, uint16_t USART_IT);

九、代码区

#include "led.h"
#include "delay.h"
#include "beep.h"
#include "sys.h"
#include "key.h"
 
 
void My_USART1_Init(void)
{
    GPIO_InitTypeDef GPIO_InitStrue;
    USART_InitTypeDef USART_InitStrue;
    NVIC_InitTypeDef NVIC_InitStrue;
    
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//GPIOA时钟 rcc.h->693
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1
    
    //USART1_TX   GPIOA.9
    GPIO_InitStrue.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
    GPIO_InitStrue.GPIO_Pin = GPIO_Pin_9;
    GPIO_InitStrue.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA,&GPIO_InitStrue);//gpio.h->351
    
    //USART1_RX      GPIOA.10初始化
    GPIO_InitStrue.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
    GPIO_InitStrue.GPIO_Pin = GPIO_Pin_10;
    GPIO_InitStrue.GPIO_Speed = GPIO_Speed_10MHz;
    GPIO_Init(GPIOA,&GPIO_InitStrue);//gpio.h->351
    
    //USART 初始化设置
    USART_InitStrue.USART_BaudRate = 115200;//串口波特率
    USART_InitStrue.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
                                            //无硬件数据流控制
    USART_InitStrue.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//收发模式
    USART_InitStrue.USART_Parity = USART_Parity_No;//无奇偶校验位
    USART_InitStrue.USART_StopBits = USART_StopBits_1;//一个停止位
    USART_InitStrue.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
    USART_Init(USART1,&USART_InitStrue);//_usart.h->366
    
    USART_Cmd(USART1,ENABLE);//串口使能 _usart.h->370
    
    USART_ITConfig(USART1,USART_IT_RXNE,ENABLE);//打开接受中断 _usart.h->371
    
    //Usart1 NVIC 配置
    NVIC_InitStrue.NVIC_IRQChannel = USART1_IRQn;
    NVIC_InitStrue.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
    NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority = 1;//抢占优先级1
    NVIC_InitStrue.NVIC_IRQChannelSubPriority = 1;//子优先级1
    NVIC_Init(&NVIC_InitStrue);//根据指定的参数初始化VIC寄存器 misc.h->197
}
 
void USART1_IRQHandler(void)//startup_stm32f10x_hd.s->117
{
    u8 res;
    if(USART_GetITStatus(USART1,USART_IT_RXNE))//判断是否为接受中断类型,
         //_usart.h->371              为避免任何中断打开都来执行下面的语句体
    {                                                                                    
        res = USART_ReceiveData(USART1); //单片机(下位机)读取接收到的数据 _usart.h->379
        USART_SendData(USART1,res);      
        //单片机(下位机)向串口1(即上位机 通过串口调试助手显示出来)发送数据 _usart.h->378
    }
}
 
int main(void)
{    
    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
    //配置NVIC需分组 系统运行后先设置中断优先级分组 misc.h->196
    My_USART1_Init();
    while(1);
}