Neste post, será apresentado um projeto avançado que permite que o usuário controle o VLC Media Player a partir de um joystick juntamente com um ESP32. As informações sobre a mídia atual que está passando no VLC media player serão exibidas através de um display LCD 128×64.
Será mostrado como é feita a manipulação do VLC Media Player remotamente, permitindo estar no controle total do volume e da navegação pelas mídias, e tendo uma representação visual da posição atual da mídia através de uma barra de progresso no display LCD. Além disso, será possível determinar com facilidade se a mídia está em reprodução ou pausa, pois tais informações serão exibidas de forma clara e intuitiva no display.
O joystick, um dispositivo de entrada, permitirá que com movimentos para cima e para baixo, você possa ajustar o volume da mídia de maneira fluida e eficiente. Mover o joystick para esquerda o conduzirá à mídia anterior, enquanto para a direita, a próxima mídia será apresentada. Já o comando de pausar/reproduzir será ativado através do simples pressionar de um botão.
Será feito também uma divisão de tarefas entre os núcleos do ESP32. Enquanto um núcleo cuida da interação com o usuário, exibindo informações no display LCD e interpretando os comandos do joystick para envio de dados ao VLC Media Player, o outro núcleo desempenha o papel vital de receber dados atualizados do VLC Media Player. Essa abordagem paralela garante um funcionamento suave e sem interrupções, criando uma experiência de usuário envolvente e responsiva.
Para permitir a integração entre o ESP32 e o VLC Media Player, a biblioteca HTTPClient entra em cena. Essa biblioteca, já incorporada no núcleo ESP32 da Arduino IDE, capacita o envio e recebimento de dados HTTP, um aspecto fundamental para a comunicação eficaz com o VLC. As respostas das requisições feitas ao VLC Media Player, em formato XML, serão analisadas com a ajuda da biblioteca tinyxml2, fornecendo acesso direto aos elementos da resposta das requisições.
Para controle do display LCD 128×64 é utilizada a biblioteca u8g2. Será mostrado neste post as principais funções da u8g2, incluindo a habilidade de exibir uma imagem bitmap.

Os seguintes materiais foram utilizados neste post:
A biblioteca U8g2 é uma poderosa ferramenta gráfica desenvolvida para dispositivos embarcados. Ela oferece suporte a uma ampla variedade de displays monocromáticos, englobando diversos controladores (incluindo o ST7920). Essa versatilidade torna a biblioteca U8g2 uma escolha ideal para trabalhar com uma ampla gama de displays com a linguagem Arduino sem se preocupar com os detalhes técnicos dos controladores subjacentes. Ela simplifica significativamente o processo de programação e exibição de informações em displays monocromáticos em projetos embarcados, incluindo também a facilitação para desenhar gráficos (linhas, retângulos e círculos) e textos com fontes diversas. Para obter a lista completa de controladores suportados, consulte a lista controladores suportados neste link.

Logotipo biblioteca U8g2
Para este post será utilizada a Arduino IDE 2.0. Caso deseje informações de instalação e de uso, consulte o post Arduino IDE 2.0: Conheça o Novo IDE Arduino do blog Eletrogate.
Siga os passos abaixo para instalar a biblioteca U8g2:



Para utilizar a biblioteca U8g2, é necessário saber o controlador e o tamanho do display utilizado. O display vendido pela loja Eletrogate possui o controlador ST7920 e tem o tamanho de 128 colunas por 64 linhas (128×64). Veja a descrição do display na página do produto:

Para que as informações gráficas sejam mostradas no display é necessário que o controlador do display receba estas informações através de um barramento físico. O display que possui o chip ST7920 tem dois barramentos físicos de comunicação:
O pino PSB do controlador ST7920 seleciona entre o Barramento de 8 bits e o Barramento SPI. Dependendo de onde este pino estiver conectado, será selecionado determinado barramento:
Para o barramento SPI, os pinos de comunicação são:
Veja abaixo a referência de todos os pinos do display:
Veja abaixo a relação de pinos entre o Display e o ESP32:
| Display | ESP32 |
| GND | GND |
| VCC | Vin |
| V0 | Vin |
| RS | GPIO16 |
| R/W | GPIO23 (MOSI) |
| E | GPIO18 (SCK) |
| PSB | GND |
| RST | GPIO17 |
| BLA | 3.3V |
| BLK | GND |
public: U8G2_ST7920_128X64_F_SW_SPI(const u8g2_cb_t *rotation, uint8_t clock, uint8_t data, uint8_t cs, uint8_t reset = U8X8_PIN_NONE) : U8G2(): este é o construtor da classe U8G2 para o modo de comunicação SPI. Existem vários modelos de construtores para a biblioteca U8g2 (veja a lista completa aqui neste link), aos quais se diferem entre si em tamanho do display, em modelo de controlador e em tipo de comunicação. Para o display utilizado neste post, utilizaremos o construtor U8G2_ST7920_128X64_F_SW_SPI. Veja abaixo a explicação do nome do construtor e também a explicação dos parâmetros deste construtor:U8G2_ST7920_128X64_F_SW_SPI: é o construtor da classe do display, sendo:rotation: define a rotação do display em graus, podendo ser 0, 90, 180 ou 270 graus. As seguintes definições definem qual será a rotação do display:clock: define o número do pino digital que está conectado ao pino E do display, que é o sinal de clock do SPI;data: define o número do pino digital que está conectado ao pino R/W do display, que é o sinal de dados do SPI;cs: define o número do pino digital que está conectado ao pino RS do display, que é o sinal de chip-select do SPI;reset: define o número do pino digital que está conectado ao pino RST do display, que é o sinal de reset. Esse parâmetro é opcional e pode ser omitido se o pino RST estiver conectado ao VCC.bool U8G2::begin(void): Procedimento simplificado de configuração do display para o ambiente Arduino. Esta função irá redefinir, configurar, limpar e desativar o modo de economia de energia do monitor. Sempre retorna o booleano true;void U8G2::clear(void): Limpa todos os pixels da tela e do buffer e após, coloca o cursor da função de impressão no canto superior esquerdo;void U8G2::drawBox(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h): Desenha uma caixa (preenchida), começando na posição x/y (borda superior esquerda). A caixa tem largura w e altura h. Partes da caixa podem estar fora dos limites de exibição caso deseje. Este procedimento usará a cor atual (definida por setDrawColor) para desenhar a caixa.x: Posição X da borda superior esquerda.y: Posição Y da borda superior esquerda.w: Largura da caixa.h: Altura da caixa.u8g2.drawBox(3,7,25,15);;
Fonte da imagem: Documentação u8g2 no GitHub.
void U8G2::drawCircle(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, uint8_t opt = U8G2_DRAW_ALL): Desenha um círculo com raio rad na posição (x0, y0). O diâmetro do círculo é 2*rad+1. Dependendo de opt, é possível desenhar apenas alguns quadrantes do círculo. Este procedimento usará a cor atual (definida por setDrawColor).x0, y0: Posição do centro do círculo;rad: Define o tamanho do círculo;opt: seleciona alguns ou todos os quadrantes do círculo. Cada valor representa uma seção do círculo, dividida em quatro quadrantes: superior direito, superior esquerdo, inferior esquerdo e inferior direito. Os valores podem ser combinados com o operador |. Por exemplo, se você quiser desenhar apenas a metade superior do círculo, você pode usar: U8G2_DRAW_UPPER_RIGHT | U8G2_DRAW_UPPER_LEFT. Agora, se você quiser desenhar o círculo inteiro, você pode usar: U8G2_DRAW_ALL ou o equivalente U8G2_DRAW_UPPER_RIGHT | U8G2_DRAW_UPPER_LEFT | U8G2_DRAW_LOWER_LEFT | U8G2_DRAW_LOWER_RIGHT. Os valores disponíveis são:| (OR lógico).u8g2.drawCircle(20, 25, 10, U8G2_DRAW_ALL);;
Fonte da imagem: Documentação u8g2 no GitHub.
void U8G2::drawFrame(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h): Desenha um quadro (caixa vazia), começando na posição x/y (borda superior esquerda). A caixa tem largura w e altura h. Partes do quadro podem ficar fora dos limites da exibição. Este procedimento usará a cor atual (definida por setDrawColor) para desenhar a caixa.x: Posição X da borda superior esquerda;y: Posição Y da borda superior esquerda;w: Largura do quadro;h: Altura do quadro.u8g2.drawFrame(3,7,25,15);
Fonte da imagem: Documentação u8g2 no GitHub.
u8g2_uint_t U8G2::drawGlyph(u8g2_uint_t x, u8g2_uint_t y, uint16_t encoding): Desenhe um único caractere. O caractere é colocado na posição de pixel especificada x e y. O parâmetro encoding pode ser qualquer valor de 0 a 65535. O glifo só pode ser desenhado se a codificação existir na fonte ativa (definida por setFont). Esta função de desenho depende do modo de fonte atual e da cor do desenho.x, y: Posição do caractere no display;encoding: Valor Unicode do caractere.u8g2.setFont(u8g2_font_unifont_t_symbols);), o código u8g2.drawGlyph(5, 20, 0x2603); desenha um glifo “boneco de neve”, o qual faz parte dos símbolos meteorológicos unicode e possui o unicode 9731 (decimal) / 2603 (hexadecimal).
Fonte da imagem: Documentação u8g2 no GitHub.
Veja abaixo a tabela da fonte u8g2 u8g2_font_unifont_t_symbols:
Para escolher um símbolo para ser impresso no display, deve-se identificar o código decimal da linha do símbolo e em seguida somar este número com o código de coluna (contagem inicia-se em zero) do símbolo. Após a soma, deve-se converter de decimal para hexadecimal. Exemplo: o símbolo de “boneco de neve” tem o código decimal de linha 9728 e tem o código de coluna 3, o que resulta em 9731 (9728 + 3 = 9731). Com o resultado 9731, devemos converte-lo para hexadecimal utilizando uma ferramenta de conversão (a calculadora do Windows no modo Programador), o que resulta em 2603, que é o mesmo que 0x2603.
void U8G2::drawLine(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t x1, u8g2_uint_t y1):Desenha uma linha entre dois pontos. Este procedimento usará a cor atual definida por setDrawColor.x0: Posição X do primeiro ponto.y0: Posição Y do primeiro ponto.x1: Posição X do segundo ponto.y1: Posição Y do segundo ponto.u8g2.drawLine(20, 5, 5, 32);
Fonte da imagem: Documentação u8g2 no GitHub.
void U8G2::drawPixel(u8g2_uint_t x, u8g2_uint_t y): Desenha um pixel na posição x/y especificada. A posição (0,0) está no canto superior esquerdo do display. A posição pode estar fora dos limites de exibição. Este procedimento utiliza o índice de cores atual para desenhar o pixel. O índice de cores 0 limpará um pixel e o índice de cores 1 definirá um pixel.x: Posição X.y: Posição Y.u8g2_uint_t U8g2::drawUTF8(u8g2_uint_t x, u8g2_uint_t y, const char *s): Desenha uma string codificada como UTF-8.x e y: Posição do primeiro caractere no display.s: texto codificado em UTF-8.u8g2.setFont(u8g2_font_unifont_t_symbols);) e o código for u8g2.drawUTF8(5, 20, "Snowman: ☃");:
void U8G2::enableUTF8Print(void): Ativa o suporte UTF8 para a função Arduino print. Quando ativado, símbolos Unicode são permitidos para strings passadas para a função print(). Normalmente esta função é chamada depois de begin().void setup() {
u8g2.begin();
u8g2.enableUTF8Print(); // habilite o suporte UTF8 para o Arduino print()
}void U8G2::disableUTF8Print(void): Desativa o suporte UTF8 para a função Arduino print().void U8G2::print(...): Esta é a função print() do Arduino. Veja a documentação na página Web do Arduino aqui. Este procedimento irá escrever o texto na posição atual do cursor com a fonte atual, definida por setFont. A posição do cursor pode ser definida por setCursor. O suporte para UTF-8 pode ser habilitado com enableUTF8Print. Esta função pode imprimir valores de variáveis e suporta a macro F().u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(0, 15);
u8g2.print("Hello World!");
void U8G2::setCursor(u8g2_uint_t x, u8g2_uint_t y): Define o cursor para a função print(). Qualquer saída da função print() começará nesta posição.x e y: Posição do pixel do cursor da função print().u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.setCursor(0, 15);
u8g2.print("Hello World!");
void U8G2::setFontMode(uint8_t is_transparent): Define se as funções de desenho de glifo e string escreverão a cor de fundo sólida ou transparente. O modo padrão é sólido.is_transparent: Habilite com 1 (transparente) ou desabilite com 0 (sólido).void U8G2::setDrawColor(uint8_t color): Define o valor do índice de cores para todas as funções de desenho. Todas as funções de desenho alterarão a memória de exibição para este valor de bit. O valor padrão é 1. A partir da versão 2.11 da biblioteca, o novo valor de cor 2 ativará o modo XOR.color: 0 (limpar valor de pixel na RAM de exibição), 1 (definir valor de pixel) ou 2 (modo XOR)u8g2.setFontMode(1); /* ativar o modo de fonte transparente */ u8g2.setDrawColor(1); /* cor 1 (sólida) para a caixa (box) */ u8g2.drawBox(22, 2, 35, 50); u8g2.setFont(u8g2_font_ncenB14_tf); u8g2.setDrawColor(0); u8g2.drawStr(5, 18, "abcd"); u8g2.setDrawColor(1); u8g2.drawStr(5, 33, "abcd"); u8g2.setDrawColor(2); u8g2.drawStr(5, 48, "abcd");

