STM32のFreeRTOSのタイマーの使い方

STM32のFreeRTOSでタイマーの使い方を、サンプルコードと合わせてわかりやすく解説します。

作成するプログラム

まずはゴールを確認しておきましょう。今回はタイマーを使ってLEDを点滅するプログラムを作ります。1000ms間隔にタイムアウトするタイマーを用意し、タイムアウトの度にLEDの点灯・消灯を切り替えることで実現します。

 

タイマーを使ったプログラム

 

前提条件

前提条件は目次の記事を参照してください。

【サンプルあり】STM32のFreeRTOSの使い方まとめ

 

プログラムの作成

タイマーの有効化

FreeRTOSではタイマーを使う場合、OSの設定で有効化しておく必要があります。

 

  • Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Config Parameters
  • USE_TIMERSをEnabledに変更してください

 

タイマーの有効化

 

タイマーの作成

タイマーを作ってみましょう。

 

  • Pinout & Configurationsタブ→Middleware→FREERTOS→Configurationタブ→Timers and Semaphores
  • TimersのAddボタンをクリックして、タイマーの設定画面を開いてください
  • 下記の図のように入力して、OKボタンを押してください

 

タイマーの作成

 

ここの設定項目が気になる方は下記の表をご覧になってください。気にせず、とにかく動かしたい方は読み飛ばしてくださいね。

 

項目 説明
Timer Name タイマーの名前。
Callback コールバック関数の名前。
Type

タイマーの種類。

osTimerOnceだと1回だけタイムアウトする。

osTimerPeriodicだと周期的にタイムアウトする。

Code Generation Option

コールバック関数の接頭語。

Defaultだと何も付けない。

As externalだとexternが付く。

As weakだと__weakが付く。

Parameter コールバック関数に渡すパラメータ。
Allocation

メモリ確保の方法。

Dymanicだと動的確保。

Staticだと静的確保。

Control Block Name コントロールブロックの名前。Staticの時のみ使用。

 

Parameterで『&ledState』を指定しました。これはタイマー側でLEDのON/OFF状態を管理できるようにするためです。ON/OFF状態を保持するledStateという変数を別途用意し、そのポインタを指定している形です。

 

設定が終わったらコードを自動生成してください。

 

LEDのON/OFF状態を保持する変数を作成

先ほどタイマの設定で指定したledStateを用意してあげましょう。0の時OFF、1の時ONということにします。

 

main.c:ledState

/* USER CODE BEGIN 0 */
uint32_t ledState = 0;
/* USER CODE END 0 */

 

タイマーを実装

LEDを点滅するタイマーを実装しましょう。まずはコードをご覧になってください。

 

main.c:LEDTimerCallback

void LEDTimerCallback(void const * argument)
{
  /* USER CODE BEGIN LEDTimerCallback */
  uint16_t ledState = getLEDState(argument);
  if (ledState == 0) {
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
  } else {
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
  }
  /* USER CODE END LEDTimerCallback */
}

 

ledStateの状態に応じてLEDの点灯・消灯を行うようにしているのがわかると思ます。

ledStateの取得はgetLEDState()関数から行うようにしました。これには理由があります。次にgetLEDState()関数の中身をご覧になってください。

 

main.c:getLEDState()

/* USER CODE BEGIN 4 */
static uint16_t getLEDState(void const *argument) {

  uint16_t *ledState = pvTimerGetTimerID((TimerHandle_t)argument);

  if (*ledState == 0) {
    *ledState = 1;
  } else {
    *ledState = 0;
  }

  return *ledState;
}

 

コールバック関数の引数からledStateを取得するかと思いきや、pvTimerGetTimerID()からledStateを取得していますね。

実は、コールバック関数の引数には、本来Parameterで指定したものが入っているべきところ、STM32のFreeRTOSではタイマーのハンドラが入っています。

そのため、そのタイマーのハンドラを使ってpvTimerGetTimerID()からParameterを取得しているのです。

おそらくこれはSTM32のFreeRTOSのバグと思われます。そのため、将来修正される可能性があることを考慮して、ledStateの取得は関数にまとめておくことにしました。こうしておけば修正が入った時に、この関数を修正すればコールバック関数に影響はありません。

 

タイマーの開始

タイマーは作っただけでは動作しません。タイマーの開始処理を忘れずに入れておきましょう。

 

main.c:タイマーの開始処理

/* USER CODE BEGIN RTOS_TIMERS */
/* start timers, add new ones, ... */
osTimerStart(LEDTimerHandle, 1000);
/* USER CODE END RTOS_TIMERS */

 

osTimerStart()でタイマーを開始できます。第1引数はタイマーのハンドラを指定します。第2引数でタイムアウトまでの時間をms単位で指定します。

 

プログラムの作成は以上です。実際に動かしてLEDが点滅することを確認してみてください。

 

まとめ

STM32のFreeRTOSのタイマーの使い方は以上です。注意すべき点がいくつかありますが、手順通り使えば問題なく動作しますので、記事をよく読み直して使ってみてください。

下記の手順は忘れやすいので気を付けてください。

  • OSの設定でタイマーの有効化
  • タイマーの開始

また、タイマーにパラメータを渡す時は、バグと思われる箇所があるので、解説した方法で取得するようにしてください。

 

目次:【サンプルあり】STM32のFreeRTOSの使い方まとめ

ソースコード:https://github.com/yuksblog/stm32_freertos