web-dev-qa-db-ja.com

割り込みによるSTM32 HAL USART受信

USART経由でデータを受信するのに問題があります。実際に達成したいのは、特定の長さ(可能な最大長のみ)なしでUSARTを介してコマンドを受信できることです。したがって、割り込みルーチンを使用して、受信した各文字をチェックしますが、どういうわけか自分が望むものを達成できません。このルーチンは、新しいキャラクターを受け取るたびに呼び出されますが、何らかの理由でHAL_UART_Receive_IT(&huart1、rx_data、buff_size_rx)がリアルタイムでアップグレードされず、rx_data [pointer]をチェックするときに受け取ったキャラクターが表示されませんが、しばらくすると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 */
}
5
HansPeterLoft

HAL_UART_Receive_IT()は、そのように割り込みハンドラーから呼び出されるのではなく、割り込みを介してfixedバイト数の受信を開始するためのものです。

可能な回避策は、入力バッファーをチェックすることですafterHAL_UART_IRQHandler()が完了した、つまり_/* USER CODE BEGIN USART1_IRQn 1 */_セクションで。コマンドが処理されると、ハンドル構造内のpRxBuffPtrRxXferCountを元の値にリセットして、バッファの先頭から再び開始できます。

別の 恐ろしい 考えられる回避策は、バッファサイズ1でHAL_UART_Receive_IT()を呼び出し、毎回受信バイトをチェックし、HAL_UART_RxCpltCallback()を再度呼び出すHAL_UART_Receive_IT()ハンドラを設定することです。必要に応じて。

もちろん、PeterJや他の人(常に)が示唆しているように、HALなしでも実行できます。

  • ピンと割り込みのセットアップは既に実装済みで、最初は変更しないでください。
  • リファレンスマニュアルに従って_UART->BRR_値を計算するか、halから関連するコードをコピーします。
  • set _UART->CR1=USART_CR1_RE|USART_CR1_TE|USART_CR1_UE|USART_CR1_RXNEIE;_現在、割り込みが発生しています。
  • 割り込み関数で、_UART->SR_を一時変数に読み込んで調べます。
  • 待機中の受信バイトがある場合は_UART->DR_を読み取り、それ以外の場合は(後で)エラー処理を行います。
  • 上記が機能しているとき、残りのHAL呼び出しを取り除きます。

組み込みアプリケーションでは、割り込み応答と処理時間はしばしばcriticalであり、HALはその多くを浪費します。

通常のHALライブラリは、長さの異なる連続受信やコマンドには役立ちません。

完全なHALパッケージがインストールされている場合、[〜#〜] l [〜#〜] ow [〜#〜] l [〜#〜 ]インターフェイスを開発します。

Projects\STM32F411RE-Nucleo\Examples_LL\USART\USART_Communication_Rx_IT_Continuous

主なことは、usartを継続的な受信に設定することです。

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ハンドラーは次のようになります

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();
  }
}

最後に設定するのはコールバックです

void USART_CharReception_Callback(void);

バイトをバッファに入れて、メインループまたは任意の場所で処理できる場所。

4
theSealion