void U8G2::setFont(const uint8_t *font): Defina uma fonte u8g2 para as funções de glifo e desenho de string. As fontes disponíveis estão listadas aqui. Os dois últimos caracteres do nome da fonte definem o tipo e o conjunto de caracteres da fonte:| Nome da fonte | Significado dos dois últimos caracteres |
| u8g2_■■■_tx | Gilfos transparentes com largura variável |
| u8g2_■■■_mx | Glifos monoespaçados/de largura fixa |
| u8g2_■■■_hx | Glifos com largura variável e altura comum |
| u8g2_■■■_8x | Glifos de largura monoespaçada/fixa em uma caixa 8×8 |
| u8g2_■■■_xe | Estendido: Glifos com unicode 32 a 701 estão incluídos na fonte (v2.16.x também incluirá ß grande) |
| u8g2_■■■_xf | Completo: Glifos com unicode 32 a 255 estão incluídos na fonte |
| u8g2_■■■_xr | Restrito: apenas caracteres de 32 a 127 estão incluídos |
| u8g2_■■■_xu | Maiúsculas: números e letras maiúsculas |
| u8g2_■■■_xn | Números e alguns glifos extras para impressão de data e hora estão incluídos |
| u8g2_■■■_x_■■■ | Seleção especial de glifos. Veja a imagem da fonte para obter detalhes. |
font: Aponte para uma fonte u8g2. Uma lista de fontes disponíveis está aqui;u8g2_font_5x7_tr e u8g2_font_pressstart2p_8u:

void U8G2::setFontDirection(uint8_t dir): define a direção de desenho de todas as strings ou glifos.dir: Direção de escrita/rotação da string.u8g2.setFont(u8g2_font_ncenB14_tf); u8g2.setFontDirection(0); u8g2.drawStr(15, 20, "Abc"); u8g2.setFontDirection(1); u8g2.drawStr(15, 20, "Abc");

void U8G2::clearBuffer(void): Limpa todos os pixels no buffer de quadros de memória.void U8G2::sendBuffer(void): Envia o conteúdo do buffer de quadros de memória para o display. Use as funções draw para desenhar algo no buffer de quadros.void U8G2::drawXBM(u8g2_uint_t x, u8g2_uint_t y, u8g2_uint_t w, u8g2_uint_t h, const uint8_t *bitmap): Desenha um bitmap XBM monocromático (NOTA: Em razão da documentação da biblioteca não recomendar mais o uso da função drawBitmap, só iremos descrever a função drawXBM). A posição (x,y) é o canto superior esquerdo do bitmap. Muitas ferramentas (incluindo o GIMP) podem salvar um bitmap como XBM.x: Posição X;y: Posição Y;w: Largura do bitmap;h: Altura do bitmap;bitmap: Ponteiro para o início do bitmap.void U8G2::firstPage(void): Este comando faz parte do loop (imagem) que renderiza o conteúdo do display.uint8_t U8G2::nextPage(void): Este comando faz parte do loop (imagem) que renderiza o conteúdo do display.| Nota: para testar os sketches abaixo deste tópico, considere a montagem de hardware como a mesma que está no tópico Biblioteca U8g2: utilizando o display LCD 128×64, seção Conectando um display à biblioteca U8g2. |
Existem dois modos diferentes de desenho no display:
O modo de buffer de tela cheia é uma abordagem que permite a preparação completa de um quadro ou imagem antes de exibi-lo na tela. Ao usar esse modo, todos os procedimentos gráficos são aplicados diretamente em um buffer de memória dedicado, em vez de atualizar a tela pixel por pixel.
O uso deste modo possui prós e contras:
#include <U8g2lib.h> // Inclusão da biblioteca U8g2 para controle do display
#include <SPI.h> // Inclusão da biblioteca SPI para comunicação serial
U8G2_ST7920_128X64_F_SW_SPI u8g2(
/* rotação */ U8G2_R2,
/* clock=*/ 18,
/* data=*/ 23,
/* CS=*/ 16,
/* reset=*/ 17); // Inicialização do display com os pinos especificados
void setup(void) {
u8g2.begin(); // Inicializa o display
}
void loop(void) {
u8g2.clearBuffer(); // Limpa o buffer do display
u8g2.setFont(u8g2_font_ncenB14_tr); // Define a fonte do texto
u8g2.drawStr(0, 20, "ABC 123 !@#"); // Desenha o texto na posição especificada
u8g2.sendBuffer(); // Envia o buffer para o display
}O modo de buffer de página organiza a renderização gráfica em segmentos, chamados páginas, em um buffer de memória. Esta abordagem permite uma economia significativa de recursos de RAM. No entanto, devido à sua natureza segmentada, pode resultar em uma exibição mais lenta na tela em comparação com métodos mais diretos de atualização.
O uso deste modo possui prós e contras:
#include <U8g2lib.h> // Inclusão da biblioteca U8g2 para controle do display
#include <SPI.h> // Inclusão da biblioteca SPI para comunicação serial
U8G2_ST7920_128X64_F_SW_SPI u8g2(
/* rotação */ U8G2_R2,
/* clock=*/ 18,
/* data=*/ 23,
/* CS=*/ 16,
/* reset=*/ 17); // Inicialização do display com os pinos especificados
void setup(void) {
u8g2.begin(); // Inicializa o display
}
void loop(void) {
u8g2.firstPage();
do {
u8g2.setFont(u8g2_font_ncenB14_tr); // Define a fonte do texto
u8g2.drawStr(0,24,"Hello World!");// Desenha o texto na posição especificada
} while ( u8g2.nextPage() );
}Para mais detalhes sobre o “Modo de página”, consulte a página Loop de imagem da documentação da biblioteca.
A exibição de imagens Bitmap em um display LCD 128×64 é uma tarefa que envolve diversas etapas, desde a preparação da imagem até a sua renderização no display. Inicialmente, é necessário converter a imagem desejada em um formato Bitmap compatível com as especificações do display. Para isso, utilizaremos o software de edição de imagens GIMP. Uma vez que o Bitmap esteja pronto, é preciso implementar o código necessário para enviar esses dados ao display LCD.
As instruções deste tópico resultará na seguinte exibição de imagem no display LCD 128×64:

