analogWriteって何となく使ってるけど、仕組みをちゃんと理解できていない…」

そんな方、意外と多いんじゃないでしょうか。😊

ArduinoのPWM制御は、LEDをふんわり光らせたり、モーターの速度を細かく調整したりするときに欠かせない技術です。でも「なぜanalogWriteで明るさが変わるの?」「デューティ比ってどういう意味?」と聞かれると、ちょっと困ってしまう方もいるかもしれません。

今回はPWM制御の仕組みから、実際に手を動かして試せるコード例まで、ゼロから丁寧に解説していきます!LEDの調光だけでなく、DCモーターの速度制御まで扱うので、ぜひ最後まで読んでみてください。

📌 この記事の対象読者と難易度

Arduino LED electronics
Arduino LED electronics / Photo by Chengxin Zhao via Pexels
  • ✅ ArduinoでdigitalWriteanalogReadは使ったことがある
  • ✅ LEDやモーターを動かしてみたい初〜中級者の方
  • ✅ PWMという言葉は聞いたことがあるけど、仕組みはよくわからない方

難易度:⭐⭐☆☆☆(初級〜中級)

PWM制御とは?まずざっくり理解しよう

PWMは「Pulse Width Modulation(パルス幅変調)」の略です。

イメージとしては、電気をものすごく速いスピードでON/OFFする仕組みです。たとえばLEDを1秒間に1000回チカチカさせると、人間の目にはずっと光り続けているように見えますよね。そのONとOFFの比率(デューティ比)を変えることで、明るさや速度を調整できるというわけです。

具体的には:

  • ON時間が50%の場合 → 最大輝度の50%の明るさ
  • ON時間が25%の場合 → 最大輝度の25%の明るさ
  • ON時間が100%の場合 → フル点灯

デジタル出力(0Vか5V)しか出せないArduinoが、まるでアナログのように「中間の値」を表現できるのは、このPWMの仕組みのおかげなんですよね。

ArduinoのPWM対応ピンを確認しよう

ArduinoのすべてのピンがPWMに対応しているわけではありません。チルダ(〜)マークがついているピンだけがPWM出力に対応しています。

Arduino UNO(R3)の場合:

  • PWM対応ピン:3・5・6・9・10・11(計6本)
  • 動作周波数:ピン3・11が約490Hz、ピン5・6が約980Hz、ピン9・10が約490Hz

Arduino UNO R4 MINIMAの場合は周波数設定の自由度が増しており、より高度な制御が可能です。まずはR3で基本をおさえましょう。

基本関数「analogWrite」の使い方

PWM制御の中心となる関数がanalogWrite()です。

analogWrite(ピン番号, 値);

ポイントをまとめるとこんな感じです:

  • 値の範囲:0〜255(8ビット)
  • 0 → デューティ比0%(完全OFF)
  • 127 → デューティ比約50%(半分の出力)
  • 255 → デューティ比100%(完全ON)
  • 呼び出すだけで自動的にPWM信号を出力し続けてくれる

名前はanalogWriteですが、実際にはデジタルのパルスを使っています。「なんでアナログって名前なの?」と思うかもしれませんが、アナログ的な効果を出すための関数という意味合いで命名されている、と覚えておけばOKです。

【実践①】LEDの明るさをゆっくり変化させる

まずは定番のフェードイン・フェードアウトを試してみましょう。LED1個と220Ω程度の抵抗があればすぐに試せます。

🔌 配線

  • LEDのアノード(長い足)→ 220Ω抵抗 → Arduinoの9番ピン
  • LEDのカソード(短い足)→ GND
// LEDフェードイン・フェードアウト
// PWM対応の9番ピンを使用

const int LED_PIN = 9;  // PWM対応ピン

void setup() {
  pinMode(LED_PIN, OUTPUT);
}

void loop() {
  // フェードイン(暗い→明るい)
  for (int brightness = 0; brightness <= 255; brightness++) {
    analogWrite(LED_PIN, brightness);  // 明るさをセット
    delay(10);  // 10ms待機(ゆっくり変化)
  }

  // フェードアウト(明るい→暗い)
  for (int brightness = 255; brightness >= 0; brightness--) {
    analogWrite(LED_PIN, brightness);
    delay(10);
  }
}

これを実行すると、LEDがふんわりと点灯して、またゆっくり消えていく動作を繰り返します。たったこれだけでPWMの基本動作が体感できますよ!

【実践②】ポテンショメーター(可変抵抗)でLED輝度をリアルタイム調整

次はアナログ入力を組み合わせてみましょう。ツマミをグルグル回すとLEDの明るさが変わる、ちょっとリアルな調光器が作れます。

🔌 追加配線(ポテンショメーター)

  • 両端のピン → それぞれ5VとGNDへ
  • 中央のピン → ArduinoのA0(アナログ入力)へ
