A nova Arduino Uno R4 WiFi possui muitas características interessantes, como um microcontrolador muito mais poderoso que a R3 e a inclusão de WiFi diretamente na placa. Neste artigo vamos falar sobre o funcionamento da sua matriz de LED, a qual ocupa uma boa parte da placa.
Como funciona a Matriz de LED da Arduino Uno R4 WiFi
A matriz de LED contém 96 LEDs organizados em 8 linhas de 12 LEDs. Para conectar este grande número de LEDs usando poucas linhas digitais do microcontrolador é usada uma técnica chamada charlieplexing.
Esta técnica tira proveito do fato que as saídas digitais do microcontrolador podem assumir três estados:
- Nível ALTO, onde o pino tem uma tensão próxima à da alimentação.
- Nível BAIXO, onde o pino tem uma tensão próxima a 0V (terra).
- ALTA IMPEDÂNCIA, onde o pino se comporta como se não estivesse conectado. Esta condição ocorre quando um pino é configurado como entrada digital.
Em cada instante, o programa que controla os LEDs vai deixar apenas duas conexões da matriz ativas, uma em nível ALTO e outra em nível BAIXO, e as demais em ALTA IMPEDÂNCIA. Com isto, pode-se colocar até dois LEDs em cada combinação de pinos.
A figura abaixo mostra a conexão de 6 LEDs usando apenas 3 pinos do microcontrolador:
A tabela abaixo mostra como acender cada LED:
LED | Pino 1 | Pino 2 | Pino 3 |
1 | ALTO | BAIXO | – |
2 | BAIXO | ALTO | – |
3 | ALTO | – | BAIXO |
4 | BAIXO | – | ALTO |
5 | – | ALTO | BAIXO |
6 | – | BAIXO | ALTO |
Para dar a aparência de que vários LEDs estão ligados simultaneamente, ficamos contínua e rapidamente atualizando os LEDs um a um. A persistência da visão fará com tenhamos a impressão de que os LEDs acendem juntos.
Interface de programação API para a Matriz de LED
Você deve estar pensando que implementar a programação descrita no item anterior é bem complicado. Mas você não precisa fazer esta programação, o Arduino já fornece rotinas para isto. A especificação destas rotinas é o que compõe a interface de programação (API). Ela está descrita em https://docs.arduino.cc/tutorials/uno-r4-wifi/led-matrix#api
Na nossa aplicação vamos usar apenas alguns dos métodos disponíveis no objeto ArduinoLEDMatrix:
- begin(): inicia o tratamento da matriz
- on(led): acende um LED da matriz, os LEDs são numerados de 0 a 95.
- off(led): apaga um LED da matriz
- loadFrame(frame): atualiza toda a matriz. ‘frame’ é um vetor com 3 inteiros sem sinal de 32 bits onde cada um dos bits corresponde a um LED
A API inclui funções para fazer animações, o que não vamos usar aqui.
Conectando a uma rede WiFi com o Arduino Uno R4
Para ter acesso às classes para uso do WiFi, você precisa colocar no início do seu programa:
#include "WiFiS3.h"
O S3 no nome faz referência ao microcontrolador ESP32-S3 usado na R4 WiFi para comunicação WiFi.
As classes, objetos e métodos são semelhantes às das bibliotecas WiFi para as outras placas e shields da Arduino. A forma mais compacta de conectar a uma rede WiFi é chamar o método WiFi.begin() para disparar a conexão, aguardar um tempo e usar WiFi.status() para verificar se ela foi bem sucedida. É o que faz o trecho abaixo, presente nos exemplos da IDE:
int status = WL_IDLE_STATUS; while (status != WL_CONNECTED) { status = WiFi.begin(ssid, pass); delay(10000); }
Neste código, ssid é o nome da sua rede e pass é a senha. A convenção dos exemplos, que vamos seguir aqui, é definir estes valores em um arquivo chamado arduino_secrets.h (este arquivo fica em uma aba separada na IDE):
Fazendo um servidor Web com a Arduino Uno R4 WiFi
A comunicação entre um navegador (browser) e um servidor Web segue um protocolo chamado HTTP, que por sua vez é implementado sobre o protocolo de rede TCP. Um servidor Web completo é algo bastante complexo, o que vamos usar aqui é um servidor TCP, que faz parte da biblioteca WiFi da Arduino, e tratar “na unha” uma pequena parte do HTTP.
O primeiro passo é declarar um objeto WiFiServer, indicando a porta TCP na qual ele vai atender conexões (no caso 80, que é a porta padrão para http):
WiFiServer server(80);
Após conseguirmos conectar à rede WiFi, iniciamos o server:
server.begin();
A interação com o navegador é feita em um laço como o abaixo:
// Aguarda uma conexão WiFiClient client = server.available(); if (client) { Serial.println("Cliente conectou"); // Recebe a solicitação do cliente while (client.connected()) { if (client.available()) { char c = client.read(); // Le um caracter enviado pelo navegador // Linha vazia indica o final da solicitação if (linhaAtualVazia) { // envia resposta } // trata o caracter recebido // … } } // aguarda a página ser enviada delay(1); // Fecha a conexão client.stop(); Serial.println("Cliente desconectou"); }
O navegador envia ao servidor uma solicitação que começa com um comando “GET recurso” e termina com uma linha vazia. A resposta do servidor contém um cabeçalho e, opcionalmente, um corpo, ambos terminados por uma linha vazia. A primeira linha do cabeçalho contém “HTTP/1.1 status”. Pouco depois de enviar a resposta o servidor fecha a conexão, uma nova conexão será feita quando o navegador fizer uma nova solicitação.
O nosso tratamento do http consiste em capturar o comando GET. Se o recurso solicitado for “/” vamos enviar uma página HTML. Se for outro recurso, vamos responder com o status 404 (indicando que não temos este recurso disponível).
A página HTML contém quatro elementos:
- Título;
- Canvas, onde serão controlados os LEDs;
- Campo invisível, usado para enviar a situação dos LEDs para o servidor;
- Botão para envio da situação dos LEDs ao servidor. Esta informação será enviada como um parâmetro no comando GET.
A página inclui código em javascript para:
- Desenhar no canvas os LEDs;
- Mudar o LED entre apagado e aceso quando for clicado;
- Preencher o campo invisível com a situação dos LEDs no canvas.
Código para utilização da Matriz de LED da Arduino Uno R4 WiFi
Abaixo você pode conferir o código completo para utilização da Matriz de LED da Arduino Uno R4 WiFi:
/* Demonstração de controle dos LEDs via WiFi Baseado/inspirado em - WiFi Web Server https://docs.arduino.cc/tutorials/uno-r4-wifi/wifi-examples#wi-fi-web-server - LED Matrix tool https://ledmatrix-editor.arduino.cc/ */ #include "WiFiS3.h" #include "Arduino_LED_Matrix.h" #include "arduino_secrets.h" char ssid[] = SECRET_SSID; char pass[] = SECRET_PASS; int status = WL_IDLE_STATUS; WiFiServer server(80); ArduinoLEDMatrix matrix; const uint32_t limpa[3] = { 0, 0, 0 }; // Página enviada const char *html[] = { "<!DOCTYPE html><html>", "<head><script>var leds = new Array(8*12).fill('.');", "var prog = new URL(window.location.href).searchParams.get(\"leds\");", "if (prog != null) { for (i = 0 ; i < 8*12; i++) {", "leds[i] = prog[i]; } } </script></head>", "<body><h1>Matriz de LEDs do Arduino R4 WiFi</h1><br />", "<canvas id=\"matriz\" width=\"480\" height=\"320\" ", "style=\"border:1px solid #000000;\"></canvas><br /><br />", "<form onsubmit=\"fillLeds()\"><input type=\"hidden\" id=\"leds\" name=\"leds\" >", "<button type=\"submit\">Atualiza</button></form>", "<script>const canvas = document.getElementById(\"matriz\"); ", "const ctx = canvas.getContext(\"2d\");", "let ind = 0; for (y = 20; y < 320; y+=40) { for (x = 20; x < 480; x+=40) {", "ctx.beginPath(); ctx.arc(x, y, 18, 0, 2 * Math.PI); ctx.stroke(); ", "ctx.fillStyle = (leds[ind] == \'*\') ? \"red\":\"white\";", "ctx.fill(); ind++; }} canvas.addEventListener(\'click\', ", "changeLed, false); canvas.onselectstart = function () { return false; }", "function changeLed(event) { var canvas = document.getElementById(\"matriz\"), ", "canvasLeft = canvas.offsetLeft + canvas.clientLeft, ", "canvasTop = canvas.offsetTop + canvas.clientTop,", "ctx = canvas.getContext(\'2d\'); var x = Math.trunc((event.pageX-canvasLeft)/40), ", "y = Math.trunc((event.pageY-canvasTop)/40), ind = y*12+x; ", "leds[ind] = leds[ind] == \'.\'? \'*\' : \'.\';", "ctx.beginPath(); ctx.arc(20+x*40, 20+y*40, 18, 0, 2 * Math.PI); ctx.stroke();", "ctx.fillStyle = (leds[ind] == \'*\') ? \"red\" : \"white\"; ctx.fill(); }", "function fillLeds() { var ledFld = document.getElementById(\"leds\"); ", "ledFld.value = leds.join(\"\"); }</script></body></html>", NULL }; // Iniciação void setup() { // Inicia serial e aguarda PC conectar Serial.begin(115200); while (!Serial) { } delay(1000); Serial.println("Controle dos LEDs via WiFi"); // Inicia matriz de LEDs matrix.begin(); // Verifica o módulo WiFi if (WiFi.status() == WL_NO_MODULE) { Serial.println("Falha na comunicação com o módulo WiFi!"); while (true) ; } String fv = WiFi.firmwareVersion(); if (fv < WIFI_FIRMWARE_LATEST_VERSION) { Serial.println("Atualize o firmware do módulo WiFi"); } // Conecta à rede WiFi int led = 0; matrix.on(led); while (status != WL_CONNECTED) { Serial.print("Conectando a rede WiFi... "); status = WiFi.begin(ssid, pass); uint32_t timeout = millis() + 10000; while (millis() < timeout) { status = WiFi.status(); if (status == WL_CONNECTED) { Serial.println("Conectado"); break; } delay(100); matrix.off(led); led = (led+1) % 96; matrix.on(led); } if (status == WL_CONNECTED) { break; } Serial.println("Falhou!"); } matrix.loadFrame(limpa); server.begin(); // Conectado IPAddress ip = WiFi.localIP(); Serial.print("Conecte com um browser no endereco: "); Serial.println(ip); } // Laço Principal void loop() { // Aguarda uma conexão WiFiClient client = server.available(); if (client) { Serial.println("Cliente conectou"); // Recebe a solicitação do cliente boolean linhaAtualVazia = true; char linhaAtual[200] = ""; char pgmLeds[12*8+1] = ""; bool primeiraLinha = true; bool enviaPagina = false; int pos = 0; while (client.connected()) { if (client.available()) { char c = client.read(); Serial.write(c); // Linha vazia indica o final da solicitação if (c == '\n' && linhaAtualVazia) { if(enviaPagina) { Serial.println("Enviando pagina"); // atualiza os leds if (pgmLeds[0] != 0) { uint32_t frame[3] = { 0, 0, 0 }; for (int i = 0; i < 8*12; i++) { if (pgmLeds[i] == '*') { frame[i/32] |= (1 << (31 - i%32)); } } matrix.loadFrame(frame); } // envia o cabeçalho HTTP seguido da nossa página client.println(F("HTTP/1.1 200 OK")); client.println(F("Content-Type: text/html")); client.println(F("Connection: close")); client.println(); for (int i = 0; html[i] != NULL; i++) { client.println(html[i]); } } else { // rejeita solicitação Serial.println("Rejeitando recurso nao disponivel"); client.println(F("HTTP/1.1 404 Not Found\nConnection: close\n\n")); } break; } if (c == '\n') { // terminou a linha anterior if (primeiraLinha) { if (memcmp(linhaAtual, "GET / ", 6) == 0) { enviaPagina = true; } else if (memcmp(linhaAtual, "GET /?leds=", 11) == 0) { enviaPagina = true; // extrai programação dos leds if (strlen(linhaAtual) > 107) { memcpy (pgmLeds, linhaAtual+11, 8*12); pgmLeds[8*12] = 0; } } else { enviaPagina = false; } } primeiraLinha = false; // começando uma nova linha linhaAtualVazia = true; pos = 0; linhaAtual[0] = 0; } else if (c != '\r') { // tem algo na linha atual linhaAtualVazia = false; linhaAtual[pos] = c; if (pos < (sizeof(linhaAtual) - 1)) { pos = pos+1; } linhaAtual[pos] = 0; } } } // aguarda a página ser enviada delay(1); // Fecha a conexão client.stop(); Serial.println("Cliente desconectou"); } }
Funcionamento da Matriz de LED da Arduino Uno R4 WiFi
Para rodar este exemplo você precisa:
- Uma placa Uno R4 WiFi;
- Um cabo USB-C para ligar a placa a um micro;
- Um micro com a IDE do Arduino, com o suporte ao Arduino Uno R4 instalado;
- Uma rede WiFi cujo nome e senha você conhece.
Carregue na IDE o programa acima e crie o arquivo arduino_secrets.h com o nome e senha da rede WiFi. Conecte a placa e mande compilar e carregar o programa. Em seguida, abra o monitor serial para iniciar a execução e acompanhar as mensagens.
Após a conexão com a rede, será informado o IP associado à placa:
OBs: A mensagem “Atualize o firmware do módulo WiFi” indica que existe uma versão mais nova. O artigo https://support.arduino.cc/hc/en-us/articles/9670986058780-Update-the-wireless-connectivity-firmware-on-UNO-R4-WiFi explica como atualizar.
Abra um navegador web e digite o IP informado:
Cada círculo corresponde a um LED. Clicando neles você muda entre apagado e aceso. Após completar o desenho, clique no botão Atualiza para enviar o desenho e apresentá-lo na matriz de LED da placa.
Próximos Passos
Este exemplo mostrou como:
- Conectar a sua placa Uno R4 WiFi a uma rede;
- Controlar por programa a matriz de LED;
- Como implementar um servidor Web simples.
Agora é deixar correr a imaginação e fazer as suas próprias aplicações! Algumas sugestões:
- Experimentar as funções de animação da matriz;
- Fazer uma página web que informa a leitura de um sensor conectado à placa.
E então, gostou de aprender a utilizar a Matriz de LED da Arduino Uno R4 WiFi? Deixe um comentário abaixo dizendo o que achou e quais as modificações que implementou. Para mais conteúdos como este, acesse nosso blog.