ПЛАВНОЕ УПРАВЛЕНИЕ РЕЛЕ С ARDUINO

Иногда требуется управлять мощностью инерционной нагрузки (ИК станция, сетевой обогреватель в комнате/инкубаторе, паяльник), и для этого совсем не хочется использовать высокочастотный ШИМ. В случае питания от сети – делать диммер тоже не очень целесообразно, потому что инерционной нагрузкой можно управлять при помощи низкочастотного ШИМ и обычного твердотельного реле, без создания сложных схем и лишнего усложнения кода проекта детектором нуля. Если опустить частоту ШИМ до 1 Гц, никакого писка мы не услышим (писк слышно в диапазоне 500 Гц – 14 кГц), но нагрузка будет замечательно управляться, особенно если это большой нагревательный элемент. Решил я сделать простенькую библиотеку для генерации программного сверхнизкочастотного ШИМ сигнала.

Сам алгоритм очень прост: обычный таймер на миллис с переменным периодом.

if (millis() - _tmr >= (_flag ? _activePeriod : (_period - _activePeriod))) {
  _tmr = millis();
  _flag = !_flag;
  digitalWrite(_pin, _flag ^ _dir);
}

В этом алгоритме:

  • _flag – флаг состояния, bool
  • _tmr – переменная времени, uint32_t
  • _dir – направление, bool
  • _pin – пин реле, byte
  • _period – общий период реле, int
  • _activePeriod – активный период (длительность импульса), int. Определяется как _period, умноженный на скважность (число от 0.0 до 1.0, соответствует 0-100%)

БИБЛИОТЕКА PWMRELAY

  • Встроенный таймер на millis()
    • Для работы системы нужно просто почаще вызывать tick()
  • Установка параметров ШИМ:
    • Настройка периода (обратно частоте)
    • Настройка длины импульса (скважности) в диапазоне 0-255
    • Настройка уровня реле

Поддерживаемые платформы: все Arduino (используются стандартные Wiring-функции)

ДОКУМЕНТАЦИЯ


Создание объекта


Объект регулятора можно создать тремя способами:

  • PWMrelay имя(пин); – создать с указанием пина реле (цифра номер пина)
  • PWMrelay имя(пин, уровень); – создать с указанием пина и уровня (уровень HIGH и LOW)
  • PWMrelay имя(пин, уровень, период); – создать с указанием пина, уровня и периода ШИМ (в миллисекундах)

Настройка параметров


Параметры ШИМ можно настроить по ходу работы в любое время:

  • setPWM(byte duty); – установка заполнения шим, 0-255 (соответствует 0-100%)
  • setPeriod(int period); – установка периода ШИМ в миллисекундах. 1000 соответствует 1 Гц и так далее
  • setLevel(bool level); – установка уровня реле, HIGH и LOW

Тик


Метод tick(); осуществляет все расчёты времени по встроенному таймеру и сам включает/выключает реле, достаточно просто вызывать его в основном цикле loop. Если в лупе у вас замкнутые места или задержки, tick() можно поместить в прерывание таймера. Период прерываний нет смысла ставить чаще, чем период ШИМ-реле, делённый на 255.

PWMrelay(byte pin, bool dir, int period);    // пин, уровень реле HIGH/LOW, период
void tick();                                 // тик, вызывать как можно чаще, сам управляет реле
void setPWM(byte duty);                      // установить величину ШИМ, 0-255. При значении 0 и 255 тик неактивен!
byte getPWM();                               // возвращает величину ШИМ
void setPeriod(int period);                  // установить период ШИМ в миллисек. (по умолч. 1000мс == 1с)
int getPeriod();                             // получить период
void setLevel(bool level);                   // установить установить уровень реле (HIGH/LOW)

ПРИМЕРЫ


#include "PWMrelay.h"
PWMrelay relay(13); // реле на 13 пине

// или так
// PWMrelay relay(13, HIGH); // реле высокого уровня на 13 пине
// PWMrelay relay(13, HIGH, 2000); // реле высокого уровня на 13 пине, период 2 секунды

void setup() {
  Serial.begin(9600);
  
  relay.setLevel(HIGH);   // можно поменять уровень реле (HIGH/LOW)
  
  relay.setPeriod(1000);  // можно поменять период, миллисекунды

  relay.setPWM(20);       // задаём сигнал ШИМ 0-255
}

void loop() {
  // вызываем в лупе, данная функция сама управляет реле
  relay.tick();   
}
#include "PWMrelay.h"
PWMrelay heater1(4);
PWMrelay heater2(5);

void setup() {
  heater1.setPWM(20);       // задаём сигнал ШИМ 0-255
  heater2.setPWM(120);       // задаём сигнал ШИМ 0-255
}

void loop() {
  heater1.tick();
  heater2.tick();
}