STM32G474单片机_串口中断接收和发送

在使用STM32G474单片机串口时,若将UART_HandleTypeDef定义的变量,用作全局变量时,确实很浪费内存,若不定义为全局变量,就无法使用HAL库自带的串口函数。若采用自定义的宏来实现标准库的部分功能,就可将UART_HandleTypeDef型变量定义为局部变量

1、自己定义的“串口宏定义”

#define _HAL_UART_SendByte(Instance, __DATA__) Instance->TDR = ( (__DATA__) & (uint16_t)0x01FF );
//将(__DATA__)写入串口发送缓冲区

#define _HAL_UART_ReceiveByte( Instance ) ( (uint16_t)( Instance->RDR & (uint16_t)0x01FF) )
//读串口接收缓冲区

/** @brief  Enable the specified UART interrupt.
  * @param  Instance specifies the UARTx.
  * @param  __INTERRUPT__ specifies the UART interrupt source to enable.
  *          This parameter can be one of the following values:
  *            @arg @ref UART_IT_RXFF  RXFIFO Full interrupt
  *            @arg @ref UART_IT_TXFE  TXFIFO Empty interrupt
  *            @arg @ref UART_IT_RXFT  RXFIFO threshold interrupt
  *            @arg @ref UART_IT_TXFT  TXFIFO threshold interrupt
  *            @arg @ref UART_IT_WUF   Wakeup from stop mode interrupt
  *            @arg @ref UART_IT_CM    Character match interrupt
  *            @arg @ref UART_IT_CTS   CTS change interrupt
  *            @arg @ref UART_IT_LBD   LIN Break detection interrupt
  *            @arg @ref UART_IT_TXE   Transmit Data Register empty interrupt
  *            @arg @ref UART_IT_TXFNF TX FIFO not full interrupt
  *            @arg @ref UART_IT_TC    Transmission complete interrupt
  *            @arg @ref UART_IT_RXNE  Receive Data register not empty interrupt
  *            @arg @ref UART_IT_RXFNE RXFIFO not empty interrupt
  *            @arg @ref UART_IT_IDLE  Idle line detection interrupt
  *            @arg @ref UART_IT_PE    Parity Error interrupt
  *            @arg @ref UART_IT_ERR   Error interrupt (frame error, noise error, overrun error)
  * @retval None
  */

#define _HAL_UART_ENABLE_IT(Instance, __INTERRUPT__)   (((((uint8_t)(__INTERRUPT__)) >> 5U) == 1U)? (Instance->CR1 |= (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
                                                           ((((uint8_t)(__INTERRUPT__)) >> 5U) == 2U)? (Instance->CR2 |= (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
                                                           (Instance->CR3 |= (1U << ((__INTERRUPT__) & UART_IT_MASK))))

/** @brief  Disable the specified UART interrupt.
  * @param  Instance specifies the UARTx.
  * @param  __INTERRUPT__ specifies the UART interrupt source to disable.
  *          This parameter can be one of the following values:
  *            @arg @ref UART_IT_RXFF  RXFIFO Full interrupt
  *            @arg @ref UART_IT_TXFE  TXFIFO Empty interrupt
  *            @arg @ref UART_IT_RXFT  RXFIFO threshold interrupt
  *            @arg @ref UART_IT_TXFT  TXFIFO threshold interrupt
  *            @arg @ref UART_IT_WUF   Wakeup from stop mode interrupt
  *            @arg @ref UART_IT_CM    Character match interrupt
  *            @arg @ref UART_IT_CTS   CTS change interrupt
  *            @arg @ref UART_IT_LBD   LIN Break detection interrupt
  *            @arg @ref UART_IT_TXE   Transmit Data Register empty interrupt
  *            @arg @ref UART_IT_TXFNF TX FIFO not full interrupt
  *            @arg @ref UART_IT_TC    Transmission complete interrupt
  *            @arg @ref UART_IT_RXNE  Receive Data register not empty interrupt
  *            @arg @ref UART_IT_RXFNE RXFIFO not empty interrupt
  *            @arg @ref UART_IT_IDLE  Idle line detection interrupt
  *            @arg @ref UART_IT_PE    Parity Error interrupt
  *            @arg @ref UART_IT_ERR   Error interrupt (Frame error, noise error, overrun error)
  * @retval None
  */

#define _HAL_UART_DISABLE_IT(Instance, __INTERRUPT__)  (((((uint8_t)(__INTERRUPT__)) >> 5U) == 1U)? (Instance->CR1 &= ~ (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
                                                           ((((uint8_t)(__INTERRUPT__)) >> 5U) == 2U)? (Instance->CR2 &= ~ (1U << ((__INTERRUPT__) & UART_IT_MASK))): \
                                                           (Instance->CR3 &= ~ (1U << ((__INTERRUPT__) & UART_IT_MASK))))


