はじめに:基板が届いた!

前回の記事では、ESP32を使ったネットワーク対応デジタル時計の設計から、KiCadでのプリント基板作成、JLCPCBへの発注までを解説しました。

本記事(第2弾)では、届いた基板への部品実装から、アラーム機能の追加、動作確認、壁掛け設置までを完全解説します。

本記事で学べること

基板到着から開封まで: JLCPCBの納期と梱包状態
部品実装テクニック: 0603チップ部品の手はんだ付けコツ
設計ミスのリカバリ: 実装時に発見したミスの修正方法
アラーム機能の実装: PWMブザー+リレー制御
RTC-8900の使い方: 正確な時刻管理
ケース収納: タカチプラボックスへの実装
動作確認: 実際に動いている様子

プロジェクト概要

項目 詳細
マイコン ESP32-WROOM-32
時刻管理 NTP同期 + RTC-8900(バックアップ)
表示 7セグ風LCDパネル × 6枚
I/O拡張 MCP23017 × 3個(I2C接続)
アラーム PWMブザー + 24Vパト ライト(リレー駆動)
基板 JLCPCB製造(2層、FR-4)

それでは、基板到着からスタートしましょう!


JLCPCBから基板が到着

前回 JLCPCB にガーバーデータをアップロードして発注をしておいたデジタル時計用基板が届きました。
さっそく開封して、部品実装→動作確認まで進めて行きます!

📦 到着までのタイムライン

前回の記事で発注を行った基板が手元に届くまでの時系列をまとめてみました。

日付 進捗
9/2 ガーバーデータをアップロード
9/3 入金確認
9/4 製造開始
9/6 完成 & 発送 🎉
9/8 手元に到着 (DHL)

発送方法にDHLを選択したというのもありますが、中国→日本でも 1 週間かからず。速さにびっくりです。 正直、2週間ぐらいは早くてもかかると思っていました…

到着した基板をチェックしていきます。

開封の儀

青いおなじみの箱で到着

青いおなじみの箱で到着

中には真空パックされた基板が 5 枚
(パック写真は興奮し過ぎて撮り忘れました…)

開封後の基板

開封後の基板

表裏ともにしっかりと仕上がっています(下記:左=表面、右=裏面)。

PCB表面
基板 表面
PCB裏面
基板 裏面

綺麗な緑色とシルクの印刷。実際に部品をはんだ付けして動かすのが楽しみです。 初めての自作基板なのでシルク・レジストの仕上がりに感動…!


基板への部品実装:SMDはんだ付けの実践

基板に部品を実装していきます。回路図は前回の記事を参照してください。

実装前に発見!設計ミスとその対策

部品を並べて実装を開始しようとしたところ、設計ミスを発見してしまいました…

発見したミス:

  • LDO(電圧レギュレータ)のフットプリントが間違っている
  • リレー駆動用のトランジスタ+プルアップ抵抗を描き忘れ

💡 2026年版アドバイス:
KiCad 8.xには Electrical Rules Check (ERC)Design Rules Check (DRC) がありますが、フットプリントの実物との照合は人間が確認する必要があります。実装前に必ずデータシートと照合しましょう!

Twitter でご指摘くださった方、本当にありがとうございます! 🙏
(回路図も修正済みです)

SMD部品実装のコツ(0603サイズ)

今回使用したチップ部品は 0603サイズ(1.6mm × 0.8mm)。手はんだの限界ギリギリです。

必要な工具

工具 推奨品 価格帯(2026年)
はんだコテ 白光 FX600 / HAKKO T12 ¥5,000~15,000
コテ先 0.5mmナイフ型 / C型 ¥500~1,000
はんだ 0.3mm~0.5mm 鉛フリー ¥500~
ピンセット ESD対応 先細 ¥500~2,000
フラックス ペンタイプ or ジェル ¥500~1,500
ルーペ 10倍拡大鏡 or USB顕微鏡 ¥1,000~5,000
はんだ吸い取り線 幅2mm ¥300~

0603チップ部品のはんだ付け手順

  1. パッドに予備はんだ: 片方のパッドにはんだを盛る
  2. 部品を片側固定: ピンセットで部品を持ち、予備はんだを溶かして片側を仮止め
  3. 反対側をはんだ付け: もう片方のパッドをはんだ付け
  4. 最初の側を再加熱: 仮止めした側を再度加熱して、しっかり接合

💡 コツ:

  • フラックスを惜しまず使う: はんだの流れが良くなる
  • コテ温度は320~350℃: 高すぎると基板やソルダーマスクを傷める
  • 3秒ルール: 1箇所への加熱は3秒以内、長時間加熱はNG
  • ブリッジしたら: 焦らず、フラックスを塗ってコテ先で吸い取る

💡 2026年版アップデート:
**0805サイズ(2.0mm × 1.25mm)**の方が手はんだしやすいので、次回の設計では0805を推奨します。価格もほぼ同じです。

実装済み基板の様子

