Управление ШИМ (PWM) на ESP32: Полное руководство от основ до практики.

Широтно-импульсная модуляция (ШИМ), или Pulse Width Modulation (PWM), является фундаментальной технологией в современной цифровой электронике. Она позволяет эффективно управлять мощностью, подаваемой на нагрузку, путем изменения длительности импульсов при постоянной частоте сигнала. Микроконтроллер ESP32, известный своей высокой производительностью и богатым набором периферийных устройств, предлагает расширенные возможности для генерации ШИМ-сигналов по сравнению с более простыми платформами, такими как Arduino Uno. Ключевое отличие ESP32 заключается в использовании канальной системы управления ШИМ, реализованной через специализированные периферийные модули. Вместо прямого управления ШИМ на конкретном выводе GPIO, как в analogWrite() на Arduino, в ESP32 необходимо сначала настроить канал ШИМ (с его частотой и разрешением), а затем привязать один или несколько выводов GPIO к этому каналу. Управление скважностью (яркостью, скоростью) осуществляется путем изменения параметров настроенного канала. Данный подход обеспечивает большую гибкость и производительность. В этом урокуе мы подробно рассмотрим особенности ШИМ на ESP32, уделив основное внимание периферийному модулю LEDC, и приведем практические примеры его использования.

Широтно-импульсная модуляция (ШИМ), или Pulse Width Modulation (PWM)

Выводы GPIO ESP32 с поддержкой ШИМ.

Выход ШИМ доступен на всех выводах GPIO микроконтроллера ESP32, за исключением четырех выводов GPIO (обычно GPIO 34, 35, 36, 39), которые сконфигурированы только как входы. Остальные выводы GPIO могут быть использованы для генерации ШИМ-сигналов.

Выводы GPIO ESP32 с поддержкой ШИМ.

Периферийные модули ШИМ в ESP32.

ESP32 оснащен двумя основными периферийными модулями для генерации ШИМ:

  1. LEDC (LED Control Peripheral): Изначально разработанный для управления светодиодами, этот модуль обладает такими функциями, как автоматическое изменение яркости (fading) и высокая гибкость настройки. Однако его применение не ограничивается светодиодами; он отлично подходит для генерации ШИМ-сигналов для широкого спектра задач, включая управление звуком (пьезоизлучатели) и простые задачи управления двигателями. Данная статья фокусируется именно на модуле LEDC.
  2. MCPWM (Motor Control Pulse Width Modulator Peripheral): Специализированный модуль, предназначенный в первую очередь для управления двигателями. Он включает дополнительные функции, такие как генерация комплементарных сигналов с "мертвым временем" (dead zone) и функции автоматического торможения, что критически важно для управления мостовыми схемами драйверов двигателей.

Частота ШИМ (PWM Frequency).

Как и большинство контроллеров ШИМ, периферийный модуль LEDC в ESP32 использует внутренний таймер для генерации сигналов. Этот таймер непрерывно считает от нуля до своего максимального значения, после чего сбрасывается в ноль и начинает новый цикл счета. Интервал времени между этими сбросами определяет период ШИМ-сигнала, а обратная ему величина – частоту, измеряемую в Герцах (Гц).

  • Например, установка частоты 1 Гц означает, что таймеру требуется 1 секунда для завершения одного цикла счета от 0 до максимального значения перед сбросом.
  • Частота 1000 Гц (1 кГц) означает, что таймер завершает один цикл за 1 миллисекунду (0.001 секунды).

ESP32 способен генерировать ШИМ-сигналы с частотой до 40 МГц (теоретический предел, на практике зависит от разрешения).

Частота ШИМ (PWM Frequency).

Скважность ШИМ (Duty Cycle).

Скважность определяет долю периода, в течение которой ШИМ-сигнал находится в высоком логическом состоянии (HIGH). В контексте таймера LEDC, это значение (обычно сохраняемое в регистре сравнения/захвата таймера - CCR) указывает, до какого значения таймер должен досчитать, прежде чем выходной сигнал переключится с высокого уровня на низкий.

Скважность ШИМ (Duty Cycle).

  • При сбросе таймера (начало периода) выход ШИМ устанавливается в HIGH.
  • Когда счетчик таймера достигает значения, заданного для скважности, выход ШИМ переключается в LOW.
  • Таймер продолжает считать до своего максимального значения.
  • При достижении максимального значения выход ШИМ снова устанавливается в HIGH, и таймер сбрасывается в ноль, начиная следующий период.