Utilizaremos o Canva para criar a imagem.




Utilizaremos o GIMP para converter a imagem.



static const unsigned char imagem_arduino [] PROGMEM = {;
Utilizaremos a função drawXBM para exibir a imagem no display.


#include <U8g2lib.h>
#include <SPI.h>
#include "imagem.h"
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R2, /* clock=*/18, /* data=*/23, /* CS=*/16, /* reset=*/17);
void setup() {
u8g2.begin();
delay(100);
u8g2.clearBuffer();
u8g2.drawXBM(0, 0, 128, 64, imagem_arduino);
u8g2.sendBuffer();
}
void loop() {
delay(1);
}Para poder controlar o VLC player através do ESP32, é necessário ativar a interface Web Lua do media player VLC. Para isso, siga o passo a passo abaixo:





Após o passo a passo anterior já é possível testar se houve sucesso na ativação da interface Web Lua do media player VLC:




Se tudo tiver ocorrido bem, a interface Web Lua do media player VLC será aberta.
As requisições para obter dados e para executar comandos são respondidas pelo media player VLC com uma resposta XML.
A interface Web Lua do media player VLC realiza de tempos em tempos uma requisição ao media player VLC no endereço http://<IP do seu PC>:8080/requests/status.xml. Esta requisição obtém os dados da mídia que está sendo reproduzida no media player. Estes dados incluem:
Estes dados da requisição estão no formato de arquivo .xml. Veja abaixo um exemplo do resultado de uma requisição enquanto uma mídia está tocando no media player VLC:
<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<root>
<fullscreen>0</fullscreen>
<seek_sec>10</seek_sec>
<apiversion>3</apiversion>
<currentplid>3</currentplid>
<time>11</time>
<volume>256</volume>
<length>109</length>
<random>false</random>
<audiofilters>
<filter_0></filter_0>
</audiofilters>
<rate>1</rate>
<videoeffects>
<hue>0</hue>
<saturation>1</saturation>
<contrast>1</contrast>
<brightness>1</brightness>
<gamma>1</gamma>
</videoeffects>
<state>playing</state>
<loop>false</loop>
<version>3.0.20 Vetinari</version>
<position>0.10803920030594</position>
<audiodelay>0</audiodelay>
<repeat>false</repeat>
<subtitledelay>0</subtitledelay>
<equalizer></equalizer>
<information>
<category name="meta">
<info name='album'>Biblioteca YouTube</info>
<info name='filename'>Colony - TrackTribe.mp3</info>
<info name='date'>2023</info>
<info name='genre'>Ambiente</info>
<info name='title'>Colony</info>
</category>
<category name='Transmissão 0'>
<info name='Canais'>Estéreo</info>
<info name='Tipo'>Áudio</info>
<info name='Taxa de bits'>320 kb/s</info>
<info name='Codificador'>MPEG Audio layer 1/2 (mpga)</info>
<info name='Bits por amostra'>32</info>
<info name='Taxa de amostragem'>44100 Hz</info>
</category>
</information>
<stats>
<lostabuffers>0</lostabuffers>
<readpackets>164</readpackets>
<lostpictures>0</lostpictures>
<demuxreadbytes>516178</demuxreadbytes>
<demuxbitrate>0.039991166442633</demuxbitrate>
<playedabuffers>492</playedabuffers>
<demuxcorrupted>0</demuxcorrupted>
<sendbitrate>0</sendbitrate>
<sentbytes>0</sentbytes>
<displayedpictures>0</displayedpictures>
<demuxreadpackets>0</demuxreadpackets>
<sentpackets>0</sentpackets>
<inputbitrate>0.039770554751158</inputbitrate>
<demuxdiscontinuity>0</demuxdiscontinuity>
<averagedemuxbitrate>0</averagedemuxbitrate>
<decodedvideo>0</decodedvideo>
<averageinputbitrate>0</averageinputbitrate>
<readbytes>522624</readbytes>
<decodedaudio>985</decodedaudio>
</stats>
</root>Este comando permite reproduzir a faixa anterior na lista de reprodução (retroceder).
Este comando permite reproduzir a próxima faixa na lista de reprodução (avançar).
Este comando permite definir o volume de reprodução da mídia. Em <VALOR>, substitua por um valor entre 0 e 512 (0= sem som, 512=volume máximo de 200%).
Este comando permite pausar ou dar play na mídia em reprodução (a cada execução deste comando, a funcionalidade alterna entre pausar e dar play).
Para descobrir outros comandos, siga os passos abaixo:
Exemplo da funcionalidade de Stop (/requests/status.xml?command=pl_stop), do media player Vlc:

Como as requisições (obter dados e executar comandos) para o media player VLC são respondidas com uma resposta no formato xml, deve-se obter uma forma facilitada para que o microcontrolador ESP32 possa analisar estas respostas. Isto é feito com a biblioteca tinyXML2.
A biblioteca tinyXML2 é uma poderosa ferramenta para manipulação de documentos XML de maneira eficiente e fácil. Ela é especialmente útil para programas C++ que necessitam ler, modificar e criar documentos XML. Vamos explorar como acessar elementos XML utilizando essa biblioteca.