/** @brief  Check whether the specified UART flag is set or not.
  * @param  Instance specifies the UART Handle.
  * @param  __FLAG__ specifies the flag to check.
  *        This parameter can be one of the following values:
  *            @arg @ref UART_FLAG_TXFT  TXFIFO threshold flag
  *            @arg @ref UART_FLAG_RXFT  RXFIFO threshold flag
  *            @arg @ref UART_FLAG_RXFF  RXFIFO Full flag
  *            @arg @ref UART_FLAG_TXFE  TXFIFO Empty flag
  *            @arg @ref UART_FLAG_REACK Receive enable acknowledge flag
  *            @arg @ref UART_FLAG_TEACK Transmit enable acknowledge flag
  *            @arg @ref UART_FLAG_WUF   Wake up from stop mode flag
  *            @arg @ref UART_FLAG_RWU   Receiver wake up flag (if the UART in mute mode)
  *            @arg @ref UART_FLAG_SBKF  Send Break flag
  *            @arg @ref UART_FLAG_CMF   Character match flag
  *            @arg @ref UART_FLAG_BUSY  Busy flag
  *            @arg @ref UART_FLAG_ABRF  Auto Baud rate detection flag
  *            @arg @ref UART_FLAG_ABRE  Auto Baud rate detection error flag
  *            @arg @ref UART_FLAG_CTS   CTS Change flag
  *            @arg @ref UART_FLAG_LBDF  LIN Break detection flag
  *            @arg @ref UART_FLAG_TXE   Transmit data register empty flag
  *            @arg @ref UART_FLAG_TXFNF UART TXFIFO not full flag
  *            @arg @ref UART_FLAG_TC    Transmission Complete flag
  *            @arg @ref UART_FLAG_RXNE  Receive data register not empty flag
  *            @arg @ref UART_FLAG_RXFNE UART RXFIFO not empty flag
  *            @arg @ref UART_FLAG_IDLE  Idle Line detection flag
  *            @arg @ref UART_FLAG_ORE   Overrun Error flag
  *            @arg @ref UART_FLAG_NE    Noise Error flag
  *            @arg @ref UART_FLAG_FE    Framing Error flag
  *            @arg @ref UART_FLAG_PE    Parity Error flag
  * @retval The new state of __FLAG__ (TRUE or FALSE).
  */

#define _HAL_UART_GET_FLAG(Instance, __FLAG__) ((Instance->ISR & (__FLAG__)) == (__FLAG__))

/** @brief  Clear the specified UART pending flag.
  * @param  Instance specifies the UART Handle.
  * @param  __FLAG__ specifies the flag to check.
  *          This parameter can be any combination of the following values:
  *            @arg @ref UART_CLEAR_PEF      Parity Error Clear Flag
  *            @arg @ref UART_CLEAR_FEF      Framing Error Clear Flag
  *            @arg @ref UART_CLEAR_NEF      Noise detected Clear Flag
  *            @arg @ref UART_CLEAR_OREF     Overrun Error Clear Flag
  *            @arg @ref UART_CLEAR_IDLEF    IDLE line detected Clear Flag
  *            @arg @ref UART_CLEAR_TXFECF   TXFIFO empty clear Flag
  *            @arg @ref UART_CLEAR_TCF      Transmission Complete Clear Flag
  *            @arg @ref UART_CLEAR_LBDF     LIN Break Detection Clear Flag
  *            @arg @ref UART_CLEAR_CTSF     CTS Interrupt Clear Flag
  *            @arg @ref UART_CLEAR_CMF      Character Match Clear Flag
  *            @arg @ref UART_CLEAR_WUF      Wake Up from stop mode Clear Flag
  * @retval None
  */

