Аналоговая RGB-полоска с эффектом затухания и NodeMCU
У меня есть аналоговая или немая RGB-лента, которой я управляю с помощью HTTP-команд. Я хочу иметь возможность заставить ленту плавно переходить от одного цвета к другому при вызове http://XX.XXXXX/fade
. Я хочу, чтобы это происходило бесконечно, пока не будет установлен другой цвет или она не включится или не выключится. Я пробовал сделать это с помощью цикла while, но больше не могу изменить состояние света с плавного затухания. Кто-нибудь знает, как это сделать? Я приведу ссылку на свой код ниже.
//NodeMCU RGB-Controller for Homebridge & HomeKit (Siri)
#include <ESP8266WiFi.h>
#include <DNSServer.h>
#include <ESP8266WebServer.h>
#define redPin 13 //D7 - Red channel
#define grnPin 12 //D6 - Green channel
#define bluPin 14 //D5 - Blue channel
#define max(a,b) ((a)>(b)?(a):(b))
WiFiServer server(80); //Set server port
String readString; //String to hold incoming request
String hexString = "FFFFFF"; //Define inititial color here (hex value), 080100 would be a calm warmtone i.e.
int state;
bool fading;
int r;
int g;
int b;
float R;
float G;
float B;
int x;
int V;
///// WiFi SETTINGS - Replace with your values /////////////////
const char* ssid = "SSID";
const char* password = "PASSWORD";
IPAddress ip(XX,X,X,XXX); // set a fixed IP for the NodeMCU
IPAddress gateway(XX.X.X.X); // Your router IP
IPAddress subnet(XXX.XXX.XXX.X); // Subnet mask
////////////////////////////////////////////////////////////////////
void WiFiStart() {
Serial.print("Connecting to ");
Serial.println(ssid);
WiFi.begin(ssid, password);
WiFi.config(ip, gateway, subnet); //Set a fixed IP. You can comment this out and set it in your router instead.
while (WiFi.status() != WL_CONNECTED) {
delay(100);
Serial.print("_");
}
Serial.println();
Serial.println("Done");
Serial.print("IP address: ");
Serial.println(WiFi.localIP());
Serial.println("");
server.begin();
}
void allOff() {
state = 0;
for (float fade = 1.0; fade >= 0.0; fade -= 0.01) {
analogWrite(redPin, map((r * fade), 0, 255, 0, 1023));
analogWrite(grnPin, map((g * fade), 0, 255, 0, 1023));
analogWrite(bluPin, map((b * fade), 0, 255, 0, 1023));
delay(2);
}
// Set r/g/b to 0 so fade in is possible
r = 0;
b = 0;
g = 0;
}
//Write requested hex-color to the pins
void setHex() {
const float STEPS = 100; // Change number of steps while fading (lower is faster)
// Save old values of r/g/b
byte oldR = r;
byte oldG = g;
byte oldB = b;
long number = (long) strtol( &hexString[0], NULL, 16);
r = number >> 16;
g = number >> 8 & 0xFF;
b = number & 0xFF;
float deltaR = (r - oldR) / STEPS;
float deltaG = (g - oldG) / STEPS;
float deltaB = (b - oldB) / STEPS;
// Fade to new colour
for (float f = 0; f < STEPS; f++) {
analogWrite(redPin, map((oldR + (deltaR * f)), 0, 255, 0, 1023));
analogWrite(grnPin, map((oldG + (deltaG * f)), 0, 255, 0, 1023));
analogWrite(bluPin, map((oldB + (deltaB * f)), 0, 255, 0, 1023));
delay(2);
}
state = 1;
}
//Compute current brightness value
void getV() {
R = roundf(r/2.55); //was (r/10.23);
G = roundf(g/2.55); //was (g/10.23);
B = roundf(b/2.55); //was (b/10.23);
x = max(R,G);
V = max(x, B);
}
//For serial debugging only
void showValues() {
Serial.print("Status on/off: ");
Serial.println(state);
Serial.print("RGB color: ");
Serial.print(r);
Serial.print(".");
Serial.print(g);
Serial.print(".");
Serial.println(b);
Serial.print("Hex color: ");
Serial.println(hexString);
getV();
Serial.print("Brightness: ");
Serial.println(V);
Serial.println("");
}
void setup() {
Serial.begin(9600);
delay(1);
pinMode(redPin, OUTPUT);
pinMode(grnPin, OUTPUT);
pinMode(bluPin, OUTPUT);
WiFi.mode(WIFI_STA);
WiFiStart();
setHex();
}
void loop() {
WiFiClient client = server.available();
if (!client) {
return;
}
while(client.connected() && !client.available()) {
delay(1);
}
//Respond on certain Homebridge HTTP requests
if (client) {
while (client.connected()) {
if (client.available()) {
char c = client.read();
if (readString.length() < 100) {
readString += c;
}
if (c == '\n') {
Serial.print("Request: ");
Serial.println(readString);
//Send reponse
client.println("HTTP/1.1 200 OK");
client.println("Content-Type: text/html");
client.println();
//On
if(readString.indexOf("on") >0) {
setHex();
showValues();
fading = false;
}
//Off
if(readString.indexOf("off") >0) {
allOff();
showValues();
fading = false;
}
//Fade
if(readString.indexOf("fade") >0) {
fade();
fading = true;
}
//Set color
if(readString.indexOf("set") >0) {
hexString = "";
hexString = (readString.substring(9,15));
setHex();
showValues();
fading = false;
}
//Status on/off
if(readString.indexOf("status") >0) {
client.println(state);
}
//Status color (hex)
if(readString.indexOf("color") >0) {
client.println(hexString);
}
//Status brightness (%)
if(readString.indexOf("bright") >0) {
getV();
client.println(V);
}
delay(1);
client.stop();
readString="";
}
}
}
}
}
void fade() {
while(fading == true){
hexString = "000000";
setHex();
hexString = "FFFFFF";
setHex();
hexString = "FF0000";
setHex();
hexString = "008000";
setHex();
hexString = "0000FF";
setHex();
hexString = "FFFF00";
setHex();
hexString = "1E1E1E";
setHex();
}
}
@Username, 👍0
1 ответ
Лучший ответ:
Переменная fading
не может измениться, как только вы находитесь в этом цикле while
, поскольку ваш код этого не делает, и вы также не используете прерывания (и я не знаю, поддерживает ли это библиотека). Таким образом, Arduino навсегда застревает в этом цикле и не будет реагировать ни на какие взаимодействия, кроме сброса.
По сути, у вас есть 2 варианта (не считая использования гипотетической возможности прерывания библиотеки Wifi, поскольку я недостаточно знаю об этой библиотеке):
- Добавление кода Wifi в цикл
while
: Вы можете просто добавить код, который отслеживает интерфейс Wifi в циклwhile
и установить переменнуюfading
соответственно. Это самый простой в программировании вариант. - Перепишите свой код (особенно функцию
fade()
) так, чтобы он был неблокирующим, то есть он не будет блокировать выполнение другого кода, а будет делать что-то только тогда, когда это нужно, а в противном случае вернётся из функции. Этого можно добиться, используя функциюmillis()
, которая возвращает миллисекунды с момента последнего запуска/сброса для использования в качестве источника времени. Обратитесь к примеруBlinkWithoutDelay
в Arduino IDE. Также вы можете поискать в Googlemillis()
; есть множество руководств. При написании неблокирующего кода вы также можете реализовать конечный автомат (FSM). Это проще, чем кажется. По сути, вы определяете простую переменную, которая задаёт ваше текущее состояние (например, состоянияfading
,off
,specific_color
, ...). В вашей функцииloop()
вы создаете операторswitch(state_variable){ case
, где вы вставляете код для каждого состояния в его собственномcase
. За пределами оператораswitch
вы можете проверить интерфейс Wifi и установить переменную состояния соответствующим образом. Если все написано неблокируемым, то это должно работать как по волшебству.
- ESP8266 не подключается к Wi-Fi
- Каково использование зарезервированных контактов и контактов SDD2, SDD3 NodeMCU?
- Обнаружение ESP8266 в сети
- NodeMCU продолжает отключаться
- Соединение сетей Wi-Fi на nodemcu: как настроить esp8266 в качестве расширителя Wi-Fi, простейший случай
- Ошибка запуска FirebaseDemo в NodeMCU
- Контакты NodeMcu и светодиод RGB
- Как связать MPU9250 и NodeMcu?