フェーズ1

E1-07 チャタリングを“見える化”する(ログ/LED):1回押したつもりでも複数回反応する

シリーズ:実験シリーズ(フェーズ1)
対応ロードマップ:フェーズ1 / E1-07
今回の役割:ボタンを1回押したつもりでも、実際には押した/離したが細かく揺れて複数回反応することを、UARTログとLEDの動きで見えるようにする。

1. 目的

今回は、チャタリング を観察します。
タクトスイッチは、押した瞬間に理想的に1回だけ切り替わるわけではなく、実際には接点が細かく揺れて、短時間に何回もON/OFFしたような状態になることがあります。

この現象を チャタリング と言います。
今回は、この現象が実際に起きる様子を

  • ログに複数回表示される
  • LEDが1回押しただけなのに複数回反応することがある

という形で確認します。

次回の E1-08 ボタン入力を安定させる(デバウンス) では、この問題を減らす方法を扱います。

2. 前提・環境

  • 評価ボード:RTK7EKA8M2S00001BE
  • 開発環境:e² studio + FSP
  • 前提:
    • E0-01〜E0-06 が完了している
    • E0-05 のUARTログ出力ができる
    • E1-05 のボタン入力(ポーリング)ができる
    • E1-06 のプルアップ/プルダウンを体験済み
  • 使用部品
    • LED × 1
    • 抵抗:1kΩ × 1
    • タクトスイッチ × 1
    • ブレッドボード
    • ジャンパ線
    • UARTログ確認用のPC環境(TeraTermなど)
  • 使用するGPIO
    • 外付けLED用GPIO:P409(J25-9)
    • ボタン入力用GPIO:P704(J25-10)
    • GND:J25-11

3. 回路・配線

今回は、E1-05 と同じ配線 を使います。
新しい部品は増やしません。
ポイントは、ボタン入力を“安定化せずにそのまま読む” ことで、チャタリングを観察することです。

  • LED側
    GPIO → 1kΩ抵抗 → LED → GND
  • ボタン側
    ボタン入力GPIO → タクトスイッチ → GND

今回は 内部プルアップ を使います。
そのため、押していないときは High、押したときは Low を読む構成です。

3-1. 配線の考え方

  • LEDは「反応した回数」を目で見やすくするために使います
  • ボタンは、押した瞬間と離した瞬間の変化をそのまま読みます
  • 今回は安定化(デバウンス)を入れません
  • そのため、1回押しただけでも、ログ上は複数回変化したように見えることがあります

3-2. 配線図・配線写真

E1 05 配線全体
外付けLED配線 ブレッドボード E1 05

3-3. 注意点

  • タクトスイッチの向きが違うと、意図した通りにつながりません
  • GNDが共通になっていないと、正しく入力を読めません
  • 今回は「わざと不安定さを見る回」ですが、配線ミスとチャタリングは別です
  • まずは E1-05 と同じ配線が正しいことを確認してから進めます

4. 接続手順

4-1. 先に電源を切る

最初に評価ボードの電源を切ります。
通電したまま配線を触ると、ショートや誤配線の原因になります。

4-2. E1-05 の配線をそのまま使う

次の2本ができているか確認します。

  • LED用GPIO → 1kΩ抵抗 → LED → GND
  • ボタン入力用GPIO → タクトスイッチ → GND

4-3. UARTログの接続を確認する

今回はログを見るので、E0-05 で使ったUARTログ出力環境も確認します。

  • COM番号が合っているか
  • TeraTermなどが開けるか
  • ログが見える状態になっているか

4-4. 配線を再確認する

今回は「チャタリング」を観察したいので、配線ミスでおかしくなっている状態ではなく、
正しい配線で、現実のスイッチのクセを見る ことが大切です。

5. FSP設定

今回は、基本的に E1-05 の設定をそのまま使います。
ボタン入力は内部プルアップ有効、LEDは出力です。
UART設定も、E0-05 の設定をそのまま使います。

5-1. Pins設定

  1. FSP Configurator(configuration.xml)→ Pins を開きます
  2. LED用GPIO:P409 を次のように設定します
    • Mode:Output mode (Initial Low)
  3. ボタン入力用GPIO:P704 を次のように設定します
    • Mode:Input mode
    • Pull-up/down:Input pull-up
  4. 設定を確認したら「Generate Project Content」を実行します

5-2. UART設定

  • E0-05 で作成した UARTログ出力設定をそのまま使います
  • 今回は新しいUART設定は追加しません

6. コード

今回は、入力状態が変わった瞬間をそのまま記録 します。
まだデバウンスは入れません。
そのため、ボタンの接点が揺れると、短時間に何回も状態が変わった と判定されることがあります。

6-1. 先に考え方

今回は次の流れで確認します。

  1. ボタン入力を読む
  2. 前回の状態と違ったら「変化した」とみなす
  3. 変化するたびに
  • LEDを反転する
  • UARTログを出す
  1. 1回押しただけでも、ログが複数回出ることを観察する

ポイントは、今回は“正しく1回だけ反応させる”のが目的ではない ことです。
むしろ、1回だけのつもりでも複数回反応してしまう ことを確認するのが目的です。

6-2. 最小コード

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

static void uart_send_string(const uint8_t * p_msg, uint32_t len)
{
    fsp_err_t err;

    err = R_SCI_B_UART_Write(&g_uart0_ctrl, p_msg, len);
    if (FSP_SUCCESS != err)
    {
        while (1) {;}
    }

    /* 簡易待ち */
    for (volatile uint32_t i = 0; i < 100000U; i++)
    {
        __asm volatile ("nop");
    }
}