#define _HAL_UART_CLEAR_FLAG(Instance, __FLAG__) (Instance->ICR = (__FLAG__))

2、串口初始化

//将PA9复用为USART1_TX
//将PA10复用为USART1_RX
//本程序适合在中断程序中处理接收和在中断程序中处理发送

uint8_t USART1_RX_Buffer[USART1_RX_Buffer_Size]; //USART1接收缓冲区数组
uint8_t USART1_RX_Buffer_Load_Index;          //USART1_RX_Buffer[]的装载索引值

uint8_t USART1_TX_Buffer[USART1_TX_Buffer_Size]; //USART1发送缓冲区数组
uint8_t USART1_TX_Buffer_Load_Index;          //USART1_TX_Buffer[]的装载索引值
uint8_t USART1_TX_Buffer_Send_Index;          //发送下标值

void USART1_Init(uint32_t baudrate);
void USART1_Load_Send_Data(void);
void Start_USART1_Send_Data(void);

void USART1_Init(uint32_t baudrate)
{
    UART_HandleTypeDef HardwareUSART1;

    HardwareUSART1.Instance = USART1;
    HAL_UART_DeInit(&HardwareUSART1);
  //目的是令HardwareUSART1.gState = HAL_UART_STATE_RESET;
    //允许HAL_UART_Init()执行时,会先调用HAL_UART_MspInit()

  HardwareUSART1.Init.BaudRate = baudrate;              //波特率
  HardwareUSART1.Init.WordLength = UART_WORDLENGTH_8B;  //字长为8位数据格式
  HardwareUSART1.Init.StopBits = UART_STOPBITS_1;       //一个停止位
  HardwareUSART1.Init.Parity = UART_PARITY_NONE;        //无奇偶校验位
  HardwareUSART1.Init.Mode = UART_MODE_TX_RX;           //收发模式
  HardwareUSART1.Init.HwFlowCtl = UART_HWCONTROL_NONE;  //无硬件流控
  HardwareUSART1.Init.OverSampling = UART_OVERSAMPLING_16; //过采样率
  HardwareUSART1.Init.OneBitSampling = UART_ONE_BIT_SAMPLE_DISABLE;
    HardwareUSART1.AdvancedInit.AdvFeatureInit = UART_ADVFEATURE_NO_INIT;
  HardwareUSART1.AdvancedInit.AutoBaudRateEnable = UART_ADVFEATURE_AUTOBAUDRATE_DISABLE;
  HardwareUSART1.AdvancedInit.AutoBaudRateMode = UART_ADVFEATURE_AUTOBAUDRATE_ONSTARTBIT;
  HardwareUSART1.Init.ClockPrescaler = UART_PRESCALER_DIV1;
    HardwareUSART1.FifoMode=UART_FIFOMODE_DISABLE;
  if (HAL_UART_Init(&HardwareUSART1) != HAL_OK)
  {
    Error_Handler();
  }

使用“中断发送和接收”配置开始/

    __HAL_UART_CLEAR_FLAG(&HardwareUSART1, UART_CLEAR_TCF);
    //Transmission Complete Clear Flag

    __HAL_UART_ENABLE_IT(&HardwareUSART1, UART_IT_RXNE);
    开启串口接收中断
    //串口接收数据时,使能"接收数据寄存器不为空"则产生中断(位RXNE=1)
    //Enable the UART Data Register not empty Interrupt

    __HAL_UART_DISABLE_IT(&HardwareUSART1, UART_IT_TXE);
    //串口发送数据时,不使能"串口发送数据寄存器为空"产生中断(位TXE=0)
    //Disable the UART Transmit Complete Interrupt

    __HAL_UART_DISABLE_IT(&HardwareUSART1,UART_IT_TC);
    //串口发送数据时,不使能"串口发送完成"产生中断(位TC=1)

    HAL_NVIC_EnableIRQ(USART1_IRQn);
    HAL_NVIC_SetPriority(USART1_IRQn,8,0);
    //设置NVIC中断分组4:4位抢占优先级,0位响应优先级
    //选择中断优先级组4,即抢占优先级为4位,取值为0~15,响应优先级组为0位,取值为0
使用“中断发送和接收”配置结束/

    USART1_RX_Buffer_Load_Index = 0;
    memset(USART1_RX_Buffer,0,USART1_RX_Buffer_Size);
}

