Основы · 5 мин чтения

Что такое PWM? analogWrite, коэффициент заполнения и частота на Arduino

Что такое PWM (широтно-импульсная модуляция) и как она работает? Коэффициент заполнения и частота, PWM-пины Arduino, яркость светодиода и скорость мотора через analogWrite, сервоприводы, LEDC на ESP32 и PWM на Pico.

Цифровые пины Arduino знают только два состояния: 0 V или 5 V. Как же тогда приглушить светодиод до половины яркости или заставить мотор крутиться медленно? Ответ — PWM (Pulse Width Modulation, широтно-импульсная модуляция, ШИМ). Пин очень быстро включается и выключается, и, меняя долю времени, когда он включён, ты задаёшь среднюю мощность, которая доходит до нагрузки. Эту технику используют для регулировки яркости светодиодов, скорости моторов, управления сервоприводами, получения звука и даже в зарядках для телефонов.

Светодиод, управляемый PWM с Arduino
С помощью PWM светодиод включается и выключается сотни раз в секунду, и его яркость можно задать на любом уровне.

Как работает PWM?

Сигнал PWM — это меандр (прямоугольные импульсы): какое-то время он в HIGH, потом в LOW, и цикл повторяется снова и снова. Длительность одного цикла «вкл-выкл» — это период, а доля периода, в течение которой сигнал остаётся в HIGH, — коэффициент заполнения (duty cycle). При заполнении 25% сигнал включён четверть времени, так что пин на 5 V в среднем ведёт себя как 1,25 V. Светодиод мигает примерно 490 раз в секунду; глаз за этим не успевает и видит только среднюю яркость. Мотор благодаря инерции сглаживает импульсы и вращается со средней скоростью.

ЗаполнениеЗначение analogWriteСреднее напряжение (5 V)Светодиод
0%00 VВыключен
25%641,25 VТускло
50%1272,5 VПоловина яркости
75%1913,75 VЯрко
100%2555 VПолная яркость

Глаза реагируют на свет нелинейно: изменения при слабом свете замечают очень хорошо, а при ярком — гораздо хуже. Поэтому светодиод при заполнении 50% кажется намного ярче, чем «наполовину». Чтобы яркость менялась естественно, используют гамма-коррекцию, показанную ниже.

Частота: насколько быстр PWM?

Частота — это сколько раз в секунду сигнал включается и выключается. На Arduino Uno пины 5 и 6 работают примерно на 980 Hz, а пины 3, 9, 10 и 11 — примерно на 490 Hz. Для светодиодов этих частот более чем достаточно. А вот с моторами 490 Hz попадают в слышимый диапазон, и мотор может слегка пищать; на ESP32 и Pico частоту можно поднять до 20 kHz, и писк пропадёт. Но если поднять частоту намного выше необходимого, транзисторы и MOSFET начинают греться.

ПлатаPWM-пиныЧастота по умолчаниюРазрешение
Arduino Uno / Nano3, 5, 6, 9, 10, 11490 Hz (5 и 6: 980 Hz)8 бит (0–255)
Arduino Mega2–13, 44–46490 Hz (4 и 13: 980 Hz)8 бит (0–255)
ESP32Почти любой выходной пинНастраивается (analogWrite: 1 kHz)1–16 бит
Raspberry Pi PicoЛюбой пин GPIOНастраивается16 бит (0–65535)

Яркость светодиода через analogWrite

На Arduino PWM получают командой analogWrite(pin, value), где значение лежит между 0 и 255. Несмотря на обманчивое название, эта команда выдаёт не настоящее аналоговое напряжение, а PWM. Работает она только на пинах, отмеченных знаком ~. Код ниже медленно разжигает и гасит светодиод — получается эффект «дыхания»:

C++ (Arduino IDE)
1const int LED_PIN = 9;   // ~ işaretli PWM pini / PWM pin marked with ~
2
3void setup() {
4  pinMode(LED_PIN, OUTPUT);
5}
6
7void loop() {
8  for (int v = 0; v <= 255; v++) {   // yavaşça yan / fade in
9    analogWrite(LED_PIN, v);
10    delay(8);
11  }
12  for (int v = 255; v >= 0; v--) {   // yavaşça sön / fade out
13    analogWrite(LED_PIN, v);
14    delay(8);
15  }
16}
Для более естественного изменения яркости масштабируй значение, возводя его в квадрат: analogWrite(LED_PIN, (long)v * v / 255);. Здесь важен (long): на Uno тип int не вмещает числа больше 32 767, поэтому 255 × 255 вызывает переполнение.

