Автономный светодиодный прожектор на Arduino

В статье представлены макет и программная часть светодиодного прожектора средней сложности, основанного на сверхъярком светодиоде, питающегося от модуля светодиодного драйвера с возможностью диммирования, и управляемого платой Arduino Pro Mini на основе восьмибитного AVR микроконтроллера ATmega328P. В таблице приведены технические характеристики и функциональность получившейся рабочей модели:

Параметр
Значение
 Напряжение питания
 12 Вольт
 Потребляемая мощность
 10 Ватт
 Регулировка яркости
 Плавная по ШИМ, с задержкой
 Цветовая температура
 3500 Кельвин
 Постоянство цветовой температуры  
 Неизменна при регулировке яркости  
 Индикация низкого заряда батареи
 Ускоряющееся мигание индикатора
 Включение/выключение
 Одна кнопка с антидребезгом

Для сборки электронной части использовались следующие компоненты:

Китайский вариант отладочной платы Arduino Pro Mini:

Плата модуля светодиодного драйвера:

И собственно сам светодиод с потребляемой мощностью 10 Вт:

Питание всей конструкции осуществлялось от трёхсекционной литий-ионной батареи с рабочим напряжением 12 В:

На все эти компоненты уже имеются материалы на сайте «Паяльник» с рассмотрением основных характеристик и рекомендациями по практическому использованию этих модулей, и ссылки на них находятся в конце данной статьи. Так же для сборки конструкции понадобится несколько дискретных радиоэлементов в виде резисторов конденсаторов и кнопки без фиксации, которые имеются у каждого радиолюбителя:

 

Всё это собрано и подключено по следующей простой принципиальной схеме:

Компоненты можно менять и подбирать в некоторых пределах в зависимости от наличия того или иного модуля. Яркость свечения и потребляемая мощность будут зависеть от выбранного светодиода и используемого вместе с ним драйвера. Функциональность устройства реализована программно и, меняя параметры в исходном тексте, можно задавать требуемые характеристики.

Статья имеет познавательный характер для изучения и понимания взаимодействия отдельных компонентов устройства, а так же служит углублению в ставшую популярной платформу Arduino, на которой с помощью различных модулей можно быстро собрать то или иное устройство. В программной части будут рассмотрены аналого-цифровой преобразователь, подавление дребезга контактов кнопки и широтно импульсная модуляция. В тексте программы будут созданы отдельные функции и процедуры для вызова и передачи им значений в основном цикле.

Исходный текст программы состоит из основного файла «LED_Projector.ino» представляющего из себя стандартный текстовый файл платформы Arduino, называемый скетчем, и дополнительно подключаемых заголовочных файлов с расширением «.h» в которых описаны дополнительные параметры и вынесены вызываемые в основной программе функции. Это сделано для большего удобства при просмотре и редактировании скетча. Во время его открывания в среде разработки Arduino IDE подключаемые файлы отображаются в отдельных вкладках и не мешают сосредоточится на основном цикле или какой-либо функции:

Далее будут подробно рассмотрены схема устройства и все подключаемые файлы по порядку. Все дополнительные файлы находятся в том же каталоге, где и основной текст программы, и каждый подключается директивой «#include» в самом скетче. Первым подключён файл «Pins.h» в котором определены номера выводов отладочной платы Arduino для подключения всей внешней обвязки:

const byte buttonPin = 10; // Кнопка включения/выключения освещения
const byte PotencPin = 12; // Питание потенциометра регулятора яркости
const byte PotencInPin = A0; // Средний контакт потенциометра регулировки
const byte BatTestPin = A1; // Проверка напряжения батареи питания
const byte LowBatLedPin = 13; // Светодиод индикации низкого заряда батареи
const byte PWMLedPin = 11; // Выход управляющего ШИМ-сигнала для освещения

 

  • К выводу «10» подключена кнопка включения/выключения, срабатывания которой обрабатываются программным антидребезгом контактов и для неё может быть использован любой вывод отладочной платы, в том числе и аналоговый.
  • С вывода «12» подаётся высокий уровень во время работы устройства и он используется для питания потенциометра регулятора яркости. На его место так же может быть назначен любой другой вывод отладочной платы Arduino (далее просто Ардуино).
  • На вывод «A0» подаётся управляющий сигнал с потенциометра для регулировки яркости свечения светодиода. Это может быть любой аналоговый вход Arduino.
  • На вывод «A1» подаётся сигнал с резистивного делителя для измерения напряжения батареи питания и определения оставшегося заряда. Делитель состоит из резисторов R1 и R2 (смотрите принципиальную схему) подключённых между общим проводом и плюсом батареи питания (не +5 Вольт, а именно к батарее +12 Вольт). Этот вывод, так же как и предыдущий, должен быть аналоговым входом Arduino.
  • Вывод «13» используется для индикации низкого заряда батареи. На плате Arduino к нему уже подключён светодиод, но если вместо указанного по какой-либо причине будет использован другой вывод (можно использовать любой), то к нему придётся отдельно подключить индикаторный светодиод с ограничительным резистором.
  • И наконец вывод «11» используется как выход управляющего ШИМ-сигнала для драйвера силового светодиода. В качестве этого вывода обязательно должен быть назначен вывод Arduino с поддержкой широтно-импульсной модуляции. На платах Arduino Pro Mini, Arduino Nano и Arduino UNO это могут быть выводы 3, 5, 6, 9, 10 или 11.

Вторым по порядку в основном тексте подключается файл «Constants.h» для установки и настройки постоянных параметров:

const byte minBrightness = 22; // Значение минимальной яркости освещения
const unsigned long R_GND = 220; // Сопротивление нижнего плеча делителя (кОм)
const unsigned long R_PWR = 390; // Сопротивление верхнего плеча делителя (кОм)
const unsigned long LowBatPwr = 10500; // Напряжение низкого уровня заряда батареи (мВ)
const unsigned long EmptyBatPwr = 8500; // Напряжение полностью разряжённой батареи (мВ)
const unsigned long BatTestDelay = 10000; // Период тестирования уровня заряда батареи
const unsigned long LowBatLedOnTime = 100; // Продолжительность вспышки индикатора заряда

// Вычисление значения низкого заряда батареи:
const int LowBatValue = 1023*R_GND*LowBatPwr/(R_GND+R_PWR)/5000;
// Вычисление значения полностью разряжённой батареи:
const int EmptyBatValue = 1023*R_GND*EmptyBatPwr/(R_GND+R_PWR)/5000;

 

  • Константой «minBrightness» задаётся минимально возможная яркость свечения светодиода, которая будет при повороте ручки потенциометра в крайнее левое положение. Это значение должно быть установлено в районе от 0 до 1023 (максимальная яркость).
  • «R_GND» и «R_PWR» резисторы делителя для тестирования заряда батареи питания (смотрите поясняющую схему ниже). Их номинал может отличаться от указанного на 50%, желательно в нижнюю сторону для уменьшения погрешности. Номинал используемых резисторов делителя нужно ввести в килоомах и далее будет произведён необходимый расчёт, о котором будет сказано дальше.
  • «LowBatPwr» и «EmptyBatPwr» соответственно напряжение низкого заряда и полного разряда батареи, которые нужно вводить в милливольтах для использования компилятором в дальнейших расчётах.
  • «BatTestDelay» определяет промежуток времени, через который будет производиться замер напряжения на батарее питания. Это значение задаётся в миллисекундах и в данном случае составляет 10 секунд.
  • При снижении напряжения на батарее ниже определённого индикаторный светодиод начинает мигать с продолжительностью вспышки задаваемой константой «LowBatLedOnTime» от которой так же зависят и пределы продолжительности погасания светодиода. В данном случае установлено довольно короткое значение в 0,1 секунды.
  • Далее по указанным данным осуществляется вычисление десятибитных значений низкого заряда и полного разряда батареи питания для непосредственного использования в программе. Вычисление происходит по формуле «Value = 1023*R_GND*BatPwr/(R_GND+R_PWR)/5000» где «BatPwr» соответствующее напряжение для конкретного случая.

