Bootstrap

STM32片上资源:USART

1.通信接口

(1)通信目的:将一个设备的数据传输到另外一个设备,开展硬件系统。

(2)通信协议:指定通信的规则,通信双方按照协议规则进行数据收发。

名称引脚双工时钟电平设备
USARTTX(数据发送引脚),RX(数据接收引脚)全双工异步单端点对点
I2CSCL(时钟线),SDA(数据线)半双工同步单端多设备
SPISCLK(时钟线),MOSI(主机输出引脚),MISO(主机输入引脚),CS全双工同步单端多设备
CANCAN_H(差分数据脚),CAN_L(差分数据脚)半双工异步差分多设备
USBDP(D+差分数据脚),DM(D-差分数据脚)半双工异步差分点对点

名词解释:

(1)双工模式:1.全双工:指通信双方能够同时进行通信。(一般有两根通信线)

                           2.半双工:值通信双方只能进行一方对另一方通信,不可双向同时通信。(一

                                                根数据线)

                          3.单工:指数据只能从一个设备到另一个设备,而不能反着来。

(2)时钟模式(作用:比如发送一个波形高电平然后低电平,接收后,如何知道是1100还是10,这时需要一个时钟信号)告诉接收方,什么时候需要接收数据。)

        1.同步通信:要求接收端时钟频率和发送端时钟频率一致,发送端发送连续的比特流。

        2.异步通信:不要求接收端时钟和发送端时钟同步,发送端发送完一个字节后,可经过任意长的时间间隔再发送下一个字节。

        补充:如何判断同步异步:看是否有单独的时钟线,接收方可在时钟信号的指引下进行选择。

(3)电平特性

        1.单端信号:引脚的高低电平是对GND的电压差,所以单端信号的双方必须要共地,就是双方的GND接在同一给地上。

        2差分信号:靠两个差分引脚的电压差来传输信号,在通信时,不需要接GND。

(4)设备特性

        1.点对点:只需双方直接传数据。

        2.多设备:一方对多方,对多方需要有一个寻址的过程,以确定通信的对象。

2.串口通信

(1)串口是一种应用十分广泛的通讯接口,串口i成本低,容易使用,通信线路简单,可实现两个设备的相互通信。

(2)单片机的串口可以是单片机以单片机,单片机与电脑,单片机与各种各样的模块相互通信,极大的扩展了单片机的应用范围,增强了单片机系统的硬件实力。

2.1串口通信的硬件电路

(1)简单双向串口通信,有两根通信线(发送端TX,接收端RX)

(2)TX与RX要交叉连接。

(3)当只需要单向的数据传输时,可以只接一根通信线。

(4)电平标准不一致时,需要加电平转化芯片。

注:

(1)VCC与GND是供电。TX与RX是通信引脚

(2)TX与RX使用的是TTL电平。TX与RX是单端信号,高低电平是相当于GND的,所以,严格上说,GND也算通信线。

2.2 电平标准

电平标准是数据1与数据0的表达方式,是传输线缆中人为规定的电压和数据的对应关系,串口常用的电平标准有如下三种。

2.2.1 电平标准——TTL电平

+3.3v 或 +5v 表示 1

0v 表示 0

注:如果5v器件就使用5v,3.3v器件就使用3.3v

2.2.2 电平标准——RS232电平

-3v ~ -15v 表示 1

+3v ~ +15v 表示 0

注:RS232一般用在大型器件上。

2.2.3 电平标准——RS485电平

注:RS485是差分信号。

两线压差 +2 ~ +6 表示 1

两线压差 -2 ~ -6 表示 0 

优点:抗干扰能力强,通信距离远。

2.3 串口参数及时序

(1)波特率:串口通信的速率。(在二进制下,一个码元为一个Bit,此时波特率 = 比特率 ,若波特率为1000bps,则串口发送速度为1s发1000位)

