【Arduino】只見駅の発車時刻案内掲示板・発車ブザーをArduinoで作ってみた

私は鉄道が子供の時から好きだったのですが、車両を運転したいというよりも電光掲示板や看板などを作ってみたいという思いがありました。
本物をヤフオクとかで落として使う技術はないですが、趣味で自作するくらいできるのでは？と思い作ってみました。

## 作成した成果物
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">⚠️音量注意！<br>只見線の発車ブザーと電光掲示板のおもちゃを自作してみました！<br>もちろん実際に鉄道会社で使われているわけではないですが、似たシステムを自分で作れると嬉しいですね。<a href="https://twitter.com/hashtag/Arduino?src=hash&amp;ref_src=twsrc%5Etfw">#Arduino</a> <a href="https://twitter.com/hashtag/%E9%9B%BB%E5%AD%90%E5%B7%A5%E4%BD%9C?src=hash&amp;ref_src=twsrc%5Etfw">#電子工作</a> <a href="https://twitter.com/hashtag/%E3%83%96%E3%82%B6%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#ブザー</a> <a href="https://twitter.com/hashtag/LCD%E3%83%87%E3%82%A3%E3%82%B9%E3%83%97%E3%83%AC%E3%82%A4?src=hash&amp;ref_src=twsrc%5Etfw">#LCDディスプレイ</a> <a href="https://twitter.com/hashtag/%E3%83%9D%E3%83%86%E3%83%B3%E3%82%B7%E3%83%A7%E3%83%A1%E3%83%BC%E3%82%BF?src=hash&amp;ref_src=twsrc%5Etfw">#ポテンショメータ</a> <a href="https://t.co/Aul2q3KTwg">pic.twitter.com/Aul2q3KTwg</a></p>&mdash; ikedat_mtbukoh3 (@ikedat_mtbukoh3) <a href="https://twitter.com/ikedat_mtbukoh3/status/1721127806409875884?ref_src=twsrc%5Etfw">November 5, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">最終列車が行ったら、ちゃんと運転終了したことを表示します笑 <a href="https://t.co/ZiUcoRQfY5">pic.twitter.com/ZiUcoRQfY5</a></p>&mdash; ikedat_mtbukoh3 (@ikedat_mtbukoh3) <a href="https://twitter.com/ikedat_mtbukoh3/status/1721154099599868226?ref_src=twsrc%5Etfw">November 5, 2023</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

JR只見線・只見駅という実在の路線の駅に列車が来たと仮定します。
ボタンAを押したらブザーが鳴って電光掲示板が点滅して、ボタンBを押したらブザーが止まって電光掲示板には次の電車が表示されるという仕組みになっています。
最終列車が行った後はちゃんと列車運転終了した表示もしていますｗ

遊びで作ったものではありますが、発車ブザーを鳴動用のON/OFFボタンの制御はできていますし、実物の電光掲示板もおそらく定数に設定したLEDを点灯させるだけなので、意外と作れるものですね。

