STM32-USART串口实现接收数据三种方法(1.根据\r\n标志符、2.空闲帧中断、3.根据定时器辅助接收)

发布于:2025-07-28 ⋅ 阅读:(15) ⋅ 点赞:(0)

本章概述思维导图:

USART串口初始化配置

串口初始化配置在(STM32-USART串口初始化章节有详细教程配置),本章不做讲解直接代码示例,本章重点在于串口实现接收数据三种方法;

配置USART1串口接收初始化函数步骤:

1. 开时钟

2. 对串口1模块开启复位时钟,在取消复位;

3. 配置GPIO模式

4. 通过在USART_CR1寄存器上置位UE位来激活USART

5. 编程USART_CR1的M位来定义字长。

6. 在USART_CR2中编程停止位的位数。

7. 利用USART_BRR寄存器选择要求的波特率。

8. 设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。

9. 设置USART_CR1的RE位。激活接收器,使它开始寻找起始位。

10. 设置USART_CR1的IDLEIE位。当USART_SR中的IDLE为’1’时,产生USART中断

11.设置USART_CR1的RXNEIE位。当USART_SR中的ORE或者RXNE为’1’产生USART中断。

12. 调用中断设置优先级函数;

代码示例:

/*
  USART1串口初始化函数
  形参bps——>保持通信的波特率
  PA10设置为输入模式,PA9设置为复用输出模式;
*/
void USART1_Init(u32 bps)
{
//  1. 开时钟
  RCC->APB2ENR|=1<<2;//开启PA时钟;
  RCC->APB2ENR|=1<<14;//开启USART1时钟
//  2. 对串口1模块开启复位时钟,在取消复位;
  RCC->APB2RSTR|=1<<14;//开启USART1复位时钟,复位这一步可以省略配置USART1步骤
  RCC->APB2RSTR&=~(1<<14);//取消复位时钟,关闭复位
//  3. 配置GPIO模式
  GPIOA->CRH&=0xfffff00f;//清空PA10、PA9引脚模式
  GPIOA->CRH|=0x000008b0;//PA10输入PA9输出
//  4.通过在USART_CR1寄存器上置位UE位来激活USART
  USART1->CR1|=1<<13;
//  5.编程USART_CR1的M位来定义字长。
  USART1->CR1&=~(1<<12);
//  6.在USART_CR2中编程停止位的位数。
  USART1->CR2&=~(0x3<<12);
//  7.利用USART_BRR寄存器选择要求的波特率。
  USART1->BRR=72000000/bps;
//  8.设置USART_CR1中的TE位,发送一个空闲帧作为第一次数据发送。
  USART1->CR1|=1<<3;
//  9.设置USART_CR1的RE位。激活接收器,使它开始寻找起始位。
  USART1->CR1|=1<<2;
//  10.设置USART_CR1的IDLEIE位。当USART_SR中的IDLE为’1’时,产生USART中断
  USART1->CR1|=1<<4;
//  11.设置USART_CR1的RXNEIE位。当USART_SR中的ORE或者RXNE为’1’产生USART中断。
  USART1->CR1|=1<<5;
//  12.调用中断优先级函数
  STM32_SetNVICPriority(USART1_IRQn ,1,1);
}

USART串口中断服务函数

/*
  串口1中断服务函数
*/
void USART1_IRQHandler()
{
  u8 c;
  if(USART1->SR&1<<5)//判断是否为:接收中断;每接收一个字符就会触发一次中断
  {
    c=USART1->DR;//将数据赋值给c
    USART1->DR=c;//将数据发生给上位机软件,使得显示界面上显示。
  }
}

USART1串口1接收实现三种方法

判断串口数据发送完一次数据有三种方法:

1. 是发送数据时以(\r\n)标志为结尾,检测到(\n)时就知道数据完成一次发送

2. 串口初始化函数中开启空闲帧中断

3,定时器辅助串口接收,判断串口1发送一字节和下一字节的间隔时间。超过定时器 初始设定的时间说明字符串数据发送完成

方法1:这里判断一次数据发送完成时根据(\r\n结束标志符)

代码示例:

u8 USART1_buffer[1024];//缓冲区数组,用来接收数据
u16 USART1_cnt=0;//缓冲区数组下标
u8 USART1_flag=0;//联合主函数标志位
/*
  USART1串口1中断服务函数
*/
void USART1_IRQHandler(void)
{
  u8 dat;
  if(USART1->SR&1<<7)//没接收到一个字符触发标志位
  {
    dat=USART1->DR;//读取数据
    if(USART1_cnt<1024)
    {
      USART1_buffer[USART1_cnt]=dat;//将读取的数据放入到缓冲区数组里
      if(USART1_buffer[USART1_cnt] == '\n')//判断是否到结束标注位"\r\n"
      {
        USART1_buffer[USART1_cnt-1]='\0';//将'\r'写入'\0'结束
        USART1_flag=1;//数据接收完成
      }
      else
      {
        USART1_cnt++;
      }
    }
    else
    {
      USART1_buffer[USART1_cnt-1]='\0';
      USART1_cnt=0;
    }
  }
}

