单片机
返回首页

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

2025-08-27 来源:cnblogs

串口接收

串口接收流程

  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)

{

        

}


}


进入单片机查看更多内容>>
相关视频
  • 【TI MSPM0 应用实战】智能小车+工业角度编码器+血氧仪+烟雾探测器!硬核参考设计详解!

  • 2022 Digi-Key KOL 系列: 你见过1GHz主频的单片机吗?Teensy 4.1开发板介绍

  • TI 新一代 C2000™ 微控制器:全方位助力伺服及马达驱动应用

  • MSP430电容触摸技术 - 防水Demo演示

  • 直播回放: Microchip Timberwolf™ 音频处理器在线研讨会

  • 基于灵动MM32W0系列MCU的指夹血氧仪控制及OTA升级应用方案分享

精选电路图
  • 1瓦线性调频增强器

  • 家用电器遥控器

  • 12V 转 28V DC-DC 变换器(基于 LM2585)

  • 红外开关

  • DS1669数字电位器

  • HA1377 桥式放大器 BCL 电容 17W(汽车音频)

    相关电子头条文章