STM32 串口接收流程-串口接收中断

发布者:悠闲之旅最新更新时间:2025-08-27 来源: cnblogs关键字:STM32  串口接收中断 手机看文章 扫描二维码
随时随地手机看文章

串口接收

串口接收流程

  1. 编程USARTx_CR1的M位来定义字长。

  2. 编程USARTx_CR2的STOP位来定义停止位位数。

  3. 编程USARTx_BRR寄存器确定波特率

  4. 使能USARTx_CR1的UE位使能USARTx。

  5. 如果进行多缓冲通信,配置USARTx_CR3的DMA使能(DMAT)。

  6. 使能USARTx_CR1的RE位为1使能接收器。

  7. 如果要使能接收中断(接收到数据后产生中断),使能USARTx_CR1的RXNEIE位为1。

当串口接收到数据时

  1. USARTx_SR(ISR)的RXNE位置1。表明移位寄存器内容已经传输到RDR(DR)寄存器。已经接收到数据并且等待读取。

  2. 如果开启了接收数据中断(USARTx_CR1寄存器的RXNEIE位为1),则会产生中断。(程序上会执行中断服务函数)

  3. 如果开启了其他中断(帧错误等),相应标志位会置1。

  4. 读取USARTx_RDR(DR)寄存器的值,该操作会自动将RXNE位清零,等待下次接收后置位。

串口接收流程(HAL库)

配置过程:

接收配置步骤①~⑥和发送流程一样,调用HAL_UART_Init函数HAL_StatusTypeDef HAL_UART_Init(UART_HandleTypeDef *huart);

步骤⑦开启接收中断:HAL_StatusTypeDef HAL_UART_Receive_IT(UART_HandleTypeDef*huart, uint8_t *pData, uint16_t Size);

接收数据过程:

步骤①获取状态标志位通过标识符实现:

   __HAL_UART_GET_FLAG            //判断状态标志位

   __HAL_UART_GET_IT_SOURCE   //判断中断标志位


步骤②~③中断服务函数:

void USARTx_IRQHandler(void) ;//(x=1~3,6)

void UARTx_IRQHandler(void) ;//(x=4,5,7,8)


在启动文件startup_stm32fxxx.s中查找。
步骤④读取接收数据:
HAL_StatusTypeDef HAL_UART_Receive(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout);


串口接收中断程序配置过程(HAL库)

  1. 初始化串口相关参数,使能串口:HAL_UART_Init();

  2. 串口相关IO口配置,复用配置:
    在HAL_UART_MspInit中调用HAL_GPIO_Init函数。

  3. 串口接收中断优先级配置和使能:
    HAL_NVIC_EnableIRQ();
    HAL_NVIC_SetPriority();

  4. 使能串口接收中断:HAL_UART_Receive_IT();

  5. 编写中断服务函数:USARTx_IRQHandler

经过上面步骤,我们就可以写完整的串口接收实验。我们就可以在中断服务函数中编写中断处理过程。


HAL库提供了详细的中断处理函数HAL_UART_IRQHandler,我们在中断服务函数中会调用此函数处理中断。

在这里插入图片描述

在void HAL_UART_IRQHandler(UART_HandleTypeDef *huart)函数里可以找到:UART_Receive_IT(huart);然后找到他的定义static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart),里面可以找到HAL_UART_RxCpltCallback(huart);他是一个接收完成处理回调函数,void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart),用户可以自己编写。


在USART_HandleTypeDef中有如下变量:RxXferSize是接收的数量,RxXferCount是剩余的数据个数,pRxBuffPtr指向数据存储位置的地址。比如,一开始要接收10个数据,pRxBuffPtr指向一个起始位置,初始时RxXferSize=10,RxXferCount=10,每接收一次,RxXferCount的值就减去1,而且pRxBuffPtr指针往下移,直到RxXferCount减为0 。


  uint8_t                       *pRxBuffPtr;      /*!< Pointer to USART Rx transfer Buffer */


  uint16_t                      RxXferSize;       /*!< USART Rx Transfer size              */


  uint16_t                      RxXferCount;      /*!< USART Rx Transfer Counter           */

static HAL_StatusTypeDef UART_Receive_IT(UART_HandleTypeDef *huart)

