天天看点

STM32F767--->串口通信接收不定长数据的处理方法超时中断空闲中断附录

文章目录

  • 超时中断
    • 相关寄存器
      • 接收器超时寄存器(USARTx_RTOR)
  • 空闲中断
    • 整体思路
  • 附录
    • 程序代码
    • 参考

超时中断

相关寄存器

接收器超时寄存器(USARTx_RTOR)

STM32F767--->串口通信接收不定长数据的处理方法超时中断空闲中断附录

空闲中断

 空闲中断:就是说每接收到一条完整的数据就会置位空闲标志位,我们只需要判断空闲标志位是否置一,就能知道是不是接收到了一条完整的数据。

用空闲中断的好处就是,对于以前我写程序通信都会在数据的后面加上尾(/n什么的),然后另一个接收的单片机通过判断数据的尾来确定是不是一条完整的数据,有了空闲中断就不需要在给数据加上尾了

整体思路

 使用STC 的HAL库在其中断服务函数USART1_IRQHandler中编写对于空闲中断触发的处理过程。

其中可以使用RXNE一个字节一个字节的获取数据,在没有数据进来的时候,进入空闲中断,这时候拿出存储的数据处理就可以了。

数据的回显使用HAL_UART_Transmit显示就好了,在有串口1连接的情况下,会直接发送至串口1

附录

程序代码

如下代码,注释部分为空闲中断实现,未注释部分使用超时中断实现

#include "sys.h"
#include "stdio.h"
#include "stm32f7xx_hal_uart.h"
#include "delay.h"
#include "uart_drv.h"
#include "string.h"

#if 1                                       //这一部分是正点原子的防止串口发送卡死的情况出现
#pragma import(__use_no_semihosting)        //
struct __FILE 
{   
    int handle; 
}; 

FILE __stdout;                              //¶¨Òå_sys_exit()ÒÔ±ÜÃâʹÓðëÖ÷»úģʽ    
void _sys_exit(int x) 
{ 
    x = x; 
} 

int fputc(int ch, FILE *f)                  //
{
    while((USART1->ISR&0X40)==0);           //
    USART1->TDR=(u8)ch;
    return ch;
}
#endif 

u8  bUsartRxBuf[USART_REC_LEN];             //数据接收缓冲区
u16 wUsartRxSta=0;                          //数据接收标志位
                                            //bit15     接收完成
                                            //bit14     接收完1个字节
                                            //bit13~0   数据长度

u16 wUartRxCounter=0;                       //长度计数
u8  bRxBuffer[RXBUFFERSIZE];                //HAL库使用的窗口接收缓冲区
UART_HandleTypeDef UART1_Handler;           //UART句柄

/**
  * @brief 串口初始化函数
  * @param bound(波特率)
  * @retval null
  */
void uart_init(u32 bound)
{
    UART1_Handler.Instance          =   USART1;
    UART1_Handler.Init.BaudRate     =   bound;
    UART1_Handler.Init.WordLength   =   UART_WORDLENGTH_8B;
    UART1_Handler.Init.StopBits     =   UART_STOPBITS_1;
    UART1_Handler.Init.Parity       =   UART_PARITY_NONE;
    UART1_Handler.Init.HwFlowCtl    =   UART_HWCONTROL_NONE;    //无硬件流控制
    UART1_Handler.Init.Mode         =   UART_MODE_TX_RX;        //读写模式
    HAL_UART_Init(&UART1_Handler);

//    delay_ms(1);                                                //这部分代码防止空闲中断打开就置1的情况发生
//    while ((__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_IDLE) != RESET))
//    {
//        __HAL_UART_CLEAR_IT(&UART1_Handler, UART_FLAG_IDLE);
//    }
    __HAL_UART_ENABLE_IT(&UART1_Handler, UART_IT_RXNE);
//    __HAL_UART_ENABLE_IT(&UART1_Handler, UART_IT_IDLE);         //打开空闲中断
    
    SET_BIT(UART1_Handler.Instance->CR2,USART_CR2_RTOEN);       //使用超时接收功能
    SET_BIT(UART1_Handler.Instance->CR1,USART_CR1_RTOIE);       //使用超时接收中断
    WRITE_REG(UART1_Handler.Instance->RTOR,22);                 //向寄存器填入需要超时的长度,单位为波特长度,2个字节*11波特长度=22
}