void hal_entry(void)
{
    fsp_err_t err;
    bsp_io_level_t sw_level;
    bsp_io_level_t prev_sw_level = BSP_IO_LEVEL_HIGH;
    bsp_io_level_t led_level = BSP_IO_LEVEL_LOW;

    static const uint8_t start_msg[]    = "Chattering observe start\r\n";
    static const uint8_t pressed_msg[]  = "PRESSED\r\n";
    static const uint8_t released_msg[] = "RELEASED\r\n";

    /* UART Open */
    err = R_SCI_B_UART_Open(&g_uart0_ctrl, &g_uart0_cfg);
    if (FSP_SUCCESS != err)
    {
        while (1) {;}
    }

    R_BSP_PinAccessEnable();

    /* 初期状態:LED消灯 */
    R_BSP_PinWrite(BSP_IO_PORT_04_PIN_09, BSP_IO_LEVEL_LOW);

    uart_send_string(start_msg, (uint32_t)(sizeof(start_msg) - 1));

    while (1)
    {
        sw_level = R_BSP_PinRead(BSP_IO_PORT_07_PIN_04);

        /* 状態が変わったら、その都度そのまま反応する */
        if (sw_level != prev_sw_level)
        {
            /* LEDを反転 */
            if (led_level == BSP_IO_LEVEL_LOW)
            {
                led_level = BSP_IO_LEVEL_HIGH;
            }
            else
            {
                led_level = BSP_IO_LEVEL_LOW;
            }

            R_BSP_PinWrite(BSP_IO_PORT_04_PIN_09, led_level);

            /* UARTログ出力 */
            if (sw_level == BSP_IO_LEVEL_LOW)
            {
                uart_send_string(pressed_msg, (uint32_t)(sizeof(pressed_msg) - 1));
            }
            else
            {
                uart_send_string(released_msg, (uint32_t)(sizeof(released_msg) - 1));
            }
        }

        prev_sw_level = sw_level;
    }
}

6-3. このコードで何が起きるか

たとえば理想的には、

  • 押したときに 1回
  • 離したときに 1回

だけ反応してほしいです。
しかし実際には、ボタンの接点が細かく揺れるため、

  • PRESSED
  • RELEASED
  • PRESSED
  • RELEASED

のように、短時間に何回も変化したようなログが出ることがあります。
これが、今回見たい チャタリング です。

7. 実行結果

7-1. 期待する観察結果

  • ボタンを1回押したつもりでも、ログが複数行 出ることがある
  • ボタンを離したときにも、複数回変化したようなログ が出ることがある
  • LEDが一瞬だけ複数回反応したように見えることがある
  • 毎回まったく同じ回数になるとは限らない

7-2. ログ例

[I] Chattering observe start
[I] edge=1 state=PRESSED press=1 release=0
[I] edge=2 state=RELEASED press=1 release=1
[I] edge=3 state=PRESSED press=2 release=1
[I] edge=4 state=RELEASED press=2 release=2

このように、1回押しただけのつもりでも複数回反応 することがあります。
これが「押した瞬間に理想通り1回だけ切り替わっていない」ことの証拠です。

8. ハマりポイントと直し方

8-1. ログがまったく出ない

原因

  • UART設定ができていない
  • TeraTermなどの設定が合っていない
  • uart_printf() などのログ関数が正しく動いていない

直し方

  • E0-05 のUARTログ記事に戻って設定を確認する
  • COM番号、ボーレート、改行設定を見直す
  • 最初に固定文字列が出るか確認する

8-2. 1回押しても1回しか反応しない

原因

  • たまたまチャタリングが目立たなかった
  • ループの中に大きな待ち時間が入っていて、細かい変化を取り逃している
  • スイッチや配線の状態によって揺れが小さい

直し方

  • 何回か押して試す
  • ゆっくり押す/ゆっくり離すも試す
  • ループの中に不要な delay が入っていないか確認する

補足

  • 1回しか出ないことがあっても失敗ではありません
  • 毎回必ず同じように見えるわけではないのが、現実の入力らしいところです

8-3. ログが多すぎて読みにくい

原因

  • 接点が大きく揺れている
  • 配線の接触も不安定になっている
  • 変化のたびに全部出しているため、短時間に行数が増える

直し方

  • まずは正しい配線か確認する
  • ジャンパ線やスイッチがしっかり刺さっているか確認する
  • 今回は「多く出ること」自体が観察対象なので、まずはそのまま見てよい

8-4. 配線ミスなのかチャタリングなのか分からない

原因

  • 入力が浮いている
  • プルアップ設定ができていない
  • GNDが共通になっていない
  • 実際のチャタリングと、単純な誤配線が混ざっている

直し方

  • E1-05 の「押したら点灯、離したら消灯」に一度戻る
  • E1-06 のプルアップ/プルダウン構成を見直す
  • 押していないときの状態が安定しているかを確認する

補足

  • 今回見たいのは「正しい配線の上で起きる、現実のスイッチの揺れ」です
  • 配線ミスで不安定になっている場合は、先にそこを直します

9. 次回やること

次は、E1-08 ボタン入力を安定させる(デバウンス) に進みます。
今回見えた「1回押したのに複数回反応する」を、自分の手で減らしていきます。

10. 関連リンク

  • E1-05 ボタン入力でLEDを点ける(ポーリング)(リンク)
  • E1-06 プルアップ/プルダウンを体験(リンク)
  • E1-08 ボタン入力を安定させる(デバウンス)(リンク)
  • E0-05 UARTログ入門(リンク)
  • プルアップ/プルダウン入門(リンク)
  • ボタンが不安定なとき(デバウンス入門)(リンク)
  • 組み込み開発とは(リンク)

-フェーズ1