## 回路図
回路図作成には[fritizing](https://fritzing.org/)を使いました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2744610/ce824224-7c51-9a61-09b7-4bd5e0cb9fc2.png)

## 使用した部品
- Arduino UNO
- Passiveブザー
- LCDディスプレイ
- ポテンショメーター
- 抵抗
- 導線
- ブレッドボード

上記はすべてArduinoスターターキットに入っていたものです。
[ELEGOO Arduino用UNO R3スターターキット](https://www.amazon.co.jp/ELEGOO-%25E3%2582%25AD%25E3%2583%2583%25E3%2583%2588-%25E3%2583%25AC%25E3%2583%2599%25E3%2583%25AB%25E3%2582%25A2%25E3%2583%2583%25E3%2583%2597-%25E3%2583%2581%25E3%2583%25A5%25E3%2583%25BC%25E3%2583%2588%25E3%2583%25AA%25E3%2582%25A2%25E3%2583%25AB%25E4%25BB%2598-mega2560-Arduino%25E7%2594%25A8/dp/B06XF2HZGT/ref=sr_1_5?adgrpid=51379988857&hvadid=665685690365&hvdev=c&hvlocphy=1009313&hvnetw=g&hvqmt=b&hvrand=15043389842159251413&hvtargid=kwd-570844455116&hydadcr=27490_14701104&jp-ad-ap=0&keywords=arduino+%25E3%2582%25B9%25E3%2582%25BF%25E3%2583%25BC%25E3%2582%25BF%25E3%2583%25BC%25E3%2582%25AD%25E3%2583%2583%25E3%2583%2588&qid=1693314577&sr=8-5&_encoding=UTF8&tag=ikeeki0f-22&linkCode=ur2&linkId=74608f745cda4ec0b146244002c8a3ef&camp=247&creative=1211)

## 今後の課題
ボタンを押すと音楽が鳴って電光掲示板が点滅して動き出す。別のボタンを押すと音楽が止まり次の列車を表示する。
ゴチャゴチャしていますがシステム自体は単純です。ポテンショメータがあるおかげで明るさの調整までできるのが良いですね。
ボタンの押し具合や接続の関係で動かない可能性があるのは良くないですね。
これはやっぱり安物だからなのか…

総制作費用は数千円程度で、この程度なら9V電池でも動くので、外国人観光客の多い地方私鉄の有人駅とかなら、配線とかを隠して大きいタクトスイッチを使用して使うのも良いんじゃないかなあ。
~~導入したい鉄道・バス会社などございましたら、当ブログまたはX（旧：twitter）までお気軽にご連絡ください~~
…もっとも、これを導入するくらいならiPadなどタブレットで使えるスマホアプリを作るほうがはるかに良さそうですね…ｗ

## ソースコード
``` C++
/*
* 　只見駅定期列車発車メロディ（2023年版）
* 　回路：ブザー・ディスプレイ回路
* 　作成日:2023/11/03 作成者:mtbukoh3
*/

//https://omoroya.com/arduino-lesson16/

#include <LiquidCrystal.h>

const int buzzerStartSwitchPin = 5;
const int buzzerStopSwitchPin = 6;
const int buzzerPin = 13;

const int rs = 7;
const int en = 8;
const int d4 = 9;
const int d5 = 10;
const int d6 = 11;
const int d7 = 12;

//変数の生成とPIN[rs:7 en:8 d4:9 d5:10 d6:11 d7:12]に対応
LiquidCrystal lcd(rs, en, d4, d5, d6, d7);

// ディスプレイ表示メッセージ
const String AIZU_WAKAMATSU = "Aizu-Wakamatsu";
const String AIZU_WAKAMATSU_TIME[3] = {"07:11(arr10:32)", "14:35(arr17:24)", "18:01(arr20:55)"};
const String KOIDE = "Koide";
const String KOIDE_TIME[3] = {"09:30(arr10:41)", "16:31(arr17:47)", "20:03(arr21:26)"};
const String FINAL_TRAIN_TOP_ROW_DISPLAY = "Train operation";
const String FINAL_TRAIN_BOTTOM_ROW_DISPLAY = "finished";

const int buzzerFrequencyInboundTrain = 554.365;
const int buzzerFrequencyOutboundTrain = 311.127;
const int buzzerMelo = 15000;

int departureCountAizuWakamatsu = 0;
int departureCountKoide = 0;

boolean DIRECTION_FLAG = false;
boolean OPERATION_FLAG = false;

void setup() {
  // put your setup code here, to run once:
  pinMode(buzzerStartSwitchPin, INPUT_PULLUP);
  pinMode(buzzerStopSwitchPin, INPUT_PULLUP);
  Serial.begin(9600);
  DIRECTION_FLAG = true;
  OPERATION_FLAG = true;
  departureCountAizuWakamatsu = 0;
  departureCountKoide = 0;

  // LCDの列を16列(0-15)、行を2行(0-1)に指定
  lcd.begin(16, 2);
  lcd.clear();
  // 文字表示位置を0文字目0行目に設定し、文字出力
  lcd.setCursor(0, 0);
  lcd.print(AIZU_WAKAMATSU);
  // ２行目の文字表示位置を1文字目1行目に設定し、文字出力
  lcd.setCursor(1, 1);
  lcd.print(AIZU_WAKAMATSU_TIME[0]);
  delay(3000);
}

void loop() {
  // put your main code here, to run repeatedly:
  if (digitalRead(buzzerStartSwitchPin) == LOW) {
    if (OPERATION_FLAG) {
      Serial.println("Switch is ON");
      if (DIRECTION_FLAG) {
        // ブザー音を鳴らす
        tone(buzzerPin, buzzerFrequencyInboundTrain, buzzerMelo);
        // LCD点滅処理
        for (int i = 0; i < 4; i++) {
          // ディスプレイを表示停止
          lcd.noDisplay();
          delay(900);
          // ディスプレイを表示
          lcd.display();
          delay(1200);
          if (digitalRead(buzzerStopSwitchPin) == LOW) {
            Serial.println("Buzzer Stop");
            break;
          }
        }
        // ブザー音を止める
        noTone(buzzerPin);

        // ディスプレイをリセットして待機
        lcd.begin(16, 2);
        delay(700);

        // 文字表示位置を0文字目0行目に設定し、文字出力
        lcd.setCursor(0, 0);
        lcd.print(KOIDE);
        // ２行目の文字表示位置を1文字目1行目に設定、文字出力
        lcd.setCursor(1, 1);
        lcd.print(KOIDE_TIME[departureCountKoide]);
        // 無限ループ(ずっと表示させる)
        //while(1);
        DIRECTION_FLAG = false;
        departureCountAizuWakamatsu++;
      } else {
        // ブザー音を鳴らす
        tone(buzzerPin, buzzerFrequencyOutboundTrain, buzzerMelo);

        // LCD点滅処理
        for (int i = 0; i < 4; i++) {
          // ディスプレイを表示停止
          lcd.noDisplay();
          delay(900);
          // ディスプレイを表示させる
          lcd.display();
          delay(1200);
          if (digitalRead(buzzerStopSwitchPin) == LOW) {
            Serial.println("Buzzer Stop");
            break;
          }
        }
        // ブザー音を停止
        noTone(buzzerPin);
        // ディスプレイをリセットして待機
        lcd.begin(16, 2);
        delay(700);

        // 文字表示位置を0文字目0行目に設定し、文字出力
        lcd.setCursor(0, 0);
        lcd.print(AIZU_WAKAMATSU);
        // ２行目の文字表示位置を1文字目1行目に設定、文字出力
        lcd.setCursor(1, 1);
        lcd.print(AIZU_WAKAMATSU_TIME[departureCountAizuWakamatsu]);
        DIRECTION_FLAG = true;
        departureCountKoide++;
      }

      if (departureCountAizuWakamatsu >= 3 && departureCountKoide >= 3 && OPERATION_FLAG) {
        OPERATION_FLAG = false;
        // ディスプレイをリセットして待機
        lcd.begin(16, 2);
        lcd.clear();
        // 文字表示位置を0文字目0行目に設定し、文字出力
        lcd.setCursor(0, 0);
        lcd.print(FINAL_TRAIN_TOP_ROW_DISPLAY);
        // ２行目の文字表示位置を1文字目1行目に設定、文字出力
        lcd.setCursor(1, 1);
        lcd.print(FINAL_TRAIN_BOTTOM_ROW_DISPLAY);
      }
    } else {
      // LCD点滅処理
      for (int i = 0; i < 3; i++) {
        // ディスプレイを表示停止
        lcd.noDisplay();
        delay(900);

        // ディスプレイを表示させる
        lcd.display();
        delay(1200);
      }
      // ディスプレイをリセットして待機
      lcd.begin(16, 2);
      delay(700);
      setup();
    }
  }
}

```
## 参考リンク
- Arduino 入門 Lesson 16 【LCD モジュール編】
https://omoroya.com/arduino-lesson16/

- ArduinoでSTEM教育​ 基礎編：LCDモジュール
https://stemship.com/post-355/