//HAL_UART_Init()执行时,会先调用HAL_UART_MspInit()
void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle)
{
  GPIO_InitTypeDef GPIO_InitStruct = {0};
  RCC_PeriphCLKInitTypeDef PeriphClkInit = {0};
  if(uartHandle->Instance==USART1)
  {
    PeriphClkInit.PeriphClockSelection = RCC_PERIPHCLK_USART1;
    PeriphClkInit.Usart1ClockSelection = RCC_USART1CLKSOURCE_PCLK2;
    if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInit) != HAL_OK)
    { //HAL_RCCEx_PeriphCLKConfig()初始化USART1外设时钟
            //Initializes the peripherals clocks

      Error_Handler();
    }

    __HAL_RCC_USART1_CLK_ENABLE(); //使能USART1外设时钟

    __HAL_RCC_GPIOA_CLK_ENABLE();  //使能GPIOA外设时钟
    GPIO_InitStruct.Pin = GPIO_PIN_9|GPIO_PIN_10;//选择引脚编号9和10
    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;      //复用功能推挽模式
    GPIO_InitStruct.Pull = GPIO_NOPULL;          //不用上拉
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; //引脚速度为低速
    GPIO_InitStruct.Alternate = GPIO_AF7_USART1; //将引脚复用为USART1
    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
  }
}

//HAL_UART_DeInit()执行时,会先调用HAL_UART_MspDeInit()
//其实这个程序没什么用

void HAL_UART_MspDeInit(UART_HandleTypeDef* uartHandle)
{
  if(uartHandle->Instance==USART1)
  {
    __HAL_RCC_USART1_CLK_DISABLE();//不使能USART1外设时钟
    HAL_GPIO_DeInit(GPIOA, GPIO_PIN_9|GPIO_PIN_10);
  }
}

3、启动发送

void Start_USART1_Send_Data(void)
{
    char i;

    for(i=0;i<USART1_RX_Buffer_Size;i++)//串口接送测试
    {
        if(USART1_RX_Buffer[i-1]=='\r'&&USART1_RX_Buffer[i]=='\n')//收到结束符号
        {
            USART1_RX_Buffer_Load_Index = 0;
            memset(USART1_TX_Buffer,0,USART1_TX_Buffer_Size);
            strcpy((char*)USART1_TX_Buffer,(char*)USART1_RX_Buffer);
            memset(USART1_RX_Buffer,0,USART1_RX_Buffer_Size);
            USART1_Load_Send_Data();
        }
  }
}

//函数功能:启动串口1发送
void USART1_Load_Send_Data(void)
{
    uint16_t k;

    k=strlen((char*)USART1_TX_Buffer);
    USART1_TX_Buffer_Load_Index = k;
    
启动发送/
    _HAL_UART_SendByte(USART1,USART1_TX_Buffer[0]);
    //发送一个字节
  //启动发送

    USART1_TX_Buffer_Send_Index=1;
    _HAL_UART_ENABLE_IT(USART1,UART_IT_TXE);//启动发送///
    //将"串口控制寄存器1(USART_CR1)中的TXEIE位"设置为1
    //串口发送数据时,使能"串口发送数据寄存器为空"产生中断(位TXEIE=1)
    //Enable the UART Transmit Complete Interrupt

}