実装済みPCB表面
実装済み基板 表面
実装済みPCB裏面
実装済み基板 裏面

設計ミスのリカバリ作業

フットプリントミスの部分を ジャンパ線で修正 しました。

パターンミス修正1
LDOフットプリントの修正
パターンミス修正2
トランジスタ回路の追加配線

これがいわゆる、違法建築というやつですね… 😅

修正内容:

  • LDOを0.5mmエナメル線でジャンパ接続
  • トランジスタとプルアップ抵抗を空中配線で追加

💡 リカバリのポイント:

  • 細いエナメル線を使用: 0.3mm~0.5mmが扱いやすい
  • 短い距離で配線: 長い配線はノイズの原因に
  • 絶縁に注意: 他のパターンとショートしないように
  • ホットボンドで固定: 配線を固定して機械的強度を確保

教訓

部品発注前にフットプリント確認
データシートと実物を照合
ERC/DRCだけに頼らない
レビューを人に頼む(自分では気づきにくい)

タカチケースへの収納

修正が終わったら、タカチのプラボックス SW-95B(または同等品)へ格納します。

ケースに収めた様子

ケースに収めた様子

ケース収納の工夫:

  • 四隅を少しヤスリで削ってジャストフィット
  • M3ネジ穴でスペーサー固定
  • LCDパネル用の窓をカッターで開口(アクリル板で保護)
  • 配線は基板裏側に這わせてすっきり

いざ、箱に収まるとプロっぽい見た目に!


アラーム機能の実装

前回の記事では時計の表示のみでしたが、今回は実用的なアラーム機能を追加します。

アラーム機能の仕様

設定時刻(例: 7:00)になると、以下が作動します:

出力 制御方法 用途
PWMブザー ESP32 GPIO5(LEDC PWM) アラーム音
24Vパトライト GPIO25 → リレー駆動 視覚的警告
解除スイッチ GPIO19(プルダウン) アラーム停止

使用したパトライト

PATLITE WH-24A-Y(中古品)

PATLITE WH-24A-Y(中古品)

PATLITE WH-24A-Y(オリジナルマインドで発掘)

仕様:

  • 24V DC駆動
  • 回転灯 + ブザー内蔵
  • 消費電流: 約200mA

💡 2026年版アップデート:
中古品の在庫は不安定です。Amazonで新品の小型回転灯(12V/24V)が¥2,000~3,000で購入できます。


Arduino プログラムの作成

プログラム全体の流れ

  1. Wi-Fi 接続 → NTP同期で現在時刻取得
  2. RTC (RX-8900) に時刻書き込み
  3. MCP23017 × 3個を初期化 → LCDパネル制御
  4. ループ処理:
    • RTCから時刻読み取り
    • LCDに表示更新
    • アラーム時刻チェック → ブザー/パトライト制御

必要なライブラリ

Arduino IDE 2.xのライブラリマネージャーからインストール:

  • Adafruit MCP23017 Arduino Library by Adafruit
  • WiFi (ESP32標準)
  • Wire (I2C、標準)

ソースコードのポイント解説

📄 クリックして全文コードを表示(800行以上あるので折りたたみ)

### スケッチ概要

1. **WiFi 接続**して NTP 同期  
2. RTC (**RX8900**) に現在時刻を書き込み  
3. I²C I/O エキスパンダで LCD ×6 枚を駆動  
4. ループで RTC から時刻読出し  LCD 更新  
5. アラーム時刻になったらブザー & パトライトを ON  
   スイッチ入力で解除

### ソースコード

作成したプログラムは以下のようになります。
※長いので冒頭のみ、クリックで全文見れます。