Под «R_GND» и «R_PWR» подразумеваются резисторы делителя соответственно нижнего плеча (подключённого к общему проводу) и верхнего плеча (подключённого к плюсу 12 Вольт батареи питания). Средняя точка делителя подключается к аналоговому входу отладочной платы:

Описанный способ расчётов в самой программе удобен и практичен — подставляя сопротивление резисторов или меняя напряжение срабатывания индикации низкого заряда можно быстро определить цифровое значение на входе микроконтроллера (а точнее значение после аналого-цифрового преобразования), но при этом расходуется довольно большой объём FLASH-памяти микроконтроллера. Потому в некотором случае данный способ неуместен, и если по какой-либо причине нет возможности его использования, то можно отдельно рассчитать значения низкого уровня заряда и полного разряда и подставить в программу уже готовые цифры. Для этого была сделана программа расчёта нужных значений в «Microsoft Excel»-е, которая выглядит следующим образом:

В Excel-е так же производится расчёт значения полного заряда батареи, которое не нужно никуда подставлять. Просто сопротивления резисторов делителя должны быть подобраны так, чтобы значение при полностью заряжённой батарее не превышало 1023. Этот файл «LED_Projector_Battery_Value_Calculator.xlsx» находится в архиве проекта и после произведения расчётов указанный выше текст подключаемого файла «Constants.h» нужно упростить и сократить приведя его до следующего вида:

const byte minBrightness = 22; // Значение минимальной яркости освещения
const unsigned long BatTestDelay = 10000; // Период тестирования уровня заряда батареи
const unsigned long LowBatLedOnTime = 100; // Продолжительность вспышки индикатора заряда

const int LowBatValue = 775; // Значение низкого заряда батареи
const int EmptyBatValue = 627; // Значение полностью разряжённой батареи

Далее в исходном тексте подключается файл «Values.h» где объявляются глобальные переменные для хранения и передачи меняющихся значений:

boolean PowerState = LOW; // Состояние освещения
boolean LastPowerState; // Последнее состояние освещения
int LedPWMValue; // Значение управляющего ШИМ-сигнала
unsigned long LowBatLedOffTime; // Продолжительность паузы индикатора заряда

 

  • Переменная «PowerState» определяет состояние активности устройства в целом, а переменная «LastPowerState» хранит последнее изменённое состояние.
  • Значением переменной «LedPWMValue» определяется яркость свечение светодиода.
  • В переменной «LowBatLedOffTime» передаётся время паузы светодиода индикатора низкого заряда батареи.

На этом установка параметров заканчивается и далее по тексту основной программы происходит подключение дополнительных файлов с функциями и процедурами. Все функции имеют комментарии для понимания назначения тех или иных элементов. Через файл «DebounceSwitch.h» подключается функция антидребезга контактов кнопки:

byte DebounceSwitch(byte buttonPin) {
const unsigned long debounceDelay = 40; // Период антидребезга кнопки
static byte buttonState; // Нынешнее состояние кнопки
static byte lastButtonState = HIGH; // Последнее состояние кнопки
static byte PowerState = LOW; // Нынешнее состояние активности
static unsigned long lastDebounceTime; // Время последнего антидребезга
// Запись состояния кнопки в локальную переменную:
byte reading = digitalRead(buttonPin);
// Если состояние изменилось из за нажатия или дребезга:
if (reading != lastButtonState) {
// сбросить таймер антидребезга
lastDebounceTime = millis();
}
if ((millis() — lastDebounceTime) > debounceDelay) {
// если состояние не менялось дольше периода антидребезга
// то значит текущее состояние равно последнему состоянию
// если текущее состояние изменилось:
if (reading != buttonState) {
buttonState = reading;
// изменить состояние активности если кнопка была нажата:
if (buttonState == LOW) {
PowerState = !PowerState;
}
}
}
// сохранить текущее состояние кнопки как последнее:
lastButtonState = reading;
return PowerState;
// Функция возвращает состояние активности
}

