Разработка ESC для BLDC. Программа. #2
Это вторая часть цикла по разработке ESC для BLDC с шестишаговой коммутацией. Для демонстрации работы кода контроллера я доработал первый вариант платы ESC.
Первая часть находится по ссылке Разработка ESC для BLDC. Схема. #1.
Все ссылки на программу управления и видео работы ESC даны в конце статьи.
В ходе тестирования в исходной плате были установлены транзисторы IRFB4410 в корпусе TO-220 и диоды Шоттки SS56 в корпусе SMC, и надо было вернуть всё в исходное состояние и установить транзисторы FDD8447L(1) в корпусе TO-252 и диоды Шоттки 1N5819 в корпусе DO-41 (установлены с нижней стороны), плата была спроектирована под эти корпуса.
Между затвором и истоком каждого транзистора установлены SMD резисторы номиналом 10 кОм (1). На каждый полумост фазы установлен твердотельный полимерный электролитический конденсатор 63 v 220 мкФ (2). На общем питании запаян электролитический конденсатор 1000 мкФ 51 В (3). Заменен разъем под датчики Холла (4). Зафиксирован на плате переменный резистор для управления скоростью оборотов двигателя (5). К имеющемуся на плате красному светодиоду добавлены ещё два светодиода зеленого и красного цвета (6). Провода фаз перенесены на нижнюю сторону платы. В качестве микроконтроллера используется чип Atmega48PA, кварц используется на 20 МГц.
Подведу итог подключений к МК и опишу работу кода по настройке архитектуры.
Фаза U: верхнее плечо (Uh) подключено к пину PD6. На этот вывод заведен аппаратный ШИМ — канал OC0A таймера 0. Управление осуществляется изменением скважности ШИМ через регистр. Нижнее плечо (Ul) подключено к пину PD7. Это цифровой вывод, управление осуществляется логическими уровнями портов (через PORTD).
Фаза V: верхнее плечо (Vh) подключено к пину PD5. На этот вывод заведен аппаратный ШИМ — канал OC0B таймера 0. Нижнее плечо (Vl) подключено к пину PD4. Это цифровой вывод, управляемый через PORTD.
Фаза W: верхнее плечо (Wh) подключено к пину PD3. На этот вывод заведен аппаратный ШИМ — канал OC2B таймера 2. Нижнее плечо (Wl) подключено к пину PD2. Это цифровой вывод, управляемый через PORTD.
Ниже представлены макросы для мгновенного переключения состояний фаз в коде, применяются битовые макросы включения/выключения пинов.
// Фаза U
#define UH_ON TCCR0A |= (1 <<COM0A1)
#define UH_OF TCCR0A &= ~(1<<COM0A1)
#define UL_ON PORTD |= (1<<PD7)
#define UL_OF PORTD &= ~(1 <<PD7)
Таймер 0 генерирует ШИМ-сигналы для фаз U и V, а таймер 2 — для фазы W. Оба таймера настраиваются в идентичный режим 8-битного быстрого ШИМ (Fast PWM).
Очистка регистров (TCCRxA = 0, TCCRxB = 0, TCNTx = 0). Перед настройкой регистры управления и счетный регистр принудительно обнуляются, чтобы сбросить любые настройки.
Режим генерации формы сигнала (Waveform Generation Mode): установка битов WGM00 и WGM01 для Таймера 0 (и WGM20, WGM21 для Таймера 2) переводит их в Режим 3 — Fast PWM (Быстрый ШИМ). В этом режиме счетчик считает от 0 до 255 (0xFF), после чего сбрасывается обратно в 0, обеспечивая максимальную частоту обновления.
Поведение выводов (Compare Output Mode): биты COM0A1, COM0B1 и COM2B1 включают неинверсный режим ШИМ. При старте цикла (счетчик равен 0) на выводах фаз устанавливается высокий логический уровень, а при совпадении значения счетчика с регистрами сравнения (OCR0A, OCR0B, OCR2B) уровень падает в ноль. Таким образом, значение в регистре напрямую определяет скважность (от 0 до 255).
Предделитель и итоговая частота (Clock Select): биты CS01 и CS21 подключают тактовый сигнал контроллера к таймерам через делитель на 8. При нестандартной частоте кварца в 20 МГц, частота переполнения таймера рассчитывается как 20000000/(8*256). Это дает итоговую частоту ШИМ около 9.7 кГц.
Настройка порта D на выход под пины фаз PD2, PD3, PD4, PD5, PD6, PD7:
DDRD = 0b11111100.
Настройка светодиодов: LedR (Красный 1) подключен к аппаратному выводу PD0. Управляется логическими уровнями через регистр PORTD. LedG (Зеленый) подключен к аппаратному выводу PD1, также управляется через регистр PORTD. Оба этих диода (LedR и LedG) работают в дискретном режиме (вкл/выкл) и применяются для приветственного перемигивания при нормальной загрузке, блокировки при «горячем старте» и аварийной индикации (например, при заклинивании ротора).
LedR2 (Красный 2) подключен к аппаратному выводу PC0. Управление осуществляется через регистр PORTC. Этот светодиод используется для динамической индикации: его яркость плавно меняется синхронно с положением ручки газа (значением АЦП).
Для того чтобы микроконтроллер мог зажигать светодиоды, соответствующие пины портов необходимо перевести в режим вывода (записать единицу в регистры направления данных DDRC и DDRD).
Так как пин PC0 не обладает поддержкой аппаратного ШИМ в архитектуре ATmega328P, для регулировки яркости диода LEDR2 применяется программный ШИМ. Для этого задействуется аппаратный Таймер 1. Таймер 1 конфигурируется в режим 8-битного быстрого ШИМ (Fast PWM, Mode 5). Предделитель устанавливается на 8, что при тактовой частоте 20 МГц обеспечивает частоту прерываний таймера около 9,7 кГц. Сама генерация ШИМ-сигнала работает полностью в фоновом режиме через два прерывания. Прерывание по переполнению таймера ISR(TIMER1_OVF_vect) отвечает за подачу логической единицы (включение диода). Прерывание по совпадению канала А ISR(TIMER1_COMPA_vect) сравнивает текущий счетчик с регистром OCR1A (куда записывается значение с АЦП ADC3) и формирует логический ноль (выключение диода). Регулировка скорости осуществляется с помощью аналогового сигнала, поступающего с переменного резистора (ручки газа). Этот сигнал подается на пин микроконтроллера ADC3.
Настройка аналого-цифрового преобразователя (АЦП) в контроллере имеет особенности. АЦП настроен на 8-битный режим, что достигается установкой бита ADLAR (выравнивание результата влево). Это позволяет считывать значение скорости от 0 до 255 непосредственно из регистра ADCH, отбрасывая младшие биты. Опорное напряжение установлено от вывода AVcc. Для оптимизации работы основного цикла АЦП переведен в неблокирующий режим Free Running. Микроконтроллер непрерывно оцифровывает сигнал в фоновом режиме. По завершении каждого преобразования аппаратно вызывается прерывание ISR(ADC_vect), которое мгновенно обновляет глобальную переменную adc_value актуальным значением.
Линия ADC3 работает без сглаживающего RC-фильтра (конденсатора). В цикле программы считанное значение АЦП используется для управления скважностью ШИМ на фазах двигателя и яркостью индикаторного светодиода LedR2.
// Обработчик прерывания АЦП ISR(ADC_vect) {adc_value = ADCH;}
Благодаря такой архитектуре функция чтения (inline unsigned char ReadADC() { return adc_value; }) отрабатывает за 1–2 машинных такта, просто возвращая актуальное значение переменной. Это избавляет основной цикл программы от блокирующих ожиданий окончания преобразования, обеспечивая плавную работу таймеров защиты от заклинивания и непрерывное обновление скважности ШИМ двигателя.
В контроллере для определения положения ротора используются сигналы с трех датчиков Холла, которые подключены к выводам порта B микроконтроллера. Holl1 заведен на пин PB0, Holl2 — на PB1, а Holl3 — на PB2.
Пины датчиков настраиваются как цифровые входы с программным включением. Входы с датчиков подтянуты внешними резисторами pull-up.
Для мгновенной реакции на смену положения магнитов ротора используется механизм прерываний по изменению состояния пинов (Pin Change Interrupt — PCINT).
Для понимания логики включения/выключения пинов фаз необходимо рассмотреть работу драйвера IR2108S. Управление драйверами полумоста IR2108S осуществляется двумя логическими сигналами: Hin (управление верхним ключом) и Lin (управление нижним ключом). В зависимости от их комбинации формируются управляющие напряжения на выходах драйвера Ho (на затвор верхнего транзистора) и Lo (на затвор нижнего транзистора).
Таблица логики IR2108S:
Hin = 0, Lin = 0 >> Ho = 0, Lo = 1
Hin = 1, Lin = 0 >> Ho = 0, Lo = 0
Hin = 0, Lin = 1 >> Ho = 0, Lo = 0
Hin = 1, Lin = 1 >> Ho = 1, Lo = 0
Опираясь на эту логику, в коде сформированы три коммутационных макроса для каждой фазы (для фазы W).
Фаза подключена к плюсу питания (макрос Wpos). На оба входа (Hin и Lin) подаются логические единицы (WH_ON; WL_ON). Результат: драйвер открывает верхний ключ (Ho = 1) и надежно закрывает нижний (Lo = 0), подавая на обмотку положительное напряжение питания.
Фаза подключена к минусу/земле (макрос Wneg). На оба входа (Hin и Lin) подаются логические нули (WH_OF; WL_OF). Результат: драйвер закрывает верхний ключ (Ho = 0) и открывает нижний (Lo = 1), замыкая обмотку на землю.
Фаза полностью отключена / Z-состояние (Макрос Wdis). На вход верхнего ключа Hin подается логический ноль, а на вход нижнего Lin — логическая единица (WH_OFF; WL_ON). Результат: драйвер принудительно закрывает оба ключа (Ho = 0, Lo = 0). Обмотка «висит в воздухе», что необходимо для третьей неактивной фазы в шестишаговом алгоритме управления. Именно эта комбинация используется для функции аварийного гашения всех драйверов моста. Имеется и вторая комбинация для Z-состояния, это когда на вход верхнего ключа Hin подается логическая единица, а на вход нижнего Lin — логический ноль, выбирайте любую.
Составные макросы коммутационных шагов для фазы W:
#define Wpos WH_ON; WL_ON // Фаза W скоммутирована на Плюс питания
#define Wneg WH_OF; WL_OF // Фаза W скоммутирована на Землю (Минус)
#define Wdis WH_OF; WL_ON // Фаза W полностью отключена (вход Z-состояния)
Базовые комбинации открытых ключей инвертора при шестишаговом упралении:
#define Step1 Vdis; Uneg; Wpos // Конфигурация: W+, U-, V висит в воздухе
#define Step2 Udis; Wneg; Vpos // Конфигурация: V+, W-, U висит в воздухе
#define Step3 Wdis; Vpos; Uneg // Конфигурация: V+, U-, W висит в воздухе
#define Step4 Wdis; Vneg; Upos // Конфигурация: U+, V-, W висит в воздухе
#define Step5 Udis; Wpos; Vneg // Конфигурация: W+, V-, U висит в воздухе
#define Step6 Vdis; Upos; Wneg // Конфигурация: U+, W-, V висит в воздухе
#define PHASE_ALL_OFF Wdis; Vdis; Udis // Аварийное гашение драйвера: закрыть все 6 ключей моста
Программная часть контроллера разделена на модули. Это позволяет легко масштабировать и читать код.
1. Главный модуль (файл AVR10x.ino). Это ядро программы и точка входа (main). Инициализирует всю периферию модулей и управление главным рабочим циклом. В главном файле реализована конечная машина состояний (State Machine) с тремя режимами работы двигателя (motor_state: 0 = STOP, 1 = STARTUP, 2 = RUNNING). Здесь же выполняется проверка безопасности при старте (защита от «горячего старта»), обработка логики защиты от заклинивания (stall_timer), а также вызовы функций предзарядки бутстрепных конденсаторов и управления скоростью.
2. Модуль BLDC.h (силовая коммутация) отвечает за низкоуровневое управление драйверами полумоста. Настраивает порты микроконтроллера для вывода ШИМ и логических сигналов на ключи инвертора. Включает функцию InitBLDC(), которая настраивает пины фаз на выход. Содержит базовые битовые макросы управления верхними и нижними ключами фаз U, V и W. Формирует составные макросы коммутации на Плюс, Минус и Z-состояние. Также в модуле прописаны шесть конфигураций открытых ключей (Step1 — Step6) для шестишагового управления и макрос аварийного гашения всех драйверов PHASE_ALL_OFF.
3. Модуль Holls.h (Синхронизация и датчики) отвечает за чтение положения ротора и переключение (коммутацию) фаз двигателя. Обрабатывает сигналы с датчиков Холла и реализации гибридного алгоритма запуска. Содержит InitHolls() для настройки пинов (PB0-PB2) на вход и активации прерываний по изменению состояния пина (PCINT). Главная функция модуля — Commutate(). Она обеспечивает принудительный перебор фаз (если мотор в состоянии магнитного залипания) и мгновенный переход к синхронному переключению (closed-loop), как только датчики зафиксируют реальное вращение. Здесь же реализован сброс таймера заклинивания при каждом физическом смещении ротора.
4. Модуль Timers.h (Аппаратные таймеры) централизует настройку всех аппаратных таймеров микроконтроллера. Конфигурирует генерацию ШИМ-сигналов и временных интервалов. В функции InitTimers() Таймер 0 и Таймер 2 настраиваются в режим быстрого 8-битного ШИМ (Fast PWM, режим 3) для аппаратного управления мощностью на фазах мотора. Таймер 1 конфигурируется в режим 5 (Fast PWM 8-bit) с прерываниями, который используется для программного ШИМ индикации и отсчета времени защиты от заклинивания.
5. Модуль ADC.h (Чтение ручки газа) отвечает за неблокирующую оцифровку аналогового сигнала скорости. Считывает уровни напряжения с переменного резистора (вывод ADC3) без задержек основного цикла программы. АЦП инициализируется в 8-битном режиме (сдвиг результата влево) и переводится в режим непрерывного преобразования (Free Running). По завершении каждого замера аппаратно вызывается прерывание ISR(ADC_vect), обновляющее переменную скорости. Функция ReadADC() моментально возвращает это значение.
6. Модуль Speed.h (Управление мощностью) изменяет скважность ШИМ двигателя. Содержит функцию set_speed(speed), которая (с временным отключением прерываний cli()) записывает новое значение скорости в регистры сравнения OCR0A, OCR0B и OCR2B. Запись синхронизируется с переполнением таймера, чтобы избежать искажения формы ШИМ на лету.
7. Модуль LED.h (Настройка индикации), первичная инициализация портов вывода для системы визуальной индикации. Настраивает пины PD0 (Красный 1), PD1 (Зеленый) и PC0 (Красный 2) на выход. Предоставляет макросы для включения (ON), выключения (OFF) и инверсии/перемигивания (IV) светодиодов без необходимости прописывать битовые маски вручную в основном коде.
8. Модуль Test.h (Процедуры безопасности и тестов), расширяющий логику индикации и защит. Визуальная обратная связь для пользователя и фоновый отсчет времени. Содержит функцию приветственного перемигивания Test_StartupBlink() и функцию аварийной блокировки контроллера Test_SafetyLockout(), которая срабатывает при поданном газе во время загрузки. Также в этом модуле размещены обработчики прерываний Таймера 1 (ISR(TIMER1_OVF_vect) и ISR(TIMER1_COMPA_vect)), которые реализуют программный ШИМ для плавной регулировки яркости диода LedR2 и увеличивают глобальный счетчик защиты от заклинивания stall_timer каждую миллисекунду.
Программная логика контроллера построена на базе конечного автомата и гибридного алгоритма запуска. Это позволяет срывать ротор с точек магнитного залипания и обеспечивать плавное управление в рабочем режиме.
Вся работа контроллера разделена на три изолированных состояния, за которые отвечает переменная motor_state.
0 (STOP) — остановка, двигатель обесточен, все ключи драйвера закрыты (Z-состояние). Контроллер переходит в этот режим при убранной ручке газа или при срабатывании аварийной защиты. При этом таймер заклинивания продолжает работу, чтобы отслеживать вращение ротора по инерции.
1 (STARTUP) — режим запуска, активируется алгоритм страгивания с места и синхронизации. На двигатель подается фиксированный стартовый ток (ШИМ), а защита от заклинивания переводится в толерантный режим.
2 (RUNNING) — рабочий режим, включается контроль заклинивания, а ШИМ начинает напрямую управляться ручкой газа (АЦП). Коммутация фаз происходит по аппаратным прерываниям от датчиков Холла.
Запуск бесколлекторного мотора является самой сложной задачей программы из-за магнитного залипания ротора и инерции. Процесс старта из состояния покоя начинается зарядкой бутстрепных конденсаторов. Перед подачей ШИМ на 5 миллисекунд открываются все нижние ключи инвертора. Это заряжает конденсаторы драйверов IR2108S.
Далее идёт срыв с залипания. Если мотор находится в магнитной «мёртвой зоне», он не сдвинется сам. Алгоритм ждёт заданное время (например, 15 мс). Если датчики Холла молчат, контроллер принудительно включает следующую фазу (шаг +1), создавая мощный боковой рывок, игнорируя показания датчиков.
Как только ротор начинает успевать за магнитным полем, датчики Холла генерируют прерывания до истечения таймаута. Программа начинает считать успешные синхронные шаги подряд (sync_count). Когда накапливается 6 успешных шагов (один полный электрический оборот), система понимает, что мотор надежно разогнался, и автоматически переключается в состояние RUNNING.
Программа умеет отличать полностью остановленный ротор от летящего по инерции. Таймер защиты обнуляется при любом изменении сигналов Холла, даже если газ убран. Если сбросить газ, а затем снова нажать его, пока ротор еще вращается, контроллер минует стадию STARTUP. Он сразу переходит в режим RUNNING и подает ток в ту фазу, которая соответствует летящему ротору в данный момент, обеспечивая бесшовное ускорение без ударов.
В коде реализован ряд механизмов, гарантирующих безопасность ESC и мотора. Если при подаче питания ручка газа выкручена (значение АЦП выше стартового порога), система блокируется и бесконечно мигает светодиодами. Двигатель не запустится до сброса питания.
Аппаратный таймер 1 генерирует прерывания каждую миллисекунду и увеличивает счетчик stall_timer. Если ротор блокируется и датчики Холла перестают переключаться, счетчик превышает заданный лимит (TIMEOUTSTALL), после чего контроллер мгновенно гасит драйвер и уходит в аварию.
При переходе из режима жесткого старта в рабочий режим предусмотрено ограничение минимального ШИМ (MIN_RUN_PWM). Это не дает ротору заглохнуть, если ручка газа установлена на слишком низкое значение, недостаточное для поддержания вращения.
Весь код написан в неблокирующей парадигме. Функции delay() исключены из рабочего цикла. Аналого-цифровой преобразователь (АЦП) работает в фоновом режиме и обновляет переменную скорости по прерыванию. Единая функция Commutate() обрабатывает как слепой перебор фаз, так и синхронное управление, что исключает фазовые конфликты при переходе режимов.
По ссылке в архиве Архив программы представлен код всех модулей. На этом всё, в следующей части опишу запуск и тестирование ESC.
ESC для BLDC своими руками. Часть 2. Программа управления (6-step)
ESC для BLDC своими руками. Часть1. Homemade BLDC ESC YouTube
ESC для BLDC своими руками. Часть 2. Программа управления (6-step) - VK
Тесты созданного своими руками ESC на Atmega328P и BLDC - VK
Еще больше интересных статей
Ультразвуковой резак с обдувом.
Подпишитесь на автора
Подпишитесь на автора, если вам нравятся его публикации. Тогда вы будете получать уведомления о его новых статьях.
Отписаться от уведомлений вы всегда сможете в профиле автора.
Неделю думал-гадал, типа нужна ли?. Ну,...
Скрипт для фильтрации авторов на дэшборде моделей.
Подпишитесь на автора
Подпишитесь на автора, если вам нравятся его публикации. Тогда вы будете получать уведомления о его новых статьях.
Отписаться от уведомлений вы всегда сможете в профиле автора.
PETPull - очередной станок по переработке PET бутылок в пруток для 3D принтера.
Подпишитесь на автора
Подпишитесь на автора, если вам нравятся его публикации. Тогда вы будете получать уведомления о его новых статьях.
Отписаться от уведомлений вы всегда сможете в профиле автора.
Это мой первый пост. Не судите строго.
Решил о...



Комментарии и вопросы
диаметр прутка это в настройка...
😄
чтобы стягивать чашечки не печ...
Всем добрый день. Итак, сгорел...
Приобрел snapmaker u1, решил п...
Печатаю шестерню из PA6 на "др...
привет всем форумчанам, подска...