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

Arduino MegaでPWM制御:プッシュボタン付きLEDフェード制御チュートリアル

プロジェクト概要

ArduinoのPWM(パルス幅変調)機能を使ってLEDの明るさを滑らかに変化(フェード)させる手法を、段階的に3つのレベルで解説します。初心者でも理解しやすいよう、基本のフェード→ボタン連動→ボタン長押し中のみ動作する改良版へとステップアップします。

必要な部品

部品数量備考
Arduino Mega 25601Uno/NanoでもPWMピンがあれば可
ブレッドボード1
ジャンパーワイヤー11本程度配線方法による
LED(赤・黄・緑推奨)各1色は任意
タクトスイッチ 12mm1
330Ω 抵抗4LED用3本+ボタン用プルダウン1本

ソフトウェア

ステップ1:基本のLEDフェード(信号灯パターン)

回路図

LEDのアノードを各PWMピン(D9, D6, D3)へ、カソードを330Ω抵抗経由でGNDへ接続。PWM対応ピンなら番号変更可能(コードも要修正)。

コード解説

int ledRed = 9;
int ledYellow = 6;
int ledGreen = 3;
const int fade = 10;  // フェード速度の共通定数

void setup() {
  pinMode(ledRed, OUTPUT);
  pinMode(ledYellow, OUTPUT);
  pinMode(ledGreen, OUTPUT);
}

void loop() {
  // 赤:フェードイン→フェードアウト
  for (int i = 0; i <= 255; i++) { analogWrite(ledRed, i); delay(fade); }
  for (int i = 255; i >= 0; i--) { analogWrite(ledRed, i); delay(fade); }
  // 黄:同上
  for (int i = 0; i <= 255; i++) { analogWrite(ledYellow, i); delay(fade); }
  for (int i = 255; i >= 0; i--) { analogWrite(ledYellow, i); delay(fade); }
  // 緑:同上
  for (int i = 0; i <= 255; i++) { analogWrite(ledGreen, i); delay(fade); }
  for (int i = 255; i >= 0; i--) { analogWrite(ledGreen, i); delay(fade); }
  // 黄:再度(信号灯サイクル完成)
  for (int i = 0; i <= 255; i++) { analogWrite(ledYellow, i); delay(fade); }
  for (int i = 255; i >= 0; i--) { analogWrite(ledYellow, i); delay(fade); }
}

ポイント:const int fadeで遅延時間を一元管理。変更時は1箇所修正するだけで全フェード速度が変わります。analogWrite(pin, 0-255)でPWMデューティ比を制御し、0=消灯、255=最大輝度。

ステップ2:プッシュボタンでフェード開始

回路追加

タクトスイッチの片足をD7へ、もう片足を5Vへ。D7とGND間に330Ω抵抗でプルダウン(押下時HIGH)。

コードの変更点

int ledRed = 9, ledYellow = 6, ledGreen = 3;
int button = 7;
const int fade = 10;

void setup() {
  pinMode(ledRed, OUTPUT);
  pinMode(ledYellow, OUTPUT);
  pinMode(ledGreen, OUTPUT);
  pinMode(button, INPUT);
  digitalWrite(ledRed, LOW);
  digitalWrite(ledYellow, LOW);
  digitalWrite(ledGreen, HIGH);  // 起動時は緑点灯
}

void loop() {
  if (digitalRead(button) == HIGH) {
    delay(15);  // ソフトウェアチャタリング対策
    if (digitalRead(button) == HIGH) {
      fadeLights();  // ボタン押下中に1サイクル実行
    }
  } else {
    digitalWrite(ledRed, LOW);
    digitalWrite(ledYellow, LOW);
    digitalWrite(ledGreen, HIGH);
  }
}

