ESP32 PWM (analogWrite): управление яркостью и скоростью без углублений в драйверы
ESP32 поддерживает широтно‑импульсную модуляцию (ШИМ), что позволяет плавно управлять яркостью светодиодов, скоростью вентиляторов и моторов, уровнем подсветки и т. п. В Arduino‑среде для ESP32 доступен простой, знакомый интерфейс analogWrite() — его достаточно, чтобы быстро запустить PWM без изучения низкоуровневых деталей.
Ключевые функции
void analogWrite(uint8_t pin, uint32_t duty);— записывает скважность (duty) на выводpin.void analogWriteResolution(uint8_t pin, uint8_t resolution);— задаёт разрешение ШИМ для пина (в битах). Диапазон значений duty будет0 … 2resolution-1.void analogWriteFrequency(uint8_t pin, uint32_t freq);— задаёт частоту ШИМ (в Гц) для пина.
Замечание: максимально возможное разрешение зависит от выбранной частоты: чем выше частота, тем меньше доступных бит. Для светодиодов часто используют 5–10 кГц с 8–12 битами; для моторов — 15–25 кГц, чтобы уйти выше слышимого диапазона.
Диапазоны значений duty
| Разрешение (бит) | Диапазон duty |
|---|---|
| 8 | 0…255 |
| 10 | 0…1023 |
| 12 | 0…4095 |
| 13 | 0…8191 |
Рекомендации по пинам и подключению
- Для ШИМ‑выходов используйте GPIO из диапазонов
4–19,21–23,25–27,32–33. - Никогда не используйте
GPIO34–39— это входы‑только. - ESP32 работает на 3.3 В, выводы не 5V‑tolerant. Для светодиода — обязательно токоограничивающий резистор 220–330 Ω.
Пример 1. Плавное «мигание» светодиода
Частота 5 кГц, разрешение 8 бит (0–255). Плавный подъём/спад яркости.
#include <Arduino.h>
const uint8_t LED_PIN = 5;
void setup() {
// Настраиваем частоту и разрешение для пина
analogWriteFrequency(LED_PIN, 5000); // 5 кГц
analogWriteResolution(LED_PIN, 8); // 8 бит → duty 0..255
}
void loop() {
for (int d = 0; d <= 255; d++) {
analogWrite(LED_PIN, d);
delay(6);
}
for (int d = 255; d >= 0; d--) {
analogWrite(LED_PIN, d);
delay(6);
}
}
Как это работает: при увеличении duty коэффициент заполнения ШИМ растёт — среднее напряжение на светодиоде увеличивается, яркость возрастает. При уменьшении — наоборот.
Пример 2. RGB‑светодиод: смешивание цветов
Три независимых канала PWM на 5 кГц, 8 бит. Выводим базовые и смешанные цвета.
#include <Arduino.h>
const uint8_t R_PIN = 21;
const uint8_t G_PIN = 22;
const uint8_t B_PIN = 23;
void setup() {
// Одинаковая частота/разрешение для всех трёх каналов
analogWriteFrequency(R_PIN, 5000);
analogWriteResolution(R_PIN, 8);
analogWriteFrequency(G_PIN, 5000);
analogWriteResolution(G_PIN, 8);
analogWriteFrequency(B_PIN, 5000);
analogWriteResolution(B_PIN, 8);
}
void solid(uint8_t r, uint8_t g, uint8_t b, uint32_t ms) {
analogWrite(R_PIN, r);
analogWrite(G_PIN, g);
analogWrite(B_PIN, b);
delay(ms);
}
void loop() {
solid(255, 0, 0, 800); // Красный
solid( 0, 255, 0, 800); // Зелёный
solid( 0, 0, 255, 800); // Синий
solid(255, 255, 0, 800); // Жёлтый
solid( 0, 255, 255, 800); // Голубой
solid(255, 0, 255, 800); // Пурпурный
solid(128, 32, 255, 800); // Произвольный оттенок
}
Как это работает: каждый из трёх каналов управляет яркостью соответствующего кристалла RGB‑светодиода. Комбинируя скважность, получаем любой цвет.
Пример 3. Регулятор скорости/яркости от потенциометра
Частота 20 кГц (выше слышимого диапазона), разрешение 12 бит для более тонкой градации. Значение с потенциометра (ADC) масштабируем в duty.
#include <Arduino.h>
const uint8_t PWM_PIN = 19; // Выход PWM (к драйверу/LED)
const uint8_t POT_PIN = 34; // Вход ADC (только-вход) - потенциометр
const uint8_t RES_BITS = 12; // 12 бит → duty 0..4095
const uint32_t F_PWM = 20000; // 20 кГц
void setup() {
Serial.begin(115200);
analogWriteFrequency(PWM_PIN, F_PWM);
analogWriteResolution(PWM_PIN, RES_BITS);
analogReadResolution(12); // чтобы сопоставить с 12-битным duty
}
void loop() {
int raw = analogRead(POT_PIN); // 0..4095 (ESP32 ADC 12 бит)
// Масштабируем ADC к duty (0..4095)
uint32_t duty = (uint32_t)raw; // при совпадающих разрядностях просто берём сырой ADC
analogWrite(PWM_PIN, duty);
// Телеметрия
static uint32_t t0 = 0;
if (millis() - t0 > 300) {
t0 = millis();
Serial.printf("ADC=%4d duty=%4lu\r\n", raw, duty);
}
}
Как это работает: с потенциометра читается 12‑битное значение, которое напрямую подаётся как duty того же разряда. Частота 20 кГц исключает акустический писк при управлении вентиляторами/моторами.
Типовые сочетания частоты и разрешения
| Задача | Частота (Гц) | Разрешение (бит) | Комментарий |
|---|---|---|---|
| Яркость LED | 5 000–10 000 | 8–12 | Без мерцания, плавные градации |
| Мотор/вентилятор | 18 000–25 000 | 8–11 | Выше слышимого диапазона |
| Подсветка/дисплей | 1 000–20 000 | 8–12 | Подбирайте на глаз/по шуму |
Подсказка: если выставили слишком высокую частоту и «не берётся» выбранное разрешение, уменьшите число бит. Для отладки начните с 5 кГц и 8 бит, затем повышайте частоту и/или разрядность.
Частые ошибки
- Использование пинов
34–39как выхода — они вход‑только, ШИМ не получится. - Слишком маленькая частота → заметное мерцание LED.
- Слишком большая частота при высоком разрешении → канал не стартует/яркость «ступенчатая». Снижайте разрядность.
- Подключение LED без резистора, нагрузок напрямую к GPIO — используйте резистор и соответствующие драйверы.
Итоги
analogWrite() на ESP32 позволяет быстро поднять PWM: задайте analogWriteFrequency(pin, freq), analogWriteResolution(pin, bits), затем меняйте duty через analogWrite(pin, value). Этого достаточно для подавляющего большинства задач — от плавной подсветки до управления вентиляторами и простыми моторами.