(2)起始位:标志一个数据帧的开始,固定位低电平(产生下降沿,告诉接收方我要发数据了

(3)数据位:数据帧的有效载荷,1位高电平,0位低电平,低位先行。

(4)校验位:用于数据验证,根据数据位计算得来。

(5)停止位:用于数据帧间隔,固定位高电平。(产生高电平,告诉接收方我要停止了

示意图:

2.4 补充:奇偶校验

奇偶校验:用于判断数据传输是否出错。

校验方式:1.无校验

                  2.奇校验

                  3.偶校验

校验原理(奇校验为例):在数据位9位的数据帧中,第9位为奇偶校验位,保证发送的数据帧的高电平个数为奇数,如果前八位为0x0F,即00001111,则校验位给0,如果前八位为0x1F,即00011111,则校验位给1。接收方接收到数据后,判断数据帧1的个数,如果为奇,则接收,若为偶,则选择丢弃或重传。

3.USART简介

(1)USART(Universal        Synchronous/Asynchronous        Receiver/Transmitter)

                            通用                        同步/异步                                收/发  器

(2)USART是STM32内部集成的硬件外设,可根据寄存器的一个字节数据自动生成数据帧时序,从TX引脚发送出去,也可自动接收RX引脚的数据帧时序,拼接为一个字节数据,存放在数据寄存器里。USART电路功能

(3)自带波特率发生器;最高达4.5Mbits/s。

(4)可配置数据位长度(8/9),停止位长度(0.5/1/1.5/2)

(5)可选校验位(无校验奇校验偶校验

(6)支持同步模式,硬件流控制,DMA,智能片,IrDA,LIN。

(7)STM32F103C8T6的USART资源:USART1,USART2,USART3。其中USART1在APB1上,USART2和USART3在APB2上。

(8)串口发送:低位先行

注:

(1)USART的同步模式只是多个时钟输出,且只支持时钟输出,不支持时钟输入。(不支持两个USART之间进行同步通信,所以这个模式更多是为了兼容别的协议或特殊用途而设计的)

(2)波特率发生器:实际上是一个时钟,比如,APB2总线给个72MHZ频率,然后波特率发生器进行合频,得到我们想要的波特率时钟,最后在这个时钟下进行收发,就是我们指定的通信波特率。

3.1 总结:串口参数一般设置

波特率:9600或115200

数据位:8位

停止位:1位

无校验

4.USART框图

由蓝圈和黄圈围住的寄存器工作流程:若在某时刻给TDR写入了0x55数据,也就是0101 0101,此时,硬件监测到了你写入;1数据,它就会检查,当前移位寄存器是不是有数据正在移位,如果没有,这个0101 0101就会立刻全部移入到发送移位寄存器里面,准备发送。当数据从TDR移动到移位寄存器时,就会置一个标志位,叫TXE(TX Empty),发送寄存器空,检查该标志位,如果置1了,我们就可以在TDR写入下一个数据了。

红圈围起的寄存器工作流程:发送移位寄存器会在发生控制器驱动下向右移位,然后一位一位,把数据输出到TX引脚(当数据移位完成后,新的数据会再次自动的从TDR转移到发送移位寄存器中来,若数据移位未完成,TDR数据会进行等待)

发送与接收数据移位寄存器的标志位:

发送移位寄存器的结束标志位:TXE(TX  Empty发送寄存器空)

接收移位寄存器的结束标志位:RXNE(RX not Empty接收移位寄存器未空,当监测到RXNE为1时,就可以把数据读走了)

总结:当数据一旦从TDR转移到移位寄存器了,不管你有没有移位完成,我就立刻把下一个数据放到TDR中等待了,一旦移完了,新的数据就会跟上。

5.USART基本结构

注:

(1)当数据从数据寄存器转移到移位寄存器时,会置一个TXE标志位,我判断这个标志位,接可以知道是不是可以写下一位数据了。

(2)RX的波形通过GPIO输入,在接收控制器控制下,一位一位移入接收移位寄存器,移完一帧后,数据就会同一转运到接收寄存器,在转移时,置一个RXNE标志位,,我们检查该标志位,就可以知道是不是收到数据了,同时,这个标志位也会申请中断(中断作用:在收到数据时,进入中中断函数,然后快速的读取和保持数据了)

6.发送的数据——数据帧

6.1 数据帧——字长设置

字长设置:9位或8位(包含校验位)

设置类型:(1)9位字长,有校验

                  (2)9位字长,无校验

                  (3)8位字长,有校验

                  (4)8位字长,无校验

时钟频率与数据速率一样,接收端可以在时钟上升沿开始采样,这样可以精确定位每一位数据。

为了刚好发一个字节,我们一般选择:9位有校验8位无校验

6.2 数据帧——配置停止位

设置类型:(1)0.5个停止位

                  (2)1个停止位

                  (3)1.5个停止位

                  (4)2个停止位

6.3 数据帧——波特率发生器

(1)发送器和接收器的波特率由波特率寄存器BRR里的DIV确定。

(2)计算公式:波特率 = Fclkx / (16 * DIV)

                        注:DIV * 16 的原因是:因为数据采集时,为了防止噪声,对采样时钟进行16倍

                                        波特率,采集中间的数据。

如:要求波特率为9600时的DIV

因为USART的时钟Fclk2 = 72MHZ

由DIV = Fclk2 / (16 * 波特率)= 72MHZ / 16 / 9600 = 468.75 = 1 1101 0100.11

6.4 数据帧——发送数据帧

USART_SendBits(USART1,Byte);                                #发数据
while(USART_GetFlagStatus(USART1,USART_HAG_TXE) == RESET)   #等待数据发送完成

6.5 数据帧——接收数据帧

if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)        #等待移位完成
{
    Serial_RxPackage = USART_ReceiveData(USART1);         #开始接收数据
    USART_ClearITPendingBit(USART1,USART_IT_RXNE);        #等待接收完成标志位RXNE
}

7.同时发送多个数据帧——数据包

7.1 HEX数据包

HEX数据包类型:(1)固定包长,含包长包尾

                             (2)不固定包长,含包头包尾

如上:包头:0xFF        包尾:0xFE、

固定包长与可变包长选择问题:对应HEX数据包,如果载荷会出现和包头包尾重复的情况,那最好选择固定包长,可以避免接收错误,如果载荷不会和包头包尾重复,那可以选择可变包长。

7.2 文本数据包

文本数据包类型:(1)固定长度,含包头包尾

                             (2)不固定长度,含包头包尾

如上:包头:'@'        包尾:'\r' '\n'

7.3 接收HEX数据包

前言:指定S变量:S变量选择不同模式转变。

static uint8_t RxState    = 0;                #用来表示不同模式
static uint8_t pRxPackage = 0;                #用来判断是否接收够数据

uint8_t RxData = USART_ReceiveData(USART1);    #接收数据,存放到RxData中

if(RxState == 0)               #模式1
{
    if(RxData == 0xFF)
    {
        RxState = 1;
        pRxPackage = 0;
    }
}
else if(RxState == 1)          #模式2
{
    Serial_RXPacket[pRxPackage] = RxData;
    pRxPackage++;
    if(pRxPackage > 4)
    {
        RxState = 2;
    }
}
else if(RxState == 2)          #模式3
{
    if(RxData == 0xFE)
    {
        RxState = 0;
        Serial_RxFlag = 1;
    }
}

7.4 接收文本数据包

static uint8_t RxStatus    = 0;                #用来表示不同模式
static uint8_t i = 0;                #用来判断是否接收够数据

if(USART_GetITStatus(USART1,USART_IT_RXNE) == SET)
{
    if(RxStatus == 0)               #模式1
    {
        if(RxData == '@')
        {
            RxState = 1;
            i = 0;
        }
    }
    else if(RxStatus == 1)          #模式2
    {
        if(USART_ReceiveData(USART) == 'r')
        {
            RxStatus = 2;
        }
        else
        {
            Serial_RxPackage[i] = USART_ReceiveData(USART1)
            i++;
        }
    }
    else if(RxStatus == 2)          #模式3
    {
        if(USART_ReceiveData(USART1) == '\n')
        {
            RxStatus = 0;
            Serial_RxFlag = 1;
            Serial_RxPackage[i] = '\0';
        }
    }
}

8.USART相关函数

8.1 标配函数

void USART_DeInit();

void USART_Init();

void USART_StructInit();

void USART_Cmd();

8.2 用于配置同步时钟中输出的

void ClockInit();

void ClockStructInit();

8.3 void USART_DMACmd();

8.4 void USART_SendData()

作用:发送数据(写DR)

8.5 void USART_ReceiveData();

作用:接收数据(读DR)

8.6 标志位标配函数

FlagStatus USART_GetFlagStatus();

void USART_ClearFlag();

ITStatus USART_GetITStatus();

void USART_ClearITPendingBit);

;