Управление яркостью потенциометром

Если подключить потенциометр к A0, яркость светодиода можно задавать вручную. analogRead() возвращает значение от 0 до 1023; деление на 4 даёт диапазон 0–255, которого ждёт analogWrite. Подключение потенциометра разобрано в статье Что такое потенциометр?

C++ (Arduino IDE)
1void loop() {
2  int pot = analogRead(A0);   // 0–1023
3  analogWrite(9, pot / 4);    // 0–255
4}

Скорость мотора постоянного тока через PWM

Даже маленький мотор постоянного тока потребляет сотни миллиампер, а пин Arduino может безопасно отдать всего около 20 mA. Поэтому мотор подключают через транзистор, MOSFET или драйвер мотора вроде L298N, а сигнал PWM подают на вход скорости драйвера. На L298N этот вход — пин ENA (и ENB для второго мотора); чтобы использовать PWM, с него нужно снять перемычку. Пины IN1 и IN2 задают направление вращения.

Модуль драйвера моторов L298N
Драйвер моторов L298N: PWM на пинах ENA и ENB независимо задаёт скорость двух моторов постоянного тока.
C++ (Arduino IDE)
1const int ENA = 9;   // hız (PWM) / speed (PWM)
2const int IN1 = 8;   // yön / direction
3const int IN2 = 7;
4
5void setup() {
6  pinMode(ENA, OUTPUT);
7  pinMode(IN1, OUTPUT);
8  pinMode(IN2, OUTPUT);
9  digitalWrite(IN1, HIGH);   // ileri / forward
10  digitalWrite(IN2, LOW);
11}
12
13void loop() {
14  analogWrite(ENA, 255);  delay(2000);   // tam hız / full speed
15  analogWrite(ENA, 150);  delay(2000);   // orta hız / medium speed
16  analogWrite(ENA, 0);    delay(2000);   // dur / stop
17}
Никогда не подключай мотор прямо к пину Arduino: потребляемый ток и обратное напряжение, которое он создаёт, сожгут пин. Кроме того, при очень малом заполнении мотор только гудит и не вращается; большинству моторов, чтобы тронуться, нужно минимальное значение около 80–120.

Сервоприводы и PWM — это одно и то же?

Сервоприводы тоже управляются импульсами, но логика другая: положение задаётся шириной импульса, а не коэффициентом заполнения. Сервопривод ждёт 50 импульсов в секунду (50 Hz); импульс длиной 1 миллисекунда означает примерно 0°, 1,5 мс — 90°, а 2 мс — 180°. analogWrite не умеет выдавать такие тайминги, поэтому для сервоприводов используют библиотеку Servo. Подробности — в статье Что такое сервопривод?

Настоящее аналоговое напряжение из PWM: RC-фильтр

Иногда действительно нужно ровное напряжение, например чтобы дать операционному усилителю опорный уровень или получить звуковой выход. Тогда PWM пропускают через фильтр нижних частот из резистора и конденсатора. С 10 kΩ и 10 µF постоянная времени равна 0,1 секунды; выход получается довольно гладким, но на изменения реагирует медленно. Разные значения можно попробовать в калькуляторе Постоянная времени RC. У классического ESP32 есть ещё и два ЦАП на GPIO 25 и 26, которые дают настоящий аналоговый выход.

PWM на ESP32: LEDC

На ESP32 PWM формирует аппаратный блок LEDC, и частоту с разрешением выбираешь ты. В ядре Arduino 3.x используются ledcAttach(pin, frequency, resolution) и ledcWrite(pin, value); в старых версиях 2.x были команды ledcSetup и ledcAttachPin с привязкой к каналам. Пример ниже плавно меняет яркость светодиода на частоте 5 kHz с разрешением 8 бит:

C++ (Arduino IDE)
1const int LED_PIN = 2;
2
3void setup() {
4  ledcAttach(LED_PIN, 5000, 8);   // 5 kHz, 8 bit (0–255) — ESP32 Arduino core 3.x
5}
6
7void loop() {
8  for (int d = 0; d <= 255; d++) { ledcWrite(LED_PIN, d); delay(5); }
9  for (int d = 255; d >= 0; d--) { ledcWrite(LED_PIN, d); delay(5); }
10}

PWM на Raspberry Pi Pico (MicroPython)