Пример: Предположим, нам нужно сгенерировать ШИМ-сигнал с частотой 1000 Гц, 8-битным разрешением и скважностью 75%.

  • Разрешение 8 бит: Максимальное значение таймера равно 2⁸ - 1 = 255. Таймер считает от 0 до 255.
  • Частота 1000 Гц: Период составляет 1 мс. За это время таймер проходит весь цикл счета.
  • Скважность 75%: Значение для регистра сравнения будет рассчитано как (Максимальное значение + 1) * Скважность = 256 * 0.75 = 192. (Или, более точно для дискретных уровней, round((2^разрешение - 1) * скважность) -> round(255 * 0.75) = 191). В библиотеке Arduino ledcWrite обычно принимает значения от 0 до 2^разрешение - 1, поэтому значение 191 будет соответствовать примерно 75% времени в состоянии HIGH.
  • Процесс: При сбросе таймера выход HIGH. Когда счетчик достигает 191, выход переключается в LOW. Когда счетчик достигает 255, выход снова становится HIGH, и таймер сбрасывается.

Разрешение ШИМ (PWM Resolution).

Разрешение ШИМ определяет количество дискретных уровней (шагов), на которые можно разделить диапазон скважности от 0% до 100%. Оно измеряется в битах. Если разрешение ШИМ составляет "n" бит, то таймер считает от 0 до 2ⁿ - 1 перед сбросом.

  • 8 бит: Таймер считает от 0 до 2⁸ - 1 = 255. Это дает 256 дискретных уровней скважности.
  • 10 бит: Таймер считает от 0 до 2¹⁰ - 1 = 1023. Это дает 1024 уровня скважности.
  • 16 бит: Таймер считает от 0 до 2¹⁶ - 1 = 65535. Это дает 65536 уровней скважности.

Более высокое разрешение означает большее количество "шагов" таймера в течение одного и того же периода времени, что приводит к увеличению "гранулярности" или точности установки скважности. Это особенно важно для задач, требующих плавного управления, таких как изменение яркости светодиодов или точное управление скоростью двигателей.

Разрешение ШИМ в ESP32 (для LEDC) можно настроить в диапазоне от 1 до 16 бит.

Каналы ШИМ (PWM Channels) - Ключевая Особенность ESP32.

Вот где проявляется основное отличие ESP32 от простых платформ. Вместо прямого управления ШИМ на выводе, ESP32 использует концепцию каналов. Канал представляет собой логическую единицу, генерирующую уникальный ШИМ-сигнал с заданными параметрами (частота, разрешение, скважность).

  • Количество каналов: ESP32 имеет 16 независимых каналов (с номерами от 0 до 15). Это означает, что он может одновременно генерировать до 16 различных ШИМ-сигналов.Количество каналов: ESP32 имеет 16 независимых каналов (с номерами от 0 до 15).
  • Группы и Таймеры: Эти 16 каналов разделены на две группы:
    • 8 каналов "высокой скорости" (High-Speed)
    • 8 каналов "низкой скорости" (Low-Speed) В каждой группе имеется 4 таймера. Каждый таймер обслуживает два канала.
    • Следствие: Каналы, использующие один и тот же таймер (например, каналы 0 и 1, каналы 2 и 3 и т.д.), должны работать на одинаковой частоте, так как частота определяется настройками общего таймера. Однако скважность каждого канала в паре может управляться независимо.

    Каналы ШИМ (PWM Channels).

    Канал Группа № Канала в группе № Таймера в группе
    0 0 0 0
    1 0 1 0 (тот же таймер, что и у канала 0)
    2 0 2 1
    3 0 3 1 (тот же таймер, что и у канала 2)
    4 0 4 2
    5 0 5 2 (тот же таймер, что и у канала 4)
    6 0 6 3
    7 0 7 3 (тот же таймер, что и у канала 6)
    8 1 0 (8) 0
    9 1 1 (9) 0 (тот же таймер, что и у канала 8)
    10 1 2 (10) 1
    11 1 3 (11) 1 (тот же таймер, что и у канала 10)
    12 1 4 (12) 2
    13 1 5 (13) 2 (тот же таймер, что и у канала 12)
    14 1 6 (14) 3
    15 1 7 (15) 3 (тот же таймер, что и у канала 14)
  • Привязка Выводов: Чтобы ШИМ-сигнал с определенного канала появился на физическом выводе микроконтроллера, необходимо "привязать" (attach) этот вывод к каналу. Один канал может быть привязан к нескольким выводам GPIO. В этом случае все эти выводы будут выдавать абсолютно одинаковый ШИМ-сигнал.
  • Гибкость: Хотя общее количество каналов равно 16 (что ограничивает количество независимых ШИМ-сигналов), количество выводов GPIO, которые могут одновременно выводить ШИМ, теоретически больше (почти все GPIO), при условии, что несколько выводов используют сигналы одних и тех же каналов.

