首页 文章

STM32 HAL USART通过中断接收

提问于
浏览
2

通过USART接收数据我遇到了一些麻烦 . 我实际想要实现的是,我可以通过USART接收没有特定长度的命令(只有最大可能的长度) . 所以我使用中断例程检查收到的每个字符,但我仍然无法实现我想要的 . 每次收到一个新字符时都会调用该例程,但不知怎的HAL_UART_Receive_IT(&huart1,rx_data,buff_size_rx)没有实时升级,那么当我检查rx_data [指针]时我看不到收到的字符,但是几次之后它位于rx_data缓冲区中 .

到目前为止我所拥有的:

int pointer =0;

...

void USART1_IRQHandler(void)
{
  /* USER CODE BEGIN USART1_IRQn 0 */
    if ( USART1->ISR & UART_IT_TXE) {

    }

    if ( USART1->ISR & UART_IT_RXNE) {
        HAL_UART_Receive_IT(&huart1,rx_data,buff_size_rx);
        if(rx_data[pointer]=='\0') {
              pointer=0;
              readCommand(rx_data);
              clearBuffer(rx_data,buff_size_rx);
        } else {
          pointer++;
          if(pointer>=buff_size_rx) {
              pointer=0;
          }
        }
    }
    /* USER CODE END USART1_IRQn 0 */
    HAL_UART_IRQHandler(&huart1);
    /* USER CODE BEGIN USART1_IRQn 1 */



  /* USER CODE END USART1_IRQn 1 */
}

2 回答

  • 3

    HAL_UART_Receive_IT() 不是要从中断处理程序那样调用,而是通过中断启动接收 fixed 字节数 .

    可能的解决方法是在 HAL_UART_IRQHandler() 完成后检查输入缓冲区,即在 /* USER CODE BEGIN USART1_IRQn 1 */ 部分 . 处理命令时,可以将句柄结构中的 pRxBuffPtrRxXferCount 重置为其原始值,以便再次从缓冲区的起始位置开始 .

    另一个可怕的可能解决方法是使用缓冲区大小为1调用 HAL_UART_Receive_IT() ,并设置一个 HAL_UART_RxCpltCallback() 处理程序,每次检查接收到的字节,并在必要时再次调用 HAL_UART_Receive_IT() .

    当然,你可以在没有HAL的情况下做到这一点,就像PeterJ和其他人(总是)建议的那样 .

    • 您已经实现了引脚和中断设置,首先保持不变 .

    • 根据参考手册计算 UART->BRR 值,或从hal复制相关代码 .

    • set UART->CR1=USART_CR1_RE|USART_CR1_TE|USART_CR1_UE|USART_CR1_RXNEIE; 现在,您正在获得中断 .

    • 在中断函数中,将 UART->SR 读入临时变量,并检查它 .

    • 当收到的字节等待时读取 UART->DR ,否则执行错误处理(稍后) .

    • 当上述工作正常时,摆脱其余的HAL调用 .

    中断响应和处理时间在嵌入式应用程序中通常至关重要,而HAL只是浪费了很多 .

  • 1

    普通的HAL库对于连续接收或具有不同长度的命令没有用 .

    如果安装了完整的HAL包,则可以查看 L ow L evel接口的示例 .

    Projects\STM32F411RE-Nucleo\Examples_LL\USART\USART_Communication_Rx_IT_Continuous
    

    最重要的是让你接受连续接收:

    void Configure_USART(void) {    
        /* (1) Enable GPIO clock and configures the USART pins *********************/
    
        /* Enable the peripheral clock of GPIO Port */
        USARTx_GPIO_CLK_ENABLE();
    
        /* Configure Tx Pin as : Alternate function, High Speed, Push pull, Pull up */
        LL_GPIO_SetPinMode(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_MODE_ALTERNATE);
        USARTx_SET_TX_GPIO_AF();
        LL_GPIO_SetPinSpeed(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
        LL_GPIO_SetPinOutputType(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
        LL_GPIO_SetPinPull(USARTx_TX_GPIO_PORT, USARTx_TX_PIN, LL_GPIO_PULL_UP);
    
        /* Configure Rx Pin as : Alternate function, High Speed, Push pull, Pull up */
        LL_GPIO_SetPinMode(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_MODE_ALTERNATE);
        USARTx_SET_RX_GPIO_AF();
        LL_GPIO_SetPinSpeed(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_SPEED_FREQ_HIGH);
        LL_GPIO_SetPinOutputType(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_OUTPUT_PUSHPULL);
        LL_GPIO_SetPinPull(USARTx_RX_GPIO_PORT, USARTx_RX_PIN, LL_GPIO_PULL_UP);
    
        /* (2) NVIC Configuration for USART interrupts */
        /*  - Set priority for USARTx_IRQn */
        /*  - Enable USARTx_IRQn */
        NVIC_SetPriority(USARTx_IRQn, 0);  
        NVIC_EnableIRQ(USARTx_IRQn);
    
        /* (3) Enable USART peripheral clock and clock source ***********************/
        USARTx_CLK_ENABLE();
    
        /* (4) Configure USART functional parameters ********************************/
        /* TX/RX direction */
        LL_USART_SetTransferDirection(USARTx_INSTANCE, LL_USART_DIRECTION_TX_RX);
    
        /* 8 data bit, 1 start bit, 1 stop bit, no parity */
        LL_USART_ConfigCharacter(USARTx_INSTANCE, LL_USART_DATAWIDTH_8B, LL_USART_PARITY_NONE, LL_USART_STOPBITS_1);
    
        /* No Hardware Flow control */
        /* Reset value is LL_USART_HWCONTROL_NONE */
        // LL_USART_SetHWFlowCtrl(USARTx_INSTANCE, LL_USART_HWCONTROL_NONE);
    
        /* Oversampling by 16 */
        /* Reset value is LL_USART_OVERSAMPLING_16 */
        // LL_USART_SetOverSampling(USARTx_INSTANCE, LL_USART_OVERSAMPLING_16);
    
        /* Set Baudrate to 115200 using APB frequency set to 100000000/APB_Div Hz */
        /* Frequency available for USART peripheral can also be calculated through LL RCC macro */
        /* Ex :
            Periphclk = LL_RCC_GetUSARTClockFreq(Instance); or 
            LL_RCC_GetUARTClockFreq(Instance); depending on USART/UART instance
    
            In this example, Peripheral Clock is expected to be equal to 
            100000000/APB_Div Hz => equal to SystemCoreClock/APB_Div
        */
        LL_USART_SetBaudRate(USARTx_INSTANCE, SystemCoreClock/APB_Div, LL_USART_OVERSAMPLING_16, 115200); 
    
        /* (5) Enable USART *********************************************************/
        LL_USART_Enable(USARTx_INSTANCE);
    }
    

    USART IT Handler看起来应该是这样的

    void USARTx_IRQHandler(void)
    {
      /* Check RXNE flag value in SR register */
      if(LL_USART_IsActiveFlag_RXNE(USARTx_INSTANCE) && LL_USART_IsEnabledIT_RXNE(USARTx_INSTANCE))
      {
        /* RXNE flag will be cleared by reading of DR register (done in call) */
        /* Call function in charge of handling Character reception */
        USART_CharReception_Callback();
      }
      else
      {
        /* Call Error function */
        Error_Callback();
      }
    }
    

    最后要设置的是Callback

    void USART_CharReception_Callback(void);
    

    您可以将字节放入缓冲区并在主循环中或您想要的位置处理它 .

相关问题