Любой пин GPIO на Pico умеет выдавать PWM. В MicroPython используется класс PWM: частота задаётся через freq(), а заполнение — через duty_u16(), который принимает значения от 0 до 65535:

MicroPython
1from machine import Pin, PWM
2import time
3
4led = PWM(Pin(15))
5led.freq(1000)                        # 1 kHz
6
7while True:
8    for d in range(0, 65536, 512):    # yavaşça yan / fade in
9        led.duty_u16(d)
10        time.sleep_ms(5)
11    for d in range(65535, -1, -512):  # yavaşça sön / fade out
12        led.duty_u16(d)
13        time.sleep_ms(5)

Идеи проектов с PWM

  • Дышащий светодиод: индикатор состояния, который медленно разгорается и гаснет, как у устройств в режиме ожидания.
  • Настольная лампа с регулировкой: светодиодная лампа, яркость которой задаётся потенциометром.
  • Вентилятор по температуре: разгоняй вентилятор по мере роста температуры, которую измеряет DHT11.
  • Смешивание цветов: получай миллионы цветов на RGB-светодиоде тремя каналами PWM.
  • Машинка-робот: делай повороты плавными, задавая скорость двух моторов по отдельности.
  • Лампа-рассвет: медленно разжигай свет в течение 15 минут перед утренним будильником.

Частые ошибки и как их исправить

  • analogWrite на пине без PWM: на Uno пины без ~ могут быть только включены или выключены; 128 и выше считается включением, всё, что ниже, — выключением.
  • Пины 9 и 10 вместе с библиотекой Servo: на Uno библиотека Servo использует Timer1 и отключает PWM на этих двух пинах; переставь светодиод или мотор на другой PWM-пин.
  • Пины 3 и 11 вместе с tone(): tone() использует Timer2 и ломает PWM на этих пинах.
  • Мотор прямо на пине: всегда используй транзистор, MOSFET или драйвер мотора.
  • Переполнение в расчёте гаммы: v * v выходит за предел int; добавь приведение (long).
  • PWM как настоящий аналог: мультиметр показывает среднее, но сигнал всё равно скачет между 0 и 5 V; для чувствительных схем используй RC-фильтр или ЦАП.

PWM — одна из самых полезных идей, которые можно освоить на Arduino: светодиоды, моторы, вентиляторы и динамики управляются этим простым приёмом. Основы — в статье Что такое светодиод?; в приложении BlueGrays есть пошаговые проекты с кодом: плавное затухание светодиода через PWM, яркость от потенциометра и смена цветов RGB.

Частые вопросы

Что такое PWM в двух словах?

PWM — способ задать среднюю мощность, которая доходит до нагрузки, очень быстро включая и выключая пин и меняя долю времени, когда он включён (коэффициент заполнения). Благодаря ему цифровой пин, который выдаёт только 0 или 5 V, может приглушить светодиод или замедлить мотор.

Какие пины Arduino Uno поддерживают PWM?

На Uno и Nano PWM поддерживают пины 3, 5, 6, 9, 10 и 11; на плате они отмечены знаком ~. На Mega PWM умеют выдавать пины 2–13 и 44–46.

Даёт ли analogWrite настоящий аналоговый выход?

Нет. analogWrite формирует PWM: пин быстро переключается между 0 и 5 V. Он задаёт среднее напряжение, но для по-настоящему ровного напряжения PWM нужно пропустить через RC-фильтр или использовать ЦАП, как у ESP32.

Как рассчитать коэффициент заполнения?

Коэффициент заполнения — это время, когда сигнал в HIGH, делённое на весь период: (время HIGH / период) × 100. На Arduino его находят, деля значение analogWrite на 255 и умножая на 100; например, 64 — это примерно 25%.

Как изменить частоту PWM на Arduino?

analogWrite частоту не меняет. На Uno её можно настроить, изменив регистры таймера (например, TCCR1B для пинов 9 и 10), но это может повлиять на millis и библиотеки. На ESP32 частота задаётся прямо в ledcAttach, а на Pico — через freq().

Может ли PWM повредить светодиод?

Нет. Во время каждого импульса светодиод горит при полном токе, но этот ток уже ограничен последовательным резистором, а средний ток падает пропорционально заполнению. Если резистор подобран правильно, PWM не сокращает срок службы светодиода.

Все проекты
Плавное затухание светодиода с PWM на ESP32
#110Новичок

