STM32 - диммер





Здравствуйте.

Вначале коротко о том как работает диммер. Переменное напряжение в розетке выглядит так…


заметка
Я обрисовал схему работы переменного напряжения упрощённо. На самом деле, там где на рисунке написано 220, напряжение больше, где-то 310. Напряжение растёт от нуля до максимума, а 220 находятся где-то во второй трети полуволны. То есть 220 это что-то типа среднего напряжения. Однако сути работы диммера это не меняет.

Кстати, есть приборы, у которых включатель сделан не в виде тупого тумблера, а с использованием микросхемы, которая замыкает контакты именно в момент перехода через ноль. Таким образом снижается нагрузка на прибор и на сеть. Ведь по сути, включение прибора это ни что иное как замыкание, и значит лучше это делать в момент наименьшего напряжения, а ни когда оно уже выросло.

Если интересно как работает переменка, и откуда она берётся, то загляните сюда.


Если сейчас подключить лампочку, то она будет гореть с максимальной яркостью. Чтобы уменьшить яркость, нужно от начала каждой полуволны (нижней и верхней) отрезать кусочек. То есть чтоб зажечь лампочку в половину накала, надо сделать так…


50%

Чем то это похоже на обычный ШИМ постоянного напряжения, только для переменки используется не транзистор, а симистор.

Чтоб отрезать кусочек полуволны, нужно ловить переход напряжения через ноль и через какое-то время подавать импульс открывающий симистор (закрывается симистор сам по себе, при переходе через ноль). Поскольку частота в сети равна 50Гц, то соответственно переход через ноль происходит каждые 10мс. Таким образом получается следующая схема работы: когда мы хотим зажечь лампочку на 80% яркости, нужно поймать переход через ноль, и подать импульс на семистор спустя две миллисекунды — семистор будет открыт в течении последующих восьми миллисекунд. Если нужно чтоб яркость была 30%, то подаём импульс через семь миллисекунд, семистор будет открыт в течении оставшихся трех миллисекунд…


30%

Ну а если хотим чтоб лампочка горела в полную силу, то подаём импульс сразу же после перехода через ноль.



Схема подключения…



U4 — это симистор. РС817 — оптопара для детектирования нуля (РС817 можно заменить на РС814, тогда не понадобится диодный мост — BR1). MOC3022 — оптопара для подачи импульса на симистор (подойдёт любая MOC302x, а вот MOC304x и MOC306x не подходят, см. спойлер). Таким образом получается полная гальваническая развязка с микроконтроллером.

MOC
У MOC304x и MOC306x есть встроенный детектор нуля, который не даёт возможности открывать симистор когда заблагорассудится, а только в момент перехода через ноль. Соответственно получается следующее: мы ловим переход, выжидаем паузу, и подаём импульс, импульс приходит, но оптопара не открывает симистор, так как ждёт перехода. В результате ничего не работает.

Не подходит:


Выше, в заметке, я писал что есть приборы, которые включаются в момент перехода через ноль, вот как раз эти или похожие оптопары там и используются. Тумблером щёлкнули, сигнал на оптопару пришёл, она дожидается перехода через ноль, и открывает симистор.


Подходит:





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

Внешнее прерывание (GPIO_EXTIx) настраиваем на любой пин, например на РА4…


Falling edge





Берём любой таймер, настраиваем какой-нибудь канал, и указываем режим One Pulse…



Предделитель настраиваем на один тик в одну микросекунду, а переполнение нужно установить такое, чтоб оно было чуть-чуть меньше 10мс, то есть так чтоб цикл работы таймера укладывался между двумя переходами через ноль. В данном случае цикл будет длиться 9мс...


Настройка предделителя предполагает, что системная частота равна 72мГц.

Обратите внимание на PWM mode 2, в этом режиме высокий уровень на выходе будет установлен после того как счётчик перевалит через значение сравнения. То есть, сейчас у нас сравнение равно 5000, это значит, что когда сработает внешнее прерывание и будет запущен таймер, он досчитает до 5000 и выдаст высокий уровень — симистор откроется. Далее таймер досчитает до 9000 и остановится. Так как симистору нужен только короткий импульс для открытия, то для нас уже не принципиально когда таймер остановится (главное чтоб это произошло до очередного прерывания). Ну а симистор, как уже говорилось выше, закроется сам, при переходе напряжения через ноль.


Теперь соедините контакт DZ (Detect Zero) со входом внешнего прерывания (РА4), а IMP с выходом канала таймера (РА6). В программу добавьте обработчик прерывания с функцией запуска таймера…

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
    HAL_TIM_PWM_Stop(&htim3, TIM_CHANNEL_1);
    HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
}


Вот и весь код , можно прошивать. Лампочка должна гореть в полнакала.

Теперь установите сравнение равное 8500, лампочка будет еле теплится, а если установить 1, то будет гореть на полную. Чтоб отключить свет, нужно указать 9001, тогда таймер вообще не будет доходить до сравнения.

Я протестировал несколько различных вариантов управления диммером, и этот показался мне наиболее удачным и весьма лаконичным — всего одно прерывание.


Чтобы менять яркость нужно изменять значение сравнения где-нибудь в цикле. Вот так она будет плавно изменяться туда-сюда…

/* USER CODE BEGIN WHILE */
  while (1)
  {
	  uint16_t compare = 0;

	  while(compare < 9000)
	  {
		  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, compare);
		  compare = compare + 10;
		  HAL_Delay(10);
	  }

	  compare = 9000;

	  while(compare > 0)
	  {
		  __HAL_TIM_SET_COMPARE(&htim3, TIM_CHANNEL_1, compare);
		  compare = compare - 10;
		  HAL_Delay(10);
	  }
  }


Что касается управления яркостью вручную, то наверное самое удобное, это использовать потенциометр подключённый к аналоговому входу. Можно сделать так: исходя из того, что диапазон значений у АЦП от 0 до 4096, тогда умножая полученное с АЦП значение на два, мы получим диапазон от 0 до 8192 (правда в этом случае не будет минимальной яркости, но тут уж сами решайте как поступить). В бесконечном цикле опрашивать АЦП, и записывать его значение в регистр сравнения первого канала.


Если диммер многоканальный, типа такого…


Один детектор нуля для нескольких каналов.

Тогда нужно просто добавить каналы таймера, и прописать их в обработчик прерывания…

void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
	HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_1);
        HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_2);
        //HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_3);
        //HAL_TIM_PWM_Start(&htim3, TIM_CHANNEL_4);
}


Если одного таймера не хватает, тогда настройте ещё один по примеру первого.



Это всё, всем спасибо. И да, будьте аккуратны, я сжёг плату пока экспериментировал. Если кому не жалко, подкиньте доната на обновку.


Телеграм-чат istarik

Телеграм-чат STM32


  • 0
  • 15778
Поддержать автора


Telegram-чат istarik

Задать вопрос по статье
Telegram-канал istarik

Известит Вас о новых публикациях






Комментарии (0)

Только зарегистрированные и авторизованные пользователи могут оставлять комментарии.