void fadeLights() {
  // 緑フェードアウト→黄フェードイン/アウト→赤フェードイン/アウト→黄フェードイン/アウト→緑フェードイン
  for (int i = 255; i >= 0; i--) { analogWrite(ledGreen, i); delay(fade); }
  for (int i = 0; i <= 255; i++) { analogWrite(ledYellow, i); delay(fade); }
  for (int i = 255; i >= 0; i--) { analogWrite(ledYellow, i); delay(fade); }
  for (int i = 0; i <= 255; i++) { analogWrite(ledRed, i); delay(fade); }
  for (int i = 255; i >= 0; i--) { analogWrite(ledRed, i); delay(fade); }
  for (int i = 0; i <= 255; i++) { analogWrite(ledYellow, i); delay(fade); }
  for (int i = 255; i >= 0; i--) { analogWrite(ledYellow, i); delay(fade); }
  for (int i = 0; i <= 255; i++) { analogWrite(ledGreen, i); delay(fade); }
}

ステップ3:ボタン長押し中のみフェード(即時停止対応)

課題

ステップ2では、一度fadeLights()が始まるとボタンを離しても関数が終わるまで動作し続けます。これを「押している間だけ動く」ように改良します。

解決策:遅延ループ内でボタン監視

delay(fade)を、空ループ+ボタンチェックに置き換えます。各フェードステップごとにボタン状態を確認し、離されていればreturnで即座に関数脱出。

void fadeLights() {
  // 緑フェードアウト
  for (int i = 255; i >= 0; i--) {
    analogWrite(ledGreen, i);
    for (int y = 0; y < 1000; y++) {  // 約10μs×1000=10ms相当の遅延
      if (digitalRead(button) == LOW) return;
    }
  }
  // 黄フェードイン
  for (int i = 0; i <= 255; i++) {
    analogWrite(ledYellow, i);
    for (int y = 0; y < 400; y++) {
      if (digitalRead(button) == LOW) return;
    }
  }
  // 黄フェードアウト
  for (int i = 255; i >= 0; i--) {
    analogWrite(ledYellow, i);
    for (int y = 0; y < 400; y++) {
      if (digitalRead(button) == LOW) return;
    }
  }
  // 赤フェードイン
  for (int i = 0; i <= 255; i++) {
    analogWrite(ledRed, i);
    for (int y = 0; y < 1000; y++) {
      if (digitalRead(button) == LOW) return;
    }
  }
  // 赤フェードアウト
  for (int i = 255; i >= 0; i--) {
    analogWrite(ledRed, i);
    for (int y = 0; y < 1000; y++) {
      if (digitalRead(button) == LOW) return;
    }
  }
  // 黄フェードイン/アウト(高速)
  for (int i = 0; i <= 255; i++) {
    analogWrite(ledYellow, i);
    for (int y = 0; y < 400; y++) {
      if (digitalRead(button) == LOW) return;
    }
  }
  for (int i = 255; i >= 0; i--) {
    analogWrite(ledYellow, i);
    for (int y = 0; y < 400; y++) {
      if (digitalRead(button) == LOW) return;
    }
  }
  // 緑フェードイン
  for (int i = 0; i <= 255; i++) {
    analogWrite(ledGreen, i);
    for (int y = 0; y < 1000; y++) {
      if (digitalRead(button) == LOW) return;
    }
  }
}

注意:空ループ回数(1000や400)は環境により調整必要。delayMicroseconds()やmillis()ベースの非ブロッキング実装の方がより正確ですが、学習用としてこの手法も理解しやすいです。

トラブルシューティング

発展アイデア

製造プロセス

  1. Arduino NanoとMPU-6050で作るリアルタイムジャイロスコープゲーム
  2. Python連携で信頼性向上: Arduino RFID勤怠管理システム
  3. DHT11温湿度センサーで作る温度アラート – LEDとピエゾブザーで視覚/聴覚通知
  4. Arduinoで超音波レベーション(浮遊)装置を自作:ステップバイステップガイド
  5. Unopad: Ableton Live連携シームレスなArduino MIDIコントローラー
  6. Arduinoで作る全自動植物水やりシステム - 湿度センサーとRTCで最適制御
  7. Arduinoでシンプルな障害物センサーを自作 – IR LEDとフォトダイオード入門
  8. ArduinoとBluetoothで作るスマート紛失防止タグ「Find Me」
  9. Arduinoで地球の質量を測定:ステップバイステップDIYガイド
  10. Arduino超音波センサーとProcessingで作るリアルタイム距離測定ソナー
  11. Arduino Unoで25kHz 4ピンPWMファンを制御 – 製作・コード・テスト