Плавное затухание светодиода с PWM на ESP32

Плавное изменение яркости светодиода от 0 до максимума и от максимума до 0. PWM управляется через analogWrite(), как в Arduino, — тот же синтаксис без проблем работает в ESP32 Arduino Core 3.0+. Достаточно определения пина, pinMode и analogWrite.

4.8(36)
54
Плавное затухание светодиода с PWM на Pico (эффект дыхания)
#160Новичок

Плавное затухание светодиода с PWM на Pico (эффект дыхания)

Светодиод больше не просто мигает — он дышит! С помощью PWM (широтно-импульсной модуляции) Raspberry Pi Pico яркость светодиода медленно растёт и медленно падает, как огонёк спящего MacBook. Изучи класс machine.PWM, duty_u16() (16-битная яркость 0–65535), частоту PWM (freq(1000) — 1000 циклов вкл/выкл в секунду, мерцания не видно), циклы range() с шагом (вверх и вниз) и почти аналоговый выход с цифрового пина.

0.0(0)
4
Регулировка яркости светодиода потенциометром на ESP32 (аналог → PWM)
#115Средний
Premium

Регулировка яркости светодиода потенциометром на ESP32 (аналог → PWM)

В этом проекте яркость светодиода плавно регулируется потенциометром. Пин АЦП ESP32 читает напряжение 0–3,3V с потенциометра, затем это значение превращается в сигнал PWM (широтно-импульсная модуляция) и подаётся на светодиод. В результате при повороте потенциометра светодиод постепенно становится ярче или тусклее. В Arduino Core 3.0+ можно сразу использовать analogWrite(); на ESP32-S2/S3 разрешение АЦП фиксировано — 12 бит.

4.5(19)
32
Плавная смена цвета RGB-светодиода
#40Новичок
Premium

Плавная смена цвета RGB-светодиода

Один RGB-светодиод медленно переходит от красного к зелёному, от зелёного к синему и обратно к красному, без остановки прокручивая радугу. Каждый переход длится около двух с половиной секунд, а жёлтый

4.8(58)
76
Управление RGB-светодиодом на ESP32
#111Новичок

Управление RGB-светодиодом на ESP32

Бесконечное число цветов одним RGB-светодиодом вместо 3 отдельных. Как в Arduino, радужный переход получается заданием значений R/G/B через analogWrite(). Теория цвета (например, красный + зелёный = жёлтый) видна на практике.

4.6(29)
51
Смена цветов RGB-светодиода на Pico (3 канала PWM)
#161Новичок

Смена цветов RGB-светодиода на Pico (3 канала PWM)

Один светодиод — миллионы цветов! RGB-светодиод содержит 3 светодиода: красный, зелёный и синий. Если управлять каждым своим каналом PWM Pico, цвета смешиваются: красный + зелёный = жёлтый, зелёный + синий = голубой, все три = белый. Светодиод перебирает 8 цветов. Изучи несколько каналов PWM, объявление функций (def set_color(...)), смешивание RGB, перевод 8 бит → 16 бит (x257) и общий катод и общий анод.

0.0(0)
6
Сервопривод на ESP32 (управление потенциометром)
#118Средний
Premium

Сервопривод на ESP32 (управление потенциометром)

В этом проекте сервопривод SG90 управляется потенциометром. Угол сервопривода задаётся сопоставлением аналогового значения потенциометра с диапазоном 0–180 градусов. Библиотека ESP32Servo формирует сигналы сервопривода на подходящих выходных пинах GPIO у ESP32; этот проект использует GPIO 18. Это базовый способ управления для роборук, подвесов камер и механизмов автоматических дверей.

4.3(29)
42
Смеситель цветов на ESP32 (3 потенциометра + RGB-светодиод + OLED)
#138Продвинутый
Premium

Смеситель цветов на ESP32 (3 потенциометра + RGB-светодиод + OLED)

Умная лампа для смешивания цветов на ESP32: вращая три потенциометра, можно получить любой цвет! Когда крутишь потенциометры красного, зелёного и синего, RGB-светодиод с общим катодом меняет цвет в реальном времени. OLED-дисплей SSD1306 показывает значения каждого цвета в диапазоне 0–255, полосы заполнения и веб-код цвета HEX (например, #FF8040). Мини-студия цвета, которая учит теории цвета RGB, чтению АЦП, регулировке яркости через PWM и дизайну экрана I2C.

4.7(6)
10