{

  uint16_t* tmp;

  uint16_t uhMask = huart->Mask;


  /* Check that a Rx process is ongoing */

  if(huart->RxState == HAL_UART_STATE_BUSY_RX)

  {


    if ((huart->Init.WordLength == UART_WORDLENGTH_9B) && (huart->Init.Parity == UART_PARITY_NONE))

    {

      tmp = (uint16_t*) huart->pRxBuffPtr ;

      *tmp = (uint16_t)(huart->Instance->RDR & uhMask);

      huart->pRxBuffPtr +=2;

    }

    else

    {

      *huart->pRxBuffPtr++ = (uint8_t)(huart->Instance->RDR & (uint8_t)uhMask);

    }


    if(--huart->RxXferCount == 0)

    {

      /* Disable the UART Parity Error Interrupt and RXNE interrupt*/

      CLEAR_BIT(huart->Instance->CR1, (USART_CR1_RXNEIE | USART_CR1_PEIE));


      /* Disable the UART Error Interrupt: (Frame error, noise error, overrun error) */

      CLEAR_BIT(huart->Instance->CR3, USART_CR3_EIE);


      /* Rx process is completed, restore huart->RxState to Ready */

      huart->RxState = HAL_UART_STATE_READY;


      HAL_UART_RxCpltCallback(huart);


      return HAL_OK;

    }


    return HAL_OK;

  }

  else

  {

    /* Clear RXNE interrupt flag */

    __HAL_UART_SEND_REQ(huart, UART_RXDATA_FLUSH_REQUEST);


    return HAL_BUSY;

  }

}


串口接收中断流程

在这里插入图片描述

串口中断服务函数执行流程

串口中断服务函数中调用HAL库串口中断通用处理函数:HAL_UART_IRQHandler(); 该函数会对中断来源进行分析,调用相应函数。

对于不同的中断类型,我们只需要编写最终的中断处理函数:


void HAL_UART_TxCpltCallback(UART_HandleTypeDef *huart);

void HAL_UART_TxHalfCpltCallback(UART_HandleTypeDef *huart);

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart);

void HAL_UART_RxHalfCpltCallback(UART_HandleTypeDef *huart);

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart);

串口接收实验

电脑通过串口助手往串口1发送字符,串口1通过中断方式接受字符,每接受一个字符就同时通过串口1返回给电脑。


初始化串口相关参数,使能串口:HAL_UART_Init();

串口相关IO口配置,复用配置:

在HAL_UART_MspInit中调用HAL_GPIO_Init函数。

串口接收中断优先级配置和使能:

HAL_NVIC_EnableIRQ();

HAL_NVIC_SetPriority();

使能串口接收中断:HAL_UART_Receive_IT();

编写中断服务函数:USARTx_IRQHandler

根据如上步骤,其中1、2步骤和串口发送设置差不多,第三步,HAL_NVIC_SetPriority(USART1_IRQn,3,3);抢占和响应优先级均设置为3.这是因为main中的HAL_Init();有一个设置是 HAL_NVIC_SetPriorityGrouping(NVIC_PRIORITYGROUP_2);


#include 'sys.h'

#include 'delay.h'

#include 'usart.h' 

u8 rdata[1];//因为是每接收一个就发出去,所以设置为1

UART_HandleTypeDef usart1_handler;

//初始化串口相关参数,使能串口

void uart1_init(void)

{

usart1_handler.Instance = USART1;

usart1_handler.Init.BaudRate = 115200;

usart1_handler.Init.WordLength = UART_WORDLENGTH_8B;

usart1_handler.Init.StopBits = UART_STOPBITS_1;

usart1_handler.Init.HwFlowCtl = UART_HWCONTROL_NONE;

usart1_handler.Init.Mode = UART_MODE_TX_RX;

usart1_handler.Init.Parity = UART_PARITY_NONE;

HAL_UART_Init(&usart1_handler);

}

//串口相关IO口配置,复用配置

void HAL_UART_MspInit(UART_HandleTypeDef *huart)

