Предисловие Летом прошлого года я заинтересовался созданием декоративной монохромной светодиодной системы освещения для ремонтируемой квартиры и встал вопрос, на каком основании ее собирать.
Я бы хотел, чтобы было возможно:
- Управляйте режимами подсветки (скоростью затухания, яркостью) удаленно, с телефона Android через Bluetooth или с пульта от бытовой техники через ИК-порт.
- Возможность легкого перепрограммирования режимов работы на самом устройстве.
- Стоимость - чем меньше, тем лучше
- Доступность компонентов
На eBay можно купить комплекты из светодиодной ленты 5 м + контроллер + ИК-пульт за $17, но этот вариант не подошел из-за необходимости направить пульт на приемник контроллера, который планируется спрятать за мебелью.
плинтус.
Идея не блистала оригинальностью, просто хотелось создать что-то удобное, долговечное и понятное в управлении всем жильцам дома.
Идея
Светодиоды, расположенные вдоль стен, расположены в отверстиях, просверленных в ламинате/паркете, на небольшом расстоянии от стены (на хабе уже было пару постов о подобном расположении светодиодов).При включении происходит плавное изменение яркости отдельных светодиодов с одновременным перемещением самого яркого из них вдоль стены — аналогично посадочным огням на взлетно-посадочной полосе.
Что вы хотели реализовать в системе освещения?
- Изменение скорости и яркости свечения, вплоть до полного отключения.
- Режим постоянной яркости
- Режим Fade без бега
Реализация — Ардуино
Для управления я выбрал телефон Android и Bluetooth, как самый простой способ, не привязанный к системе команд конкретного пульта, не подверженный проблемам передачи команд через препятствия, такие как стены, мебель, кошки.За основу была взята одна из многочисленных схем бегущего огня с затуханием, найденных на просторах бесконечности.
Максимальное количество светодиодов — 6, в зависимости от количества ШИМ-выходов выбранного Arduino. Что нужно было доделать: возможность подключения bluetooth-модуля для приема команд управления и отправки данных о текущем состоянии на телефон для отображения.
Я с этим успешно справился, в результате получился скетч для Arduino: Код эскиза
В зависимости от полученной команды контроллер либо меняет скорость, либо яркость светодиодов.#include <SoftwareSerial.h> enum LedState { LED_ON, LED_OFF }; boolean isFadeMode = false; #define LED_CNT 6 int ledPins[LED_CNT] = {11, 10, 9, 6, 5, 3}; // pwm pins int ledBrightnessesWave[LED_CNT] = {0, 50, 100, 150, 205, 255}; // represents initial brightness for wave mode int ledStepsWave[LED_CNT] = {-5, 5, 5, 5, 5, 5}; // represents initial change for wave mode int ledBrightnesses[LED_CNT]; // represents brightness for pin int ledSteps[LED_CNT]; // represents change, each pin gets its own change so it wont interfere with any other pin int ledSpeed = 50; int maxLedBrightness = 255; int ledBrightnessesConst = 255; // represents brightness for pins in no wave or fade mode LedState led_state; #define rxPin 2 #define txPin 4 #define SPEED_PREFIX 'G' #define SPEED_PREFIX_MAX 'P' #define BRIGHTNESS_PREFIX 'Q' #define BRIGHTNESS_PREFIX_MAX 'Z' #define MIN_SPEED_DELAY 5 #define MAX_SPEED_DELAY 100 #define MIN_BRIGHTNESS 5 #define MAX_BRIGHTNESS 255 // set up a new serial port SoftwareSerial mySerial = SoftwareSerial(rxPin, txPin); void setup() { for (int i = 0; i < LED_CNT; i++) { pinMode(ledPins[i], OUTPUT); //set pwm pins to output //copy initial values ledBrightnesses[i] = ledBrightnessesWave[i]; ledSteps[i] = ledStepsWave[i]; } led_state = LED_ON; Serial.begin(9600); pinMode(rxPin, INPUT); pinMode(txPin, OUTPUT); mySerial.begin(115200); } int getBrightness(int b) { return b; } int valueToDelay(int value) { return MIN_SPEED_DELAY + (MAX_SPEED_DELAY - MIN_SPEED_DELAY) * value / (SPEED_PREFIX_MAX - SPEED_PREFIX); } int valueToBrightness(int value) { return MIN_BRIGHTNESS + (MAX_BRIGHTNESS - MIN_BRIGHTNESS) * value / (BRIGHTNESS_PREFIX_MAX - BRIGHTNESS_PREFIX); } void recalculateBrightness(int brValue) { ledBrightnessesConst = valueToBrightness(brValue); } void ledFade() { if (led_state == LED_OFF) { for (int i = 0; i < LED_CNT; i++) { analogWrite(ledPins[i], ledBrightnessesConst); // update all pins } return; } String s = "###"; for (int i = 0; i < LED_CNT; i++) { analogWrite(ledPins[i], getBrightness(ledBrightnesses[i])); int newBr = ledBrightnesses[i] + ledSteps[i]; if (newBr <= 0 || newBr >= maxLedBrightness) { ledSteps[i] =- ledSteps[i]; //change direction if exceeds max/min value } else { ledBrightnesses[i] = newBr; } s.concat(ledBrightnesses[i]); if (i < LED_CNT - 1) //skip separator for last entity s.concat("-"); } s.concat("***"); char charBuf[1000]; s.toCharArray(charBuf, 1000); mySerial.write(charBuf); mySerial.flush(); delay(ledSpeed); } void loop() { if (mySerial.available()) { char command = mySerial.read(); Serial.println("command is -> " + command); boolean handled = false; boolean changeFadeMode = false; switch (command) { case 'a': led_state = LED_OFF; handled = true; break; case 'b': led_state = LED_ON; ledSpeed = 50; handled = true; //do these lines to set wave mode changeFadeMode = true; isFadeMode = true; break; case 'c': led_state = LED_ON; ledSpeed = 30; handled = true; //do these lines to set wave mode changeFadeMode = true; isFadeMode = true; break; case 'd': led_state = LED_ON; ledSpeed = 10; handled = true; //do these lines to set wave mode changeFadeMode = true; isFadeMode = true; break; case 'e': led_state = LED_ON; changeFadeMode = true; handled = true; break; default: break; } if (changeFadeMode) { if (isFadeMode) { Serial.println("Set fade mode off"); for (int i = 0; i < LED_CNT; i++) { //copy initial values ledBrightnesses[i] = ledBrightnessesWave[i]; ledSteps[i] = ledStepsWave[i]; } } else { Serial.println("Set fade mode on"); for (int i = 0; i < LED_CNT; i++) { ledBrightnesses[i] = 0; ledSteps[i] = 5; } } isFadeMode = !isFadeMode; } else { //do nothing } if (!handled) { boolean isSpeedCommand = command >= SPEED_PREFIX && command <= SPEED_PREFIX_MAX; boolean isBrCommand = command >= BRIGHTNESS_PREFIX && command <= BRIGHTNESS_PREFIX_MAX; if (isSpeedCommand) { led_state = LED_ON; int speedValue = command - SPEED_PREFIX; //from 0 to 9 ledSpeed = valueToDelay(speedValue); } if (isBrCommand) { led_state = LED_OFF; int brValue = command - BRIGHTNESS_PREFIX; //from 0 to 9 recalculateBrightness(brValue); } } } ledFade(); }
Также можно запрограммировать любые произвольные действия по полученной команде — в примере я отключаю подсветку и меняю скорость.
В каждом цикле контроллер отправляет на сопряженное устройство строку вида ###0-50-100-150-200-250***, где цифры — значения яркости шести светодиодов, максимум 255. .
Схема:
Проблемы
С чем столкнулся: невозможностью принимать с телефона многосимвольные команды.Например, при отправке команды s150 (идея была поставить скорость 150 попугаев максимум 255) я получил на Ардуино вместо передаваемой строки полную ерунду типа s###, где были любые символы ASCII используется вместо острого.
Это может быть связано с использованием класса SoftwareSerial для подключения Bluetooth. Курение Гугла показало, что я не единственный счастливчик с этой проблемой, но нет единственного решения, кроме смены режимов модуля HC-05. Заморачиваться с АТ-командами мне не хотелось, поэтому я решил использовать только односимвольные команды из определенных диапазонов, тем более что для поставленной задачи этого было вполне достаточно.
Например - для скорости есть 10 значений и команды от G до P, для яркости - диапазон от Q до Z соответственно.
Реализация - Android
Для телефона было написано приложение, с возможностью указания передаваемых команд без переписывания и компиляции кода - для универсальности.Скриншоты приложения:
|
|
|
// Get a BluetoothSocket to connect with the given BluetoothDevice
try
{
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
}
catch (IOException e) { }
Вместо этого мне пришлось задуматься и извлечь приватный метод:
try
{
Class class1 = device.getClass();
Class aclass[] = new Class[1];
aclass[0] = Integer.TYPE;
Method method = class1.getMethod("createRfcommSocket", aclass);
Object aobj[] = new Object[1];
aobj[0] = Integer.valueOf(1);
tmp = (BluetoothSocket)method.invoke(device, aobj);
}
Что вызывает эту проблему, неизвестно, но она есть у многих людей.
Еще одна проблема возникла при разборе строки, полученной от микроконтроллера.
Вместо строк типа ###0-50-100-150-200-250***###0-50-100-150-200-250***.
иногда получались строки с неверным количеством элементы, неправильные разделители или маркеры начала/конца последовательности.
Я решил проблему, написав анализатор полученной строки и отбрасывая неверные последовательности.
После этого было легко реализовать представление, отображающее текущее состояние светодиодов.
Полученные результаты
Рабочее приложение для телефона и скетч для Ардуино, рабочая схема на макетке.Видео пример работы схемы: Что дальше:
- Собственно финальная пайка схемы и разводка всех светодиодных проводов по комнате.
- Подключение модулей громкости-присутствия для включения/выключения системы в зависимости от присутствия человека в помещении
- Подключение модуля часов - почему подсветка днем?
Поэтому, если вам нужен больший ток — используйте, например, транзистор BC557 — вы получите до 100 мА.
Если нужно еще больше, можно использовать любой драйвер, например ULN2803APG — там уже будет до полампера на канал.
Теги: #arduino #Android #Bluetooth #домашнее декоративное освещение #Разработка Android
-
Интел И Гигабайт. Встреча На 10 Дюймах
19 Oct, 24 -
Майкрософт. Яблоко. Лояльность Клиентов
19 Oct, 24 -
Щелчок В Суставе
19 Oct, 24