代码讲解:

创建缓冲区数组用来接收字符,只要字符不为:' \n ';就一直接收;当字符为:' \n '时;将' \r'位置写入' \0 '表示接收完成,同时将标志位置1,联合主函数使用;

主函数代码示例:


#include "USART1.h"
#include "stdio.h"
int main()
{

  USART1_Init(115200);//USART1串口1初始化函数
  while(1)
  {
    if(USART1_flag)
    {
      printf("buffer=%s\tcnt=%d\n",USART1_buffer,USART1_cnt);
      USART1_cnt=0;//下标清零
      USART1_flag=0;//标志位置0;
    }
  }
}

代码运行结果图:

数据发送图:

数据成功接收图:

方法2:开启空闲帧中断

在串口初始化函数中配置USART1_CR1的IDLEIE:IDLE中断使能位

中断服务函数配置示例代码:

/*
  USART1串口1中断服务函数
*/
void USART1_IRQHandler(void)
{
  u8 dat;
  if(USART1->SR&1<<5)//每接收到一个字符触发标志位
  {
    
    dat=USART1->DR;//读取数据
    if(USART1_cnt<1024)
    {
      
      USART1_buffer[USART1_cnt]=dat;//将读取的数据放入到缓冲区数组里
      USART1_cnt++;
    }
    else
    {
      USART1_cnt=0;
    } 
  }
  if(USART1->SR&1<<4)//空闲帧标志,这是全部发送完触发一次
  {
    dat=USART1->DR;
    USART1_flag=1;//数据接收完成
  }
  USART1->SR=0;
}

主函数示例代码:

#include "USART1.h"
#include "stdio.h"
int main()
{

  USART1_Init(115200);//USART1串口1初始化函数
  while(1)
  {
    if(USART1_flag)
    {
      USART1_buffer[USART1_cnt]='\0';//写入结束标志符
      printf("buffer=%s\tcnt=%d\n",USART1_buffer,USART1_cnt);
      USART1_cnt=0;//下标清零
      USART1_flag=0;//标志位置0;
    }
  }
}

代码运行结果图:

数据发送图:

数据成功接收图:

方法3:定时器辅助串口接收

定时器辅助串口接收,判断串口1发送一字节和下一字节的间隔时间。超过定时器 初始设定的时间说明字符串数据发送完成

配置步骤:

第一步:算出发送一个字节数据要多少时间:

1m=1000ms=1000000us;

1000000/(115200/10)=86.80555555us;发送一字节数据需要86.8055微秒;

判断第一个字节数据和第二字节数据的间隔时间有没有超过10ms

第二步:在串口1初始化函数中关闭空闲帧中断并且串口中断服务函数里关闭空闲帧中断; 在定时器2初始化函数里关闭使能计数器,并且关闭定时器。设定定时时间10毫 秒

第三步:在串口第一次接收一字节数数时,在串口1中断服务函数里清空计数器并且开启定 时器。

第四步:如果数据全部返送完成,在定时器2中断服务函数里将标志位置一并且关闭定时器 等待下一次数据发送玩出触发定时器2中断

第三步示例代码:

/*
  USART1串口1中断服务函数
*/
void USART1_IRQHandler(void)
{
  u8 dat;
  if(USART1->SR&1<<5)//每接收到一个字符触发标志位
  {
    
    dat=USART1->DR;//读取数据
    if(USART1_cnt<1024)
    {
      TIM2->CNT=0;//清空计数器
      TIM2->CR1|=1<<0;//开启定时器
      USART1_buffer[USART1_cnt]=dat;//将读取的数据放入到缓冲区数组里
      USART1_cnt++;
    }
    else
    {
      USART1_flag=1;
    } 
  }
  USART1->SR=0;
}

第四步示例代码:

/*
  定时器2中断服务函数
*/
void  TIM2_IRQHandler(void)
{
  if(TIM2->SR&1<<0)
    {
      USART1_flag=1;//定时时间到标志位置1
      TIM2->SR&=~(1<<0);
      TIM2->CR1&=~(1<<0);//关闭定时器
    }
}

主函数示例代码:


#include "USART1.h"
#include "stdio.h"
#include "TIM.h"
int main()
{
  
  USART1_Init(115200);//USART1串口1初始化函数
  TIM2_Init(7200,10000);//定时器2设置定时时间为10毫秒
  while(1)
  {
    if(USART1_flag)
    {
      USART1_buffer[USART1_cnt]='\0';//给缓冲区数组写入结束标识符;
      printf("buffer=%s cnt=%d\n",USART1_buffer,USART1_cnt);
      USART1_cnt=0;//下标清零
      USART1_flag=0;//标志位置0;
    }
  }
}

代码运行结果图:

数据发送图:

数据成功接收图:


制作不易!喜欢的小伙伴给个小赞赞!喜欢我的小伙伴点个关注!有不懂的地方和需要的资源随时问我哟!


网站公告

今日签到

点亮在社区的每一天
去签到