```cpp
#include <WiFi.h>
#include <Wire.h>
#include<time.h>
#include <stdlib.h>
#include <stdio.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp0;
Adafruit_MCP23017 mcp1;
Adafruit_MCP23017 mcp2;
const int alert = 5;
const int lump = 25;

const int switch_r = 19;
const int switch_w = 18;

char *ssid = "SSID";
char *pass = "PASSWORD";
★クリックして全文コードを表示
#include <WiFi.h>
#include <WiFi.h>
#include <Wire.h>
#include<time.h>
#include <stdlib.h>
#include <stdio.h>
#include "Adafruit_MCP23017.h"
Adafruit_MCP23017 mcp0;
Adafruit_MCP23017 mcp1;
Adafruit_MCP23017 mcp2;
const int alert = 5;
const int lump = 25;

const int switch_r = 19;
const int switch_w = 18;

char *ssid = "SSID";
char *pass = "PASSWORD"

int ihour, imin, isec, i, alert_flag = 0;
int h1, h2, m1, m2, s1, s2;
char hour, minute, sec;
int RegTbl[16];
byte RTC8900 = 0x32;
struct tm timeInfo;//時刻を格納するオブジェクト
char s[20];//文字格納用

int s0_D0_Pin = 0; //データライン0 out
int s0_D1_Pin = 1; //データライン1 out
int s0_D2_Pin = 2; //データライン2 out
int s0_D3_Pin = 3; //データライン3 out
int s0_Bsy_Pin = 4; //BUSY信号 in
int s0_Rst_Pin = 5; //RESET信号 通常LOW out
int s0_Str_Pin = 6; //STROBE信号 out

int s1_D0_Pin = 8; //データライン0 out
int s1_D1_Pin = 9; //データライン1 out
int s1_D2_Pin = 10; //データライン2 out
int s1_D3_Pin = 11; //データライン3 out
int s1_Bsy_Pin = 12; //BUSY信号 in
int s1_Rst_Pin = 13; //RESET信号 通常LOW out
int s1_Str_Pin = 14; //STROBE信号 out

int s2_D0_Pin = 0; //データライン0 out
int s2_D1_Pin = 1; //データライン1 out
int s2_D2_Pin = 2; //データライン2 out
int s2_D3_Pin = 3; //データライン3 out
int s2_Bsy_Pin = 4; //BUSY信号 in
int s2_Rst_Pin = 5; //RESET信号 通常LOW out
int s2_Str_Pin = 6; //STROBE信号 out

int s3_D0_Pin = 8; //データライン0 out
int s3_D1_Pin = 9; //データライン1 out
int s3_D2_Pin = 10; //データライン2 out
int s3_D3_Pin = 11; //データライン3 out
int s3_Bsy_Pin = 12; //BUSY信号 in
int s3_Rst_Pin = 13; //RESET信号 通常LOW out
int s3_Str_Pin = 14; //STROBE信号 out

int s4_D0_Pin = 0; //データライン0 out
int s4_D1_Pin = 1; //データライン1 out
int s4_D2_Pin = 2; //データライン2 out
int s4_D3_Pin = 3; //データライン3 out
int s4_Bsy_Pin = 4; //BUSY信号 in
int s4_Rst_Pin = 5; //RESET信号 通常LOW out
int s4_Str_Pin = 6; //STROBE信号 out

int s5_D0_Pin = 8; //データライン0 out
int s5_D1_Pin = 9; //データライン1 out
int s5_D2_Pin = 10; //データライン2 out
int s5_D3_Pin = 11; //データライン3 out
int s5_Bsy_Pin = 12; //BUSY信号 in
int s5_Rst_Pin = 13; //RESET信号 通常LOW out
int s5_Str_Pin = 14; //STROBE信号 out

//データの定義
int disp_0[8] = {0, 0, 0, 0, 0, 0, 0, 1};
int disp_1[8] = {1, 0, 0, 0, 0, 0, 0, 1};
int disp_2[8] = {0, 1, 0, 0, 0, 0, 0, 1};
int disp_3[8] = {1, 1, 0, 0, 0, 0, 0, 1};
int disp_4[8] = {0, 0, 1, 0, 0, 0, 0, 1};
int disp_5[8] = {1, 0, 1, 0, 0, 0, 0, 1};
int disp_6[8] = {0, 1, 1, 0, 0, 0, 0, 1};
int disp_7[8] = {1, 1, 1, 0, 0, 0, 0, 1};
int disp_8[8] = {0, 0, 0, 0, 1, 0, 0, 1};
int disp_9[8] = {1, 0, 0, 0, 1, 0, 0, 1};
int disp_A[8] = {0, 1, 0, 0, 1, 0, 0, 1};
int disp_B[8] = {1, 1, 0, 0, 1, 0, 0, 1};
int disp_C[8] = {0, 0, 1, 0, 1, 0, 0, 1};
int disp_D[8] = {1, 0, 1, 0, 1, 0, 0, 1};
int disp_E[8] = {0, 1, 1, 0, 1, 0, 0, 1};
int disp_F[8] = {1, 1, 1, 0, 1, 0, 0, 1};

int disp_H[8] = {1, 0, 0, 0, 0, 1, 0, 1};
int disp_I[8] = {0, 1, 0, 0, 0, 1, 0, 1};
int disp_J[8] = {1, 1, 0, 0, 0, 1, 0, 1};
int disp_L[8] = {1, 0, 1, 0, 0, 1, 0, 1};

int disp_O[8] = {0, 0, 0, 0, 1, 1, 0, 1};
int disp_P[8] = {1, 0, 0, 0, 1, 1, 0, 1};
int disp_S[8] = {0, 0, 1, 0, 1, 1, 0, 1};
int disp_U[8] = {0, 1, 1, 0, 1, 1, 0, 1};

int disp_BL[8] = {0, 0, 1, 0, 0, 0, 1, 1};
int disp_RR[8] = {0, 1, 1, 0, 0, 0, 1, 1};
int disp_RL[8] = {1, 1, 1, 0, 0, 0, 1, 1};


// DECIMAL -> BCD
byte dec2bcd( byte data )
{
  return ((( data / 10) << 4) + (data % 10));
}

// BCD -> DECIMAL

byte BCDtoDec(byte data) {
  return ((data >> 4) * 10) + (data & 0x0F) ;
}


void init_pin() {
  //各ピンLowにセット
  mcp0.digitalWrite(s0_D0_Pin, LOW);
  mcp0.digitalWrite(s0_D1_Pin, LOW);
  mcp0.digitalWrite(s0_D2_Pin, LOW);
  mcp0.digitalWrite(s0_D3_Pin, LOW);
  mcp0.digitalWrite(s0_Str_Pin, LOW);
  mcp0.digitalWrite(s0_Rst_Pin, LOW);
  mcp0.digitalWrite(s1_D0_Pin, LOW);
  mcp0.digitalWrite(s1_D1_Pin, LOW);
  mcp0.digitalWrite(s1_D2_Pin, LOW);
  mcp0.digitalWrite(s1_D3_Pin, LOW);
  mcp0.digitalWrite(s1_Str_Pin, LOW);
  mcp0.digitalWrite(s1_Rst_Pin, LOW);
  delay(100);
  mcp1.digitalWrite(s2_D0_Pin, LOW);
  mcp1.digitalWrite(s2_D1_Pin, LOW);
  mcp1.digitalWrite(s2_D2_Pin, LOW);
  mcp1.digitalWrite(s2_D3_Pin, LOW);
  mcp1.digitalWrite(s2_Str_Pin, LOW);
  mcp1.digitalWrite(s2_Rst_Pin, LOW);
  mcp1.digitalWrite(s3_D0_Pin, LOW);
  mcp1.digitalWrite(s3_D1_Pin, LOW);
  mcp1.digitalWrite(s3_D2_Pin, LOW);
  mcp1.digitalWrite(s3_D3_Pin, LOW);
  mcp1.digitalWrite(s3_Str_Pin, LOW);
  mcp1.digitalWrite(s3_Rst_Pin, LOW);
  delay(100);
  mcp2.digitalWrite(s4_D0_Pin, LOW);
  mcp2.digitalWrite(s4_D1_Pin, LOW);
  mcp2.digitalWrite(s4_D2_Pin, LOW);
  mcp2.digitalWrite(s4_D3_Pin, LOW);
  mcp2.digitalWrite(s4_Str_Pin, LOW);
  mcp2.digitalWrite(s4_Rst_Pin, LOW);
  mcp2.digitalWrite(s5_D0_Pin, LOW);
  mcp2.digitalWrite(s5_D1_Pin, LOW);
  mcp2.digitalWrite(s5_D2_Pin, LOW);
  mcp2.digitalWrite(s5_D3_Pin, LOW);
  mcp2.digitalWrite(s5_Str_Pin, LOW);
  mcp2.digitalWrite(s5_Rst_Pin, LOW);
  delay(100);
  //リセットかける
  mcp0.digitalWrite(s0_Rst_Pin, HIGH);
  mcp0.digitalWrite(s1_Rst_Pin, HIGH);
  delay(100);
  mcp1.digitalWrite(s2_Rst_Pin, HIGH);
  mcp1.digitalWrite(s3_Rst_Pin, HIGH);
  delay(100);
  mcp2.digitalWrite(s4_Rst_Pin, HIGH);
  mcp2.digitalWrite(s5_Rst_Pin, HIGH);
  delay(1000);
  mcp0.digitalWrite(s0_Rst_Pin, LOW);
  mcp0.digitalWrite(s1_Rst_Pin, LOW);
  delay(100);
  mcp1.digitalWrite(s2_Rst_Pin, LOW);
  mcp1.digitalWrite(s3_Rst_Pin, LOW);
  delay(100);
  mcp2.digitalWrite(s4_Rst_Pin, LOW);
  mcp2.digitalWrite(s5_Rst_Pin, LOW);
  delay(1000);
}


void write_display0(int disp_data) {
  int i;
  int val = 0;
  int data[8];

  switch (disp_data) {
    case 0:    memcpy(data, disp_0, sizeof(int) * 8);    break;
    case 1:    memcpy(data, disp_1, sizeof(int) * 8);    break;
    case 2:    memcpy(data, disp_2, sizeof(int) * 8);    break;
    case 3:    memcpy(data, disp_3, sizeof(int) * 8);    break;
    case 4:    memcpy(data, disp_4, sizeof(int) * 8);    break;
    case 5:    memcpy(data, disp_5, sizeof(int) * 8);    break;
    case 6:    memcpy(data, disp_6, sizeof(int) * 8);    break;
    case 7:    memcpy(data, disp_7, sizeof(int) * 8);    break;
    case 8:    memcpy(data, disp_8, sizeof(int) * 8);    break;
    case 9:    memcpy(data, disp_9, sizeof(int) * 8);    break;
  }

  while (mcp0.digitalRead(s0_Bsy_Pin) != LOW)
    continue;
  //LOWDATA書き込み
  mcp0.digitalWrite(s0_D0_Pin, data[0]);
  mcp0.digitalWrite(s0_D1_Pin, data[1]);
  mcp0.digitalWrite(s0_D2_Pin, data[2]);
  mcp0.digitalWrite(s0_D3_Pin, data[3]);
  mcp0.digitalWrite(s0_Str_Pin, HIGH);
  while (mcp0.digitalRead(s0_Bsy_Pin) != HIGH)
    continue;
  mcp0.digitalWrite(s0_Str_Pin, LOW);
  while (mcp0.digitalRead(s0_Bsy_Pin) != LOW)
    continue;
  mcp0.digitalWrite(s0_D0_Pin, data[4]);
  mcp0.digitalWrite(s0_D1_Pin, data[5]);
  mcp0.digitalWrite(s0_D2_Pin, data[6]);
  mcp0.digitalWrite(s0_D3_Pin, data[7]);
  delay(10);
  mcp0.digitalWrite(s0_Str_Pin, HIGH);
  while (mcp0.digitalRead(s0_Bsy_Pin) != HIGH)
    continue;
  mcp0.digitalWrite(s0_Str_Pin, LOW);

}

void write_display1(int disp_data) {
  int i;
  int val = 0;
  int data[8];

  switch (disp_data) {
    case 0:    memcpy(data, disp_0, sizeof(int) * 8);    break;
    case 1:    memcpy(data, disp_1, sizeof(int) * 8);    break;
    case 2:    memcpy(data, disp_2, sizeof(int) * 8);    break;
    case 3:    memcpy(data, disp_3, sizeof(int) * 8);    break;
    case 4:    memcpy(data, disp_4, sizeof(int) * 8);    break;
    case 5:    memcpy(data, disp_5, sizeof(int) * 8);    break;
    case 6:    memcpy(data, disp_6, sizeof(int) * 8);    break;
    case 7:    memcpy(data, disp_7, sizeof(int) * 8);    break;
    case 8:    memcpy(data, disp_8, sizeof(int) * 8);    break;
    case 9:    memcpy(data, disp_9, sizeof(int) * 8);    break;
  }

  while (mcp0.digitalRead(s1_Bsy_Pin) != LOW)
    continue;
  mcp0.digitalWrite(s1_D0_Pin, data[0]);
  mcp0.digitalWrite(s1_D1_Pin, data[1]);
  mcp0.digitalWrite(s1_D2_Pin, data[2]);
  mcp0.digitalWrite(s1_D3_Pin, data[3]);
  mcp0.digitalWrite(s1_Str_Pin, HIGH);
  while (mcp0.digitalRead(s1_Bsy_Pin) != HIGH)
    continue;
  mcp0.digitalWrite(s1_Str_Pin, LOW);
  while (mcp0.digitalRead(s1_Bsy_Pin) != LOW)
    continue;
  mcp0.digitalWrite(s1_D0_Pin, data[4]);
  mcp0.digitalWrite(s1_D1_Pin, data[5]);
  mcp0.digitalWrite(s1_D2_Pin, data[6]);
  mcp0.digitalWrite(s1_D3_Pin, data[7]);
  delay(10);

  mcp0.digitalWrite(s1_Str_Pin, HIGH);
  while (mcp0.digitalRead(s1_Bsy_Pin) != HIGH)
    continue;
  mcp0.digitalWrite(s1_Str_Pin, LOW);
}



void write_display2(int disp_data) {
  int i;
  int val = 0;
  int data[8];
  switch (disp_data) {
    case 0:    memcpy(data, disp_0, sizeof(int) * 8);    break;
    case 1:    memcpy(data, disp_1, sizeof(int) * 8);    break;
    case 2:    memcpy(data, disp_2, sizeof(int) * 8);    break;
    case 3:    memcpy(data, disp_3, sizeof(int) * 8);    break;
    case 4:    memcpy(data, disp_4, sizeof(int) * 8);    break;
    case 5:    memcpy(data, disp_5, sizeof(int) * 8);    break;
    case 6:    memcpy(data, disp_6, sizeof(int) * 8);    break;
    case 7:    memcpy(data, disp_7, sizeof(int) * 8);    break;
    case 8:    memcpy(data, disp_8, sizeof(int) * 8);    break;
    case 9:    memcpy(data, disp_9, sizeof(int) * 8);    break;
  }
  while (mcp1.digitalRead(s2_Bsy_Pin) != LOW)
    continue;
  //LOWDATA書き込み

  mcp1.digitalWrite(s2_D0_Pin, data[0]);
  mcp1.digitalWrite(s2_D1_Pin, data[1]);
  mcp1.digitalWrite(s2_D2_Pin, data[2]);
  mcp1.digitalWrite(s2_D3_Pin, data[3]);
  mcp1.digitalWrite(s2_Str_Pin, HIGH);
  while (mcp1.digitalRead(s2_Bsy_Pin) != HIGH)
    continue;
  mcp1.digitalWrite(s2_Str_Pin, LOW);
  while (mcp1.digitalRead(s2_Bsy_Pin) != LOW)
    continue;
  mcp1.digitalWrite(s2_D0_Pin, data[4]);
  mcp1.digitalWrite(s2_D1_Pin, data[5]);
  mcp1.digitalWrite(s2_D2_Pin, data[6]);
  mcp1.digitalWrite(s2_D3_Pin, data[7]);
  delay(10);
  mcp1.digitalWrite(s2_Str_Pin, HIGH);
  while (mcp1.digitalRead(s2_Bsy_Pin) != HIGH)
    continue;
  mcp1.digitalWrite(s2_Str_Pin, LOW);

}

void write_display3(int disp_data) {
  int i;
  int val = 0;
  int data[8];

  switch (disp_data) {
    case 0:    memcpy(data, disp_0, sizeof(int) * 8);    break;
    case 1:    memcpy(data, disp_1, sizeof(int) * 8);    break;
    case 2:    memcpy(data, disp_2, sizeof(int) * 8);    break;
    case 3:    memcpy(data, disp_3, sizeof(int) * 8);    break;
    case 4:    memcpy(data, disp_4, sizeof(int) * 8);    break;
    case 5:    memcpy(data, disp_5, sizeof(int) * 8);    break;
    case 6:    memcpy(data, disp_6, sizeof(int) * 8);    break;
    case 7:    memcpy(data, disp_7, sizeof(int) * 8);    break;
    case 8:    memcpy(data, disp_8, sizeof(int) * 8);    break;
    case 9:    memcpy(data, disp_9, sizeof(int) * 8);    break;
  }

  while (mcp1.digitalRead(s3_Bsy_Pin) != LOW)
    continue;
  mcp1.digitalWrite(s3_D0_Pin, data[0]);
  mcp1.digitalWrite(s3_D1_Pin, data[1]);
  mcp1.digitalWrite(s3_D2_Pin, data[2]);
  mcp1.digitalWrite(s3_D3_Pin, data[3]);
  mcp1.digitalWrite(s3_Str_Pin, HIGH);

  while (mcp1.digitalRead(s3_Bsy_Pin) != HIGH)
    continue;
  mcp1.digitalWrite(s3_Str_Pin, LOW);
  while (mcp1.digitalRead(s3_Bsy_Pin) != LOW)
    continue;
  mcp1.digitalWrite(s3_D0_Pin, data[4]);
  mcp1.digitalWrite(s3_D1_Pin, data[5]);
  mcp1.digitalWrite(s3_D2_Pin, data[6]);
  mcp1.digitalWrite(s3_D3_Pin, data[7]);
  delay(10);

  mcp1.digitalWrite(s3_Str_Pin, HIGH);
  while (mcp1.digitalRead(s3_Bsy_Pin) != HIGH)
    continue;
  mcp1.digitalWrite(s3_Str_Pin, LOW);

}



void write_display4(int disp_data) {
  int i;
  int val = 0;
  int data[8];

  switch (disp_data) {
    case 0:    memcpy(data, disp_0, sizeof(int) * 8);    break;
    case 1:    memcpy(data, disp_1, sizeof(int) * 8);    break;
    case 2:    memcpy(data, disp_2, sizeof(int) * 8);    break;
    case 3:    memcpy(data, disp_3, sizeof(int) * 8);    break;
    case 4:    memcpy(data, disp_4, sizeof(int) * 8);    break;
    case 5:    memcpy(data, disp_5, sizeof(int) * 8);    break;
    case 6:    memcpy(data, disp_6, sizeof(int) * 8);    break;
    case 7:    memcpy(data, disp_7, sizeof(int) * 8);    break;
    case 8:    memcpy(data, disp_8, sizeof(int) * 8);    break;
    case 9:    memcpy(data, disp_9, sizeof(int) * 8);    break;
  }

  while (mcp2.digitalRead(s4_Bsy_Pin) != LOW)
    continue;
  //LOWDATA書き込み
  mcp2.digitalWrite(s4_D0_Pin, data[0]);
  mcp2.digitalWrite(s4_D1_Pin, data[1]);
  mcp2.digitalWrite(s4_D2_Pin, data[2]);
  mcp2.digitalWrite(s4_D3_Pin, data[3]);
  mcp2.digitalWrite(s4_Str_Pin, HIGH);
  while (mcp2.digitalRead(s4_Bsy_Pin) != HIGH)
    continue;
  mcp2.digitalWrite(s4_Str_Pin, LOW);
  while (mcp2.digitalRead(s4_Bsy_Pin) != LOW)
    continue;
  mcp2.digitalWrite(s4_D0_Pin, data[4]);
  mcp2.digitalWrite(s4_D1_Pin, data[5]);
  mcp2.digitalWrite(s4_D2_Pin, data[6]);
  mcp2.digitalWrite(s4_D3_Pin, data[7]);
  delay(10);
  mcp2.digitalWrite(s4_Str_Pin, HIGH);
  while (mcp2.digitalRead(s4_Bsy_Pin) != HIGH)
    continue;
  mcp2.digitalWrite(s4_Str_Pin, LOW);
}

void write_display5(int disp_data) {
  int i;
  int val = 0;
  int data[8];

  switch (disp_data) {
    case 0:    memcpy(data, disp_0, sizeof(int) * 8);    break;
    case 1:    memcpy(data, disp_1, sizeof(int) * 8);    break;
    case 2:    memcpy(data, disp_2, sizeof(int) * 8);    break;
    case 3:    memcpy(data, disp_3, sizeof(int) * 8);    break;
    case 4:    memcpy(data, disp_4, sizeof(int) * 8);    break;
    case 5:    memcpy(data, disp_5, sizeof(int) * 8);    break;
    case 6:    memcpy(data, disp_6, sizeof(int) * 8);    break;
    case 7:    memcpy(data, disp_7, sizeof(int) * 8);    break;
    case 8:    memcpy(data, disp_8, sizeof(int) * 8);    break;
    case 9:    memcpy(data, disp_9, sizeof(int) * 8);    break;
  }

  while (mcp2.digitalRead(s5_Bsy_Pin) != LOW)
    continue;
  mcp2.digitalWrite(s5_D0_Pin, data[0]);
  mcp2.digitalWrite(s5_D1_Pin, data[1]);
  mcp2.digitalWrite(s5_D2_Pin, data[2]);
  mcp2.digitalWrite(s5_D3_Pin, data[3]);
  mcp2.digitalWrite(s5_Str_Pin, HIGH);
  while (mcp2.digitalRead(s5_Bsy_Pin) != HIGH)
    continue;
  mcp2.digitalWrite(s5_Str_Pin, LOW);
  while (mcp2.digitalRead(s5_Bsy_Pin) != LOW)
    continue;
  mcp2.digitalWrite(s5_D0_Pin, data[4]);
  mcp2.digitalWrite(s5_D1_Pin, data[5]);
  mcp2.digitalWrite(s5_D2_Pin, data[6]);
  mcp2.digitalWrite(s5_D3_Pin, data[7]);
  delay(10);

  mcp2.digitalWrite(s5_Str_Pin, HIGH);
  while (mcp2.digitalRead(s5_Bsy_Pin) != HIGH)
    continue;
  mcp2.digitalWrite(s5_Str_Pin, LOW);

}

void setup() {
  // initialize the digital pin as an output.
  delay(1000);
  Serial.begin(115200);
  Wire.begin();
  pinMode(lump, OUTPUT);
  pinMode(switch_w, OUTPUT);
  pinMode(switch_r, INPUT);
  gpio_set_pull_mode(GPIO_NUM_19, GPIO_PULLDOWN_ONLY);

  ledcSetup(0, 1000, 8);
  ledcAttachPin(alert, 0);

  WiFi.mode(WIFI_STA);
  WiFi.disconnect();
  if (WiFi.begin(ssid, pass) != WL_DISCONNECTED) {
    ESP.restart();
  }
  while (WiFi.status() != WL_CONNECTED) {
    delay(1000);
  }
  Serial.println("Connected to the WiFi network!");
  delay(1000);
  configTime(9 * 3600L, 0, "ntp.nict.jp", "time.google.com", "ntp.jst.mfeed.ad.jp");//NTPの設定
  getLocalTime(&timeInfo);//tmオブジェクトのtimeInfoに現在時刻を入れ込む
  delay(1);
  ihour = timeInfo.tm_hour;
  imin = timeInfo.tm_min;
  isec = timeInfo.tm_sec;
  sprintf(s, " %04d/%02d/%02d %02d:%02d:%02d",
          timeInfo.tm_year + 1900, timeInfo.tm_mon + 1, timeInfo.tm_mday,
          timeInfo.tm_hour, timeInfo.tm_min, timeInfo.tm_sec);//人間が読める形式に変換
  Serial.println(s);//時間をシリアルモニタへ出力

  mcp0.begin();
  mcp1.begin(0x04);
  mcp2.begin(0x06);

  mcp0.pinMode(s0_D0_Pin, OUTPUT);
  mcp0.pinMode(s0_D1_Pin, OUTPUT);
  mcp0.pinMode(s0_D2_Pin, OUTPUT);
  mcp0.pinMode(s0_D3_Pin, OUTPUT);
  mcp0.pinMode(s0_Bsy_Pin, INPUT);
  mcp0.pinMode(s0_Str_Pin, OUTPUT);
  mcp0.pinMode(s0_Rst_Pin, OUTPUT);

  mcp0.pinMode(s1_D0_Pin, OUTPUT);
  mcp0.pinMode(s1_D1_Pin, OUTPUT);
  mcp0.pinMode(s1_D2_Pin, OUTPUT);
  mcp0.pinMode(s1_D3_Pin, OUTPUT);
  mcp0.pinMode(s1_Bsy_Pin, INPUT);
  mcp0.pinMode(s1_Str_Pin, OUTPUT);
  mcp0.pinMode(s1_Rst_Pin, OUTPUT);

  mcp1.pinMode(s2_D0_Pin, OUTPUT);
  mcp1.pinMode(s2_D1_Pin, OUTPUT);
  mcp1.pinMode(s2_D2_Pin, OUTPUT);
  mcp1.pinMode(s2_D3_Pin, OUTPUT);
  mcp1.pinMode(s2_Bsy_Pin, INPUT);
  mcp1.pinMode(s2_Str_Pin, OUTPUT);
  mcp1.pinMode(s2_Rst_Pin, OUTPUT);

  mcp1.pinMode(s3_D0_Pin, OUTPUT);
  mcp1.pinMode(s3_D1_Pin, OUTPUT);
  mcp1.pinMode(s3_D2_Pin, OUTPUT);
  mcp1.pinMode(s3_D3_Pin, OUTPUT);
  mcp1.pinMode(s3_Bsy_Pin, INPUT);
  mcp1.pinMode(s3_Str_Pin, OUTPUT);
  mcp1.pinMode(s3_Rst_Pin, OUTPUT);

  mcp2.pinMode(s4_D0_Pin, OUTPUT);
  mcp2.pinMode(s4_D1_Pin, OUTPUT);
  mcp2.pinMode(s4_D2_Pin, OUTPUT);
  mcp2.pinMode(s4_D3_Pin, OUTPUT);
  mcp2.pinMode(s4_Bsy_Pin, INPUT);
  mcp2.pinMode(s4_Str_Pin, OUTPUT);
  mcp2.pinMode(s4_Rst_Pin, OUTPUT);

  mcp2.pinMode(s5_D0_Pin, OUTPUT);
  mcp2.pinMode(s5_D1_Pin, OUTPUT);
  mcp2.pinMode(s5_D2_Pin, OUTPUT);
  mcp2.pinMode(s5_D3_Pin, OUTPUT);
  mcp2.pinMode(s5_Bsy_Pin, INPUT);
  mcp2.pinMode(s5_Str_Pin, OUTPUT);
  mcp2.pinMode(s5_Rst_Pin, OUTPUT);

  init_pin();


  Wire.beginTransmission(RTC8900);
  Wire.write(0x00);
  Wire.write(byte(dec2bcd(isec)));// [02]Seconds(15秒)
  Wire.write(byte(dec2bcd(imin))); // [03]Minutes(20分)
  Wire.write(byte(dec2bcd(ihour)));// [04]Hours(12時)
  Wire.endTransmission();
  Wire.beginTransmission(RTC8900);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(RTC8900, 16);
  for (i = 0; i < 16; i++) {
    while (Wire.available() == 0 ) {}
    RegTbl[i] = Wire.read();
  }
  ihour = (BCDtoDec(RegTbl[2] & 0x3F));
  imin = (BCDtoDec(RegTbl[1] & 0x7F));
  isec = (BCDtoDec(RegTbl[0] & 0x7F));
  WiFi.disconnect();
}

// the loop routine runs over and over again forever:
void loop() {
  //アラームの設定
  if (ihour == 7 && imin = 0 && isec == 0) {
    alert_flag = 1;
    digitalWrite(lump, HIGH);
    digitalWrite(switch_w, HIGH);
    ledcWrite(0, 127);
  }
  if (alert_flag == 1 && digitalRead(switch_r) == 1) {
    alert_flag = 0;
    digitalWrite(lump, LOW);
    digitalWrite(switch_w, LOW);
    ledcWrite(0, 0);
  }
  Serial.println("LOOP");
  Wire.beginTransmission(RTC8900);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(RTC8900, 16);
  for (i = 0; i < 16; i++) {
    while (Wire.available() == 0 ) {}
    RegTbl[i] = Wire.read();
  }

  ihour = (BCDtoDec(RegTbl[2] & 0x3F));
  imin = (BCDtoDec(RegTbl[1] & 0x7F));
  isec = (BCDtoDec(RegTbl[0] & 0x7F));
  h1 = ihour / 10;
  h2 = ihour % 10;
  m1 = imin / 10;
  m2 = imin % 10;
  s1 = isec / 10;
  s2 = isec % 10;

  //LCDの表示
  write_display0(h1);
  write_display1(h2);
  write_display2(m2);
  write_display3(m1);
  write_display4(s2);
  write_display5(s1);

  delay(50);
}

相変わらず、長々と書いていますが参考になれば幸いです。

動作テスト

壁に掛けてみた様子。配線はまだ雑ですが、前回のユニバーサル基板 ver. と比べると雲泥の差でスッキリ✨

壁掛け設置

壁掛け設置

動作動画はこちら↓

時計もアラームも想定通りに動かすことができましたね。 これで、寝坊もしないし、朝は緊急感のある起床ができると思います!!


今後の展望

  • ケーブルを多芯でまとめてさらに美しく
  • アラーム/時刻設定を ブラウザ UI → 将来はクラウド連携へ
  • センサ値の表示やスマートリモコン化など、
      温湿度センサーや赤外線送受信モジュールを組み合わせて、スマートホーム連携にも対応させたい。

プリント基板を作れるようになると電子工作の世界が一気に広がりますね。
それでは Good Hack Life!

See You …