// ポテンショメーターでLEDの明るさをリアルタイム調整

const int POT_PIN  = A0;  // ポテンショメーター(アナログ入力)
const int LED_PIN  = 9;   // LED(PWM出力)

void setup() {
  pinMode(LED_PIN, OUTPUT);
  Serial.begin(9600);  // シリアル出力でデバッグ確認
}

void loop() {
  int potValue = analogRead(POT_PIN);    // 0〜1023 の値を読み取る
  int ledBrightness = potValue / 4;      // 0〜255 にスケール変換

  analogWrite(LED_PIN, ledBrightness);   // PWM出力

  Serial.print("ポテンショ値: ");
  Serial.print(potValue);
  Serial.print("  LED輝度: ");
  Serial.println(ledBrightness);

  delay(50);
}

ここが重要です:

  • analogRead()は0〜1023の10ビット値を返す
  • analogWrite()は0〜255の8ビット値が必要
  • だから「÷4」でスケールを合わせています(map()関数でも書けます)

map()を使うともっとスッキリ書けます:

// map()関数を使ったスマートな書き方
int ledBrightness = map(potValue, 0, 1023, 0, 255);

シリアルモニタを開いて、ツマミを回しながら値の変化を確認してみてください。数値がリアルタイムで変わっていくのが見えるはずです。

PWMの仕組みをもう少し深堀り!デューティ比と周波数


ここで、PWMの2つの重要な概念を整理しておきます。

デューティ比(Duty Cycle)

1周期の中でON(HIGH)になっている時間の割合です。

  • デューティ比25% → 1周期のうち1/4がON
  • デューティ比50% → 1周期のうち1/2がON
  • デューティ比75% → 1周期のうち3/4がON

analogWrite(9, 64)なら 64÷255 ≒ 25%のデューティ比、ということになります。

周波数(Frequency)

1秒間に何回ON/OFFを繰り返すかです。Arduino UNOのデフォルトは490Hz〜980Hz程度です。この周波数は人間の目では認識できないほど速いので、LEDが「ついている」ように見えるわけですね。

モーター制御の場合、周波数が低すぎると「ブーン」というノイズが発生することがあります。用途に応じてタイマーレジスタを直接操作して変更することも可能ですが、まずはデフォルトで十分です。

【実践③】DCモーターの速度制御(L298Nモータードライバー使用)

いよいよモーター制御に挑戦しましょう!ArduinoのPWMピンから直接DCモーターに電流を流すのはNGです。理由は電流不足と逆起電力によるArduinoの破損リスクがあるから。必ずモータードライバーを使いましょう。

ここでは定番のL298Nモータードライバーを使います。

🔌 配線(片方のモーターのみ)

  • L298N の ENA → Arduino の 9番(PWM)
  • L298N の IN1 → Arduino の 7番
  • L298N の IN2 → Arduino の 8番
  • L298N の OUT1・OUT2 → DCモーターの端子
  • L298N の 12V端子 → 外部電源(単三4本など)
  • L298N の GND → ArduinoのGNDと共通GND
// L298NでDCモーターの速度・方向を制御する

const int ENA = 9;   // PWM(速度制御)
const int IN1 = 7;   // 方向制御1
const int IN2 = 8;   // 方向制御2

void setup() {
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  Serial.begin(9600);
}

// モーターを正転させる関数
void motorForward(int speed) {
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, speed);  // 0〜255で速度指定
  Serial.print("正転 速度: ");
  Serial.println(speed);
}

// モーターを逆転させる関数
void motorBackward(int speed) {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, HIGH);
  analogWrite(ENA, speed);
  Serial.print("逆転 速度: ");
  Serial.println(speed);
}

// モーターを停止させる関数
void motorStop() {
  digitalWrite(IN1, LOW);
  digitalWrite(IN2, LOW);
  analogWrite(ENA, 0);
  Serial.println("停止");
}

void loop() {
  motorForward(100);   // 低速で正転
  delay(2000);

  motorForward(255);   // フル速度で正転
  delay(2000);

  motorStop();         // 一時停止
  delay(1000);

  motorBackward(150);  // 中速で逆転
  delay(2000);

  motorStop();
  delay(1000);
}

ポイントをまとめるとこんな感じです:

  • IN1・IN2の組み合わせで回転方向を決める
  • ENAピンへのPWM値(0〜255)で速度を決める
  • 両方を組み合わせることで「正転・低速」「逆転・高速」など自由自在に制御できる

⚠️ 注意:モーターの動作には大きな電流が必要です。外部電源を必ず用意してください。Arduino本体だけでは電流不足になります。

【実践④】加速・減速を滑らかにする(ソフトスタート)

いきなりフル速度でモーターを動かすと、機械的な衝撃やスリップが起きやすいです。ゆっくり加速する「ソフトスタート」を実装してみましょう。

