三,USART串口

串口发送数据过程介绍
三,USART串口_第1张图片

标志位
三,USART串口_第2张图片
USART_FLAG_TXE的用途:

当发送数据寄存器里的数据被全部取完时,该寄存器是空的,那么该标志位就会被置1。通过这个标志位的值可以判断发送数据寄存器中的数据有没有完全被取走,当该寄存器是空的时候,可以提醒CPU继续往该寄存器里存入新的数据;。所以,其实USART_FLAG_TXE就是用来标志一个事件的,通过它的值可以知道该事件有没有发生(即发送数据寄存器中的数据有没有被取走)

USART_FLAG_TC的用途:

当发送移位寄存器里的每个字节通过TX脚一位一位发送出去之后,该标志位值就会被置1。通过这个标志位的值可以判断发送移位寄存器里的数据有没有被全部发送出去;USART_FLAG_TC就是用来标志“发送移位寄存器中的数据有没有全部发送出去”这件事的

USART_FLAG_TXE和USART_FLAG_TC之间的联系:

结合上面流程图来进行说明,实际上发送移位寄存器通过TX脚发送数据这个过程是比较耗时的,所以在此过程进行时,可通过判断当USART_FLAG_TXE = 1,即发送数据寄存器里的数据已被全部转入发送移位寄存器时,就让CPU往发送数据寄存器转入新的数据。

当发送移位寄存器把数据帧全部发送出去之后,可通过判断USART_FLAG_TC = 1,证明数据帧的最后一个字节都已经通过TX脚发送完了。

————————————————

版权声明:本文为CSDN博主「努力的小肥丸」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/lnfiniteloop/article/details/111475410

  1. USART_FLAG_TXE(发送数据寄存器非空标志位)

  1. USART_FLAG_RXNE(接收数据寄存器非空标志位)

  1. USART_FLAG_TC(发送完成标志位)

三,USART串口_第3张图片
USART_FLAG_TXE(发送数据寄存器非空标志位):

注意左上角紫色的框,以及发送数据的流程,当我们去调用函数*USART_SendData(pUSARTx,ch);的时候,一个字节的数据就会被写入发送数据寄存器(TDR),注意USART_FLAG_TXE这个标志位,不发送数据的时候,闲着的时候都是0,当检测到数据写入发送数据寄存器TDR的时候,就会立刻将USART_FLAG_TXE置1,然后数据移位寄存器(TSR)就开始从TDR寄存器中取数据,一位一位的取走发送出去,当被取完的时候,发送数据寄存器TDR也就为空了,所以此时USART_FLAG_TXE*标志位就会被置0 ,所以也是我们while检测这个标志的原因

USART_FLAG_TC(发送完成标志位):

我们来假设一个过程,当我们调用USART_SendData(USART_TypeDef* USARTx, uint16_t Data)发送一个字节的数据的时候,此时数据移位寄存器(TSR)就会立刻从数据发送寄存器(TDR)中开始搬运数据并一位一位发送出去,但是受限于波特率,搬运的速度会远大于发送的速率,而只要搬运完了,USART_FLAG_TXE这个标志位就会立刻被置0,我们while循环检测这个标志,此时就会被唤醒,看我上面发送字符串的函数就能看出来,下一个数据立刻又被写入发送数据寄存器(TDR),然后移位数据寄存器又开始搬运了,注意注意:此时移位数据寄存器中,上一个字节的数据还不一定发送完成呢,所以会为空吗?不会,所以所以:USART_FLAG_TC这个标志位的作用是:检测数据移位寄存器是否为空,当开始发送数据,数据移位寄存器从数据发送寄存器中搬运数据,这个标志位就会被置1,当所有数据发送完成,移位寄存器为空时,就会被置0,所以通过这个标志位,可以实现在字节流的传输方式中实现帧传输

USART_IT_RXNE(接收数据寄存器满标志):

再简单分析,首先,当接收到数据的时候,就会立刻进入到这个函数,但是这里为什么要一直检测这个标志位呢?USART_IT_RXNE的取值只有SET和RESET两种,当接收数据完成,也就说8个bit都接收了,代表一个字节的数据接收完成,就能跳出while循环,调用了*USART_ReceiveData()*这个函数读取数据,实际上这个函数是读取DR寄存器,读DR寄存器会将这个标志位清0,所以此处没有手动清0,当然手动清0也可以,我真的服了去百度上搜这个标志位,我就想搜这玩意的作用,真的是很难搜到,搜索结果真是花里胡哨牛头不对马嘴

通信概念:

我们常常容易混淆通讯方式和通讯协议,很多初学者分不清这些东西,USART(串口)可以理解为一种通讯的方式或者说通讯的桥梁,那通信协议呢,打个比方,两个人事先约定好,你说1,我就说2,听到你说2之后,我就接3……像这样是通讯协议,那具体你们是打电话说,还是见面说,都行,在这个例子中,使用电话或者线下见面直接说就是通讯方式,可以理解为串口/wifi/以太网,而你们之间的约定就是通讯协议,串口比较常用,通常用来调试输入信息,以及数据接收和发送,有很多的嵌入式设备都是依靠串口发送和接收的。