Практическое применение каналов:

  • Синхронное управление: Если вам нужно, чтобы группа светодиодов мигала или изменяла яркость синхронно, вы настраиваете один канал с нужными параметрами и привязываете к нему все выводы GPIO, к которым подключены эти светодиоды.
  • Независимое управление: Если вам нужно управлять несколькими устройствами независимо (например, сервоприводами в роботизированной руке, где каждый сустав требует своего угла поворота, или несколькими светодиодами с разной яркостью), вы должны использовать разные каналы для каждого независимо управляемого устройства/вывода. Вы настраиваете каждый канал (возможно, с одинаковой частотой и разрешением, но это не обязательно) и привязываете каждый вывод GPIO к своему уникальному каналу. Затем вы управляете скважностью каждого канала по отдельности.

Выбор Частоты и Разрешения ШИМ.

ESP32 способен генерировать ШИМ с частотой до 40 МГц и разрешением до 16 бит. Однако существует компромисс между максимальной частотой и максимальным разрешением. Невозможно одновременно установить частоту 40 МГц и разрешение 16 бит.

Ограничение связано с тактовой частотой источника для таймеров ШИМ. Для генерации ШИМ-сигнала с N битами разрешения и частотой F_pwm, тактовая частота источника (F_clk) должна удовлетворять условию:

F_clk >= F_pwm * 2^N

  • Из этого следует:
    • Произведение частоты ШИМ на 2 в степени разрешения не может превышать тактовую частоту источника таймера.
    • При увеличении требуемой частоты ШИМ максимальное доступное разрешение уменьшается, и наоборот, при увеличении разрешения максимальная достижимая частота ШИМ снижается.

Согласно документации Espressif, источником тактового сигнала для таймеров LEDC (как минимум для Low-Speed группы) часто является шина APB_CLK, работающая на частоте 80 МГц. Поэтому рекомендуется, чтобы произведение F_pwm * 2^N оставалось ниже 80 МГц.

Примеры из документации Espressif:

  • Частота ШИМ 5 кГц: Максимальное разрешение ~13 бит (2¹³ = 8192 уровней скважности). (5000 * 8192 ≈ 41 МГц < 80 МГц)
  • Частота ШИМ 20 МГц: Максимальное разрешение ~2 бита (2² = 4 уровня скважности). (20 * 10^6 * 4 = 80 МГц)
  • Частота ШИМ 40 МГц: Максимальное разрешение ~1 бит (2¹ = 2 уровня, т.е. скважность практически фиксирована на 50%). (40 * 10^6 * 2 = 80 МГц)

Практический совет: Для большинства задач, таких как плавное управление яркостью светодиодов, частоты в диапазоне 500 Гц - 5 кГц и разрешения 8-10 бит более чем достаточно. Можно начать с частоты 1-5 кГц и разрешения 8 бит, а затем экспериментировать при необходимости. Для сервоприводов обычно используется частота 50 Гц.


Генерация ШИМ-сигнала с использованием библиотеки LEDC в Arduino IDE.

Ядро ESP32 для Arduino IDE включает встроенную библиотеку ledc, которая упрощает работу с ШИМ через периферийный модуль LEDC.

