フェーズ2

E2-03 時間になったら動く(周期処理:正確な点滅)

シリーズ:実験シリーズ(フェーズ2)
対応ロードマップ:フェーズ2 / E2-03
今回の役割:E2-02で作った1msの時刻を使い、delayに頼らずに一定周期で処理を実行する基本形を作る。

1. 目的

今回は、1msごとに増えるカウンタを使って、500msたったらLEDを切り替える 実験を行います。
これにより、delay で待つのではなく、時間を数えて周期的に動く処理 の基本を作るのが目的です。

2. 前提・環境

  • 評価ボード:RTK7EKA8M2S00001BE
  • 開発環境:e² studio + FSP
  • 前提
    • E1-02:点滅周期を変える(定数→変数)ができている
    • E2-01:delayの限界を体験(他処理できない)ができている
    • E2-02:タイマで1ms毎にカウントアップするストップウォッチを作る ができている
  • 今回使うもの
    • 評価ボード本体
    • オンボードLED
  • 今回の考え方
    • E2-02 で作った 1msごとに増えるカウンタ を使う
    • そのカウンタを見て、「500msたったらLEDを反転する」という処理を書く

3. 今回の変更点

3-1. 配線変更

  • なし
  • 評価ボードのオンボードLEDをそのまま使います

3-2. 設定変更

  • なし(E2-02のまま)
  • 1ms周期のタイマ設定をそのまま使います

3-3. コード変更

E1-02 では、R_BSP_SoftwareDelay() を使ってLEDを点滅させました。
E2-02 では、1msごとに増える時刻を作りました。
今回はその2つを合わせて、LED点滅を delay ではなくタイマを使って動かす 形に変えます。

4. 手順

4-1. まず今回やりたいことを日本語で整理する

今回は次の流れです。

  1. タイマの割り込みで、1msごとにカウンタを増やす
  2. 繰り返しの処理(メインループ)中には止まらず、ずっと繰り返す
  3. 500ms たっていたら、LEDを反転する
  4. カウンタを0クリアして、これを繰り返す

ここで大事なのは、「500ms待つ」のではなく、「500msたったかどうかを確認する」 ことです。

4-2. 考え方:delay と何が違うか

delay(500ms) を使うと、その 500ms の間、CPUは待ち続けます。
一方で今回のやり方は、繰り返しの処理を続けながら

  • まだ500msたっていない → 今回は何もしない
  • 500ms経過した → LEDを切り替える

という形にします。
つまり、CPUは「止まって待つ」のではなく、タイマを見て判断する ようになります。

4-3. 今回の考え方

今回は、LED用として 500msカウンタ を1つ持ちます。

  • 1msごとに g_blink_count_ms を増やす
  • 500になったらLEDを反転する
  • 反転したら g_blink_count_ms を0に戻す

この形なら、

  • 1msが500回たまる
  • だから500msたった

と考えられます。

4-4. FSP設定を確認する

今回は E2-02 の設定をそのまま使います。
E2-02で設定した概要は次の通りです。

  1. FSP Configurator(configuration.xml)を開く
  2. 1ms周期のタイマが設定されていることを確認する
  3. コールバック関数が設定されていることを確認する
  4. Generate Project Content」を実行する

※今回はタイマ設定の追加ではなく、E2-02で作った1msタイマを使って周期処理を作ること です。

5. コード

5-1. 考え方

今回のコードでやることは、次の4つです。

  1. 1msタイマのコールバックで g_blink_count_ms を 1msごとに増やす
  2. 繰り返し処理(メインループ)でg_blink_count_ms を読む
  3. 500ms経過していたらLEDを反転する
  4. g_blink_count_msを0クリアして、次の500msをカウントする

5-2. コード例

※オンボードLEDのピン名は、これまでの実験で使っているものに合わせてください。
※下の例では、以前と同じく BSP_IO_PORT_06_PIN_00 を使っています。
※タイマ名やコールバック名は、FSPで生成された名前に合わせて読み替えてください。

#include "hal_data.h"
#include <stdbool.h>
#include <stdint.h>

volatile uint32_t g_blink_count_ms = 0;  
volatile bool g_blink_500ms_flag = false;

void timer0_callback(timer_callback_args_t * p_args)
{
    FSP_PARAMETER_NOT_USED(p_args);

    g_blink_count_ms++;

    if (g_blink_count_ms >= 500)
    {
        g_blink_count_ms = 0;
        g_blink_500ms_flag = true;
    }
}