Para instalar a biblioteca tinyXML2 acesse github.com/leethomason/tinyxml2/releases e clique em Source code (zip) para fazer o download do arquivo .zip contendo a biblioteca. Em seguida, com a Arduino IDE aberta, navegue no menu Sketch ➜ Incluir Biblioteca ➜ Adicionar Biblioteca .ZIP. Então, selecione o arquivo .ZIP que foi baixado e clique em Abrir.
Após a instalação da Biblioteca, para utilizá-la, basta adicionar no começo do sketch a seguinte inclusão:
#include <tinyxml2.h>
class XMLDocument: Classe tinyXML2 para manipulação eficiente de documentos XML em C++. Fornece métodos simples para carregar, acessar, modificar e criar elementos XML.class XMLNode: Classe tinyXML2 que representa um nó em um documento XML. Utilize para navegar e manipular diferentes elementos dentro do XML.class XMLElement: Classe tinyXML2 que representa um elemento específico em um documento XML. Use para acessar e modificar propriedades de elementos XML.XMLError tinyxml2::XMLDocument::Parse (const char * xml, size_t nBytes = static_cast< size_t >(-1)): Este método analisa o texto XML fornecido, convertendo-o em uma estrutura de árvore XML. Retorna um código de erro indicando o resultado da análise XML ou XML_SUCCESS (0) em caso de sucesso.const char * xml: O texto XML a ser analisado.size_t nBytes = static_cast< size_t >(-1): Número opcional de bytes a serem considerados. O padrão é processar todo o texto.const XMLNode * FirstChild(): Obtém o primeiro nó filho do elemento atual, ou null se não houver nenhum.const XMLElement * tinyxml2::XMLNode::FirstChildElement (const char * name = 0): Obtém o primeiro elemento filho do nó atual, ou opcionalmente o primeiro elemento filho com o nome especificado, se nenhum elemento filho existir, ou se nenhum tiver o nome especificado, o retorno será null.const char * name = 0: Nome opcional do elemento desejado.XMLError tinyxml2::XMLElement::QueryIntText (int * ival): Método de conveniência para consultar o valor de um nó de texto filho como um inteiro. Este método é útil para extrair o valor de um nó de texto filho, convertendo-o para um inteiro. Retorna um código indicando o resultado da consulta (erro ou sucesso).int * ival: Ponteiro para a variável onde o valor inteiro será armazenado.const char * tinyxml2::XMLElement::Attribute(const char *name, const char *value=0): Obtém o valor de um atributo com o nome especificado. Este método retorna um ponteiro constante para o valor do atributo com o nome fornecido. Se nenhum atributo com o nome especificado existir, o retorno será null.const char *name: nome do atributo desejado.const char *value=0: valor opcional que deve coincidir com o valor real do atributo.const char * tinyxml2::XMLElement::GetText(): Função de conveniência para fácil acesso ao texto dentro de um elemento. Este método retorna o texto dentro de um elemento, se o primeiro filho for um XMLText. Se o primeiro filho não for um nó de texto, o retorno será null.const XMLElement * NextSiblingElement (const char *name=0): Obtém o próximo elemento irmão (à direita) deste nó, opcionalmente com um nome específico. Este método retorna um ponteiro constante para o próximo elemento irmão à direita do nó atual. Se nenhum próximo elemento existir, ou se nenhum tiver o nome especificado, o retorno será null.const char *name=0: Nome opcional do próximo elemento desejado.XMLError QueryDoubleText (double *dval): Método de conveniência para consultar o valor de um nó de texto filho como um double. Este método é semelhante ao QueryIntText() e é utilizado para extrair o valor de um nó de texto filho, convertendo-o para um double. Retorna um código indicando o resultado da consulta (sucesso ou erro).double *dval: ponteiro para a variável onde o valor double será armazenado.Outras funções, classes, estruturas, uniões e interfaces podem ser vistas na documentação da biblioteca em leethomason.github.io/tinyxml2/annotated.html.
Clique aqui para fazer o download do sketch completo.
Antes de prosseguir, modifique o valor das seguintes variáveis no sketch:
<IP_VLC> pelo endereço IP do servidor VLC (consulte Habilitando interface Web Lua do media player VLC para detalhes de como obter este IP);<SSID> pelo nome da sua rede Wi-Fi;<SENHA> pela senha da sua rede Wi-Fi;<SENHA_VLC> pela senha utilizada para acessar a interface Web lua do media player VLC (consulte Habilitando interface Web Lua do media player VLC para detalhes de como obter a senha);Em seguida, faça o upload do sketch para a placa ESP32.
Veja abaixo o sketch (contendo os arquivos sketch.ino, credenciais.h e splashScreen.h):
/******************************************************************************
Controlando o media player VLC de um PC via joystick no ESP32
Criado em 16 de Janeiro de 2024
por Michel Galvão (https://micsg.com.br)
Sketch Principal
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
//Inclusão das bibliotecas
#include <WiFi.h>
#include <HTTPClient.h>
#include "credenciais.h"
#include "splashScreen.h"
#include <U8g2lib.h>
#include <SPI.h>
#include <tinyxml2.h>
// Protótipos das funções
void showAlbum();
void showNome();
void atualizaVariaveis(String textXML);
String requestVlc();
int getVolume();
void setStatusPlayer(bool status);
void setVolume(bool comVerificacao = true); // deixa a fução com protótipo opcional
void showPosicao();
void showVolume();
void showPlayPause();
uint8_t showAvancar();
uint8_t showRetroceder();
bool verificarConexaoVlc();
// Instanciação dos objetos das classes das biblitecas
U8G2_ST7920_128X64_F_SW_SPI u8g2(U8G2_R2, /* clock=*/18, /* data=*/23, /* CS=*/16, /* reset=*/17);
//// Definição dos pinos do Joystick
const int pushButton = 32;
const int joyY = 36;
const int joyX = 39;
// definição de veriáveis de controle e armazenamento
bool statusPlayer = false; // indica o estado do player: true para reproduzindo, false para pausado
int volume = 0; // nível de volume atual (local [ESP32])
int volumeVLC = 0; // nível de volume do VLC (online [media player VLC])
int textNomeX = 10; // posição inicial do texto do nome na tela
float position = 0.0; // posição atual da mídia em reprodução
int lengthMidia = 0; // comprimento total da mídia em reprodução
String nomeMidia; // nome da mídia atual
String albumMidia; // álbum da mídia atual
unsigned long timerGetHttp; // temporizador para controle de solicitações HTTP
unsigned long timerNome; // temporizador para controle de atualização do nome
bool conexaoPerdida = false; // indica se a conexão com o VLC foi perdida ou não
// definição de constantes
const String ipServerVlc = "<IP_VLC>"; // endereço IP do servidor VLC
const String portaServerVlc = "8080"; // porta de comunicação com o servidor VLC
void setup() {
Serial.begin(115200);// inicialização da comunicação serial
// Inicialização do display
u8g2.begin(); // inicialização do objeto u8g2 para controle do display
delay(100); // delay obrigatório para inicialização correta do display
// Exibição da SplashScreen no display
u8g2.clearBuffer(); // limpeza do buffer do display
u8g2.drawXBM(0, 0, 128, 64, splashScreen); // desenho da tela de SplashScreen
u8g2.sendBuffer(); // envio do buffer para o display
delay(2000); // aguardo de 2 segundos
// Configuração do WiFi e exibição do status do WiFi no display
u8g2.clearBuffer(); // limpeza do buffer do display
u8g2.setFont(u8g2_font_ncenB08_tr); // definição da fonte para o texto principal
u8g2.enableUTF8Print(); // habilita o suporte UTF-8 para a função print() do display
u8g2.drawStr(0, 10, "Conectando ao WiFi..."); // exibição do texto no display
u8g2.setFont(u8g2_font_squeezed_b6_tr); // definição da fonte para informações menores
u8g2.setCursor(0, 20);
u8g2.print(ssid); // exibição do SSID no display
u8g2.sendBuffer(); // envio do buffer para o display
WiFi.begin(ssid, password); // início da conexão WiFi
u8g2.setCursor(0, 30);
while (WiFi.status() != WL_CONNECTED) {
delay(500);
u8g2.print(".");
u8g2.sendBuffer();
}
u8g2.setCursor(0, 40);
u8g2.print("OK"); // exibição do status de conexão bem-sucedida no display
u8g2.sendBuffer(); // envio do buffer para o display
delay(2000); // aguardo de 2 segundos
// Verificação da conexão com media player VLC
u8g2.clearBuffer(); // Limpa o buffer do display
u8g2.setFont(u8g2_font_ncenB08_tr); // Define a fonte para exibição de texto
u8g2.drawStr(0, 10, "Conectando ao VLC..."); // Exibe mensagem no display
u8g2.setFont(u8g2_font_squeezed_b6_tr); // Define outra fonte para exibição de texto
u8g2.setCursor(0, 20);
u8g2.print(ipServerVlc); // Exibe o IP do servidor VLC no display
u8g2.sendBuffer(); // Envia o buffer para o display
u8g2.setCursor(0, 30);
do {
delay(500); // Aguarda 500 milissegundos
u8g2.print("."); // Exibe um ponto no display
u8g2.sendBuffer(); // Envia o buffer atualizado para o display
} while (verificarConexaoVlc() != true); // Continua o loop até que a conexão com o servidor VLC seja estabelecida
u8g2.setCursor(0, 40);
u8g2.print("OK"); // Exibe "OK" no display
u8g2.sendBuffer(); // Envia o buffer atualizado para o display
delay(1000); // Aguarda 1000 milissegundos (1 segundo)
// Limpa o display
u8g2.clear();
// Configura o pino de leitura do botão do joystick
pinMode(pushButton, INPUT_PULLUP);
// Cria a tarefa "loop2()" com uma pilha de 10000 bytes, prioridade 1, e a associa ao core 0 do processador
xTaskCreatePinnedToCore(loop2, "loop2", 10000, NULL, 1, NULL, 0);
}
void loop() { // destinado ao envio/recebimento de dados HTTP
// Timer das requisições GET da interface Web do media player VLC
if (millis() - timerGetHttp > 500) {// Verifica se o intervalo de tempo para a próxima requisição GET da interface Web do media player VLC foi atingido
HTTPClient http;// Inicialização do objeto HTTPClient
String url; // Declara uma variável do tipo String chamada url
// Concatenações na variável url
url += "http://";
url += ipServerVlc;
url += ":";
url += portaServerVlc;
url += "/requests/status.xml";
http.begin(url); // Inicia a comunicação HTTP com a URL especificada
http.setAuthorization("", senhaVlc); // Define a autorização para a requisição HTTP (usuário vazio, senha senhaVlc)
http.setConnectTimeout(100); // Define o tempo limite de conexão para 100 milissegundos
int httpCode = http.GET();// Realiza uma requisição HTTP GET e armazena o código de resposta na variável httpCode
// O cabeçalho HTTP foi enviado e o cabeçalho de resposta do servidor foi tratado
if (httpCode > 0) {
if (httpCode == HTTP_CODE_OK) { // O endereço foi encontrado no servidor
conexaoPerdida = false; // Define a variável conexaoPerdida como false, indicando que a conexão não foi perdida
String response = http.getString(); // Obtém a resposta do servidor como uma String
atualizaVariaveis(response); // atualiza as variáveis de armazenamento chamando a função atualizaVariaveis passando a resposta do servidor como argumento
} else if (httpCode == HTTP_CODE_UNAUTHORIZED) { // se não tiver permissão para acessar o endereço no servidor
Serial.println("As credenciais de acesso estão incorretas. Corrija-as e tente novamente."); // Imprime mensagem no monitor serial
delay(5000);// Aguarda 5 segundos
}
} else { // se houve algum outro erro, ...
Serial.println("[HTTP] GET... falhado");
conexaoPerdida = true; // Define a variável conexaoPerdida como true, indicando que a conexão com o VLC foi perdida
}
http.end(); // Finaliza a conexão HTTP
timerGetHttp = millis(); // Atualiza o timer para controle do intervalo entre requisições HTTP
}
delay(1); // delay antitravamento do core do ESP32
}
void loop2(void* z) { // destinado ao gerenciamento da interface do usuário 9dispaly e joystick)
// Mostra pela primeira vez a interface no display
showRetroceder(); // mostra no display o ícone de Retroceder
showAvancar(); // mostra no display o ícone de Avançar
showPlayPause(); // mostra no display o ícone de Play/Pause
showVolume(); // mostra no display o Volume
showPosicao(); // mostra no display a Posição da mídia
u8g2.sendBuffer(); // Envia o buffer atualizado para o display
while (1) { // entra em um loop infinito
if (conexaoPerdida) { // Verificação e espera da reconexão em caso de perda de conexão
u8g2.clear(); // Limpa o display
u8g2.clearBuffer(); // Limpa o buffer do display
u8g2.setFont(u8g2_font_ncenB08_tr); // Define a fonte para exibição de texto
u8g2.drawStr(0, 10, "Reconectando..."); // Exibe mensagem no display
u8g2.setCursor(0, 30); // Configura a posição do cursor no display
u8g2.sendBuffer(); // Envia o buffer para o display
while (conexaoPerdida) { // enquanto houver conexão perdida
delay(1500); // Aguarda 1,5 segundos
u8g2.print("."); // Exibe um ponto no display
u8g2.sendBuffer(); // Envia o buffer para o display
}
u8g2.setCursor(0, 40); // Posiciona o cursor no display
u8g2.print("OK"); // Exibe "OK" no display
u8g2.sendBuffer(); // Envia o buffer para o display
delay(1000); // Aguarda 1 segundo
u8g2.clear(); // Limpa o conteúdo do display
}
if (analogRead(joyX) > 4000) { // se a leitura analógica do pino do eixo X do joystick for maior que 4000, ...
Serial.println("Para esquerda"); // Imprime "Para esquerda" na porta serial
uint8_t width = showRetroceder(); // Mostra o elemento retroceder e obtém a largura dele
u8g2.drawFrame(31, 51, width + 1, 13); // Desenha um quadro na posição especificada com base na largura obtida
u8g2.sendBuffer(); // Envia o buffer para o display
textNomeX = 10; // Define o valor de textNomeX como 10
// Se o joystick continuar pressionado, nehuma ação de retroceder deve ser tomada, apenas atualizações da interface do display deve ser feita
while (analogRead(joyX) > 4000) {
delay(1); // Aguarda 1 milissegundo
showVolume(); // Exibe o volume
showPosicao(); // Exibe a posição
showNome(); // Exibe o nome
showAlbum(); // Exibe o álbum
u8g2.sendBuffer(); // Envia o buffer para o display
}
HTTPClient http; // Instanciação do objeto HTTPClient
String url; // Declaração da variável String para armazenar a URL
// Construção da URL com o endereço IP do servidor VLC e a porta 8080
url += "http://";
url += ipServerVlc;
url += ":8080/requests/status.xml?command=pl_previous";
http.begin(url); // Inicialização da conexão HTTP com a URL construída
http.setAuthorization("", senhaVlc); // Configuração da autorização (usuário vazio e senha senhaVlc)
int httpCode = http.GET(); // Envio da solicitação HTTP tipo GET e armazenamento do código de resposta
if (httpCode > 0) {
// Verificação do código de resposta
if (httpCode == HTTP_CODE_UNAUTHORIZED) {
Serial.println("As credenciais de acesso estão incorretas. Corrija-as e tente novamente.");
delay(5000);
}
} else {
// Tratamento de erro em caso de falha na requisição
Serial.printf("[HTTP] GET... falhou, erro: %s\n", http.errorToString(httpCode).c_str());
}
http.end(); // Finalização da conexão HTTP
u8g2.setDrawColor(0); // Definição da cor de desenho como 0 (preto)
u8g2.drawFrame(31, 51, width + 1, 13); // Desenho do contorno do quadro na posição especificada
u8g2.setDrawColor(1); // Restauração da cor de desenho para 1 (branco)
u8g2.sendBuffer(); // Envio do buffer para o display
}
if (analogRead(joyX) < 100) { // se a leitura analógica do pino do eixo X do joystick for menor que 100, ...
Serial.println("Para direita"); // Imprime mensagem no monitor serial
textNomeX = 10; // Define a posição inicial do texto
uint8_t width = showAvancar(); // Mostra o elemento avançar e obtém a largura dele
u8g2.drawFrame(80, 51, width + 1, 13); // Desenha um quadro ao redor
u8g2.sendBuffer(); // Envia o buffer para o display
// Se o joystick continuar pressionado, nehuma ação de avançar deve ser toamda, apenas atualizações da interface do display deve ser feita
while (analogRead(joyX) < 100) {
delay(1); // Aguarda 1 milissegundo
showVolume(); // Exibe o volume no display
showPosicao(); // Exibe a posição no display
showNome(); // Exibe o nome no display
showAlbum(); // Exibe o álbum no display
u8g2.sendBuffer(); // Envia o buffer para o display
}
HTTPClient http; // Objeto para fazer requisições HTTP
String url; // String para armazenar a URL da requisição
url += "http://";
url += ipServerVlc;
url += ":8080/requests/status.xml?command=pl_next";
http.begin(url); // Inicia a conexão HTTP
http.setAuthorization("", senhaVlc); // Configura a autorização (usuário e senha)
int httpCode = http.GET(); // Envia a requisição GET e armazena o código de resposta
if (httpCode > 0) { // Verifica se a resposta foi recebida com sucesso
if (httpCode == HTTP_CODE_UNAUTHORIZED) { // caso a resposta seja informando que a requisição não tem autorização de acesso, ...
Serial.println("As credenciais de acesso estão incorretas. Corrija-as e tente novamente.");
delay(5000); // pausa de 5 segundos
}
} else { // se a resposta foi um erro, ...
Serial.printf("[HTTP] GET... falhado, erro: %s\n", http.errorToString(httpCode).c_str()); // mostra o erro na Serial
}
http.end();// Encerra a conexão HTTP
u8g2.setDrawColor(0); // define a cor de desenho como 0 (preto)
u8g2.drawFrame(80, 51, width + 1, 13); // desenha um retângulo transparente na posição especificada
u8g2.setDrawColor(1); // define a cor de desenho para 1 (branco)
u8g2.sendBuffer(); // envia o buffer para o display
}
if (analogRead(joyY) < 100) { // se a leitura analógica do pino do eixo Y do joystick for menor que 100, ...
unsigned long timer = millis(); // obtém o tempo atual em milissegundos
bool flag = true; // variável para controle do volume
while (analogRead(joyY) < 100) { // enquanto a leitura do joystick indica movimento para cima
Serial.println("Para cima");
showVolume(); // exibe o volume no display
showPosicao(); // exibe a posição no display
u8g2.sendBuffer(); // envia o buffer para o display
if (millis() - timer > 1000) { // se passou mais de 1 segundo desde o último ajuste de volume, aumenta o volume em velocidade maior
volumeVLC = volume;
volume += 10;// aumenta o volume em 10 unidades
if (volume > 512) {
volume = 512; // limita o volume máximo a 512
}
setVolume(); // ajusta o volume no VLC
} else { // se não, aumenta o volume em velocidade normal
volumeVLC = volume;
if (flag == true) {
flag = false;
if (volume < 512) {
volume += 1; // aumenta o volume em 1 unidade
setVolume(); // ajusta o volume no VLC
}
} else {
if (millis() - timer > 500) {
if (volume < 512) {
volume += 1;// aumenta o volume em 1 unidade
setVolume();// ajusta o volume no VLC
}
}
}
}
delay(1);// aguarda 1 milissegundo
}
}
if (analogRead(joyY) > 4000) { // se a leitura analógica do pino do eixo Y do joystick for maior que 4000, ...
unsigned long timer = millis(); // obtém o tempo atual em milissegundos
bool flag = true; // sinalizador para controle do volume
while (analogRead(joyY) > 4000) { // enquanto a leitura do joystick indica movimento para baixo
Serial.println("Para baixo");
showVolume(); // exibe o volume no display
showPosicao(); // exibe a posição no display
u8g2.sendBuffer(); // envia o buffer para o display
if (millis() - timer > 1000) { // se passou mais de 1 segundo desde o último ajuste de volume
volumeVLC = volume;
volume -= 10; // reduz o volume em 10 unidades
if (volume < 0) {
volume = 0; // limita o volume mínimo a 0
}
setVolume(); // ajusta o volume no VLC
} else {
volumeVLC = volume;
if (flag == true) {
flag = false;
if (volume > 0) {
volume -= 1; // reduz o volume em 1 unidade
setVolume(); // ajusta o volume no VLC
}
} else {
if (millis() - timer > 500) {
if (volume > 0) {
volume -= 1; // reduz o volume em 1 unidade
setVolume(); // ajusta o volume no VLC
}
}
}
}
delay(1); // aguarda 1 milissegundo
}
}
if (digitalRead(pushButton) == false) { // se o botão foi pressionado
Serial.println("Clique"); // exibe mensagem no console
setStatusPlayer(!statusPlayer); // inverte o estado do player (play/pause)
showPlayPause(); // exibe o ícone de play/pause no display
u8g2.sendBuffer(); // envia o buffer para o display
while (digitalRead(pushButton) == false) { // enquanto o botão estiver pressionado
delay(1); // aguarda 1 milissegundo
showVolume(); // exibe o volume no display
showPosicao(); // exibe a posição no display
u8g2.sendBuffer(); // envia o buffer para o display
}
}
delay(1); // aguarda 1 milissegundo
// Atualiza a interface no display
showNome();// mostra no display o nome da mídia
showAlbum();// mostra no display o nome do álbum da mídia
showRetroceder(); // mostra no display o ícone de Retroceder
showAvancar(); // mostra no display o ícone de Avançar
showPlayPause(); // mostra no display o ícone de Play/Pause
showVolume(); // mostra no display o Volume
showPosicao(); // mostra no display a Posição da mídia
u8g2.sendBuffer(); // Envia o buffer atualizado para o display
}
delay(1); // aguarda 1 milissegundo
}
bool verificarConexaoVlc() {
HTTPClient http; // Cria uma instância do objeto HTTPClient para fazer requisições HTTP
http.begin("http://" + ipServerVlc + ":" + portaServerVlc); // Inicia a comunicação HTTP com o servidor VLC
int httpCode = http.GET(); // Realiza uma requisição GET e armazena o código de resposta
http.end(); // Encerra a conexão HTTP
if (httpCode > 0) { // Verifica se o código de resposta é maior que zero (indica uma resposta válida)
return true; // Retorna verdadeiro se a conexão for bem-sucedida
}
return false; // Retorna falso se a conexão não for bem-sucedida ou ocorrer um erro
}
uint8_t showRetroceder() {
u8g2.setFont(u8g2_font_unifont_t_symbols); // Define a fonte para unifont_t_symbols
uint16_t encoding = 9184 + 15 - 1; // Calcula o valor de codificação para o símbolo de retroceder
return u8g2.drawGlyph(32, 62, encoding); // Desenha o símbolo na posição (32, 62) no display gráfico
}
uint8_t showAvancar() {
u8g2.setFont(u8g2_font_unifont_t_symbols); // Define a fonte para unifont_t_symbols
uint16_t encoding = 9184 + 14 - 1; // Calcula o valor de codificação para o símbolo de avançar
return u8g2.drawGlyph(81, 62, encoding); // Desenha o símbolo na posição (81, 62) no display gráfico
}
void showPlayPause() {
u8g2.setFont(u8g2_font_unifont_t_symbols); // Define a fonte para unifont_t_symbols
u8g2.setCursor(0, 0); // Define a posição do cursor no display gráfico
if (statusPlayer == true) {
u8g2.drawGlyph(56, 63, 9200 + 9 - 1); // Desenha o símbolo de reprodução na posição (56, 63)
} else {
u8g2.drawGlyph(57, 63, 9200 + 6 - 1); // Desenha o símbolo de pausa na posição (57, 63)
}
}
void showVolume() {
// Desenha o contorno externo do indicador de volume
u8g2.drawFrame(2, 2, 6, 60);
// Define a fonte para u8g2_font_squeezed_b6_tr
u8g2.setFont(u8g2_font_squeezed_b6_tr);
u8g2.setFontDirection(0);
// Desenha o contorno interno do indicador de volume
u8g2.drawFrame(4, 4, 2, 56);
// Calcula a altura do indicador com base no volume
int vol = round((volume / 5.12) * 2);
int h = map(vol, 0, 200, 55, 0);
// Define a cor de desenho como preto
u8g2.setDrawColor(0);
// Desenha o indicador de volume preenchido
if (vol == 0) {
u8g2.drawFrame(4, 4, 2, 56);
} else {
u8g2.drawFrame(4, 4, 2, h);
}
// Define a cor de desenho como preto
u8g2.setDrawColor(0);
// Desenha a parte inferior do indicador
u8g2.drawBox(9, 56, 15, 6);
// Define a cor de desenho como branco
u8g2.setDrawColor(1);
// Posiciona o cursor e imprime o valor do volume
u8g2.setCursor(9, 62);
u8g2.print(vol);
}
void showPosicao() {
u8g2.drawFrame(10, 40, 116, 6); // desenha um retângulo para indicar a barra de progresso
u8g2.setDrawColor(0); // define a cor de desenho como 0 (preto)
u8g2.drawFrame(12, 42, 112, 2); // desenha a linha de progresso
u8g2.drawBox(10, 30, 116, 10); // desenha a área de fundo da barra de progresso
u8g2.setDrawColor(1); // redefine a cor de desenho como 1 (branco)
u8g2.setFont(u8g2_font_squeezed_b6_tr); // define a fonte para o texto
// Calcula e exibe o tempo atual no formato MM:SS
int minutos = int(position * lengthMidia) / 60; // calcula os minutos
int segundos = int(position * lengthMidia) % 60; // calcula os segundos
String tempoFormatado = minutos < 10 ? "0" + String(minutos) : String(minutos); // formata os minutos
tempoFormatado += ":"; // adiciona dois pontos entre minutos e segundos
tempoFormatado += segundos < 10 ? "0" + String(segundos) : String(segundos); // formata os segundos
u8g2.setCursor(11, 37); // define a posição para exibir o tempo
u8g2.print(tempoFormatado); // exibe o tempo formatado
// Calcula e exibe o tempo total da mídia no formato MM:SS
minutos = lengthMidia / 60; // calcula os minutos totais
segundos = lengthMidia % 60; // calcula os segundos totais
tempoFormatado = minutos < 10 ? "0" + String(minutos) : String(minutos); // formata os minutos
tempoFormatado += ":"; // adiciona dois pontos entre minutos e segundos
tempoFormatado += segundos < 10 ? "0" + String(segundos) : String(segundos); // formata os segundos
u8g2.setCursor(128 - 2 - u8g2.getStrWidth(tempoFormatado.c_str()), 37); // define a posição para exibir o tempo total
u8g2.print(tempoFormatado); // exibe o tempo total formatado
// Calcula e desenha a porcentagem de progresso na barra
float percentual = position * 100; // calcula a porcentagem de progresso
int w = map(percentual, 0, 100, 0, 112); // mapeia a porcentagem para a largura da barra
u8g2.drawFrame(12, 42, w, 2); // desenha a parte preenchida da barra
}
void setVolume(bool comVerificacao) { // Define a função 'setVolume' com um parâmetro booleano 'comVerificacao'
int volumeAtual = volumeVLC; // Declara e inicializa a variável 'volumeAtual' com o valor do volume do VLC
if (volume != 0) { // Verifica se o volume não é zero
while (round((volumeAtual / 5.12) * 2) == round((volume / 5.12) * 2)) { // Inicia um loop enquanto o volume do VLC não é alterado
bool flag; // Declara uma variável booleana 'flag'
if (volume < volumeAtual) {
flag = true; // Atribui verdadeiro à 'flag' se o volume é menor que 'volumeAtual'
} else {
flag = false; // Atribui falso à 'flag' se o volume não é menor que 'volumeAtual'
}
if (flag != true) { // Verifica se 'flag' não é verdadeiro
if (volume < 512) {
volume++; // Incrementa o volume se for menor que 512
} else {
break; // Sai do loop se o volume atingir 512
}
} else {
if (volume > 0) {
volume--; // Decrementa o volume se for maior que zero
} else {
break; // Sai do loop se o volume atingir zero
}
}
}
}
showVolume(); // Chama a função 'showVolume' para exibir o volume no display
HTTPClient http; // Declara uma instância do cliente HTTP
String url; // Declara uma variável String 'url'
url += "http://";
url += ipServerVlc; // Concatena o endereço IP do servidor VLC à 'url'
url += ":8080/requests/status.xml?command=volume&val="; // Concatena o restante da URL para ajustar o volume
url += volume; // Concatena o valor do volume à 'url'
http.begin(url); // Inicia a conexão HTTP com a 'url'
http.setAuthorization("", senhaVlc); // Configura as credenciais de acesso
int httpCode = http.GET(); // Envia uma solicitação HTTP GET e armazena o código de resposta
if (httpCode > 0) { // Verifica se a solicitação foi bem-sucedida
if (httpCode == HTTP_CODE_UNAUTHORIZED) {
Serial.println("As credenciais de acesso estão incorretas. Corrija-as e tente novamente."); // Imprime uma mensagem se as credenciais estiverem incorretas
delay(5000); // Aguarda 5 segundos em caso de credenciais incorretas
}
} else {
Serial.printf("[HTTP] GET... falhado, erro: %s\n", http.errorToString(httpCode).c_str()); // Imprime uma mensagem de erro em caso de falha na solicitação HTTP
}
http.end(); // Encerra a conexão HTTP
}
void setStatusPlayer(bool status) { // Define a função 'setStatusPlayer' com um parâmetro booleano 'status'
HTTPClient http; // Declara uma instância do cliente HTTP
String url; // Declara uma variável String 'url'
url += "http://";
url += ipServerVlc; // Concatena o endereço IP do servidor VLC à 'url'
url += ":8080/requests/status.xml?command=pl_pause"; // Concatena o restante da URL para pausar ou retomar a reprodução
http.begin(url); // Inicia a conexão HTTP com a 'url'
http.setAuthorization("", senhaVlc); // Configura as credenciais de acesso
int httpCode = http.GET(); // Envia uma solicitação HTTP GET e armazena o código de resposta
if (httpCode > 0) { // Verifica se a solicitação foi bem-sucedida
if (httpCode == HTTP_CODE_OK) {
String response = http.getString(); // Obtém a resposta do servidor e armazena em 'response'
atualizaVariaveis(response); // Chama a função 'atualizaVariaveis' para atualizar as variáveis com base na resposta do servidor
} else if (httpCode == HTTP_CODE_UNAUTHORIZED) {
Serial.println("As credenciais de acesso estão incorretas. Corrija-as e tente novamente."); // Imprime uma mensagem se as credenciais estiverem incorretas
delay(5000); // Aguarda 5 segundos em caso de credenciais incorretas
}
} else {
Serial.printf("[HTTP] GET... falhado, erro: %s\n", http.errorToString(httpCode).c_str()); // Imprime uma mensagem de erro em caso de falha na solicitação HTTP
}
http.end(); // Encerra a conexão HTTP
}
int getVolume() { // Define a função 'getVolume' que retorna um inteiro
int vol; // Declaração da variável inteira 'vol'
String textXML; // Declaração da variável String 'textXML' para armazenar o XML
HTTPClient http; // Declaração de uma instância do cliente HTTP
String url; // Declaração da variável String 'url'
url += "http://";
url += ipServerVlc; // Concatena o endereço IP do servidor VLC à 'url'
url += ":8080/requests/status.xml"; // Concatena o restante da URL para obter o status
http.begin(url); // Inicia a conexão HTTP com a 'url'
http.setAuthorization("", senhaVlc); // Configura as credenciais de acesso
int httpCode = http.GET(); // Envia uma solicitação HTTP GET e armazena o código de resposta
if (httpCode > 0) { // Verifica se a solicitação foi bem-sucedida
if (httpCode == HTTP_CODE_OK) { // Verifica se o código de resposta é OK
textXML = http.getString(); // Obtém a resposta do servidor e armazena em 'textXML'
String aRemover = textXML.substring(textXML.indexOf("<?xml"), textXML.indexOf(" ?>") + 3); // Encontra e remove a declaração XML
textXML.replace(aRemover, ""); // Remove a declaração XML da string 'textXML'
tinyxml2::XMLDocument xmlDocument; // Declaração de um documento XML
if (xmlDocument.Parse(textXML.c_str()) != tinyxml2::XML_SUCCESS) { // Verifica se o parsing do XML foi bem-sucedido
Serial.println("Erro ao fazer parsing"); // Imprime uma mensagem em caso de erro no parsing
} else {
tinyxml2::XMLNode* root = xmlDocument.FirstChild(); // Obtém o nó raiz do documento XML
tinyxml2::XMLElement* element = root->FirstChildElement("volume"); // Obtém o elemento 'volume' do XML
element->QueryIntText(&vol); // Converte o texto do elemento 'volume' para um inteiro e armazena em 'vol'
}
} else if (httpCode == HTTP_CODE_UNAUTHORIZED) {
Serial.println("As credenciais de acesso estão incorretas. Corrija-as e tente novamente."); // Imprime uma mensagem se as credenciais estiverem incorretas
delay(5000); // Aguarda 5 segundos em caso de credenciais incorretas
}
} else {
Serial.printf("[HTTP] GET... falhou, erro: %s\n", http.errorToString(httpCode).c_str()); // Imprime uma mensagem de erro em caso de falha na solicitação HTTP
}
http.end(); // Encerra a conexão HTTP
return vol; // Retorna o valor do volume obtido do servidor VLC
}
String requestVlc() { // Define a função 'requestVlc' que retorna uma String
String response; // Declaração da variável String 'response' para armazenar a resposta do servidor VLC
HTTPClient http; // Declaração de uma instância do cliente HTTP
String url; // Declaração da variável String 'url'
url += "http://";
url += ipServerVlc; // Concatena o endereço IP do servidor VLC à 'url'
url += ":8080/requests/status.xml"; // Concatena o restante da URL para obter o status
http.begin(url); // Inicia a conexão HTTP com a 'url'
http.setAuthorization("", senhaVlc); // Configura as credenciais de acesso
int httpCode = http.GET(); // Envia uma solicitação HTTP GET e armazena o código de resposta
if (httpCode > 0) { // Verifica se a solicitação foi bem-sucedida
if (httpCode == HTTP_CODE_OK) { // Verifica se o código de resposta é OK
response = http.getString(); // Obtém a resposta do servidor e armazena em 'response'
} else if (httpCode == HTTP_CODE_UNAUTHORIZED) {
Serial.println("As credenciais de acesso estão incorretas. Corrija-as e tente novamente."); // Imprime uma mensagem se as credenciais estiverem incorretas
delay(5000); // Aguarda 5 segundos em caso de credenciais incorretas
}
} else {
Serial.printf("[HTTP] GET... falhou, erro: %s\n", http.errorToString(httpCode).c_str()); // Imprime uma mensagem de erro em caso de falha na solicitação HTTP
}
http.end(); // Encerra a conexão HTTP
return response; // Retorna a resposta obtida do servidor VLC
}
void atualizaVariaveis(String textXML) { // Define a função 'atualizaVariaveis' que recebe uma String 'textXML'
String aRemover = textXML.substring(textXML.indexOf("<?xml"), textXML.indexOf(" ?>") + 3); // Obtém a substring da declaração XML da String
textXML.replace(aRemover, ""); // Remove a declaração XML da String 'textXML'
tinyxml2::XMLDocument xmlDocument; // Declaração de uma instância da classe XMLDocument do TinyXML2
if (xmlDocument.Parse(textXML.c_str()) != tinyxml2::XML_SUCCESS) { // Verifica se o parsing do XML foi bem-sucedido
Serial.println("Erro ao fazer o parsing do XML"); // Imprime uma mensagem de erro em caso de falha no parsing
} else {
tinyxml2::XMLNode* root = xmlDocument.FirstChild(); // Obtém o nó raiz do XML
tinyxml2::XMLElement* element = root->FirstChildElement("volume"); // Obtém o elemento 'volume' do XML
int _volume;
element->QueryIntText(&_volume); // Extrai o valor do volume do XML
String _state = root->FirstChildElement("state")->GetText(); // Obtém o estado (playing/pausado) do XML
tinyxml2::XMLElement* categoriaElementos = root->FirstChildElement("information")
->FirstChildElement("category"); // Obtém o primeiro elemento 'category' dentro de 'information'
while (categoriaElementos) { // Loop para percorrer todos os elementos 'category'
tinyxml2::XMLElement* infoElementos = categoriaElementos->FirstChildElement("info"); // Obtém o primeiro elemento 'info' dentro de 'category'
bool atualizaNomeMidia = true;
while (infoElementos) { // Loop para percorrer todos os elementos 'info' dentro de 'category'
const char* attributeName = infoElementos->Attribute("name"); // Obtém o atributo 'name' do elemento 'info'
if (attributeName && strcmp(attributeName, "title") == 0) { // caso o atributo 'name' seja "title"
nomeMidia = infoElementos->GetText(); // Atualiza o nome da mídia
atualizaNomeMidia = false;
} else if (atualizaNomeMidia && attributeName && strcmp(attributeName, "filename") == 0) { // se o atributo 'name' for "filename" e ainda não foi atualizado
nomeMidia = infoElementos->GetText(); // Atualiza o nome da mídia
}
if (attributeName && strcmp(attributeName, "album") == 0) { // se o atributo 'name' for "album"
albumMidia = infoElementos->GetText(); // Atualiza o álbum da mídia
}
infoElementos = infoElementos->NextSiblingElement("info"); // Move para o próximo elemento 'info'
}
categoriaElementos = categoriaElementos->NextSiblingElement("category"); // Move para o próximo elemento 'category'
}
volume = _volume; // Atualiza a variável 'volume' com o valor obtido do XML
root->FirstChildElement("position")->QueryFloatText(&position); // Obtém e atualiza a posição da mídia do XML
root->FirstChildElement("length")->QueryIntText(&lengthMidia); // Obtém e atualiza o comprimento da mídia do XML
statusPlayer = _state == "playing" ? true : false; // Atualiza o status do player com base no estado obtido do XML
}
}
void showNome() { // Define a função 'showNome'
u8g2.setFont(u8g2_font_unifont_t_symbols); // Define a fonte do display para 'u8g2_font_unifont_t_symbols'
u8g2.setDrawColor(0); // Define a cor de desenho como 0 (preto)
u8g2.drawBox(9, 0, 128 - 9, 14); // Desenha uma caixa preta no buffer
u8g2.setDrawColor(1); // Define a cor de desenho como 1 (branco)
// Desenha o texto no buffer
u8g2.setCursor(textNomeX, 12);
u8g2.print(nomeMidia);
u8g2.setDrawColor(0); // Define a cor de desenho como 0 (preto)
u8g2.drawBox(0, 0, 9, 14); // Desenha uma caixa preta no canto esquerdo do buffer
u8g2.setDrawColor(1); // Define a cor de desenho como 1 (branco)
showVolume(); // Chama a função 'showVolume'
// Envia o buffer para o display
u8g2.sendBuffer();
if (textNomeX == 10) { // Verifica se a posição X do texto é 10
if (millis() - timerNome > 1000) { // Verifica se passou 1 segundo desde a última atualização
timerNome = millis(); // Atualiza o temporizador
textNomeX = 0; // Reinicia a posição X para reiniciar a rolagem
}
} else { // Caso contrário
if (millis() - timerNome > 700) { // Verifica se passou 700 milissegundos desde a última atualização
textNomeX -= 25; // Atualiza a posição X para fazer a rolagem
u8g2.setFont(u8g2_font_unifont_t_symbols); // Define a fonte do display para 'u8g2_font_unifont_t_symbols'
int w = u8g2.getStrWidth(nomeMidia.c_str()); // Obtém a largura do texto
if (textNomeX + w <= 0) { // Verifica se o texto passou completamente pela tela
textNomeX = 10; // Reinicia a posição X para reiniciar a rolagem
}
timerNome = millis(); // Atualiza o temporizador
}
}
}
void showAlbum() { // Define a função 'showAlbum'
u8g2.setFont(u8g2_font_6x12_t_symbols); // Define a fonte do display para 'u8g2_font_6x12_t_symbols'
u8g2.setDrawColor(1); // Define a cor de desenho como 1 (branco)
u8g2.setCursor(10, 23); // Define a posição do cursor para desenhar o texto
u8g2.print(albumMidia); // Imprime o texto referente ao álbum
}
/******************************************************************************
Controlando o media player VLC de um PC via joystick no ESP32
Criado em 16 de Janeiro de 2024
por Michel Galvão (https://micsg.com.br)
Credenciais
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Definição das credenciais de rede Wi-Fi
const char* ssid = "<SSID>"; // Substitua <SSID> pelo nome da sua rede Wi-Fi
const char* password = "<SENHA>"; // Substitua <SENHA> pela senha da sua rede Wi-Fi
const char* senhaVlc = "<SENHA_VLC>";// Substitua <SENHA_VLC> pela senha utilizada para acessar a interface Web lua do media player VLC/******************************************************************************
Controlando o media player VLC de um PC via joystick no ESP32
Criado em 16 de Janeiro de 2024
por Michel Galvão (https://micsg.com.br)
Imagem Bitmap de Splash Screen
Eletrogate - Loja de Arduino \\ Robótica \\ Automação \\ Apostilas \\ Kits
https://www.eletrogate.com/
******************************************************************************/
// Definição de um array de bytes para uma tela de inicialização (splash screen)
static const unsigned char splashScreen [] PROGMEM = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xc0, 0xff, 0x03, 0x00, 0x00, 0xe0, 0xff, 0x01,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0xff, 0x1f, 0x00,
0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xfc, 0xff, 0x3f, 0x00, 0x00, 0xff, 0xff, 0x1f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x7f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x01,
0xe0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xc0,
0xff, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0xff, 0x01, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xe0, 0xff, 0xab, 0xff, 0x07, 0xf0, 0xff, 0xea, 0xff,
0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0xfc, 0x0f,
0xfc, 0x1f, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0,
0x1f, 0x00, 0xf8, 0x1f, 0xfc, 0x07, 0x00, 0xfc, 0x07, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0xe0, 0x3f, 0xfe, 0x03, 0x00, 0xf8,
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x03, 0x00, 0xc0, 0x7f,
0xff, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x03, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00, 0xe0, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x0f, 0xc0,
0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x01, 0x00, 0x00, 0xff,
0x3f, 0x00, 0x0f, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
0x00, 0x00, 0x00, 0xfe, 0x1f, 0x00, 0x0f, 0x80, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfe, 0x80, 0xed, 0x01, 0xfc, 0x1f, 0xa0, 0x2f, 0x80,
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0xff, 0x03, 0xf8,
0x0f, 0xe0, 0x7f, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
0xc0, 0xff, 0x03, 0xf8, 0x0f, 0xe0, 0xff, 0x80, 0x3f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfe, 0x80, 0xff, 0x03, 0xf8, 0x0f, 0xe0, 0x7f, 0x80,
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x80, 0xa4, 0x02, 0xfc,
0x0f, 0x00, 0x0f, 0x80, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfe,
0x00, 0x00, 0x00, 0xfc, 0x1f, 0x00, 0x0f, 0x80, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0x3f, 0x00, 0x0f, 0xc0,
0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x01, 0x00, 0x00, 0xff,
0x3f, 0x00, 0x0f, 0xc0, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xfc,
0x01, 0x00, 0x00, 0xff, 0x7f, 0x00, 0x00, 0xc0, 0x1f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x03, 0x00, 0xc0, 0xff, 0xff, 0x00, 0x00, 0xe0,
0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x07, 0x00, 0xc0, 0x3f,
0xff, 0x01, 0x00, 0xf0, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8,
0x0f, 0x00, 0xe0, 0x3f, 0xfe, 0x03, 0x00, 0xf8, 0x0f, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xf0, 0x1f, 0x00, 0xf8, 0x1f, 0xfc, 0x07, 0x00, 0xfc,
0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x7f, 0x00, 0xfc, 0x0f,
0xfc, 0x1f, 0x00, 0xff, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xe0,
0xff, 0xab, 0xff, 0x0f, 0xf0, 0xff, 0xea, 0xff, 0x03, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xc0, 0xff, 0xff, 0xff, 0x03, 0xf0, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0xff, 0xff, 0xff, 0x03,
0xc0, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xff, 0xff, 0xff, 0x00, 0x80, 0xff, 0xff, 0x3f, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xfc, 0xff, 0x7f, 0x00, 0x00, 0xff, 0xff, 0x1f,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf0, 0xff, 0x1f, 0x00,
0x00, 0xfc, 0xff, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0xc0, 0xff, 0x07, 0x00, 0x00, 0xf0, 0xff, 0x01, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x28, 0x80, 0x02, 0x10, 0x10, 0xa9, 0x82, 0x40,
0x80, 0x02, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x07, 0xff, 0xe1, 0x3f, 0x3c,
0x3c, 0xff, 0xf7, 0xe1, 0xf1, 0x0f, 0x00, 0x00, 0x00, 0x00, 0xc0, 0x0f,
0xff, 0xe7, 0xff, 0x3c, 0x3c, 0xff, 0xe7, 0xe3, 0xf9, 0x1f, 0x00, 0x00,
0x00, 0x00, 0xe0, 0x0f, 0xff, 0xe7, 0xff, 0x3c, 0x3c, 0xff, 0xf7, 0xe3,
0xfd, 0x1f, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x0f, 0x8f, 0xe7, 0xf1, 0x3d,
0x3c, 0x78, 0xe0, 0xe7, 0x3d, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xe0, 0x1f,
0x8f, 0xe7, 0xe1, 0x3d, 0x3c, 0xf8, 0xe0, 0xe7, 0x3d, 0x3c, 0x00, 0x00,
0x00, 0x00, 0xf0, 0x1f, 0x8f, 0xe7, 0xe1, 0x3d, 0x3c, 0x78, 0xf0, 0xef,
0x1f, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x1e, 0xff, 0xe7, 0xe1, 0x3f,
0x7c, 0xf8, 0xe0, 0xef, 0x1f, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x3e,
0xff, 0xe3, 0xe1, 0x3d, 0x3c, 0x78, 0xf0, 0xff, 0x1f, 0x3c, 0x00, 0x00,
0x00, 0x00, 0x70, 0x3c, 0xff, 0xe1, 0xe1, 0x3f, 0x3c, 0xf8, 0xe0, 0xfe,
0x1e, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f, 0xff, 0xe3, 0xe1, 0x3d,
0x3c, 0x78, 0xf0, 0xfe, 0x1f, 0x3c, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x3f,
0xcf, 0xe3, 0xe1, 0x3d, 0x3c, 0xf8, 0xe0, 0xfc, 0x3d, 0x3c, 0x00, 0x00,
0x00, 0x00, 0xf8, 0x7f, 0xcf, 0xe7, 0xf1, 0x3d, 0x3c, 0x78, 0xf0, 0xfc,
0x3f, 0x3e, 0x00, 0x00, 0x00, 0x00, 0xfc, 0x7f, 0x8f, 0xe7, 0xff, 0xfc,
0x3e, 0xff, 0xe7, 0xf8, 0xfd, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x78,
0x8f, 0xef, 0x7f, 0xf8, 0x1f, 0xff, 0xf7, 0xf8, 0xf9, 0x1f, 0x00, 0x00,
0x00, 0x00, 0x3c, 0xf8, 0x0f, 0xef, 0x3f, 0xf0, 0x0f, 0xff, 0xe7, 0xf1,
0xf9, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x14, 0x20, 0x0d, 0xab, 0x06, 0xc0,
0x07, 0xaa, 0x62, 0x40, 0xc0, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00 };Aqui está um resumo explicativo com base no código:
showNome() e showAlbum() são responsáveis por exibir informações, como nome da mídia e álbum, em um display usando a biblioteca U8g2.Veja no vídeo abaixo o funcionamento do projeto:
|
A Eletrogate é uma loja virtual de componentes eletrônicos do Brasil e possui diversos produtos relacionados à Arduino, Automação, Robótica e Eletrônica em geral.
Conheça a Metodologia Eletrogate e Lecione um Curso de Robótica nas Escolas da sua Região!