Алгоритм использования библиотеки ledc:

  1. Выбрать канал ШИМ: Выберите один из 16 доступных каналов (0-15). Рекомендуется начинать с каналов с большими номерами (например, 15, 14, ...) и двигаться к меньшим, чтобы минимизировать конфликты с автоматическим назначением таймеров другими библиотеками.
  2. Определить частоту ШИМ: Задайте желаемую частоту (например, 5000 Гц для светодиодов).
  3. Определить разрешение ШИМ: Задайте разрешение в битах (например, 8 бит для 256 уровней или 10 бит для 1024 уровней).
  4. Выбрать вывод(ы) GPIO: Определите, какой(ие) вывод(ы) GPIO будет(ут) использоваться для вывода ШИМ-сигнала.
  5. Настроить канал ШИМ: Используйте функцию ledcSetup(channel, freq, resolution_bits). Эта функция конфигурирует выбранный канал с указанной частотой и разрешением.
  6. Привязать вывод(ы) к каналу: Используйте функцию ledcAttachPin(pin, channel). Эта функция связывает физический вывод GPIO с настроенным логическим каналом ШИМ.
  7. Установить скважность: Используйте функцию ledcWrite(channel, duty_cycle_value) для установки желаемой скважности на выбранном канале. Значение duty_cycle_value должно быть в диапазоне от 0 до 2^resolution_bits - 1.

Пример 1 – Плавное изменение яркости одного светодиода LEDC в Arduino IDE.

Простой пример, демонстрирующий генерацию ШИМ для плавного зажигания и гашения светодиода.

Схема подключения: Подключите светодиод к выводу GPIO 18 через

  • Схема подключения: Подключите светодиод к выводу GPIO 18 через токоограничивающий резистор (например, 330 Ом). Анод (длинный вывод) светодиода через резистор к GPIO 18, катод (короткий вывод) к GND ESP32.
  • Код (Arduino IDE):
/*
Управление ШИМ (PWM) на ESP32: Полное руководство от основ до практики.
https://arduino-tex.ru/news/217/upravlenie-shim-pwm-na-esp32-polnoe-rukovodstvo-ot-osnov.html
*/
// Константы для настройки ШИМ
const int PWM_CHANNEL      = 0;     // Выбираем канал 0 (из 0-15)
const int PWM_FREQ         = 5000;  // Частота ШИМ 5 кГц (рекомендовано ESP32 примером)
const int PWM_RESOLUTION   = 8;     // Разрешение 8 бит (0-255), как у Arduino Uno
// Максимальное значение скважности, зависит от разрешения
const int MAX_DUTY_CYCLE = (int)(pow(2, PWM_RESOLUTION) - 1); // Будет равно 255 для 8 бит
// Вывод GPIO для подключения светодиода
const int LED_OUTPUT_PIN   = 18;
// Задержка между шагами изменения яркости (в миллисекундах)
const int FADE_DELAY_MS    = 10;
void setup() {
  // 1. Настройка канала ШИМ
  // ledcSetup(канал, частота, разрешение);
  ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
  // 2. Привязка вывода GPIO к настроенному каналу
  // ledcAttachPin(пин, канал);
  ledcAttachPin(LED_OUTPUT_PIN, PWM_CHANNEL);
  Serial.begin(115200); // Инициализация серийного порта для отладки (опционально)
  Serial.println("PWM Fade Example Initialized");
}
void loop() {
  // Плавное увеличение яркости (от 0 до MAX_DUTY_CYCLE)
  Serial.println("Fading UP...");
  for(int dutyCycle = 0; dutyCycle <= MAX_DUTY_CYCLE; dutyCycle++){
    // 3. Установка скважности для канала
    // ledcWrite(канал, значение_скважности);
    ledcWrite(PWM_CHANNEL, dutyCycle);
    delay(FADE_DELAY_MS); // Небольшая задержка для плавности
  }
   Serial.println("Reached Max Brightness");
  // Плавное уменьшение яркости (от MAX_DUTY_CYCLE до 0)
  Serial.println("Fading DOWN...");
  for(int dutyCycle = MAX_DUTY_CYCLE; dutyCycle >= 0; dutyCycle--){
    ledcWrite(PWM_CHANNEL, dutyCycle);
    delay(FADE_DELAY_MS); // Небольшая задержка для плавности
  }
  Serial.println("Reached Min Brightness");
}
  • Тестирование: Загрузите код на ESP32. Вы увидите, как яркость светодиода плавно нарастает от нуля до максимума, а затем плавно убывает до нуля, циклически повторяясь.
  • Пояснения к коду:
    • ledcSetup(0, 5000, 8): Настраивает канал 0 на частоту 5000 Гц с 8-битным разрешением.
    • ledcAttachPin(18, 0): Связывает вывод GPIO 18 с каналом 0. Теперь сигнал, генерируемый каналом 0, будет выводиться на пин 18.
    • ledcWrite(0, dutyCycle): Внутри циклов for эта функция изменяет скважность канала 0, передавая значения от 0 до 255 и обратно. Это напрямую влияет на яркость светодиода, подключенного к пину 18.