{

GPIO_InitTypeDef GPIO_Initure;

if(huart->Instance==USART1)

{

__HAL_RCC_GPIOA_CLK_ENABLE(); //使能GPIOA时钟

__HAL_RCC_USART1_CLK_ENABLE(); //使能USART1时钟

GPIO_Initure.Pin=GPIO_PIN_9; //PA9

GPIO_Initure.Mode=GPIO_MODE_AF_PP; //复用推挽输出

GPIO_Initure.Pull=GPIO_PULLUP; //上拉

GPIO_Initure.Speed=GPIO_SPEED_HIGH; //高速

GPIO_Initure.Alternate=GPIO_AF7_USART1; //复用为USART1

HAL_GPIO_Init(GPIOA,&GPIO_Initure);     //初始化PA9


GPIO_Initure.Pin=GPIO_PIN_10; //PA10

HAL_GPIO_Init(GPIOA,&GPIO_Initure);     //初始化PA10

        

        //串口接收中断优先级配置和使能

HAL_NVIC_SetPriority(USART1_IRQn,3,3);//设置中断优先级

HAL_NVIC_EnableIRQ(USART1_IRQn);//使能中断通道

}

}

//编写中断服务函数

void USART1_IRQHandler()

{

HAL_UART_IRQHandler(&usart1_handler);

//由于调用一次中断,进入中断回调函数后,中断就结束了,所以还要开启中断

HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata));//使能接收中断

}

//编写接收完成中断回调函数

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)

{

u8 rec;

if(huart->Instance==USART1)

{

//rec = *((huart->pRxBuffPtr)-1);

rec = rdata[0];//保存接收到的数据

HAL_UART_Transmit(&usart1_handler,&rec,1,1000);

}

}

int main(void)

{

  Cache_Enable();                 //打开L1-Cache

  HAL_Init();         //初始化HAL库

  Stm32_Clock_Init(432,25,2,9);   //设置时钟,216Mhz 

delay_init(216);

uart1_init();

    HAL_UART_Receive_IT(&usart1_handler,rdata,sizeof(rdata));//使能接收中断

while(1)

{

        

}


}


关键字:STM32  串口接收中断 引用地址:STM32 串口接收流程-串口接收中断

上一篇:STM32-UART-串口通信框图-波特率计算
下一篇:STM32-串口发送数据-过程与配置

推荐阅读最新更新时间:2026-03-25 00:15

