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() { }
2 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?
ResponderExcluir