工業製造
産業用モノのインターネット | 工業材料 | 機器のメンテナンスと修理 | 産業プログラミング |
home  MfgRobots >> 工業製造 >  >> Manufacturing Technology >> 製造プロセス

Arduinoで作る本格キッチンタイマー:LCD表示・4ボタン操作・ブザー搭載

必要な部品と材料

Arduino UNO ×1
Adafruit 16x2 LCD(白文字/青背景) ×1
タクトスイッチ 12mm ×4
抵抗 10kΩ(プルダウン用) ×4
抵抗 220Ω(ブザー/LED用) ×2
ポテンショメータ 100kΩ(LCDコントラスト調整) ×1
ブザー(圧電スピーカー) ×1
ブレッドボード & ジャンパーワイヤー 各1

プロジェクト概要

市販の100円キッチンタイマーを自作し、その仕組みを理解しようというプロジェクトです。Arduino Starter Kitの部品だけで構築でき、電源はPCのUSBポートで動作します。

動作モード(4つのステート)

タイマーは常に以下のいずれか1つのモードで動作します。

ハードウェア構成のポイント

ソフトウェア構成

ライブラリ

主要な処理フロー(loop内)

  1. ボタン状態読み取り:前回値と比較し、変化があれば「押下フラグ」を立てる
  2. モード遷移(switch文):現在モードとボタンフラグに基づき次のモードへ
  3. 時刻計算:RUNNINGモードではnow() - startTimeで経過時間を求め、設定時間を超えたらRINGINGへ
  4. LCD表示更新:モードごとに適切な文字列・数値を所定位置へ出力
  5. ブザー制御:RINGINGモードでPWMオン/オフを繰り返しビープ音生成

コード全文(ArduinoSketch v1.0)

/**************************************************
 * Arduino Kitchen Timer v1.0 - 2016/01/27
 * By Angelo Fiorillo (Rome, IT) - GPL3+
 **************************************************/
#include <LiquidCrystal.h>
#include <TimeLib.h> // now()関数のため必須

LiquidCrystal lcd(12, 11, 5, 4, 3, 2);
const int buzzerPin = 10;
const int resetButtonPin = 6;
const int startStopButtonPin = 7;
const int downButtonPin = 8;
const int upButtonPin = 9;

// 設定値(セットアップモードで変更)
int setupHours = 0, setupMinutes = 0, setupSeconds = 0;
time_t setupTime = 0;

// 現在値(カウントダウン中)
int currentHours = 0, currentMinutes = 0, currentSeconds = 0;
time_t currentTime = 0, startTime = 0, elapsedTime = 0;

// ボタン状態管理変数群
int resetButtonState = LOW, startStopButtonState = LOW, upButtonState = LOW, downButtonState = LOW;
int resetButtonPrevState = LOW, startStopButtonPrevState = LOW, upButtonPrevState = LOW, downButtonPrevState = LOW;
bool resetButtonPressed = false, resetButtonLongPressed = false;
bool startStopButtonPressed = false, upButtonPressed = false, downButtonPressed = false;
long resetButtonLongPressCounter = 0;

// モード定義
const int MODE_IDLE = 0, MODE_SETUP = 1, MODE_RUNNING = 2, MODE_RINGING = 3;
int currentMode = MODE_IDLE;
int dataSelection = 0; // 設定モードでの選択項目:0=時, 1=分, 2=秒

void setup() {
  lcd.begin(16, 2);
  pinMode(resetButtonPin, INPUT);
  pinMode(startStopButtonPin, INPUT);
  pinMode(upButtonPin, INPUT);
  pinMode(downButtonPin, INPUT);
  pinMode(buzzerPin, OUTPUT);
  Serial.begin(9600);
}