// ソフトスタート・ソフトストップでなめらかな速度制御

const int ENA = 9;
const int IN1 = 7;
const int IN2 = 8;

void setup() {
  pinMode(ENA, OUTPUT);
  pinMode(IN1, OUTPUT);
  pinMode(IN2, OUTPUT);
  // 正転方向に固定
  digitalWrite(IN1, HIGH);
  digitalWrite(IN2, LOW);
}

// 加速処理(start → end まで stepDelay[ms]ごとに1ずつ増やす)
void rampUp(int startSpeed, int endSpeed, int stepDelay) {
  for (int spd = startSpeed; spd <= endSpeed; spd++) {
    analogWrite(ENA, spd);
    delay(stepDelay);
  }
}

// 減速処理(start → end まで stepDelay[ms]ごとに1ずつ減らす)
void rampDown(int startSpeed, int endSpeed, int stepDelay) {
  for (int spd = startSpeed; spd >= endSpeed; spd--) {
    analogWrite(ENA, spd);
    delay(stepDelay);
  }
}

void loop() {
  rampUp(0, 255, 10);    // 約2.5秒かけて加速
  delay(3000);            // フル速度で3秒維持
  rampDown(255, 0, 10);  // 約2.5秒かけて減速
  delay(2000);            // 停止状態で2秒待機
}

これ、実際に動かしてみると「なめらか!」と思うはずです。ロボットや自動車型の工作では、この処理を入れるだけで完成度がぐっと上がります。ぜひstepDelayの値を変えて、加速の速さを調整してみてください。

PWM制御でよくあるトラブルと対処法


初めて試すとつまずきやすいポイントをまとめておきます。

❌ LEDが全く光らない

  • PWM非対応ピン(例:13番)を使っていないか確認
  • LEDの向き(アノード・カソード)を確認
  • 抵抗なしで直結していないか確認(LEDが壊れる原因になります)

❌ モーターが回らない/すぐ止まる

  • 外部電源の電圧・電流が足りているか確認(モーターに合った電源を使う)
  • GNDがArduinoとモータードライバーで共通になっているか確認
  • ENAピンがきちんとPWMピンに接続されているか確認

❌ モーターからノイズ(ブーン音)がする

  • PWMの周波数が低いと可聴域のノイズが出ることがあります
  • Arduinoのタイマープリスケーラを変更すると改善できますが、上級者向けの操作です
  • まずはモーターや回路の接続を再確認することをおすすめします

❌ analogWriteしても変化しない

  • pinMode()でOUTPUTを指定しているか確認
  • 値が0か255になっていないか確認(スケール変換のミスが多い)

まとめ

今回はArduinoのPWM制御について、仕組みから実際のコードまで解説しました。ポイントを整理すると:

  • PWMは高速ON/OFFのデューティ比でアナログ的な出力を実現する技術
  • analogWrite(ピン, 0〜255)で手軽にPWM制御できる
  • PWM対応ピンはチルダ(〜)マーク付きのピンのみであることに注意
  • DCモーター制御にはL298Nなどのモータードライバーが必須
  • ソフトスタート実装で動作の安定感がぐっと上がる

PWMをマスターすると、電子工作の表現力が一気に広がります。LEDをふんわり光らせるだけでなく、ロボットのモーター制御・ブザーの音量調整・ファンの回転数制御など、応用先はたくさんありますよ。

まずは手元のArduinoとLED1個でフェードイン・フェードアウトから試してみてください!「むずかしそう」が「できそう」に変わる瞬間を、ぜひ体験してみてください。💡

一緒に電子工作を楽しんでいきましょう!

📡 Arduinoをもっと深く学ぼう!

Arduino・ラズパイ・ロボットプログラミングを体系的に学びたい方へ。おすすめのUdemyコースや電子部品もまとめています。

Arduinoロボット入門のおすすめコース・部品を見る →

📚 関連商品・おすすめ書籍

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

もしも

スッキリわかるPython入門 第2版 (スッキリわかる入門シリーズ)

初心者に定番のPython入門書

Amazonで見る

Arduinoをはじめよう 第4版 (Make: PROJECTS)

もしも

Arduinoをはじめよう 第4版 (Make: PROJECTS)

Arduino公式推薦の定番入門書

Amazonで見る

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

もしも

徹底攻略! 電子工作&プログラミング Arduinoで学ぶ電子工作完全ガイド

電子工作とプログラミングを同時に学べる

Amazonで見る

※本記事にはアフィリエイトリンクが含まれます。

ABOUT ME
やまちゃん
これまで学生と社会人を合わせて5000人以上にプログラミング学習を指導。 ゼロからイチをわかりやすく解説する専門家として活動しており、本業ではArduinoを用いたIoT開発とロボットプログラミングが専門。 Pythonを用いたアプリ開発、ウェブアプリケーションの開発で業務の効率化をサポートしています。