4、串口中断程序

void USART1_IRQHandler(void)
{
    uint8_t RX_temp;

    (void)RX_temp;//防止RX_temp不使用而产生警告

    if( _HAL_UART_GET_FLAG(USART1,UART_FLAG_RXNE) )
    {//在串口状态寄存器中,发现RXNE=1
        RX_temp =_HAL_UART_ReceiveByte(USART1);//读串口数据

        USART1_RX_Buffer[USART1_RX_Buffer_Load_Index] = RX_temp;//保存接收到的新数据
        USART1_RX_Buffer_Load_Index++;
        if(USART1_RX_Buffer_Load_Index>=USART1_RX_Buffer_Size-2)
        {
            USART1_RX_Buffer[USART1_RX_Buffer_Size-2]='\0';
            USART1_RX_Buffer_Load_Index = 0;//防止USART1_RX_Buffer[]溢出
        }
        if(USART1_RX_Buffer[USART1_RX_Buffer_Load_Index-2]=='\r'&&USART1_RX_Buffer[USART1_RX_Buffer_Load_Index-1]=='\n')
        {//收到"\r\n"结束符号
            USART1_RX_Buffer[USART1_RX_Buffer_Load_Index]='\0';
            USART1_RX_Buffer_Load_Index++;
        }
        //软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将ORE位(Overrun错误标志)清零;
        //软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将NE位(噪声错误标志)清零;
        //软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将FE位(帧错误标志)清零;
        //软件先读"串口状态寄存器(USART_ISR)",然后再读"串口数据寄存器USART_RDR",就可以将PE位(奇偶校验值错误)清零;
        //软件读"串口数据寄存器USART_RDR",就可以将RXNE位清零

    }

  if( _HAL_UART_GET_FLAG(USART1,USART_ISR_TXE) )
    {
        _HAL_UART_CLEAR_FLAG(USART1,UART_CLEAR_TCF);//清除TXE标志位
        if(USART1_TX_Buffer_Send_Index < USART1_TX_Buffer_Load_Index) //未发送完全部数据
        {
        _HAL_UART_SendByte(USART1,USART1_TX_Buffer[USART1_TX_Buffer_Send_Index]);
        //将USART1_TX_Buffer[USART1_TX_Buffer_Send_Index]的值写入串口发送"串口发送数据寄存器"
            USART1_TX_Buffer_Send_Index++;
        }
        else
        {
        _HAL_UART_DISABLE_IT(USART1,UART_IT_TXE);
        //串口发送数据时,不使能"串口发送数据寄存器为空"产生中断(位TXE=0)
        //Disabless Transmit Data Register empty interrupt

          _HAL_UART_ENABLE_IT(USART1,UART_IT_TC);
            //将"串口控制寄存器1(USART_CR1)中的TCIE位"设置为1
            //串口发送数据时,使能"串口发送完成"产生中断(位TCIE=1)
            //Enables Transmission complete interrupt  
 
        }
    }
    if( _HAL_UART_GET_FLAG(USART1,USART_ISR_TC) )
    {
        _HAL_UART_CLEAR_FLAG(USART1,UART_CLEAR_TCF);

        _HAL_UART_DISABLE_IT(USART1,UART_IT_TC);
        //将"串口控制寄存器1(USART_CR1)中的TCIE位"设置为0
        //串口发送数据时,不使能"串口发送完成"产生中断(位TCIE=0)
        //Disable the UART Transmit Complete Interrupt

        USART1_TX_Buffer_Send_Index = 0;//清除USART1_TX_Buffer[]的发送索引值
        USART1_TX_Buffer_Load_Index = 0;//清除USART1_TX_Buffer[]的装载索引值
    }
}

  • 5
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值