STM32でシリアル通信してみる 割り込み編 その1

  • 2020.02.08
  • HAL
STM32でシリアル通信してみる 割り込み編 その1

前回はポーリングによるシリアル通信を行いました。
今回は割り込みを使ったシリアル通信を行います。

割り込みを使うと手間がかかりますが、より細かい処理を行うことができます。
またポーリングの場合には事後処理になりますが、割り込みを使うと通信中の処理を書くことができます。

投稿時の開発環境を記しておきます。

PC:Windows10 OS
IDE: STM32CubeIDE Version1.1.0
Configurator: STM32CubeMX Version5.4.0
Board: STM32Nucleo-F401RE

File – New – STM32 Project から新規にプロジェクトを作成します。

Boart Selector で Boart List から NUCLEO-F401RE をクリックして選択し Nextボタンを押します。

Project Name にプロジェクト名(例えばここでは) F401UartIT を入力し Finishボタンを押します。

Initialize all peripherals with their default Mode? と聞いてきますので Yesボタンを押します。

コンフィグレーターで割り込みを許可する

Project Explorer で見えている水色のアイコンの F401UartIT.ioc をダブルクリックします。

左側の Connectivity の USART2 をクリックし、その右側の NVIC Interrupt Table の USART2 global interrupt の Enabled にチェックを入れます。

このチェックを入れないと割り込み処理に入りませんので注意してください。

コーディングしてみる

Project Explorer で F401UartIT – Core – Src – main.c をダブルクリックしてファイルを開きます。
まず以下のように2種類の変数を記述してください。
受信が完了したことを知らせる変数と受信バッファを定義します。

/* USER CODE BEGIN 0 */
int gUartReceived = 0;

/* USER CODE END 0 */

/**
  * @brief  The application entry point.
  * @retval int
  */
int main(void)
{
  /* USER CODE BEGIN 1 */
  uint8_t buffer[256];
  /* USER CODE END 1 */

次に whileループの部分を以下のようにコーディングします。

/* USER CODE BEGIN WHILE */
  while (1)
  {
    /* USER CODE END WHILE */

    /* USER CODE BEGIN 3 */
	HAL_UART_Receive_IT(&huart2, buffer, 2);
	while (gUartReceived == 0)
	{
		;
	}
	HAL_UART_Transmit_IT(&huart2, buffer, 2);
	gUartReceived = 0;
  }
  /* USER CODE END 3 */

受信割り込みが完了すると HAL_UART_RxCpltCallback() に来るので USER CODE BEGIN と END の間に以下のコードを書いてください。

/* USER CODE BEGIN 4 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
	gUartReceived = 1;
}
/* USER CODE END 4 */

PCからデータが2つ送られてきたら HAL_UART_RxCpltCallback() に来て gUartReceived を 1 にするので、その結果 whileループをぬけて、送られてきたデータを返すというものです。
ここまで書いたらビルドしてエラーがないことを確認しておいてください。

それでは次の関数が何を行っているのかさっと確認してみましょう。

HAL_UART_Receive_IT(&huart2, buffer, 2);

この関数をダブルクリックして選択し右クリック後、Open Declarationを選択します。(またはF3キーを押します)

huart->pRxBuffPtr = pData;
huart->RxXferSize = Size;
huart->RxXferCount = Size;
__HAL_UART_ENABLE_IT(huart, UART_IT_PE);
__HAL_UART_ENABLE_IT(huart, UART_IT_ERR);
__HAL_UART_ENABLE_IT(huart, UART_IT_RXNE);

構造体のポインタ変数に受信バッファの先頭アドレスをセットしています。
それから受信するデータのサイズをサイズとカウンタ変数にセットしています。
そして受信系の割り込み要因を検出したら割り込みが入るようにしています。

割り込みベクタを確認する

STM32ではNVICと呼ばれる割り込みコントローラがあります。

それについてはSTM32F401のリファレンスマニュアル(日本語)に詳しく書かれているのでご覧になってください。
マニュアルは こちら からダウンロードすることができます。

マニュアルの10項にベクタテーブルがあり、ここにいろいろな割り込み要因が書かれています。
USART2は位置38のところに見つかりました。

このベクタテーブルはソース上では F401UartIT > Core > Startup > startup_stm32f401retx.s に書かれています。
ツリーをたどってファイルをダブルクリックしてください。

197行目に USART2_IRQHandler というベクタが見つかりました。
ベクタは関数のアドレスと考えておけば良いです。

USART2_IRQHandler をダブルクリックして選択し右クリックして Open Declaration を選択します。
候補が2つ出てくるので、 stm32f4xx_it.c の方を選んでください。

HAL_UART_IRQHandler をダブルクリックして選択し右クリックして Open Declaration を選択します。

ここに UART の割り込み処理が書かれています。
ここではデータを受信する部分の UART_Receive_IT について見てみましょう。

HAL_UART_IRQHandler の中をたどっていくと UART_Receive_IT があるのでダブルクリックして選択し、右クリック後 Open Declaration を選択します。

関数内の処理概要:

受信したデータをバッファに保存した後、カウンタの値を -1 してゼロになったら受信完了の処理を行う。

受信完了処理の中に HAL_UART_RxCpltCallback があるので、受信完了時に処理を行いたい場合には、この関数の中に書けば良いわけです。
このプログラムでは gUartReceived = 1; にしています。

尚 HAL_UART_RxCpltCallback には _weak属性がついているので、ここでは main.c に関数を実装しています。
_weak属性のついている関数は、何も書かなければデフォルトのものが採用されるし、書けばそちらを使うことになっています。
(関数名が重複していてもエラーにならないしくみになっています)

少し長くなりましたので、この続きは次回にします。

HALカテゴリの最新記事