void loop() {
  // --- ボタン読み取り & エッジ検出 ---
  resetButtonPressed = false; resetButtonLongPressed = false;
  resetButtonState = digitalRead(resetButtonPin);
  if (resetButtonState != resetButtonPrevState) {
    resetButtonPressed = (resetButtonState == HIGH);
    resetButtonPrevState = resetButtonState;
  } else {
    // 長押し判定
    if (resetButtonState == HIGH) {
      if (++resetButtonLongPressCounter == 100) {
        resetButtonPressed = false;
        resetButtonLongPressed = true;
        resetButtonLongPressCounter = 0;
      }
    } else {
      resetButtonLongPressCounter = 0;
    }
  }

  startStopButtonPressed = false;
  startStopButtonState = digitalRead(startStopButtonPin);
  if (startStopButtonState != startStopButtonPrevState) {
    startStopButtonPressed = (startStopButtonState == HIGH);
    startStopButtonPrevState = startStopButtonState;
  }

  downButtonPressed = false;
  downButtonState = digitalRead(downButtonPin);
  if (downButtonState != downButtonPrevState) {
    downButtonPressed = (downButtonState == HIGH);
    downButtonPrevState = downButtonState;
  }

  upButtonPressed = false;
  upButtonState = digitalRead(upButtonPin);
  if (upButtonState != upButtonPrevState) {
    upButtonPressed = (upButtonState == HIGH);
    upButtonPrevState = upButtonState;
  }

  // --- モード遷移 ---
  switch (currentMode) {
    case MODE_IDLE:
      if (resetButtonPressed) Reset();
      if (resetButtonLongPressed) currentMode = MODE_SETUP;
      if (startStopButtonPressed) {
        currentMode = (currentMode == MODE_IDLE) ? MODE_RUNNING : MODE_IDLE;
        if (currentMode == MODE_RUNNING) startTime = now();
      }
      break;
    case MODE_SETUP:
      if (resetButtonPressed) { // 設定確定・終了
        setupTime = setupSeconds + 60L * setupMinutes + 3600L * setupHours;
        currentHours = setupHours; currentMinutes = setupMinutes; currentSeconds = setupSeconds;
        dataSelection = 0; currentMode = MODE_IDLE;
      }
      if (startStopButtonPressed) { dataSelection = (dataSelection + 1) % 3; }
      if (downButtonPressed) { // 値デクリメント(ロールオーバーあり)
        switch (dataSelection) {
          case 0: if (--setupHours < 0) setupHours = 99; break;
          case 1: if (--setupMinutes < 0) setupMinutes = 59; break;
          case 2: if (--setupSeconds < 0) setupSeconds = 59; break;
        }
      }
      if (upButtonPressed) { // 値インクリメント
        switch (dataSelection) {
          case 0: if (++setupHours == 100) setupHours = 0; break;
          case 1: if (++setupMinutes == 60) setupMinutes = 0; break;
          case 2: if (++setupSeconds == 60) setupSeconds = 0; break;
        }
      }
      break;
    case MODE_RUNNING:
      if (startStopButtonPressed || resetButtonPressed) {
        currentMode = MODE_IDLE;
        if (resetButtonPressed) Reset();
      }
      break;
    case MODE_RINGING:
      if (resetButtonPressed || startStopButtonPressed || downButtonPressed || upButtonPressed)
        currentMode = MODE_IDLE;
      break;
  }

  // --- 時刻計算 & ブザー ---
  switch (currentMode) {
    case MODE_RUNNING:
      currentTime = setupTime - (now() - startTime);
      if (currentTime <= 0) currentMode = MODE_RINGING;
      break;
    case MODE_RINGING:
      analogWrite(buzzerPin, 20); delay(20);
      analogWrite(buzzerPin, 0); delay(40);
      break;
  }

  // --- LCD表示 ---
  lcd.setCursor(0, 0);
  switch (currentMode) {
    case MODE_IDLE:
      lcd.print("Timer ready ");
      lcd.setCursor(0, 1);
      lcd.print(currentHours); lcd.print(" ");
      lcd.print(currentMinutes); lcd.print(" ");
      lcd.print(currentSeconds); lcd.print(" ");
      break;
    case MODE_SETUP:
      lcd.print("Setup mode: ");
      lcd.print(dataSelection == 0 ? "HRS " : dataSelection == 1 ? "MINS" : "SECS");
      lcd.setCursor(0, 1);
      lcd.print(setupHours); lcd.print(" ");
      lcd.print(setupMinutes); lcd.print(" ");
      lcd.print(setupSeconds); lcd.print(" ");
      break;
    case MODE_RUNNING:
      lcd.print("Counting down...");
      lcd.setCursor(0, 1);
      if (hour(currentTime) < 10) lcd.print("0");
      lcd.print(hour(currentTime)); lcd.print(":");
      if (minute(currentTime) < 10) lcd.print("0");
      lcd.print(minute(currentTime)); lcd.print(":");
      if (second(currentTime) < 10) lcd.print("0");
      lcd.print(second(currentTime));
      break;
    case MODE_RINGING:
      lcd.print(" RING-RING! ");
      lcd.setCursor(0, 1); lcd.print(" ");
      break;
  }
  delay(10);
}

void Reset() {
  currentMode = MODE_IDLE;
  currentHours = setupHours; currentMinutes = setupMinutes; currentSeconds = setupSeconds;
}

配線図・回路図

ブレッドボード上の配線はフリッツィング図を参照してください。Starter Kit付属の小型ブレッドボードでも収まります(ブザーを黄色ワイヤーの下に配置)。

まとめ

ステートマシン(状態遷移)の基本を学ぶのに最適なプロジェクトです。ボタンのエッジ検出、長押し判定、TimeLibを使った時刻計算、LCDの動的表示など、Arduinoプログラミングの重要なテクニックが詰まっています。自分専用のタイマーを作って、キッチンだけでなく作業時間管理などにも活用してみてください。

製造プロセス

  1. スマート渇きアラート植物アラーム – 最適な水やりタイミングを知らせるDIYセンサー
  2. Arduino Nanoで20kHzオシロスコープを自作:Nokia 5110 LCD搭載・簡易DIYガイド
  3. スマートブラインド:Arduinoとソーラー電源で実現する自動光制御
  4. イタリア語ワードクロック自作:Arduino Nano、NeoPixel、LCD、RTCで時刻を文字で表示
  5. SparkFun 7セグメントディスプレイで作る信頼性の高いArduinoカウントダウンタイマー
  6. Arduino MKR Fox 1200で作る信頼性の高いSigfox kWhメーター
  7. Bluetooth対応温度モニター:Arduino NanoとHC-06でスマホ監視
  8. 非接触ジェスチャー錠: APDS-9960とArduinoでセキュアアクセス
  9. Arduino Nanoコンパニオンキット – 電子工作に必須の部品とツールを搭載した多機能IC型デバイス
  10. Arduino用絶縁アナログ入力回路の設計:LM331 V-F変換+フォトカプラでノイズ耐性を確保
  11. Arduino UNOで作る精密反応速度テスター