В функцию передаётся номер вывода, к которому подключена кнопка, сама функция же возвращает состояние активности для включения или выключения всего устройства в целом. Константой «debounceDelay» задаётся задержка в миллисекундах для исключения влияния дребезга контактов кнопки. Если срабатывания кнопки будут нестабильны то нужно будет подобрать это значение.

После функции антидребезга подключается функция «TestingBattery.h» для определения заряда аккумулятора и установки периода мигания индикатора:

unsigned long TestingBattery(byte BatTestPin, unsigned long BatTestDelay, int LowBatValue, int EmptyBatValue, unsigned long LowBatLedOnTime) {
static unsigned long LowBatLedOffTime; // переменная для хранения продолжительности паузы индикатора разряда
static unsigned long lastBatTestTime; // время последней проверки напряжения батареи
if ((millis() — lastBatTestTime) > BatTestDelay) {
// если после последней проверки прошло время более периода тестирования
int BatValue = analogRead(BatTestPin); // произвести замер напряжения
if (BatValue < LowBatValue){
// если замеренное значение ниже значения низкого заряда
BatValue = max(BatValue, EmptyBatValue);
LowBatLedOffTime = map(BatValue, EmptyBatValue, LowBatValue, LowBatLedOnTime/2, LowBatLedOnTime*20);
// рассчитать и установить продолжительность паузы индикатора разряда
} else {
// в противном случае установить продолжительность паузы равной нулю
LowBatLedOffTime = 0;
}
lastBatTestTime = millis(); // запомнить время последней проверки батареи
}
return LowBatLedOffTime;
// Функция возвращает продолжительность паузы индикатора низкого заряда
}

В функцию передаются аргументы в следующем порядке:

  • Номер вывода Arduino, подсоединённый к делителю, для проверки заряда батареи;
  • Период тестирования батареи питания в миллисекундах;
  • Десятибитное значение уровня низкого заряда батареи;
  • Десятибитное значение уровня полностью разряжённой батареи;
  • Заданная продолжительность вспышки индикатора низкого заряда в миллисекундах, пропорционально которой вычисляется продолжительность паузы.

Функция производит замер напряжения батареи питания с периодом в «BatTestDelay», и если оно опустилось ниже заданного уровня низкого заряда, то происходит вычисление продолжительности паузы индикатора, прямо пропорционально времени вспышки и уровню заряда батареи. В противном случае время паузы устанавливается в «0».

Далее по тексту основной программы подключается дополнительный файл «LedBlink.h» с непосредственно процедурой мигания индикатора низкого заряда:

void LedBlink(byte LedPin, unsigned long OnTime, unsigned long OffTime) {
static byte LedPwrState; // состояние светодиода
static byte LastLedPwrState; // последнее состояние светодиода
static unsigned long LastOnTime; // время последнего включения
static unsigned long LastOffTime; // время последнего выключения
// если время паузы не равно нулю и светодиод не светится:
if (OffTime != 0 && LedPwrState != HIGH) {
// и если после времени последнего гашения прошло
// время большее продолжительности паузы
if ((millis() — LastOffTime) > OffTime) {
LedPwrState = HIGH; // зажечь светодиод
LastOnTime = millis(); // запомнить время зажигания
}
}
// если время паузы не равно половине времени свечения и светодиод не погашен
if (OffTime != OnTime/2 && LedPwrState != LOW) {
// и если после времени последнего зажигания прошло
// время большее продолжительности свечения
if ((millis() — LastOnTime) > OnTime) {
LedPwrState = LOW; // погасить светодиод
LastOffTime = millis(); // запомнить время гашения
}
}
// если состояние светодиода изменилось
if (LastLedPwrState != LedPwrState) {
// записать состояние светодиода в порт:
digitalWrite (LedPin, LedPwrState);
// запомнить последнее состояние светодиода:
LastLedPwrState = LedPwrState;
}
}

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