串口又分为TTL、RS232、RS485,那具体这些有什么区别呢?其实都一样,都是接3条线,只是TTL串口就是单片机上的串口,5V代表1,0V代表0,这样传输的时候,抗干扰能力很弱,远距离的时候,传输的波形会失真,所以后来发明了RS232和RS485,使用的是差分信号,RS232大概就是15V表示1,-15V表示0,这样传输的时候波形抗干扰就会很强,传输距离就远,差不多是这意思,下面就详细了解一下STM32的USART的使用

配置串口结构体步骤:
  1. 使能 RX 和 TX 引脚 GPIO 时钟和 USART 时钟

  1. 初始化 GPIO,并将 GPIO 复用到 USART

  1. 配置 USART 参数

————————————————

版权声明:本文为CSDN博主「__void」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。

原文链接:https://blog.csdn.net/Newmamahaha/article/details/125431488

源码:
usart.c文件
#include "usart.h"
#include "stm32f10x.h"

void usart_init(void)
{
    GPIO_InitTypeDef gpiostruct;  //定义结构体变量
    USART_InitTypeDef Usartstruct;//定义结构体变量
    
  //配置时钟:GPIOA的时钟,串口的时钟,引脚复用的时钟
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
     RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
    
  //配置GPIO的结构体 配置PA9 TX输出引脚
    gpiostruct.GPIO_Mode  =  GPIO_Mode_AF_PP;//复用推挽输出
    gpiostruct.GPIO_Pin   =  GPIO_Pin_9;//选定管脚为pA9
    gpiostruct.GPIO_Speed =  GPIO_Speed_50MHz;
    
    GPIO_Init(GPIOA,&gpiostruct);//调用初始化函数
    
  //配置PA10 RX输入引脚
    gpiostruct.GPIO_Mode = GPIO_Mode_IN_FLOATING ;//浮空输入
    gpiostruct.GPIO_Pin  = GPIO_Pin_10;//选定管脚为pA10

  //配置串口的结构体

    GPIO_Init(GPIOA,&gpiostruct);//调用初始化函数

    Usartstruct.USART_BaudRate = 115200;//波特率  配置波特率115200
    Usartstruct.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//硬件流控制
    Usartstruct.USART_Mode = USART_Mode_Rx  | USART_Mode_Tx;//USART模式 配置工作模式 收或发
    Usartstruct.USART_Parity = USART_Parity_No;//检验位
    Usartstruct.USART_StopBits = USART_StopBits_1;//停止位
    Usartstruct.USART_WordLength = USART_WordLength_8b;//字长 配置控制数据位的字长:八位
    
    USART_Init(USART1, &Usartstruct);//调用初始化函数
    USART_Cmd(USART1, ENABLE);
  
}
//串口的发送
//创建发送单个字符的函数UsartSendByte()
void UsartSendByte(USART_TypeDef* USARTx, uint16_t Data)//参数结构体指针,要发送的数据
{

    USART_SendData(USARTx,Data);//串口发送函数 在库函数中,
    while( USART_GetFlagStatus(USARTx,USART_FLAG_TXE) ==  RESET );

}
//创建发送字符串的函数
void UsartSendStr(USART_TypeDef* USARTx,char *str)
{
    uint16_t i =0;
    do
    {
          UsartSendByte( USARTx, *(str + i));//调用上面UsartSendByte()函数
             i++;
        
        
    }while( *(str + i) != '\0' );
     while( USART_GetFlagStatus(USARTx,USART_FLAG_TC) ==  RESET );
      
}
usart.h文件
#include "stm32f10x.h"
void usart_init(void);
void UsartSendByte(USART_TypeDef* USARTx, uint16_t Data);
void UsartSendStr(USART_TypeDef* USARTx,char *str);
main.c文件
#include "stm32f10x.h"
#include "main.h"
#include "usart.h"
void delay(uint16_t time)//延时函数
{
    uint16_t i=0;
    while(time--){
         i=12000;
        while(i--);
    }
}
int main()
{
   /* 
       //2.发送字符
      usart_init();//初始化该函数
      UsartSendByte(USART1, 'O');//调用UsartSendByte()函数打开串口1,发送字符O
    UsartSendByte(USART1, 'K');//调用UsartSendByte()函数打开串口1,发送字符K
    */
    
    /* 
         //3.发送字符串
      usart_init();//初始化该函数
      UsartSendStr(USART1,"无危险哈哈哈" );
    */



  //1.调用USART_SendData()函数发送字符 
  //usart_init();//初始化该函数
   while(1)
  {
/*
        USART_SendData( USART1,'o');
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        USART_SendData( USART1,'K');
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        USART_SendData( USART1,'\n');
        while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
        delay(1000);
 */
  }

}
硬件连接:
三,USART串口_第4张图片

发送结果展示:

1.调用USART_SendData()函数发送字符

三,USART串口_第5张图片

2.发送字符

ps:需要按开发板的复位键才会发送

三,USART串口_第6张图片

3.发送字符串

ps:需要按开发板的复位键才会发送

三,USART串口_第7张图片

你可能感兴趣的:(单片机,嵌入式硬件)