/**
  * @brief UART底层配置,引脚配置,中断配置
  * @param huart:串口句柄
  * @retval null
  */
void HAL_UART_MspInit(UART_HandleTypeDef *huart)
{
    GPIO_InitTypeDef GPIO_Initure = {0};

    if (huart->Instance == USART1)                              //如果是串口1 进行串口1MSP初始化
    {
        __HAL_RCC_GPIOA_CLK_ENABLE();
        __HAL_RCC_USART1_CLK_ENABLE();

        GPIO_Initure.Pin        =   GPIO_PIN_9;
        GPIO_Initure.Mode       =   GPIO_MODE_AF_PP;
        GPIO_Initure.Pull       =   GPIO_PULLUP;
        GPIO_Initure.Speed      =   GPIO_SPEED_FAST;
        GPIO_Initure.Alternate  =   GPIO_AF7_USART1;
        HAL_GPIO_Init(GPIOA, &GPIO_Initure);

        GPIO_Initure.Pin = GPIO_PIN_10;
        HAL_GPIO_Init(GPIOA, &GPIO_Initure);
        
    #if EN_USART1_RX
        HAL_NVIC_EnableIRQ(USART1_IRQn);                        //使能中断通道
        HAL_NVIC_SetPriority(USART1_IRQn, 3, 3);                //设置优先级
    #endif
    }
}

void USART1_IRQHandler(void)
{ 
    uint32_t isrflags   = READ_REG(UART1_Handler.Instance->ISR);
    uint32_t cr1its     = READ_REG(UART1_Handler.Instance->CR1);
    uint32_t cr3its     = READ_REG(UART1_Handler.Instance->CR3);

    if (((isrflags & USART_ISR_ORE) != RESET) &&
        (((cr1its & USART_CR1_RXNEIE) != RESET) || ((cr3its & USART_CR3_EIE) != RESET)))
    {
        __HAL_UART_CLEAR_IT(&UART1_Handler, UART_CLEAR_OREF);
    }
    
    if ((__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_RXNE) != RESET))
    {
        if (wUsartRxSta == 0x0000)                                       //接收到1帧中的1个字节
        {
            wUsartRxSta = 0x4000;
            wUartRxCounter = 0;
            memset(bUsartRxBuf,0,sizeof(bUsartRxBuf));
            bUsartRxBuf[wUartRxCounter] = (uint8_t)(UART1_Handler.Instance->RDR & (uint8_t)0x00FF);
            wUartRxCounter++;
        }
        else if (wUsartRxSta == 0x4000)                                  //接收1帧中除第一个字节外的字节
        {
            bUsartRxBuf[wUartRxCounter] = (uint8_t)(UART1_Handler.Instance->RDR & (uint8_t)0x00FF);
            wUartRxCounter++;
        }
    }

//    if ((__HAL_UART_GET_FLAG(&UART1_Handler, UART_FLAG_IDLE) != RESET))  //进入空闲中断
//    {
//        __HAL_UART_CLEAR_IT(&UART1_Handler, UART_FLAG_IDLE);
//        if (wUartRxCounter > 0)
//        {
//            wUsartRxSta |= 0x8000;                                       //将状态置位接收完成状态,在处理完数据后,将该状态再重置
//        }
//    }
    
    if (READ_BIT(UART1_Handler.Instance->ISR,USART_ISR_RTOF))              //进入超时中断
    {
        SET_BIT(UART1_Handler.Instance->ICR,USART_ICR_RTOCF);              //超时中断清零
        if (wUartRxCounter > 0)
        {
            wUsartRxSta |= 0x8000;                                         
        }
    }
} 
           

参考

【超时中断参考】