Тестирование: Загрузите код на ESP32.

Пример 2 – Один ШИМ-сигнал на нескольких выводах GPIO.

Можно вывести один и тот же ШИМ-сигнал на несколько выводов одновременно. Для этого достаточно привязать все нужные выводы к одному и тому же каналу.

Добавьте еще два светодиода с резисторами. Подключите их к выводам GPIO 19 и GPIO 21

  • Схема подключения: Добавьте еще два светодиода с резисторами. Подключите их к выводам GPIO 19 и GPIO 21 по аналогии с первым светодиодом (аноды через резисторы к пинам, катоды к GND).
  • Код (Arduino IDE):
/*
Управление ШИМ (PWM) на ESP32: Полное руководство от основ до практики.
https://arduino-tex.ru/news/217/upravlenie-shim-pwm-na-esp32-polnoe-rukovodstvo-ot-osnov.html
*/
// Константы для настройки ШИМ (те же, что и в Примере 1)
const int PWM_CHANNEL      = 0;
const int PWM_FREQ         = 5000;
const int PWM_RESOLUTION   = 8;
const int MAX_DUTY_CYCLE = (int)(pow(2, PWM_RESOLUTION) - 1);
// Выводы GPIO для подключения светодиодов
const int LED_1_OUTPUT_PIN = 18;
const int LED_2_OUTPUT_PIN = 19;
const int LED_3_OUTPUT_PIN = 21;
const int FADE_DELAY_MS    = 10;
void setup() {
  // 1. Настройка канала ШИМ (только один раз для канала 0)
  ledcSetup(PWM_CHANNEL, PWM_FREQ, PWM_RESOLUTION);
  // 2. Привязка НЕСКОЛЬКИХ выводов GPIO к ОДНОМУ каналу
  ledcAttachPin(LED_1_OUTPUT_PIN, PWM_CHANNEL); // Пин 18 к каналу 0
  ledcAttachPin(LED_2_OUTPUT_PIN, PWM_CHANNEL); // Пин 19 к каналу 0
  ledcAttachPin(LED_3_OUTPUT_PIN, PWM_CHANNEL); // Пин 21 к каналу 0
  Serial.begin(115200);
  Serial.println("PWM Multi-LED Sync Fade Example Initialized");
}
void loop() {
  // Циклы изменения яркости остаются ТЕМИ ЖЕ,
  // так как мы управляем только ОДНИМ каналом (PWM_CHANNEL)
  Serial.println("Fading UP...");
  for(int dutyCycle = 0; dutyCycle <= MAX_DUTY_CYCLE; dutyCycle++){
    ledcWrite(PWM_CHANNEL, dutyCycle); // Изменяем скважность канала 0
    delay(FADE_DELAY_MS);
  }
   Serial.println("Reached Max Brightness");
  Serial.println("Fading DOWN...");
  for(int dutyCycle = MAX_DUTY_CYCLE; dutyCycle >= 0; dutyCycle--){
    ledcWrite(PWM_CHANNEL, dutyCycle); // Изменяем скважность канала 0
    delay(FADE_DELAY_MS);
  }
  Serial.println("Reached Min Brightness");
}
  • Тестирование: Загрузите код. Вы увидите, что все три светодиода изменяют яркость абсолютно синхронно, так как все они управляются одним и тем же ШИМ-сигналом с канала 0.
  • Пояснения к коду: Основное отличие от Примера 1 – многократный вызов ledcAttachPin() в setup(), привязывающий разные пины (18, 19, 21) к одному и тому же каналу (0). Функция loop() осталась без изменений, так как управление яркостью всех светодиодов осуществляется через изменение скважности единственного канала 0 функцией ledcWrite(0, ...).

Пример 2 – Один ШИМ-сигнал на нескольких выводах GPIO.

Пример 3 – Независимое управление яркостью нескольких светодиодов.

Этот пример демонстрирует ключевое преимущество канальной системы ESP32: возможность независимого управления ШИМ на разных выводах. Мы будем использовать разные каналы для управления тремя светодиодами, заставляя их изменять яркость асинхронно.

