Nesse post eu explico como você pode controlar 3 fitas de LED RGB e 3 fitas monocromáticas, usando uma página web servida por um ESP32.
Usando o transistor MOSFET IRF1404 e aqui eu uso 12 desses poderosos transistores, você poderá montar uma controladora realmente potente. Ele pode controlar 1 LED ou milhares deles.
Para fazer um casamento de tensão do ESP32 com o transistor mosfet eu usei o CI ULN2803 que é comumente um circuito usado para controlar motor de passo, contudo eu percebi que poderia simplificar o circuito.
O ESP32 é um WebServer que também controla as potências em cima dos LEDs. Apenas um transistor irf1404 pode suportar até 202 amperes, agora veja, eu usei 12 deles !!!
RECURSOS USADOS
- 1x ESP WROOM 32.
- Fonte 12Vdc e corrente suficiente para alimentar os LEDs.
- 2x ULN2803apg.
- 12x IRF1404 (um para cada PWM).
- 12x resistores de 10k ohms (um para cada irf404).
- Multímetro para determinar as correntes máximas das fitas de LEDs utilizadas.
- Fitas de LEDs (3x RGB e 3x monocromáticas).
- WiFi e um dispositivo com navegador (pc, tablete, smartphone . . .)
ESQUEMA: VISÃO GERAL
ESQUEMA: LINHAS CONTROLADAS
ESQUEMA: LINHAS CONTROLADAS
Bloco básico RGB
ESQUEMA: LINHAS CONTROLADAS
Bloco básico MONO
ESQUEMA: Tabelas de atribuição dos pinos do ESP32
ESQUEMA: Tabelas de atribuição dos canais PWM
<!DOCTYPE html> <html> <head> <meta name="viewport" content="width=device-width, initial-scale=1"> </head> <body style="font-family: Arial, Helvetica, sans-serif; display:flex; flex-direction:column; align-items:center;"> <h2>Fitas de led rgb</h2> <input id="colorPicker1" value="#%rgb1%" data-jscolor="{}"> <input id="colorPicker2" value="#%rgb2%" data-jscolor="{}"> <input id="colorPicker3" value="#%rgb3%" data-jscolor="{}"> <h2>Fitas de led brancas</h2> <input id="range1" type="range" value="%white1%" min="0" max="100"> <input id="range2" type="range" value="%white2%" min="0" max="100"> <input id="range3" type="range" value="%white3%" min="0" max="100"> <br/> <br/> <button id="changeButton" onclick="onClick()">Mudar</button> <script src="https://cdnjs.cloudflare.com/ajax/libs/jscolor/2.4.5/jscolor.min.js"></script> <script> //Recuperamos os colorpickers que serão utilizados para modificar as fitas de led rgb var colorPicker1 = document.getElementById("colorPicker1"); var colorPicker2 = document.getElementById("colorPicker2"); var colorPicker3 = document.getElementById("colorPicker3"); //Recuperamos os ranges que serão utilizados para modificar as fitas de led brancas var range1 = document.getElementById("range1"); var range2 = document.getElementById("range2"); var range3 = document.getElementById("range3"); //Esta função é executada quando se clica no botão "Mudar" function onClick() { //Pegamos os valores do rgb em hexadecimal (retiramos o "#" já que não precisamos") var rgb1 = colorPicker1.value.replace("#", ""); var rgb2 = colorPicker2.value.replace("#", ""); var rgb3 = colorPicker3.value.replace("#", ""); //Pegamos os valores dos ranges var white1 = range1.value; var white2 = range2.value; var white3 = range3.value; //Enviamos os valores para o ESP post(rgb1, rgb2, rgb3, white1, white2, white3); } function post(rgb1, rgb2, rgb3, white1, white2, white3) { //Cria uma requisição var xhr = new XMLHttpRequest(); //A url que colocamos no ESP para receber os valores dos leds var url = "/api/led"; //Os dados das fitas que vamos enviar var data = `rgb1=${rgb1}&rgb2=${rgb2}&rgb3=${rgb3}&white1=${white1}&white2=${white2}&white3=${white3}`; //Enviamos como post xhr.open("POST", url, true); //Indicamos como a requisição está enviando os dados xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded"); //Esta função será executada quando terminarmos de receber a resposta do ESP xhr.onload = function () { console.log(xhr.responseText); }; //Enviamos os dados dos leds xhr.send(data); } </script> </body> </html>
Código Fonte: Arquivo HTML gravado na Flash
Código Fonte: Arquivo HTML gravado na Flash
[SPIFFS] data : C:\Controle WiFi de fitas de LED RGB\Controle_WiFI_Fitas_LED_RGB_SPIFFS_Server_v13\data [SPIFFS] start : 1376256 [SPIFFS] size : 704 [SPIFFS] page : 256 [SPIFFS] block : 4096 /index.html [SPIFFS] upload : C:\Users\David\AppData\Local\Temp\arduino_build_446617/Controle_WiFI_Fitas_LED_RGB_SPIFFS_Server_v13.spiffs.bin [SPIFFS] address: 1376256 [SPIFFS] port : COM12 [SPIFFS] speed : 921600 [SPIFFS] mode : dio [SPIFFS] freq : 80mSeguida de:
esptool.py v2.6
Serial port COM12
Connecting......
Chip is ESP32D0WDQ5 (revision 1)
Features: WiFi, BT, Dual Core, 240MHz, VRef calibration in efuse, Coding Scheme None
MAC: 98:f4:ab:63:e4:18
Uploading stub...
Running stub...
Stub running...
Changing baud rate to 921600
Changed.
Configuring flash size...
Auto-detected Flash size: 4MB
Compressed 720896 bytes to 3036...
Wrote 720896 bytes (3036 compressed) at 0x00150000 in 0.0 seconds (effective 144179.3 kbit/s)...
Hash of data verified.
Leaving...
Hard resetting via RTS pin...
Código Fonte: Biblioteca de Servidor Assícrono
Código Fonte: Declarações
#include <WiFi.h> //Inclui a biblioteca de WiFi #include <ESPAsyncWebServer.h> //Inclui a biblioteca do servidor WEB #include <SPIFFS.h> //Inclui a biblioteca do SPIFFS (SPI Flash File System) // Matriz dos pinos de controle (Linhas RGB 1, 2 e 3 e Linha MONO) //RED,GREEN,BLUE const int pinos_RGB_1[3] = {23, 22, 21}; //Pinos usados pela linha RGB 1 const int pinos_RGB_2[3] = {19, 18, 17}; //Pinos usados pela linha RGB 2 const int pinos_RGB_3[3] = {27, 26, 25}; //Pinos usados pela linha RGB 3 // 1, 2, 3 const int pinos_MONO[3] = {16, 14, 13}; //Pinos usados pela linha MONOcromática // Canais dos PWMs (Linhas RGB 1, 2 e 3 e Linha MONO) const int canais_RGB_1[3] = {0, 1, 2}; //Canais usados pela linha RGB 1 const int canais_RGB_2[3] = {3, 4, 5}; //Canais usados pela linha RGB 2 const int canais_RGB_3[3] = {6, 7, 8}; //Canais usados pela linha RGB 3 const int canais_MONO[3] = {9, 10, 11}; //Canais usados pela linha MONOcromática // Frequência e resolução dos PWMs (Linhas RGB 1, 2 e 3 e Linha MONO) const int frequencia = 1000; // Frequência dos PWMs const int resolucao = 8; // 8 bits const float maxPWM = float(pow(2, resolucao) - 1); //para 8 bits, 255 estados //Configurações para o WiFi const char *ssid = “Seu SSID"; const char *password = “Sua Senha"; //O nosso server que vai receber requisições na porta 80 AsyncWebServer server(80); //Quantidade de fitas RGB const int rgbCount = 3; //Quantidade de fitas brancas const int whiteCount = 3; //Array com os valores das fitas rgb unsigned int rgb[rgbCount] = {0xFF0000, 0x00FF00, 0x0000FF}; //Array com os valores das fitas brancas unsigned int white[whiteCount] = {30, 60, 100};
Código Fonte: setup()
void setup() { //Faz os ajustes dos PWMs setupPWM(); //Faz o auto teste autoTeste(); //Inicializa Serial Serial.begin(115200); //Se não foi possível inicializar o SPIFFS if (!SPIFFS.begin(true)) { Serial.println("SPIFFS Error"); return; } //Conecta à rede WiFi setupWiFi(); //Configura e inicializa o server setupServer(); }
Código Fonte: setupPWM()
void setupPWM() { // Ajusta a frequência e resolução de todos os canais de cada linha for (int i = 0; i < 3; i++) { ledcSetup(canais_RGB_1[i], frequencia, resolucao); //linha RGB 1 ledcSetup(canais_RGB_2[i], frequencia, resolucao); //linha RGB 2 ledcSetup(canais_RGB_3[i], frequencia, resolucao); //linha RGB 3 ledcSetup(canais_MONO[i], frequencia, resolucao); //linha monocromática } // Relaciona cada pino ao seu respectivo canal PWM em cada linha for (int i = 0; i < 3; i++) { ledcAttachPin(pinos_RGB_1[i], canais_RGB_1[i]); //linha RGB 1 ledcAttachPin(pinos_RGB_2[i], canais_RGB_2[i]); //linha RGB 2 ledcAttachPin(pinos_RGB_3[i], canais_RGB_3[i]); //linha RGB 3 ledcAttachPin(pinos_MONO[i], canais_MONO[i]); //linha monicromática } // Ajusta todos os PWM inicialmente para zero changeWhiteLed(1, 0.0); changeWhiteLed(2, 0.0); changeWhiteLed(3, 0.0); changeRGBLed(1, 0.0, 0.0, 0.0); changeRGBLed(2, 0.0, 0.0, 0.0); changeRGBLed(3, 0.0, 0.0, 0.0); }
Código Fonte: setupWifi()
void setupWiFi() { Serial.print("Conectando em "); Serial.print(ssid); //Manda conectar à rede com ssid e senha WiFi.begin(ssid, password); //Enquanto não conectar while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } //Se chegou aqui está conectado Serial.println(); Serial.println("Conectado !!!"); //Exibe no Monitor Serial o IP que utilizaremos no navegador para visualizar a página html Serial.println(WiFi.localIP()); }
Código Fonte: setupServer()
void setupServer() { //Quando uma requisição do tipo GET acontecer no path "/" executaremos a função getIndex server.on("/", HTTP_GET, getIndex); //Quando uma requisição do tipo POST acontecer no path "/api/led" executaremos a função postApiLed server.on("/api/led", HTTP_POST, postApiLed); //Inicializamos o server server.begin(); }
Código Fonte: getIndex()
//Esta função irá carregar o arquivo "index.html" do SPIFFS, fará um processamento nele com a função //"templateProcessor" para substituir os %rgb1%, %rgb2% e %rgb3% pelos valores das nossas variáveis e por //fim enviará a página para quem fez a requisição void getIndex(AsyncWebServerRequest *request) { request->send(SPIFFS, "/index.html", String(), false, templateProcessor); }
Código Fonte: templateProcessor()
//Função que executará o processamento do arquivo html, substituindo as //ocorrências de %rgb1%, %rgb2%, %rgb3%, %white1%, %white2% e %white3% por //seus respectivos valores String templateProcessor(const String &v) { //Vamos verificar para cada fita de led rgb e trocar o seu valor para a apresentação correta do html for (int i = 1; i <= rgbCount; i++) { String str = String("rgb") + i; //Se encontramos o valor if (v == str) { //Criamos um buffer char buffer[8] = {0}; //Na interface o id começa do 1, porém aqui no array começa do 0, então tiramos 1 int index = i - 1; //Transformamos o valor em string hexadecimal sprintf(buffer, "#%06x", rgb[index]); //Retornamos o valor que é para substituir no html return String(buffer); } } //Vamos verificar para cada fita de led branca e trocar o seu valor para a apresentação correta do html for (int i = 1; i <= whiteCount; i++) { String str = String("white") + i; //Se encontramos o valor if (v == str) { //Na interface o id começa do 1, porém aqui no array começa do 0, então tiramos 1 int index = i - 1; //Retornamos o valor que é para substituir no html return String(white[index]); } } return ""; }
Código Fonte: postApiLed()
//Está função receberá os novos valores de rgb vindos da página void postApiLed(AsyncWebServerRequest *request) { //Verificaremos se recebemos o parâmetro correspondente a cada fita de led rgb for (int i = 1; i <= rgbCount; i++) { String param = String("rgb") + i; //Se recebemos o parâmetro if (request->hasParam(param, true)) { //Recuperamos o valor String strRgb = request->getParam(param, true)->value(); //Na interface o id começa do 1, porém aqui no array começa do 0, então tiramos 1 int index = i - 1; //Transformamos o valor (que está como uma string hexadecimal, portanto base 16) em inteiro sem sinal rgb[index] = strtoul(strRgb.c_str(), NULL, 16); //Chamamos a função para indicar que o valor que vai para fita de led rgb em questão precisa ser alterado onRgbChange(i, rgb[index]); } } //Verificaremos se recebemos o parâmetro correspondente a cada fita de led branca for (int i = 1; i <= whiteCount; i++) { String param = String("white") + i; //Se recebemos o parâmetro if (request->hasParam(param, true)) { //Recuperamos o valor String strWhite = request->getParam(param, true)->value(); //Na interface o id começa do 1, porém aqui no array começa do 0, então tiramos 1 int index = i - 1; //Transformamos de string para inteiro white[index] = atoi(strWhite.c_str()); //Chamamos a função para indicar que o valor que vai para fita de led branca em questão precisa ser alterado onWhiteChange(i, white[index]); } } //Informamos a quem fez a requisição que tudo ocorreu conforme esperado request->send(200, "text/plain", "OK"); }
Código Fonte: onRgbChange()
void onRgbChange(int id, unsigned int rgb) { //Recuperamos os valores de cada cor (r, g e b) que a fita com o id passado deverá ficar int r = (rgb >> 16) & 0xFF; int g = (rgb >> 8) & 0xFF; int b = rgb & 0xFF; //Convertemos em termos de porcentagem onde 0.5 = 50%, 0.75 == 75%, 1 == 100%, etc. float rPercentage = r / 255.0; float gPercentage = g / 255.0; float bPercentage = b / 255.0; //Mudamos na fita de led com o id passada changeRGBLed(id, rPercentage, gPercentage, bPercentage); }
Código Fonte: changeRgbLed()
void changeRGBLed(int id, float rPercentage, float gPercentage, float bPercentage) { //Imprimimos os valores recebidos tabulados (somente para debug) Serial.print("RGB "); Serial.print(id); Serial.print("\t"); Serial.print(rPercentage); Serial.print("\t"); Serial.print(gPercentage); Serial.print("\t"); Serial.print(bPercentage); Serial.print("\t"); Serial.println(); /* Antes de alterar, lembramos que o sinal é inverido, assim, invertemos a porcentagem usando uma subtração. (1.0 - rPercentage). */ if (id == 1) //Se a mudança for para a Linha RGB 1 { ledcWrite(canais_RGB_1[0], (1.0 - rPercentage) * maxPWM); ledcWrite(canais_RGB_1[1], (1.0 - gPercentage) * maxPWM); ledcWrite(canais_RGB_1[2], (1.0 - bPercentage) * maxPWM); } else if (id == 2) //Se a mudança for para a Linha RGB 2 { ledcWrite(canais_RGB_2[0], (1.0 - rPercentage) * maxPWM); ledcWrite(canais_RGB_2[1], (1.0 - gPercentage) * maxPWM); ledcWrite(canais_RGB_2[2], (1.0 - bPercentage) * maxPWM); } else if (id == 3) //Se a mudança for para a Linha RGB 3 { ledcWrite(canais_RGB_3[0], (1.0 - rPercentage) * maxPWM); ledcWrite(canais_RGB_3[1], (1.0 - gPercentage) * maxPWM); ledcWrite(canais_RGB_3[2], (1.0 - bPercentage) * maxPWM); } else //Algo deu errado! { Serial.println("ID RGB não reconhecido."); } }
Código Fonte: onWhiteChange()
void onWhiteChange(int id, unsigned int white) { float whitePercentage = white / 100.0; changeWhiteLed(id, whitePercentage); }
Código Fonte: changeWhiteLed()
void changeWhiteLed(int id, float whitePercentage) { //Imprimimos os valores recebidos tabulados (somente para debug) Serial.print("MONO "); Serial.print(id); Serial.print("\t"); Serial.println(whitePercentage); /* Antes de alterar, lembramos que o sinal é invertido, assim, invertemos a porcentagem usando uma subtração. (1.0 - whitePercentage). */ if (id == 1) //Se a mudança for para a Linha MONO 1 { ledcWrite(canais_MONO[0], (1.0 - whitePercentage) * maxPWM); } else if (id == 2) //Se a mudança for para a Linha MONO 2 { ledcWrite(canais_MONO[1], (1.0 - whitePercentage) * maxPWM); } else if (id = 3) //Se a mudança for para a Linha MONO 3 { ledcWrite(canais_MONO[2], (1.0 - whitePercentage) * maxPWM); } else //Algo deu errado! { Serial.println("ID MONO não reconhecido."); } }
Código Fonte: autoTeste()
void autoTeste() { // *** NÃO ESQUECER QUE A LÓGICA É INVERTIDA *** const int intervalo = 5; //Determina a rapidez do auto teste // INCREMENTA todos os canais VERMELHOS for (int i = maxPWM; i >= 0; i--) { ledcWrite(canais_RGB_1[0], i); ledcWrite(canais_RGB_2[0], i); ledcWrite(canais_RGB_3[0], i); delay(intervalo); } // DECREMENTA todos os canais VERMELHOS for (int i = 0; i <= maxPWM; i++) { ledcWrite(canais_RGB_1[0], i); ledcWrite(canais_RGB_2[0], i); ledcWrite(canais_RGB_3[0], i); delay(intervalo); } // INCREMENTA todos os canais VERDES for (int i = maxPWM; i >= 0; i--) { ledcWrite(canais_RGB_1[1], i); ledcWrite(canais_RGB_2[1], i); ledcWrite(canais_RGB_3[1], i); delay(intervalo); } // DECREMENTA todos os canais VERDES for (int i = 0; i <= maxPWM; i++) { ledcWrite(canais_RGB_1[1], i); ledcWrite(canais_RGB_2[1], i); ledcWrite(canais_RGB_3[1], i); delay(intervalo); } // INCREMENTA todos os canais AZUIS for (int i = maxPWM; i >= 0; i--) { ledcWrite(canais_RGB_1[2], i); ledcWrite(canais_RGB_2[2], i); ledcWrite(canais_RGB_3[2], i); delay(intervalo); } // DECREMENTA todos os canais AZUIS for (int i = 0; i <= maxPWM; i++) { ledcWrite(canais_RGB_1[2], i); ledcWrite(canais_RGB_2[2], i); ledcWrite(canais_RGB_3[2], i); delay(intervalo); } // INCREMENTA todos os canais MONOCROMÁTICOS for (int i = maxPWM; i >= 0; i--) { ledcWrite(canais_MONO[0], i); ledcWrite(canais_MONO[1], i); ledcWrite(canais_MONO[2], i); delay(intervalo); } // DECREMENTA todos os canais MONOCROMÁTICOS for (int i = 0; i <= maxPWM; i++) { ledcWrite(canais_MONO[0], i); ledcWrite(canais_MONO[1], i); ledcWrite(canais_MONO[2], i); delay(intervalo); } }
Código Fonte: loop()
//Não precisamos fazer nada no loop, pois já utilizamos os callbacks //para executar as tarefas necessárias void loop() { }
6 Comentários
Fernando, em 'codigo fonte: declaracoes', as linha que têm o #include estão corretas?
ResponderExcluirEu usei IRF740 e funcionou bem no meu projeto. Mais barato e no meu caso mais fácil de encontrar. Particularmente vc enxerga algum problema?
ResponderExcluirSPIFFS Not Supported on esp8266
ResponderExcluirAinda bem que tem seu tutorial, nao achei em outro lugar como poderia usar requisição em js para controlar alguma coisa, tava quase criando um servidor em cada core do esp Kkkkkk
ResponderExcluirObrigado pelo projeto. Falta o ficheiro .ino completo para download.
ResponderExcluirEu não entendi a questão em qual pino eu conecto na ESP32
ResponderExcluir