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!