Схема подключения: Та же, что и в Примере 2 (светодиоды на GPIO 18, 19, 21).

  • Схема подключения: Та же, что и в Примере 2 (светодиоды на GPIO 18, 19, 21).
  • Код (Arduino IDE):
/*
Управление ШИМ (PWM) на ESP32: Полное руководство от основ до практики.
https://arduino-tex.ru/news/217/upravlenie-shim-pwm-na-esp32-polnoe-rukovodstvo-ot-osnov.html
*/
// Общие параметры ШИМ (можно использовать одинаковые для простоты)
const int PWM_FREQ         = 5000;
const int PWM_RESOLUTION   = 8;
const int MAX_DUTY_CYCLE = (int)(pow(2, PWM_RESOLUTION) - 1);
// Определяем КАНАЛЫ и ПИНЫ для каждого светодиода
const int LED1_PIN = 18;
const int LED1_CH  = 0; // Канал 0 для LED 1
const int LED2_PIN = 19;
const int LED2_CH  = 1; // Канал 1 для LED 2
const int LED3_PIN = 21;
const int LED3_CH  = 2; // Канал 2 для LED 3
// Задержки для управления скоростью "дыхания" каждого светодиода
const int FADE_DELAY1_MS = 10;
const int FADE_DELAY2_MS = 15;
const int FADE_DELAY3_MS = 20;
// Переменные для хранения текущей скважности и направления изменения для каждого канала
int dutyCycle1 = 0;
int dutyCycle2 = MAX_DUTY_CYCLE / 2; // Начнем со средних значений для разнообразия
int dutyCycle3 = MAX_DUTY_CYCLE;
int fadeDir1 = 1; // 1 = вверх, -1 = вниз
int fadeDir2 = -1;
int fadeDir3 = -1;
unsigned long lastUpdate1 = 0;
unsigned long lastUpdate2 = 0;
unsigned long lastUpdate3 = 0;
void setup() {
  Serial.begin(115200);
  Serial.println("PWM Independent Fade Example Initialized");
  // Настраиваем КАЖДЫЙ канал ШИМ
  ledcSetup(LED1_CH, PWM_FREQ, PWM_RESOLUTION);
  ledcSetup(LED2_CH, PWM_FREQ, PWM_RESOLUTION);
  ledcSetup(LED3_CH, PWM_FREQ, PWM_RESOLUTION);
  // Привязываем КАЖДЫЙ пин к своему СОБСТВЕННОМУ каналу
  ledcAttachPin(LED1_PIN, LED1_CH);
  ledcAttachPin(LED2_PIN, LED2_CH);
  ledcAttachPin(LED3_PIN, LED3_CH);
}
void loop() {
  unsigned long currentTime = millis(); // Получаем текущее время
  // --- Управление Светодиодом 1 (Канал 0) ---
  if (currentTime - lastUpdate1 >= FADE_DELAY1_MS) {
    lastUpdate1 = currentTime; // Обновляем время последнего изменения
    dutyCycle1 += fadeDir1; // Изменяем скважность
    // Проверяем границы и меняем направление
    if (dutyCycle1 >= MAX_DUTY_CYCLE) {
      dutyCycle1 = MAX_DUTY_CYCLE;
      fadeDir1 = -1; // Начать убывание
    } else if (dutyCycle1 <= 0) {
      dutyCycle1 = 0;
      fadeDir1 = 1; // Начать возрастание
    }
    // Применяем новую скважность к КАНАЛУ 0
    ledcWrite(LED1_CH, dutyCycle1);
  }
  // --- Управление Светодиодом 2 (Канал 1) ---
  if (currentTime - lastUpdate2 >= FADE_DELAY2_MS) {
    lastUpdate2 = currentTime;
    dutyCycle2 += fadeDir2;
    if (dutyCycle2 >= MAX_DUTY_CYCLE) {
      dutyCycle2 = MAX_DUTY_CYCLE;
      fadeDir2 = -1;
    } else if (dutyCycle2 <= 0) {
      dutyCycle2 = 0;
      fadeDir2 = 1;
    }
    // Применяем новую скважность к КАНАЛУ 1
    ledcWrite(LED2_CH, dutyCycle2);
  }
  // --- Управление Светодиодом 3 (Канал 2) ---
  if (currentTime - lastUpdate3 >= FADE_DELAY3_MS) {
     lastUpdate3 = currentTime;
    dutyCycle3 += fadeDir3;
    if (dutyCycle3 >= MAX_DUTY_CYCLE) {
      dutyCycle3 = MAX_DUTY_CYCLE;
      fadeDir3 = -1;
    } else if (dutyCycle3 <= 0) {
      dutyCycle3 = 0;
      fadeDir3 = 1;
    }
    // Применяем новую скважность к КАНАЛУ 2
    ledcWrite(LED3_CH, dutyCycle3);
  }
}
  • Тестирование: Загрузите код. Вы увидите, что три светодиода изменяют свою яркость независимо друг от друга и с разной скоростью. Это достигается за счет использования отдельных каналов ШИМ (0, 1 и 2) для каждого светодиода и независимого управления скважностью каждого канала функцией ledcWrite().
  • Пояснения к коду:
    • В setup() мы теперь вызываем ledcSetup() трижды, настраивая каналы 0, 1 и 2 (с одинаковыми параметрами частоты и разрешения для простоты).
    • Затем мы вызываем ledcAttachPin() трижды, связывая пин 18 с каналом 0, пин 19 с каналом 1 и пин 21 с каналом 2.
    • В loop() используется неблокирующий подход с millis() для управления скоростью изменения яркости каждого светодиода независимо.
    • Ключевой момент: для изменения яркости первого светодиода вызывается ledcWrite(LED1_CH, ...), для второго - ledcWrite(LED2_CH, ...), для третьего - ledcWrite(LED3_CH, ...). Мы управляем разными каналами, что приводит к независимому поведению светодиодов.

