Вопрос про RGB-светодиоды.
Думаю, многие знают о лестничном освещении, которое включается двумя ИК-датчиками (1 наверху и 1 внизу).
Вот мой код, который хорошо работает. Это не очищено - так как я не знаю, как я могу упростить это. Я думаю, что будет гораздо более приятный способ получить тот же результат. :)
#include "FastLED.h"
#define NUM_LEDS 300
CRGB leds[NUM_LEDS];
#define PIN 3
int sensorUP = 5;
int sensorDOWN = 7;
int state = LOW;
int valUP = 0;
int valDOWN = 0;
void setup()
{
FastLED.addLeds<WS2811, PIN, GRB>(leds, NUM_LEDS).setCorrection( TypicalLEDStrip );
FastLED.setBrightness(20);
pinMode(2, INPUT_PULLUP); // внутренний подтягивающий резистор
pinMode(sensorUP, INPUT);
pinMode(sensorDOWN, INPUT);
Serial.begin(9600);
}
void loop() {
valUP = digitalRead(sensorUP);
valDOWN = digitalRead(sensorDOWN);
if (valUP == HIGH) {
colorWipeUP(0x55, 0xFF, 0x00, 2);
delay(600);
colorWipeUP(0x00, 0x00, 0x00, 2);
delay(100);
}
if (valDOWN == HIGH) {
colorWipeDOWN(0x55, 0xFF, 0x00, 2);
delay(6000);
colorWipeDOWN(0x00, 0x00, 0x00, 2);
delay(100);
}
}
void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
for (uint16_t i = 0; i < NUM_LEDS; i++) {
setPixel(i, red, green, blue);
FastLED.show();
delay(SpeedDelay);
}
}
void colorWipeDOWN(byte red, byte green, byte blue, int SpeedDelay) {
for (uint16_t i = 299; i < NUM_LEDS; i--) {
setPixel(i, red, green, blue);
FastLED.show();
delay(SpeedDelay);
}
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
}
void setAll(byte red, byte green, byte blue) {
for (int i = 0; i < NUM_LEDS; i++ ) {
setPixel(i, red, green, blue);
}
FastLED.show();
}
В данный момент светодиоды просто загораются и после задержки снова гаснут (один за другим).
ВОПРОС: Я хочу добиться более плавного эффекта, включив и выключив их. Итак, я достиг фактического результата, используя разные фрагменты и пытаясь понять. Чего я не понимаю, так это того, как добавить затухание.
@Axel Kummerlöwe, 👍1
Обсуждение2 ответа
Лучший ответ:
Ваш код сейчас написан как блокирующий, поэтому мы можем оставить его таким и добавить еще один блокирующий вложенный цикл. Возьмем в качестве примера функцию colorWipeUP()
:
void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
for (uint16_t i = 0; i < NUM_LEDS; i++) {
setPixel(i, red, green, blue);
FastLED.show();
delay(SpeedDelay);
}
}
Вы проходите по всем светодиодам, зажигая их один за другим заданным цветом с задержкой между светодиодами. Яркость светодиода регулируется общим значением RGB. Если вы просто умножаете компоненты RGB, красный, зеленый и синий, на число от 0 до 1, вы (в основном) сохраняете цвет и управляете только яркостью. Например так:
void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
for (uint16_t i = 0; i < NUM_LEDS; i++) {
for(uint8_t brightness = 0; brightness <= 100; brightness++){
setPixel(i, red*brightness/100, green*brightness/100, blue*brightness/100);
FastLED.show();
delay(fadeDelay);
}
delay(SpeedDelay);
}
}
Для каждого светодиода теперь мы переходим от нулевой яркости к 100% яркости в цикле, показывая каждый отдельный шаг на светодиодной ленте. fadeDelay
определяет, насколько быстрым должно быть это постепенное появление. Вам придется настроить обе задержки, чтобы они соответствовали вашим ожиданиям. Вы можете использовать тот же принцип для очистки.
Вы можете спросить себя, почему я считаю от 0 до 100, а затем делю на 100 вместо прямого счета от 0 до 1 с шагом 0,01. Я сделал это, потому что на микроконтроллерах на основе AVR у вас нет встроенных вычислений с плавающей запятой. Это означает, что каждое вычисление с плавающей запятой требует выполнения множества инструкций (поскольку математика с плавающей запятой реализована программно, а не аппаратно). Здесь я считаю целыми числами и при расчете яркости тоже задействована только целочисленная математика (деление на 100 - это целочисленное деление, которое автоматически отрежет все цифры после запятой. Нам они не нужны).
Примечание. При наличии 300 светодиодов вызов FastLED.show()
займет некоторое время. Я не тестировал код, но в зависимости от ваших потребностей затухание может быть слишком медленным, даже если вы удалите вызов задержки. Затем вы можете просто увеличить приращение цикла for, например, чтобы использовать 10 шагов вместо 100:
for(uint8_t brightness=0; brightness<100; brightness+=10)
что-то вроде затухания 10 светодиодов
Для этого я бы использовал совершенно другой подход. Если посмотреть математически, яркость каждого светодиода зависит от положения и времени. Таким образом, мы можем реализовать функцию, очень похожую на математическую функцию, которая возвращает яркость для заданного положения и заданного времени. Как я понял, вам нужна функция a, которая сначала постоянно равна нулю, затем линейно растет со временем и положением, а затем постоянно полная яркость. Мы можем считать время с момента срабатывания датчика, затем начинаем с нулевой яркости и позволяем ей расти линейно. Что-то вроде этого:
int fadeBrightness(int position, unsigned long time){
int brightness = m_p*position+m_t*time;
if(brightness > 100) return 100;
if(brightness < 0) return 0;
return brightness;
}
m_p
и m_t
— это константы, которые необходимо определить и настроить. Для затухания более 10 светодиодов m_p
должно быть -10
. время
указывается в миллисекундах. В настоящее время я не уверен в значении m_t
, но вы можете просто попробовать несколько значений и использовать подходящее.
Затем в функции colorWipeUP()
вы можете перебрать все светодиоды и установить их пиксели, как в коде выше, но на этот раз вы используете только что созданную функцию.
void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
unsigned long timestamp = millis();
while(millis()-timestamp < duration){
for (uint16_t i = 0; i < NUM_LEDS; i++) {
setPixel(i, red*fadeBrightness(i, millis()-timestamp)/100, green*fadeBrightness(i, millis()-timestamp)/100, blue*fadeBrightness(i, millis()-timestamp)/100);
}
FastLED.show();
}
}
Вам необходимо определить duration
в соответствии с тем, как долго будет происходить затухание с вашим m_t
. Если вы установите его дольше, цикл будет продолжаться дольше, удерживая яркость на уровне 100%.
В функции мы сначала создаем метку времени из функции millis()
. Затем зацикливаемся, пока длительность эффекта не прошла. В каждой итерации цикла while мы устанавливаем цветовые компоненты каждого светодиодного пикселя с яркостью в соответствии с нашей функцией fadeBrightness()
. Затем показываем это на светодиодной ленте. Функция постоянно обновляет полосу на максимальной скорости. Фактическая скорость анимации определяется функцией fadeBrightness()
.
Эта версия также блокирует код, но ее можно легко преобразовать в неблокирующий код, который вы будете вызывать неоднократно, пока анимация не будет завершена.
Привет, Крисл, большое спасибо за это подробное объяснение. Пытаясь что-то из этого выжать, я начал бороться с «fadeDelay», и похоже, что светодиоды будут выключаться один за другим, но на этот раз с небольшим затуханием. :) То, что я пытаюсь сделать, это что-то вроде затухания более 10 светодиодов. Не знаю, как объяснить это лучше, но я нашел видео, которое объяснит это, возможно, лучше. [ссылка] https://www.tweaking4all.com/wp-content/uploads/2015/11/LEDEffect-Fire.mp4?_=1 [ссылка], @Axel Kummerlöwe
@AxelKummerlöwe Я добавил это в свой ответ, сохранив старый ответ без изменений, так как это может быть кому-то полезно., @chrisl
Эй, Крисл, большое спасибо за ваш отзыв - ЕЩЕ РАЗ! :) Поскольку я становлюсь отцом сегодня, может быть, завтра - я вернусь к этому посту как можно скорее. Но я думаю, что смогу работать с вашей помощью. Еще раз спасибо и счастливого нового года <3, @Axel Kummerlöwe
Вы можете сделать что-то вроде этого. (не проверено)
void colorWipeUP(byte red, byte green, byte blue, int SpeedDelay) {
for (int i = -5; i < NUM_LEDS + 5; i++) {
setPixel(i , red, green, blue); // только пример
setPixel(i + 1, .8 * red, green, blue); // также меняем зеленый и синий
setPixel(i + 2, .6 * red, green, blue);
setPixel(i + 3, .4 * red, green, blue); // последующие пиксели имеют меньшую яркость
setPixel(i + 4, .2 * red, green, blue);
FastLED.show();
delay(SpeedDelay);
}
}
void setPixel(int Pixel, byte red, byte green, byte blue) {
if (Pixel < 0 || Pixel >= NUM_LEDS) return; // не задавать цвет несуществующих пикселей
leds[Pixel].r = red;
leds[Pixel].g = green;
leds[Pixel].b = blue;
}
- avrdude ser_open() can't set com-state
- Загрузка Arduino Nano дает ошибку: avrdude: stk500_recv(): programmer is not responding
- Какое максимальное энергопотребление Arduino Nano 3.0?
- Как навсегда изменить скорость передачи данных ESP8266 (12e)?
- Питание светодиодной ленты - Сколько ампер?
- Arduino nano как клавиатура HID
- Как я могу запитать Arduino Nano от батареи LiPo, желательно 3,7 В
- В чем разница между библиотеками Software Serial? Какая из них совместима с Arduino Nano?
поищите
analogWrite
и широтно-импульсную модуляцию или ШИМ, чтобы узнать, как затухать светодиоды., @MichaelT