void hal_entry(void)
{
    fsp_err_t err;
    bool led_on = false;

    /* 1msタイマ開始 */
    err = R_AGT_Open(&g_timer0_ctrl, &g_timer0_cfg);
    if (FSP_SUCCESS != err)
    {
        while (1)
        {
        }
    }

    err = R_AGT_Start(&g_timer0_ctrl);
    if (FSP_SUCCESS != err)
    {
        while (1)
        {
        }
    }

    while (1)
    {
        if (g_blink_500ms_flag)
        {
            g_blink_500ms_flag = false;
            led_on = !led_on;

            if (led_on)
            {
                R_BSP_PinWrite(BSP_IO_PORT_06_PIN_00, BSP_IO_LEVEL_HIGH);
            }
            else
            {
                R_BSP_PinWrite(BSP_IO_PORT_06_PIN_00, BSP_IO_LEVEL_LOW);
            }
        }

        /* ここは空でもよい
           将来はこの中にボタン監視やログ出力などを追加できる */
    }
}

5-3. このコードで見てほしいポイント

1) g_blink_count_ms は500msを数えるカウンタ

この変数は、1msごとに1ずつ増えます。
そして 500 になったら、

  • 500msたった
  • だからLEDを切り替えてよい

と判断します。

2) 500になったら0へ戻す

今回は初心者向けに分かりやすくするため、
500msカウンタ方式 にしています。
つまり、

  • 0から数える
  • 500になったら動く
  • また0から数える

という形です。

3) 割り込みの中ではLEDを直接切り替えない

今回は、割り込みの中では

  • カウントを増やす
  • 500msたったらフラグを立てる

だけにしています。

実際のLED切り替えはメインループ側で行います。

6. 実行結果

  • オンボードLEDが 約500msごとに点灯/消灯 した
  • delay を使っていないのに、一定周期で点滅した
  • メインループが止まっていないので、今後ここへ別の処理を足せる形になった

7. 今回わかったこと

今回の実験で一番大事なのは、次の1点です。

  • 時間になったら動く、という書き方にすると、待ち時間でもプログラム全体が止まらない

8. ハマりポイント/原因と対策

8-1. LEDがまったく点滅しない

原因

  • タイマが開始できていない
  • コールバック関数が呼ばれていない
  • LEDピン名が違う

対策

  • R_AGT_Open()R_AGT_Start() の戻り値を確認する
  • timer0_callback() が正しく登録されているか確認する
  • これまでの実験と同じオンボードLEDピンを使っているか確認する

8-2. LEDが1回だけ変わって止まる

原因

  • フラグをfalseにしていない
  • カウンタを0クリアしていない
  • コールバックが継続して呼ばれていない

対策

  • g_blink_500ms_flag = false; が記述されているか確認する
  • g_blink_count_ms = 0; が記述されているか確認する
  • g_blink_count_ms が増え続けているかデバッガで見る

8-3. g_blink_count_ms が増えない

原因

  • タイマの開始に失敗している
  • コールバック名がFSP設定と合っていない
  • 割り込み設定が入っていない

対策

  • FSPで生成されたタイマ名が g_timer0 か確認する
  • コールバック名が timer0_callback になっているか確認する
  • Generate後の名前とコード中の名前が一致しているか確認する

8-4. 周期が不安定に見える

原因

  • タイマ周期が1msになっていない
  • ほかの重い処理を入れている

対策

  • E2-02 の設定が 1ms周期になっているか見直す
  • まずはLED反転だけの最低限のシンプルなコードで確認する

9. 次回やること

次は、E2-04 複数周期タスク(例:A=100ms / B=700ms) に進みます。
1つの時刻を使って、複数の周期処理を同時に動かす形へ広げます。

10. 関連リンク

  • E2-01 delayの限界を体験(他処理できない)(リンク)
  • E2-02 タイマで1ms毎にカウントアップするストップウォッチを作る(リンク)
  • E2-04 複数周期タスク(例:A=100ms/B=700ms)(リンク)
  • 基礎:組み込み開発とは(リンク)
  • 基礎:マイコン(RA8M2):はじめに読む(リンク)
  • 基礎:C言語のはじめ(LED点滅で必要なところだけ)(リンク)

-フェーズ2