И наконец через дополнительный файл «SetBrightness.h» подключается процедура установки яркости освещения:

void SetBrightness(byte PWMLedPin, byte Brightness) {
static byte LedPWMValue; // переменная для хранения текущей яркости
// пока установленная яркость не равна требуемой будет выполнятся цикл:
while (LedPWMValue != Brightness) {
// если яркость меньше требуемой:
if (LedPWMValue < Brightness) {
LedPWMValue += 1; // значение яркости увеличивается на единицу
}
// если яркость больше требуемой:
if (LedPWMValue > Brightness) {
LedPWMValue -= 1; // значение яркости уменьшается на единицу
}
analogWrite(PWMLedPin, LedPWMValue); // запись значения яркости в порт
delay(4); // время задержки до следующего шага
}
}

В процедуру нужно передать номер вывода с поддержкой ШИМ для управления освещением, и необходимый уровень яркости в восьмибитном значении. На указанном выводе постепенно будет установлено переданное значение яркости, с задержкой между шагами в 4 миллисекунды.

После подключения всех дополнительных файлов следует процедура настройки Arduino, где происходит конфигурация всех необходимых выводов как входов или выходов и установка начальных значений на них:

void setup() {
// настройка buttonPin как вход с подтягивающим резистором:
pinMode(buttonPin, INPUT_PULLUP);
// настройка PotencPin как выход:
pinMode(PotencPin, OUTPUT);
// настройка LowBatLedPin как выход:
pinMode(LowBatLedPin, OUTPUT);
// запись значения яркости в порт:
analogWrite(PWMLedPin, 0);
}

В завершение следует основной цикл, в котором, периодически друг за другом, происходит вызов всех ранее подключённых и объявленных функций и процедур:

void loop() {
// ***************************************************************
// Определяем состояние активности вызовом функции антидребезга:
PowerState = DebounceSwitch(buttonPin);
// ****************************************************
// если состояние активности изменилось:
if (LastPowerState != PowerState) {
// то перезаписать состояние в PotencPin:
digitalWrite(PotencPin, PowerState);
// запомнить последнее активное состояние:
LastPowerState = PowerState;
}
// ****************************************************
// если состояние активно и освещение включено:
if (PowerState == HIGH) {
// считать уровень значения регулятора яркости:
LedPWMValue = analogRead(PotencInPin);
// привести десятибитное значение к восьмибитному с учётом минимальной яркости:
LedPWMValue = map(LedPWMValue, 0, 1023, minBrightness, 255);
// Вызов функции измерения напряжения батареи питания:
LowBatLedOffTime = TestingBattery(BatTestPin, BatTestDelay, LowBatValue, EmptyBatValue, LowBatLedOnTime);
} else {
// если же состояние не активно установить значение яркости и время паузы индикатора в ноль:
LedPWMValue = 0;
LowBatLedOffTime = 0;
}
// *******************************************************************************
// Вызов процедуры индикации низкого уровня заряда батареи:
LedBlink(LowBatLedPin, LowBatLedOnTime, LowBatLedOffTime);
// *******************************************************************************
// Вызов процедуры установки требуемой яркости освещения:
SetBrightness(PWMLedPin, LedPWMValue);
}

Весь текст программы со всеми подключаемыми дополнительными файлами можно скачать и посмотреть в архиве проекта по ссылке LED_Projector.rar . Там же есть принципиальная схема подключения и ранее упомянутый калькулятор цифровых значений уровня заряда батареи питания.

Исходный текст программы успешно компилируется и его можно загружать в микроконтроллер:

Загрузка программы в микроконтроллер так же завершается успешно и можно проверить работу конструкции:

Для проверки всё нужно собрать согласно принципиальной схеме и выполнить все необходимые соединения:

Светодиод перевёрнут и направлен лицевой стороной вниз, для того, что бы после включения не засветить снимок и не испортить фотографию:

После подачи питания светодиод ярко вспыхивает и гаснет. Происходит это потому, что используемый светодиодный драйвер диммируется низким уровнем на управляющем входе, и пока микроконтроллер загрузится, здесь присутствует высокий уровень (смотрите предыдущую статью с описанием данного драйвера) и светодиод кратковременно зажигается на полную яркость. Индикаторный светодиод же Arduino продолжает светиться указывая на наличие питающего напряжения:

Для активации устройства и включения освещения следует нажать на кнопку, которая при выключенном состоянии производит активацию, а при включённом наоборот, деактивацию устройства:

При этом происходит плавное зажигание силового светодиода до установленной яркости и периодический замер напряжения батареи питания. Внимательный читатель наверное заметил отсутствие на макете делителя для замера уровня заряда. Демонстрация работы индикатора низкого заряда будет представлена немного позже, ну а при отсутствии напряжения на измерительном входе индикатор будет светиться постоянно, указывая что напряжение батареи опустилось ниже критичного. Зажигание индикатора не произойдёт, пока не истечёт заданное время периода тестирования:

После истечения периода тестирования, сразу же при первом замере напряжения на входном выводе тестирования заряда, произойдёт зажигание индикатора, сигнализирующего полный разряд батареи питания:

Как уже говорилось, такое поведение будет наблюдаться при полном разряде батареи питания или при отсутствии напряжения на измерительном входе, например при обрыве или плохом контакте. Если же напряжение батареи выше критичного, но не превышает номинальное, то индикаторный светодиод мигает с частотой, зависящей от уровня заряда — чем ближе разряд батареи к критичному, тем выше частота мигания, а точнее — короче время паузы индикатора, а время вспышки остаётся постоянным:

При вращении ручки регулятора плавно изменяется яркость свечения силового светодиода от заданной минимальной, до максимально возможной:

Это происходит с некоторой задержкой, потому что данная конструкция разрабатывалась для использования совместно с видеокамерой, и что бы во время процесса съёмок не была заметна регулировка яркости и изменение освещённости. Так же само изменение яркости свечения светодиода производится с использованием ШИМ-диммирования, что бы не менялась цветовая температура (что негативно сказалось бы на отснятом видеоматериале). Мерцание светодиода на камеру не заметно, хотя при появлении полос на изображении можно установить дополнительный конденсатор параллельно выходу светодиодного драйвера.

Описанная модель конструкции довольно долго разрабатывалась и тестировалась. Параметры и технические характеристики тщательно подгонялись под требуемые. Устройство вполне можно использовать по назначению, а именно для освещения снимаемых объектов и сцен. В конце статьи можно посмотреть видео работы устройства. В дальнейшем планируется доработать конструкцию и довести её до товарного вида. Отладочная плата будет заменена на дискретный микроконтроллер, в котором будет использоваться режим сна для минимизации энергопотребления и возможности на долгое время оставлять подключённой батарею питания. В силовом драйвере светодиода так же будет использовано диммирование по питанию, и следовательно его обесточивание во время неактивного состояния устройства в целом. Программный функционал тоже немного изменится для большего удобства в использовании. Просьба к читателю оставить свои рекомендации и пожелания в виде комментариев. И кому интересно увидеть переработанную конструкцию обязательно оцените статью и подпишитесь на неё.

Ссылки на связанные статьи:


Список радиоэлементовОбозначение
Тип
Номинал
Количество
ПримечаниеМагазинМой блокнот

Отладочная платаArduino Pro Mini1
На базе ATmega328P
LED драйверLM3406HV1
Ток стабилизации 1 АLED1
Светодиод10W1
С напряжением 10 В
Батарея питания12 V1
S1
КнопкаБез фиксации1
C1
Электролитический конденсатор470uF 16V1
P1
Переменный резистор100 кОм1
R1
Резистор220 кОм1
R2
Резистор390 кОм1
Добавить все

Скачать список элементов (PDF)

Прикрепленные файлы:

Добавить комментарий

Ваш адрес email не будет опубликован.