Дополнительные замечания и рекомендации.

  • Распределение каналов и таймеров: Как упоминалось, каналы сгруппированы попарно и используют общие таймеры. Помните, что каналы, использующие один таймер, должны иметь одинаковую частоту ШИМ.
  • Стратегия выбора каналов: Чтобы избежать потенциальных конфликтов с другими библиотеками, которые могут автоматически использовать таймеры ШИМ (например, для сервоприводов или других нужд), некоторые разработчики предпочитают начинать использовать каналы с конца списка (15, 14, 13...).
  • Рекомендуемые выводы для ШИМ (особенно для серво): Хотя большинство GPIO поддерживают ШИМ, некоторые выводы могут быть связаны с другими функциями (например, JTAG, strapping pins). Часто рекомендуемые для ШИМ (включая серво) выводы: 2, 4, 12-19, 21-23, 25-27, 32, 33. Избегайте использования выводов, используемых для Flash (6-11) или только входных (34-39).

Заключение.

Микроконтроллер ESP32 предоставляет мощную и гибкую систему для генерации ШИМ-сигналов, значительно превосходящую возможности базовых платформ вроде Arduino Uno. Ключевым элементом этой системы является периферийный модуль LEDC с его 16 независимыми каналами. Понимание концепции каналов, их настройки ledcSetup, привязки к физическим выводам ledcAttachPin и управления скважностью ledcWrite является основой для эффективного использования ШИМ на ESP32.

Возможность настраивать частоту и разрешение в широких пределах, а также независимо управлять несколькими ШИМ-сигналами одновременно, делает ESP32 идеальным выбором для проектов, требующих точного управления яркостью светодиодов, скоростью двигателей, генерации звуковых сигналов и многих других задач. Для более сложных приложений управления двигателями следует рассмотреть использование специализированного модуля MCPWM. Освоение ШИМ на ESP32 открывает двери к созданию более продвинутых и функциональных электронных устройств.

Дополнительная информация к данному уроку:

Понравился урок: Управление ШИМ (PWM) на ESP32: Полное руководство от основ до практики? Не забудь поделиться с друзьями в соц. сетях.

А также подписаться на наш канал на YouTube, вступить в группу Вконтакте, в Telegram.

Спасибо за внимание!

Технологии начинаются с простого!

Фотографии к статье

Файлы для скачивания

Пример 1 – Плавное изменение яркости одного светодиода Пример 1 – Плавное изменение яркости одного светодиода.ino2 Kb 23 Скачать
Пример 2 – Один ШИМ-сигнал на нескольких выводах GPIO Пример 2 – Один ШИМ-сигнал на нескольких выводах GPIO.ino2 Kb 19 Скачать
Пример 3 – Независимое управление яркостью нескольких светодиодов Пример 3 – Независимое управление яркостью нескольких светодиодов.ino3 Kb 20 Скачать

Комментарии

Ваше Имя*


Разработка проектов