【菜鸟必看】STM32 串口接收不定长数据中断检测相关问题
今天给大家介绍STM32串口接受不定长数据中断检测的相关问题。能够推测,在UART收到最后一帧数据后,假如随后的一个数据帧的时长内未收到新的数据,则IDLE信号有效.假如数据包之间间隔大于一个数据帧,就能够用IDLE信号作为检测数据包完毕的标志. 运用DMA接管UART-Rx数据,当检测到DMA数据满,或DMA数据半满,或UART的IDLE时,读取DMA数据.假如DMA缓存空间足够大(大于最大的数据包长度),也能够只以IDLE信号为标志. 运用类似的思维,能够用3种方式达到. 启用UART的RXNE中断,运用RXNE中断检测第一数据帧,并读取第一个数据,其次启动DMA接管(DMA设置为Normal模式)和IDLE中断,并关闭RXN
[单片机]
STM32 一直进入串口接收中断
解决方法一: 串口初始化配置时,需要打开ORE 溢出中断,否则串口中断没有及时读取数据会触发溢出中断(打开接收中断默认开启溢出中断,但是为了读取溢出标志位还需要明确执行以下打开溢出中断),如果没有清溢出中断就会一直进串口中断。 USART_ITConfig(USART2, USART_IT_ORE, ENABLE);//USART_IT_ORE参数在这个函数中是不合法,参数检测过不去,关闭参数检测这样写确实有效 串口接收中断函数要增加如下代码: if (USART_GetITStatus(USART2, USART_IT_ORE) == SET) {   USART_ClearITPendingBit(USART2,USART
[单片机]
STM32 HAL库使用中断实现串口接收不定长数据
以前用DMA实现接收不定长数据,DMA的方法接收串口助手的数据,全部没问题,不过如果接收模块返回的数据,而这些数据如果包含回车换行的话就会停止接收,例如接收:ATrnOKrn,就只能接收到ATr,导致没有接收完成,具体原因还没搞懂,有了解的,希望可以告知一下,DMA不定长接收方法传输门:https://www.cnblogs.com/xingboy/p/9714907.html。 好了,不多说了,现在进入正文。首先建立一个STM32Cumebx的工程,打开串口中断,完成配置,具体的配置流程就不细说了,没什么难度就只是打开串口跟中断而已。 生成工程代码后,先定义好一些变量: //串口4中断接收定义 #define MAX
[单片机]
<font color='red'>STM32</font> HAL库使用<font color='red'>中断</font>实现<font color='red'>串口</font><font color='red'>接收</font>不定长数据
STM32串口USART1中断接收中断发送
  先贴出中断函数:    view plain copy   void USART1_IRQHandler(void){   IF (USART_GetiTStatus(USART1, USART_IT_RXNE) != RESET) {   USART_ClearITPendingBit(USART1, USART_IT_RXNE);   USART1_Buffer =USART_ReceiveData(USART1); //USART1_Buffesh是一个自己定义的接收数组   if(i 3){   SendFlag = 1;   }   }   if(USART_GetITStatus(USART1, USART_I
[单片机]
关于STM32串口接收中断中只能接收一个字节
最近调试STM32的串口接收时发现例程中只能接收一个字节 例程如下: 1 //初始化串口1 2 void uart_init(u32 bound){ 3 //GPIO端口设置 4 GPIO_InitTypeDef GPIO_InitStructure; 5 USART_InitTypeDef USART_InitStructure; 6 NVIC_InitTypeDef NVIC_InitStructure; 7 8 RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能USA
[单片机]
STM32—无需中断来实现使用DMA接收串口数据
本节目标: 通过DMA,无需中断,接收不定时长的串口数据 描述: 当在串口多数据传输下,CPU会产生多次中断来接收串口数据,这样会大大地降低CPU效率,同时又需要CPU去做其它更重要的事情,我们应该如何来优化? 比如四轴飞行器,当在不停地获取姿态控制方向时,又要去接收串口数据. 答:使用DMA,无需CPU中断便能实现接收串口数据 1.DMA介绍 DMA,全称为: Direct Memory Access,即直接存储器访问, DMA 传输方式无需 CPU 直接控制传输,通过硬件为 RAM 与 I/O 设备开辟一条直接传送数据的通路,能使 CPU 的效率大为提高。 2在main()中调用串口配置函数,初始化串口后,然后使能UA
[单片机]
<font color='red'>STM32</font>—无需<font color='red'>中断</font>来实现使用DMA<font color='red'>接收</font><font color='red'>串口</font>数据
STM32串口中断、DMA接收的几点注意地方
1UART串口中断接收 使能UART串口中断之后,有接收到UART数据,进入中断,此时要清除RXNE接收标志位: 1.通过软件向该RXNE标志位写入零来清零; 2.通过对 USART_DR 寄存器执行读入操作将该位清零。 这里可以查看对应《参考手册》,一般我们选择第2种,通过读取UART串口数据来清零。 1.中断接收数据丢失 在UART串口中断函数中,或者更高优先级中断函数中长时间执行,导致接收丢失,所以,请勿在中断函数中长时间执行。 特别有些人,还在中断函数添加延时函数。实际应用中,只要不是特殊情况,比如测试某个功能可以添加延时函数,都不建议在中断函数添加延时函数。 2.ORE上溢错误 ORE上溢错误是什么意思呢? 可能很
[单片机]
STM32 串口3 总是进入接收中断
近日,调试stm32f103串口3 发现一个奇怪的问题 USART3------------RXD----------PB11 悬空会导致程序频繁进入串口接收中断!!! //USART3_RX PB11 GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入 GPIO_Init(GPIOB, &GPIO_InitStructure); //初始化PB11 原因就是 PB11引脚配置成了浮空输入模式!!!! 改成上拉输入问题解决
[单片机]
小广播
最新单片机文章
何立民专栏 单片机及嵌入式宝典

北京航空航天大学教授,20余年来致力于单片机与嵌入式系统推广工作。

厂商技术中心

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

 
机器人开发圈

电子工程世界版权所有 京ICP证060456号 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2026 EEWORLD.com.cn, Inc. All rights reserved