100% acharam este documento útil (1 voto)
173 visualizações124 páginas

Robótica Com ESP32 e Arduino

O documento é um livro eletrônico intitulado 'Robótica com ESP32 e Arduino', que aborda a programação e aplicações do microcontrolador ESP32 em robótica. Ele inclui tutoriais práticos sobre circuitos, LEDs, botões, entradas analógicas, sensores e atuadores, além de projetos finais. O conteúdo é voltado para o ensino e aprendizado de robótica, utilizando ferramentas como Arduino IDE e Tinkercad.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd
100% acharam este documento útil (1 voto)
173 visualizações124 páginas

Robótica Com ESP32 e Arduino

O documento é um livro eletrônico intitulado 'Robótica com ESP32 e Arduino', que aborda a programação e aplicações do microcontrolador ESP32 em robótica. Ele inclui tutoriais práticos sobre circuitos, LEDs, botões, entradas analógicas, sensores e atuadores, além de projetos finais. O conteúdo é voltado para o ensino e aprendizado de robótica, utilizando ferramentas como Arduino IDE e Tinkercad.
Direitos autorais
© © All Rights Reserved
Levamos muito a sério os direitos de conteúdo. Se você suspeita que este conteúdo é seu, reivindique-o aqui.
Formatos disponíveis
Baixe no formato PDF, TXT ou leia on-line no Scribd

Copyright © 2024 by

Igor Rodrigues Cassimiro


João Guilherme Lourenço de Souza
Caio Lopes de Oliveira
Carlos Torturella Valadão
Marco Antonio de Souza Leite Cuadros
Marcelo Souza
Ilustrações Diagramação
Autores Lara Design Editorial

Revisão Capa
Pablo Santos Sheila Sana
[2024]
Todos os direitos reservados
CURSO DE ROBÓTICA ROBOTECH,
1ª EDIÇÃO, 2024
Serra, Espírito Santo

É proibida a reprodução total e parcial desta obra, de qualquer forma ou por qualquer
meio eletrônico, mecânico, inclusive por meio de processos xerográficos, incluindo ainda
o uso da internet, sem permissão expressa dos escritores. (Lei 9.610 de 19/02/1998)

Dados Internacionais de Catalogação na Publicação (CIP)


(Câmara Brasileira do Livro, SP, Brasil)

Robótica com ESP32 e arduino [livro eletrônico] :


vol. 1 / Igor Cassimiro...[et al.]. -- 1. ed. --
Serra, ES : Robotech, 2024.
PDF

Outros autores: João de Souza, Caio Oliveira,


Carlos Valadão, Marcos Cuadros, Marcelo Souza
ISBN 978-65-983127-0-1

1. Arduino (Linguagem de programação para


computadores) 2. Linguagem de programação
(Computadores) 3. Robótica - Estudo e ensino
I. Cassimiro, Igor. II. Souza, João de.
III. Oliveira, Caio. IV. Valadão, Carlos.
V. Cuadros, Marcos. VI. Souza, Marcelo.

24-200117 CDD-372.358
Índices para catálogo sistemático:

1. Robótica : Estudo e ensino 372.358

Cibele Maria Dias - Bibliotecária - CRB-8/9427


SUMÁRIO

1. Programação Básica do ESP32 5


1.1 Que é o ESP32? 5
1.2 Caraterísticas do ESP32 6
1.3Como simular circuitos no Tinkercad – Primeiros Passos 7
1.4 Tutorial: como fazer login? 10
1.5 Circuitos simples de bateria e resistores Tinkercad 12
1.6 Instalação de Programas 14
1.7 Programas práticos e básicos usando o ESP-32 – Vamos às práticas 15

2. Revisão, leds e botões 16


2.1 Como fazer um pisca-pisca de dois Leds com e sem Delay 16
2.1.1 Pisca-pisca de dois Leds com Delay 16
2.1.2 Pisca-pisca de dois Leds sem Delay  19
2.2 Como usar botões no Esp32 21
2.2.1 Uso de botões com Delay 21
2.2.2 Uso de botões com detecção de borda 24
2.2.3 Uso de botões usando tempo anti-debounce 28
2.2.4 Uso de botões em tempo anti debounce com a biblioteca ezButton 31

3. Entradas Analógicas 33
3.1 Como realizar a leitura de uma entrada analógica e visualizar no
monitor serial 34
3.2 Controlando a velocidade de um sequencial de 5 leds usando uma
entrada analógica 37
3.3 Ligando 5 leds em função do nível de tensão de uma entrada ana-
lógica40
3.4 Plotando 3 entradas analógicas usando o serial plotter 42
3.5 Uso do Display OLED 47
4. Sensores51
4.1 Sensor de Luminosidade – LDR  52
4.2 Ultrassom 56
4.2.1 NTC – Resistor sensível à temperatura 58
4.2.2 NTC – Mostrando a temperatura num Display OLED 62
4.3 O DHT22 – Sensor de Umidade e Temperatura 65
4.3.1 Programa Básico do DHT22 66
4.3.2 Mostrando a umidade e temperatura medida pelo DHT22 num
display OLED 70
4.3.3 Medição da umidade e temperatura usando o DHT22 e DHT11
num display OLED 73
4.4 O MAX9814 – Sensor de som 77

5. Atuadores81
5.1. O PWM, modulação por largura de pulso 83
5.1.1. Controlando a luminosidade de um Led usando o PWM 83
5.1 Usando o PWM e entradas Analógicas 86
5.1.1 Regular a luminosidade de um Led com PWM usando um potenci-
ômetro86
5.2 Como usar um Led RGB 89
5.3 Buzzer, Passivo, produzindo SOM 93
5.4 Buzzer Passivo - construindo um mini piano 95
5.5 Buzzer Passivo, o hino de um time de futebol  98
5.6 Como ligar um motor de corrente contínua usando o LD298 102
5.7 Ligando um servomotor – controlando a posição de uma haste  104
5.8 Ligando um servomotor – controlando sua velocidade  105

6. Projetos Finais 106


6.1 Detector de linha 106
6.2 Montagem de um robô móvel usando motores CC 109
6.3 Montagem de um robô móvel usando servomotores 114
6.4 Exemplo do ensino de robótica - Montagem de um robô que mexe
cabeça e braços e pisca os olhos. 115
6.5 Exemplo prático de aplicação - montagem de uma garra que separa
bolas de isopor de cores diferentes 117

Sobre os autores 121


1.
PROGRAMAÇÃO
BÁSICA DO ESP32

1.1 Que é o ESP32?

O ESP32 é um microcontrolador desenvolvido pela Espressif


Systems, que possui uma vasta gama de aplicações no campo de
Internet das Coisas (IoT) e robótica, devido às suas capacidades
avançadas de conectividade que conta com Wi-Fi e Bluetooth e alto
poder de processamento com dois núcleos de 32 bits. Além disso,
o ESP32 oferece uma variedade de recursos, como interfaces para
periféricos, conversores analógico-digital (ADC), interfaces de co-
municação serial, GPIOs (General Purpose Input/Output), dentre
outros.
Uma das principais vantagens do ESP32 é sua flexibilidade e
capacidade de integração, podendo ser programado usando o Ar-
duino IDE, Micropython, ESP-IDF (Espressif IoT Development
Framework), dentre outras opções de desenvolvimento, o que faci-
lita a criação de projetos de robótica.

5
Figura 1 - Exemplo de placa de desenvolvimento baseada
em ESP-32 com formato similar ao Arduino.

1.2 Caraterísticas do ESP32

Característica Descrição
Arquitetura Xtensa LX6 (Dual-Core)
Frequência de clock Até 240 MHz
520 KB de SRAM (Static Random-Access Memory)
Memória 448 KB de ROM (Read-Only Memory)
4 MB de Flash SPI (Serial Peripheral Interface)
Wi-Fi 802.11 b/g/n
Conectividade
Bluetooth (Classic e BLE - Bluetooth Low Energy)
GPIOs (General Purpose Input/Output)
UART (Universal Asynchronous Receiver-Transmitter)
I2C (Inter-Integrated Circuit)
SPI (Serial Peripheral Interface)
ADC (Analog-to-Digital Converter)
Interfaces
DAC (Digital-to-Analog Converter)
PWM (Pulse Width Modulation)
I2S (Integrated Interchip Sound)
SD/MMC (Secure Digital/Multimedia Card)
USB (Universal Serial Bus)

6
Linguagens de Arduino IDE, Micropython, ESP-IDF (Espressif IoT
programação suportadas Development Framework)
Tensão de operação: 2,2V a 3,6V
Alimentação
Consumo de energia baixo
Internet das Coisas (IoT)
Automação residencial
Monitoramento e controle de dispositivos
Aplicações
Wearables (Dispositivos Vestíveis)
Sistemas de segurança
Robótica

1.3Como simular circuitos no Tinkercad – Primeiros


Passos

O software Tinkercad é o ambiente que utilizaremos para efe-


tuar simulações e colocar em prática a teoria estudada. Ele é um
software gratuito desenvolvido pela Autodesk, que pode ser utili-
zado para modelar projetos em 3D de forma rápida e fácil, além de
permitir executar simulações de circuitos projetados e até mesmo
preparar projetos para impressão 3D. Abaixo segue o tutorial de
acesso e criação de conta no ambiente:

1. Acesse https://www.Tinkercad.com e clique em inscrever-se.

Figura 2 - Página para inscrição no Tinkercad.

7
​2. Clique em Criar uma conta pessoal.


Figura 3 - Página do Tinkercad para criar uma conta pessoal.

3. Escolha uma opção se tiver uma conta do google (Gmail). Caso


faça login com o GMail, pule os passos abaixo.

Figura 4 - Inscrição usando e-mail da Google.

8
4. Caso você tenha escolhido a opção “Entrar com o e-mail” (opção
em azul), siga escolhendo o país e sua data de nascimento.

Figura 5 - Tela para criar conta.

5. Coloque seu e-mail e escolha uma senha para acessar o Tinker-


cad e clique em CRIAR CONTA.

Figura 6 - Local para colocar e-mail e senha


para finalizar a criação da conta.

9
6. Parabéns! Você criou sua conta.

Figura 7 - Tela mostrando que a conta foi criada.

1.4 Tutorial: como fazer login?

Para fazer login no Tinkercad, siga os passos:

1. Clique no botão indicado na Figura 7.

Figura 8 - Tela inicial do Tinkercad para fazer login e se inscrever.

10
2. Clique no link indicado na Figura 8.

Figura 9 - Tela para entrar na conta.

Figura 8: imagem 8 referente ao passo a passo para executar o


Tinkercad

3. Escolha uma opção de sua preferência, conforme mostrado na


Figura 9.

Figura 10 - Entrada via e-mail do Google,


conta Apple ou conta Autodesk.

4. Agora você está pronto para utilizar o software, projetando cir-


cuitos e as simulações que desejar.

11
1.5 Circuitos simples de bateria e resistores Tinkercad

Após finalizar o tutorial e efetuar o login no Tinkercad, vamos cli-


car em novo projeto e selecionar circuito, como mostra o tutorial abaixo.

Passo 1: após efetuar o login no site clique em “Novo”, como mostra


a figura abaixo.

Figura 11 - Tela inicial do Tinkercad com o


botão “Novo” (projeto) sinalizado.

Passo 2: Depois de efetuar o passo 1, selecione “circuito” e o am-


biente para modelagem e simulação será aberto.

Figura 12 - Seleção da opção para criar um novo circuito.

12
Dentro deste ambiente vamos começar a montar nossos primei-
ros circuitos. Em nosso primeiro exemplo vamos ligar uma bateria
em série com um resistor e efetuar a medição da corrente. Ao lado
direito do painel, que é apresentado para o usuário, estão todos os
componentes que podemos utilizar. Para este caso, será necessária:
uma bateria de 3 volts, um resistor, que será mantido com o valor
de 1 KΩ, além de um multímetro que utilizaremos para efetuar a
medição da corrente. Execute a montagem como mostra a figura
abaixo e verifique se a medição apresentada é condizente com valor
encontrado na fórmula da corrente, .

Figura 13 - Circuito com um resistor.

Agora, adicione um novo resistor ao circuito construído e verifique


o novo valor da corrente medida.

13
Figura 14 - Circuito com 2 resistores.

Ratifique que o valor apresentado no multímetro estará conforme


o esperado nesse novo caso. Como temos uma nova resistência de
1 KΩ no circuito, a resistência total se torna maior e a corrente que
circula se torna menor. É possível notar o valor de 1,49 mA apre-
sentado pelo software, enquanto no primeiro caso a medição foi
de 2,97 mA. Como foi observado, é preciso ligar o multímetro em
série com o circuito para efetuar a medição da corrente. Porém, no
caso de efetuar a medição da tensão em cima do resistor, é necessá-
rio efetuar a medição em paralelo.

1.6 Instalação de Programas

O software que será utilizado para programar a ESP-32 será o


Arduino IDE, onde se pode programar o ESP-32 utilizando a lin-
guagem C++. Para fazer a instalação do Arduino IDE, podemos
seguir os seguintes passos:

• Passo 1: acesse o site oficial do Arduino em https://www.ardui-


no.cc/.
• Passo 2: clique na seção “Software” no menu principal.

14
• Passo 3: na página do software, você verá as opções de Down-
load do “Arduino IDE para Windows, macOS e Linux. Escolha
a versão adequada ao seu sistema operacional e clique no link
correspondente.
• Passo 4: após o download do arquivo de instalação, abra-o e
siga as instruções do instalador.
• Passo 5: durante a instalação, você poderá escolher o local de
instalação e outras opções, como a adição de atalhos na área de
trabalho.
• Passo 6: após a conclusão da instalação, o Arduino IDE estará
pronto para ser usado.
• Passo 7: uma vez instalado, você pode conectar o seu Arduino
ao computador através de uma porta USB, abrir o Arduino IDE
e começar a programar e enviar o código para o seu Arduino.

1.7 Programas práticos e básicos usando o ESP-32 –


Vamos às práticas

Neste livro, veremos como fazer alguns programas básicos uti-


lizando o ESP-32, a fim de treinarmos conceitos e componentes
importantes. Inicialmente, faremos uma revisão e aprenderemos
sobre o controle de leds e de botões conectados ao ESP-32. Poste-
riormente, serão abordados os temas de entradas analógicas, sen-
sores e atuadores. Para finalizar, há um projeto final que engloba
todos os conceitos aprendidos no curso.

15
2.
REVISÃO, LEDS E BOTÕES

2.1 Como fazer um pisca-pisca de dois Leds com e


sem Delay

Nesta seção, veremos como fazer um pisca-pisca utilizando


LEDs. Primeiramente, vamos utilizar a função delay, que faz com
que o sistema aguarde sem realizar nenhuma operação. Posterior-
mente, faremos o mesmo pisca-pisca sem utilizar a função delay,
utilizando a contagem de tempo da função millis.

2.1.1 Pisca-pisca de dois Leds com Delay

No código abaixo, declaramos os pinos do led verde e do led


amarelo, representados respectivamente pelas variáveis ledPinVer-
de e ledPinAmarelo, cujos valores são respectivamente 2 e 4. O
estado do led é declarado na linha seguinte pela variável ledState e
é iniciado com o valor 0, ou seja, led apagado. Em seguida, é decla-
rada a variável do contador, que se inicia com zero.
A seguir, temos a função setup, que roda uma única vez dentro do
microcontrolador ESP-32 e serve para fazer as configurações iniciais.
Nesta função, os pinos do led vermelho e led amarelo, respectivamente
declarados pelas variáveis ledPinVerde e ledPinAmarelo, são defini-

16
dos como pino de saída por meio da função pinMode. Além disso, é
configurada a velocidade de comunicação serial em 9.600bps.
Posteriormente, há a função loop que roda continuamente. A
primeira linha da função loop, inverte o estado da variável, ledState,
e retorna para ela mesma. A seguir, as duas próximas linhas confi-
guram o valor dos leds verde e amarelo para o valor de ledState e o
inverso do valor de ledState. Após isso, o sistema aguarda 1000 ms,
ou seja, 1 s, e depois a variável contador é incrementada em uma
unidade. Para finalizar e voltar ao loop, o sistema envia para a porta
serial o valor do contador que pode ser lida pelo monitor serial.

/*
* Programando um pisca-pisca com delay no Esp32
* Nosso canal no Youtube: https://www.youtube.com/@
RoboTech-ProfeMC
*/
const int ledPinVerde = 2; // pino do esp32 ligado ao Led verde
const int ledPinAmarelo = 4; // pino do esp32 ligado ao
Led Amarelo
bool ledState = 0; // variável que representa o estado do Led
int Contador = 0;
void setup() {
pinMode(ledPinVerde, OUTPUT); //Definição do pino do Led
como saída
pinMode(ledPinAmarelo, OUTPUT); //Definição do pino do Led
como saída
// Inicialização da comunicação serial 9600 bps:
Serial.begin(9600);
}

void loop() {
ledState = !ledState;
digitalWrite(ledPinVerde, ledState); //atualiza o valor do Led
digitalWrite(ledPinAmarelo, !ledState); //atualiza o valor do Led
delay(1000);
Contador = Contador + 1;
Serial.println(Contador);
}

17
Figura 15 - Circuito do pisca-pisca com a função delay.

Figura 16 - Diagrama no fritzing do pisca-pisca.

Figura 17 - Programação e visualização de exemplo do pisca-pisca.

18
2.1.2 Pisca-pisca de dois Leds sem Delay

Neste exemplo, veremos como podemos fazer o mesmo pro-


cesso realizado no código anterior, porém sem a utilização da fun-
ção delay. Para isso, vamos definir uma variável usada para arma-
zenar o último valor do tempo (em milissegundos), no qual o led
mudou de estado, chamada de previousMillis e iniciada com zero.
Além disso, é declarada a variável interval, que é o intervalo de
tempo em que os leds piscarão, ou seja, 1000 ms ou 1 s.
Para realizar a contagem de tempo dentro da função loop, pri-
meiro declaramos uma variável inteira, chamada de currentMillis
e atribuímos a ela o valor retornado da função millis. Esta função
retorna o valor do tempo atual e servirá para fazermos o cálculo da
passagem de tempo.
Em seguida, comparamos o valor de currentMillis com o va-
lor de previousMillis, fazendo a subtração currentMillis – previous-
Millis. Observe que essa diferença é justamente a passagem de tem-
po e é feita uma verificação para ver se essa diferença é maior ou
igual ao valor interval definido previamente. Caso seja, o valor de
previousMillis recebe o valor de currentMillis e o estado do led é
trocado, isto é, se estiver aceso, ele apaga e vice-versa, assim como
no exemplo anterior.
Note que apenas quando a diferença de tempo é maior ou igual
a 1 s, que o sistema troca o estado dos leds. Então o currentMillis
volta para a contagem de tempo e apenas depois de passar mais
um segundo que o led troca de estado. Esta é uma abordagem em
que é feita a contagem de tempo para que seja feito o controle do
pisca-pisca. No exemplo anterior, isso é feito esperando 1 s passar
por meio da função delay.

19
/*
* Programando um pisca-pisca sem delay no Esp32
* Nosso canal no Youtube: https://www.youtube.com/@
RoboTech-ProfeMC
*/
const int ledPinVerde = 2; // pino do esp32 ligado ao Led verde
const int ledPinAmarelo = 4; // pino do esp32 ligado ao Led
Amarelo
bool ledState = 0; // variável que representa o estado do Led
int Contador = 0;

// variável usada para armazenar o último valor do tempo em


que o Led mudou de estado
unsigned long previousMillis = 0;
const long interval = 1000; // intervalo de tempo em
milisegundos

void setup() {
pinMode(ledPinVerde, OUTPUT); //Definição do pino do Led
como saída
pinMode(ledPinAmarelo, OUTPUT); //Definição do pino do Led
como saída
// Inicialização da comunicação serial 9600 bps:
Serial.begin(9600);
}

void loop() {
unsigned long currentMillis = millis();

if (currentMillis - previousMillis >= interval) {


// armazena o valor do tempo
previousMillis = currentMillis;

// o estado atual será o negado do anterior


ledState = !ledState;
digitalWrite(ledPinVerde, ledState); //atualiza o valor do Led
digitalWrite(ledPinAmarelo, !ledState); //atualiza o valor do Led
}

Contador = Contador + 1;
Serial.println(Contador);
}

20
2.2 Como usar botões no Esp32

Os botões são uma interface de entrada no ESP-32, sendo im-


portante para obter informações do usuário e colocar dentro do
sistema. Os botões alteram o valor lógico nos pinos de entrada que
estão conectados, levando assim a informação desejada para den-
tro do sistema. Vamos ver diferentes formas de tratar os botões, que
é a utilização de delay, detecção de borda e utilização de anti-de-
bouncing. Esses recursos são importantes para garantir uma leitura
estável do botão e evitar que seja acionado de forma incorreta.

2.2.1 Uso de botões com Delay

No caso do uso de botões, o delay é importante para fazer com


que o ESP32 dê um intervalo nas leituras do botão. Isso é impor-
tante, pois caso não houvesse o delay, pelo fato do ESP32 ser muito
rápido, com um rápido toque no botão, o sistema contaria como se
o usuário tivesse apertado o botão diversas vezes.
Imagine a situação em que se utiliza o botão para incrementar
um contador. Se não houvesse o delay, a pessoa iria apertar o botão
e em poucos milissegundos (enquanto a pessoa está apertando e
soltando o botão) o ESP32 contaria diversas vezes que o botão foi
pressionado, com isso o contador subiria rapidamente, quando na
verdade deveria incrementar em apenas 1. O delay é capaz de cor-
rigir isso ao colocar um tempo de espera para a próxima leitura.
Com isso, dá tempo da pessoa pressionar o botão, o sistema contar
que o botão foi pressionado e a pessoa soltar o botão. Com isso, se
contabiliza apenas um incremento no botão.
O código a seguir mostra um exemplo do uso do delay para
fazer com que o sistema não verifique de forma tão rápida os bo-

21
tões de forma a parecer que o usuário o pressionou múltiplas vezes,
quando na verdade pressionou uma única vez.
Como se pode observar no código, primeiro são definidos os
pinos do botão e do led por meio das constantes BUTTON_PIN e
LedPino2, que são respectivamente os pinos 26 e 2. Posteriormen-
te, são definidas as variáveis inteiras currentState e contador, além
da variável booleana ledState. Note que o contador é iniciado com
o valor 0, enquanto a condição booleana de ledState é iniciada em
0, o que corresponde a false.
Dentro da função setup, que será executada uma única vez
e no início, são definidas a velocidade de comunicação serial em
9600bps, por meio do comando Serial.begin(9600) e os pinos
do botão e do led por meio das funções pinMode(BUTTON_PIN,
INPUT_PULLUP) e pinMode(LedPino2, OUTPUT). Note que BUT-
TON_PIN é definido como botão de entrada com PULL UP, já o
pino do led é definido como saída.
A seguir, tem-se a função loop, a qual fica executando de for-
ma contínua e, como o próprio nome diz, em loop.

/*
* Código para testar o uso simples de um button
* Neste exemplo será possível visualizar o problema do
debounce
* Ao apertar o botão uma vez, o uC detecta isto como se o
botão tivesse sido apertado várias vezes
* Código para uma placa Esp32
* Nosso canal no Youtube: https://www.youtube.com/@
RoboTech-ProfeMC
*/

#define BUTTON_PIN 26 // Pino 26 Conectado ao Button


#define LedPino2 2 // Pino do Led

//Variáveis
int currentState; // O estado atual do button

22
int Contador = 0;
bool ledState = 0; // variável que representa o estado do Led

void setup() {
// Inicialização da comunicação serial 9600 bps:
Serial.begin(9600);
// Inicializando o pino do Button como entrada e com
resistência PullUp
// Nesta configuração existe uma resistência para 3.3 V, assim
quando o button esteja
//pressionado, a leitura do pino de entrada será HIGH ou “1” e
ao apertar o buttons o valor será LOW ou “0”
pinMode(BUTTON_PIN, INPUT_PULLUP);

pinMode(LedPino2, OUTPUT);
}

void loop() {
// Leitura do valor atual do button
currentState = digitalRead(BUTTON_PIN);

if (currentState == LOW)
{
ledState = !ledState;
Serial.print(“Apertou o botão “);
Contador = Contador + 1;
Serial.print(Contador);
Serial.println(“ Vezes “);
digitalWrite(LedPino2, ledState);
delay(100);
}

23
Figura 18 - Circuito que utiliza um botão para acender um LED

Figura 19 - Diagrama do circuito da figura anterior.

2.2.2 Uso de botões com detecção de borda

Outra forma de trabalhar com botões e verificar a borda de


subida e descida da tensão do pino no qual o botão está conectado.
Em outras palavras, o pino onde está conectado o botão fica sendo
monitorado e, quando a pessoa pressiona o botão, o ESP32 detecta
que a tensão mudou de 0V para 3.3V (gerando assim uma borda de

24
subida). De forma contrária, quando a pessoa solta o botão há uma
queda de tensão de 3.3V para 0, gerando uma borda de descida.
Dentro do código abaixo, temos a definição das constantes
BUTTON_PIN e LedPino2, como 26 e 2, respectivamente. Assim
como nos exemplos anteriores, os comandos #define servem para
atribuirmos um valor constante para essas variáveis, como se fosse
um “apelido”. Dessa forma podemos programar todo o código uti-
lizando o “apelido” BUTTON_PIN e LedPino2, ao invés de termos
que lembrar de que o pino do botão é 26 e do LED é 2. Adicional-
mente, caso queiramos trocar os pinos basta modificarmos nessa
parte do código e automaticamente funcionará .
Após declarar os pinos utilizando #define, temos a declaração
das variáveis. Inicialmente são feitas as declarações das variáveis
lastState, currentState, Contador e ledState. A variável lastSta-
te guardará a informação do estado anterior do pino de entrada
e será definida inicialmente como LOW, ou seja, considera-se ini-
cialmente que o botão está desligado. Posteriormente, há a variável
currentState que guarda o estado atual do botão. Como ela será
utilizada mais para frente do código e será resultado do usuário
apertar ou não o botão naquele momento, não é necessário atribuir
agora um valor para ela.
Continuando temos uma variável inteira Contador que é ini-
ciada com 0 e o estado do LED que é iniciado também com zero,
visto que se considera que o LED começa desligado.
Em seguida, tem-se a função setup(), que é executada uma
única vez ao iniciar o código. Dentro da função setup() é definida
a taxa de comunicação a 9600bps, por meio do comando Serial.
begin(9600). Além disso, a linha pinMode(BUTTON_PIN, INPUT_
PULLUP) define o botão BUTTON_PIN como input com resistores
de pullup e o pino do LED (LedPino2) como saída.

25
Dentro da função loop() a seguir será utilizado o conceito de
borda de subida para acender o LED. Inicialmente é feita uma leitu-
ra do estado atual do led, que vai ser guardado na variável current-
LedState. Note que, como a variável, já receberá essa informação
sem que seja utilizada para outro processamento, não foi necessário
definir um valor para ela no início do código (onde tem a declara-
ção das variáveis). Por meio do comando digitalRead (BUTTON_
PIN), o ESP32 registra o valor de tensão no pino BUTTON_PIN e
guarda na variável currentLedState.
Posteriormente é feita uma comparação utilizando o if. Esta
comparação verifica se o estado anterior do botão lastState era
HIGH e o atual currentState é LOW. Se isso for verdade, isso sig-
nifica que o usuário pressionou o botão e soltou.
Com isso, o algoritmo entra dentro do if. Primeiramente ele
vai trocar o estado do LED, ligando-o caso esteja desligado ou des-
ligando-o, caso esteja ligado. É o que faz a seguinte linha:

ledState = !ledState;

A seguir, o ESP32 mostrará no serial monitor a mensagem:


“Apertou o botão” e incrementará o valor da variável Contador em
1, além de exibir o seu valor no serial monitor seguido da palavra
“Vezes”. Por fim, o código escreve o valor do ledState (que foi tro-
cado no início do if) no LedPino2, ou seja, ele vai, de fato, trocar
o estado do LED, pois quando se alterou a variável ainda não ti-
nha sido “jogada” esta informação para a porta do LED, portanto
o LED não havia ainda trocado de estado. Por fim, é feito um delay
para realizar uma pausa de 50 ms.
Após sair do if, o sistema atualiza o valor da lastState para o
valor do currentState, já que haverá uma nova leitura do estado
atual do botão no próximo loop. Isso garantirá que o lastState do
próximo ciclo seja o currentState do ciclo atual.

26
/*
* Código para testar o uso simples de um button
* Código para uma placa Esp32
* Nosso canal no Youtube: https://www.youtube.com/@
RoboTech-ProfeMC
*/

#define BUTTON_PIN 26 // Pino 26 Conectado ao Button


#define LedPino2 2 // Pino do Led

//Variáveis
int lastState = LOW; // O estado anterior do pino de entrada ou
button
int currentState; // O estado atual do button
int Contador = 0;
bool ledState = 0; // V ariável que representa o estado do Led

void setup() {
// Inicialização da comunicação serial 9600 bps:
Serial.begin(9600);
// Inicializando o pino do Button como entrada e com
resistência PullUp
// Nesta configuração existe uma resistência para 3.3 V, assim
quando o button esteja
//Sem apertar o botão, o estado do pino será HIGH ou “1” e, ao
apertar o button, o valor será LOW ou “0”
pinMode(BUTTON_PIN, INPUT_PULLUP);

pinMode(LedPino2, OUTPUT);
}

void loop() {
// Leitura do valor atual do button
currentState = digitalRead(BUTTON_PIN);

if (lastState == HIGH && currentState == LOW)


{
ledState = !ledState;
Serial.print(“Apertou o botão “);
Contador = Contador + 1;
Serial.print(Contador);

27
Serial.println(“ Vezes “);
digitalWrite(LedPino2, ledState);
delay(50);
}

// salva o valor atual em outra variável, para que depois seja o


estado anterior do button
lastState = currentState;
}

2.2.3 Uso de botões usando tempo anti-debounce

Quando botões são pressionados, eles podem gerar ruídos elé-


tricos devido ao seu comportamento mecânico. Este fenômeno, co-
nhecido como “quicar” (ou “bouncing” em inglês), ocorre porque
o contato físico dentro do botão pode rapidamente alternar entre
os estados de aberto (HIGH) e fechado (LOW) antes de se estabi-
lizar. Isso pode levar à leituras múltiplas e erráticas, especialmen-
te em sistemas como o ESP32 que leem o estado dos pinos muito
rapidamente.
Dessa maneira, o debouncing é uma técnica utilizada para fil-
trar esses ruídos. Em vez de considerar cada mudança rápida de
estado como uma ação válida (por exemplo, pressionar o botão),
o sistema espera um tempo pré-definido para confirmar se a mu-
dança de estado é estável e intencional. Isso evita que o sistema
interprete erroneamente o ruído como múltiplas pressões de botão.
Para o código de debouncing, inicialmente definimos o pino
do botão (BUTTON_PIN) e o tempo de debounce (DEBOUNCE_
TIME). Em seguida, a variável currentState é utilizada para arma-
zenar o estado atual do botão, indicando se ele está pressionado
(estado LOW) ou não (estado HIGH). Por sua vez, lastFlickera-
bleState guarda o último estado instável do botão, sendo útil para

28
detectar mudanças imediatas no seu estado que ainda não foram
confirmadas como estáveis.
A variável lastSteadyState mantém o registro do último es-
tado estável do botão, que é atualizado após a mudança de estado
do botão persistir pelo período definido em DEBOUNCE_TIME.
Finalmente, lastDebounceTime é usada para registrar o momento
da última alteração de estado, auxiliando no cálculo se o intervalo
de tempo de debounce foi cumprido desde a última mudança.
Essas variáveis são fundamentais no processo de debouncing,
garantindo que o sistema reconheça apenas mudanças significati-
vas e estáveis no estado do botão, filtrando os ruídos causados pelo
efeito de bouncing.
Com relação a organização do código, dentro da função setup,
iniciamos a comunicação serial e configuramos o pino do botão
como entrada com resistor pull-up, garantindo que o estado pa-
drão seja HIGH (aberto) e mude para LOW quando pressionado.

// Código para anti-debouncing

#define BUTTON_PIN 26 // GIOP21 pin connected to button


#define DEBOUNCE_TIME 50 // the debounce time in
millisecond, increase this time if it still chatters

// Variables will change:


int lastSteadyState = LOW; // the previous steady state from
the input pin
int lastFlickerableState = LOW; // the previous flickerable state
from the input pin
int currentState; // the current reading from the input
pin

// the following variables are unsigned longs because the time,


measured in
// milliseconds, will quickly become a bigger number than can
be stored in an int.
unsigned long lastDebounceTime = 0; // the last time the

29
output pin was toggled

void setup() {
// initialize serial communication at 9600 bits per second:
Serial.begin(9600);
// initialize the pushbutton pin as an pull-up input
// the pull-up input pin will be HIGH when the switch is open
and LOW when the switch is closed.
pinMode(BUTTON_PIN, INPUT_PULLUP);
}

void loop() {
// read the state of the switch/button:
currentState = digitalRead(BUTTON_PIN);

// check to see if you just pressed the button


// (i.e. the input went from LOW to HIGH), and you’ve waited
long enough
// since the last press to ignore any noise:

// If the switch/button changed, due to noise or pressing:


if (currentState != lastFlickerableState) {
// reset the debouncing timer
lastDebounceTime = millis();
// save the the last flickerable state
lastFlickerableState = currentState;
}

if ((millis() - lastDebounceTime) > DEBOUNCE_TIME) {


// whatever the reading is at, it’s been there for longer than
the debounce
// delay, so take it as the actual current state:

// if the button state has changed:


if(lastSteadyState == HIGH && currentState == LOW)
Serial.println(“The button is pressed”);
else if(lastSteadyState == LOW && currentState == HIGH)
Serial.println(“The button is released”);

// save the the last steady state


lastSteadyState = currentState;
}

30
}

2.2.4 Uso de botões em tempo anti debounce com


a biblioteca ezButton

Uma forma de lidar com o debouncing é por meio da bibliote-


ca ezButton, que já vem com funções implementadas para realizar
tal operação. No código abaixo, incialmente importamos a bibliote-
ca ezButton. Posteriormente, definimos o DEBOUNCE_TIME, que
é uma constante utilizada para controlar o tempo de debouncing.
Em seguida, uma instância do objeto ezButton é criada e nomeada
como button, que está associado ao pino 26, onde está localizado
o botão.
Continuando, é feita a inicialização da comunicação serial, no
caso em 115200 bps, e também é definindo que o tempo de debou-
ncing será configurado para o botão (anteriormente havíamos ape-
nas definido quanto seria esse tempo, mas não tínhamos aplicado
ao botão, como estamos fazendo agora).
Como estamos utilizando a biblioteca, a próxima parte fica
mais fácil, visto que a biblioteca já faz os processos de debouncing
internamente. Na função loop inicialmente chamamos a função
button.loop(), que atualiza o estado interno do botão e lida com a
lógica de debouncing, com isso nas linhas seguinte precisa-se ape-
nas verificar se o botão está pressionado ou foi liberado por meio
das funções button.isPressed() e button.isReleased(), respectiva-
mente. Com a biblioteca ezButton, lidar com botões torna-se uma
tarefa simples e eficiente, eliminando a necessidade de escrever có-
digo complexo de debouncing.

/*

31
#include <ezButton.h>

#define DEBOUNCE_TIME 40 // the debounce time in


millisecond, increase this time if it still chatters

ezButton button(26); // create ezButton object that attach to


pin GIOP26

void setup() {
Serial.begin(115200);
button.setDebounceTime(DEBOUNCE_TIME); // set debounce
time to 50 milliseconds
}

void loop() {
button.loop(); // MUST call the loop() function first

if (button.isPressed())
Serial.println(“The button is pressed”);

if (button.isReleased())
Serial.println(“The button is released”);
}

32
3.
ENTRADAS ANALÓGICAS

Para entendermos o que são entradas analógicas, imagine o


mundo ao seu redor como um filme contínuo, onde tudo flui sem
interrupções, assim como a temperatura. Ela não pula de 30ºC para
31ºC instantaneamente; há muitos valores intermediários, como
30,1ºC, 30,11ºC, e assim por diante. Se você tivesse um sensor per-
feito, veria infinitos valores entre 30ºC e 31ºC.
Mas, computadores e dispositivos como o ESP-32 não podem
entender infinitos valores. Eles preferem filmes em quadros, onde
cada quadro é uma parte do todo. Em vez de ver todos os valores
entre 30ºC e 31ºC, eles veem intervalos, como 30ºC, 30,2ºC, 30,4ºC,
e assim por diante.
Isso ocorre porque os computadores trabalham com infor-
mações em pedaços ou “quadros” chamados de valores discretos.
Então, em vez de ter um filme contínuo, eles trabalham com uma
sequência de fotos.
A boa notícia é que computadores e dispositivos como o ESP-
32 são tão bons em dividir tudo em pequenos pedaços que, para
nós, parece quase contínuo. É como assistir a um filme: mesmo
sendo feito de quadros individuais, parece fluir sem interrupções.

33
Então, nesta seção, aprenderemos como o ESP-32 pega esses
“filmes contínuos” do mundo real e os transforma em “coleções de
fotos” para entender e trabalhar com eles.

3.1 Como realizar a leitura de uma entrada analógi-


ca e visualizar no monitor serial

Como dito anteriormente, a maior parte das grandezas que


temos no mundo ao nosso redor são analógicas. Entretanto, os cir-
cuitos que compõem os computadores e ESP-32, além de vários
outros microcontroladores são em sua grande maioria digitais e
trabalham com valores discretos. Isso traz inúmeras vantagens com
relação a menor ruído, maior facilidade de transmissão de dados
etc. Entretanto, precisamos fazer com que as grandezas do mundo
real, como temperatura, pressão, radiação solar, vento, velocidade,
umidade, força, dentre outras sejam possíveis de serem lidas e in-
terpretadas pelos circuitos digitais.
Para fazer isso, utilizamos os chamados conversores analó-
gicos-digitais. Eles são circuitos que convertem sinais analógicos,
como os que vêm de um microfone ou de um sensor de tempera-
tura, em sinais digitais que o computador pode entender. Imagi-
ne que você está desenhando uma linha ondulada em um papel;
essa linha representa o sinal analógico, que varia suavemente. O
conversor analógico-digital pega essa linha e a divide em pequenos
degraus ou blocos, cada um representando um valor numérico es-
pecífico. Essa é a forma digital do sinal. Ao fazer isso, transforma
informações contínuas do mundo real, como som, luz ou tempera-
tura, em dados que os dispositivos eletrônicos, como computado-
res e smartphones, podem processar e usar. Essa conversão é fun-
damental para que possamos, por exemplo, gravar uma voz em um
smartphone ou medir a temperatura com um termômetro digital.

34
/*
* Código que demonstra como usar uma entrada analógica no
Esp32
* mostra o valor analógico de um potenciômetro no monitor
serial
* Código para uma placa Esp32
* Nosso canal no Youtube: https://www.youtube.com/@
RoboTech-ProfeMC
*/
#define AN_Pot1 2
int AN_Pot1_Resultado = 0;
#define Led1Menor 14
#define Led2Maior 17

void setup()
{
Serial.begin(115200);
pinMode(Led1Menor, OUTPUT);
pinMode(Led2Maior, OUTPUT);
}

void loop()
{
AN_Pot1_Resultado = analogRead(AN_Pot1);
Serial.println(AN_Pot1_Resultado);
if (AN_Pot1_Resultado < 400)
digitalWrite(Led1Menor, HIGH);
else
digitalWrite(Led1Menor, LOW);

if (AN_Pot1_Resultado > 600)


digitalWrite(Led2Maior, HIGH);
else
digitalWrite(Led2Maior, LOW);

delay(100);
}

35
Figura 20 - Circuito utilizado no código anterior para exemplificar
a leitura de um valor analógico do potenciômetro. De acordo
com o valor do sinal analógico ele acende um dos LEDs.

Figura 21 - Circuito montado na prática com


o potenciômetro e os dois LEDs.

36
3.2 Controlando a velocidade de um sequencial de
5 leds usando uma entrada analógica

Neste projeto, estamos usando um dispositivo chamado po-


tenciômetro para controlar a velocidade com que uma série de
LEDs acende em sequência. No início do código, damos “apelidos”
aos pinos do microcontrolador para facilitar a leitura. Por exemplo,
o pino 2, ao qual o potenciômetro está conectado, é chamado de
AN_Pot1. Da mesma forma, os LEDs têm seus respectivos “apeli-
dos”, como LedAz para o LED azul conectado ao pino 25.
Temos também algumas variáveis. A variável Tempo determi-
nará quanto tempo cada LED ficará aceso, enquanto AN_Pot1_Re-
sult armazenará o valor que lemos do potenciômetro.

Quando ligamos o microcontrolador, a primeira função que


é executada é a setup(). Nela, iniciamos uma comunicação com o
computador para enviar e receber mensagens. Também definimos
como os pinos dos LEDs serão usados, ou seja, como saídas para
enviar energia e acender os LEDs.
A função loop(), como o nome sugere, é executada em um
loop contínuo. Nela, lemos o valor do potenciômetro, que nos dirá
o quanto ele foi girado. Este valor é então ajustado e usado para
determinar o tempo que cada LED ficará aceso. Em seguida, temos
um loop que acende os LEDs um após o outro. Usamos um co-
mando chamado digitalWrite para controlar se um LED está aceso
ou apagado. Por exemplo, quando queremos acender o LED azul,
usamos digitalWrite(LedAz, i==0). Depois de acender um LED, o
programa “espera” pelo tempo determinado pelo potenciômetro
antes de acender o próximo. Com isso, o resultado é uma sequência
de LEDs que acendem em ordem, sendo que a velocidade com que
eles acendem pode ser controlada girando o potenciômetro.

37
/*
#define AN_Pot1 2
#define LedAz 25
#define LedVerde 17
#define LedAmar 16
#define LedLaran 27
#define LedVerm 14
int Tempo = 0;
int AN_Pot1_Result = 0;

void setup()
{
Serial.begin(115200);
pinMode(LedAz, OUTPUT);
pinMode(LedVerde, OUTPUT);
pinMode(LedAmar, OUTPUT);
pinMode(LedLaran, OUTPUT);
pinMode(LedVerm, OUTPUT);
}

void loop()
{
AN_Pot1_Result = analogRead(AN_Pot1);
Serial.println(AN_Pot1_Result);
Tempo = AN_Pot1_Result/4;
for (int i = 0; i <= 4; i++) {
digitalWrite(LedAz, i==0);
digitalWrite(LedVerde, i==1);
digitalWrite(LedAmar, i==2);
digitalWrite(LedLaran, i==3);
digitalWrite(LedVerm, i==4);
delay(Tempo);
}
}

38
Figura 22 - Diagrama de sequência de LEDs que acendem.
O tempo que cada LED fica aceso é determinado pela
variável tempo, controlada pelo potenciômetro.

Figura 23 - Circuito referente ao diagrama


anterior montado na prática.

39
3.3 Ligando 5 leds em função do nível de tensão de
uma entrada analógica

Neste projeto, estamos usando um potenciômetro para medir


um nível de tensão e, com base nesse nível, acender um dos cinco
LEDs. A ideia é que cada LED represente uma faixa de tensão, e o
LED correspondente à faixa atual de tensão acenderá.
No início do código, temos definições semelhantes ao exem-
plo anterior, onde damos “apelidos” aos pinos do microcontrolador
para saber onde cada LED e o potenciômetro estão conectados.
A variável AN_ValDig é usada para armazenar o valor digital
lido do potenciômetro, enquanto Volts armazena a tensão corres-
pondente em volts. Note que usamos a variável do tipo double para
Volts, o que nos permite armazenar valores com maior precisão.
No entanto, também é mencionado que podemos usar o tipo float,
que é uma alternativa mais comum e menos precisa.
Na função setup(), iniciamos a comunicação com o compu-
tador e definimos os pinos dos LEDs como saídas, assim como no
exemplo anterior.
A função loop() é onde a lógica principal acontece. Primeiro,
lemos o valor do potenciômetro com analogRead(AN_Pot1) e o
exibimos no monitor serial. Em seguida, convertemos esse valor di-
gital em uma tensão usando a fórmula Volts = AN_ValDig*3.3/4095.
Esta fórmula leva em consideração que a tensão máxima é 3,3V e o
valor digital máximo é 4095.
Depois de calcular a tensão, decidimos qual LED acender com
base nessa tensão. Por exemplo, se a tensão for menor ou igual a
0,66V, acendemos o LED azul. Se estiver entre 0,66V e 1,32V, acen-
demos o LED verde, e assim por diante. Usamos o comando digi-

40
talWrite para acender ou apagar os LEDs de acordo com a tensão
medida.
Finalmente, temos um delay(500), que faz o programa espe-
rar meio segundo antes de ler o potenciômetro novamente. Isso dá
tempo suficiente para vermos qual LED está aceso e ler os valores
no monitor serial.
Em resumo, este código nos permite visualizar o nível de ten-
são de uma entrada analógica por meio de LEDs. Girando o po-
tenciômetro, podemos ver diferentes LEDs acendendo, cada um
representando uma faixa de tensão.

#define AN_Pot1 2
#define LedAz 25
#define LedVerde 17
#define LedAmar 16
#define LedLaran 27
#define LedVerm 14

int AN_ValDig = 0;
double Volts = 0; //pode usar float também
void setup()
{
Serial.begin(115200);
pinMode(LedAz, OUTPUT);
pinMode(LedVerde, OUTPUT);
pinMode(LedAmar, OUTPUT);
pinMode(LedLaran, OUTPUT);
pinMode(LedVerm, OUTPUT);
}

void loop()
{
AN_ValDig = analogRead(AN_Pot1);
Serial.print(“Valor Digital: “);
Serial.print(AN_ValDig);

Volts = AN_ValDig*3.3/4095;
Serial.print(“ Tensão: “);

41
Serial.println(Volts);

digitalWrite(LedAz, Volts <= 0.66);


digitalWrite(LedVerde, (Volts >= 0.66) && (Volts <= 1.32));
digitalWrite(LedAmar, (Volts >= 1.32) && (Volts <= 1.98));
digitalWrite(LedLaran, (Volts >= 1.98) && (Volts <= 2.64));
digitalWrite(LedVerm, Volts >= 2.64);

delay(500);
}

3.4 Plotando 3 entradas analógicas usando o serial


plotter

Neste projeto, estamos trabalhando com três potenciômetros


que estão conectados a três entradas analógicas diferentes do mi-
crocontrolador. O objetivo é ler os valores desses potenciômetros
e plotá-los em um gráfico usando o Serial Plotter do ambiente de
desenvolvimento Arduino.
No início do código, temos as definições dos pinos onde os
potenciômetros estão conectados: AN_Pot1, AN_Pot2 e AN_Pot3.
Em seguida, declaramos três variáveis para armazenar os valores
lidos de cada potenciômetro: AN_Pot1_Resultado, AN_Pot2_Re-
sultado e AN_Pot3_Resultado.

Também temos três variáveis do tipo double para armazenar


os valores de tensão correspondentes a cada leitura: Volts1, Volts2
e Volts3. Novamente, é mencionado que podemos usar o tipo float
em vez de double, se desejarmos.
Na função setup(), iniciamos a comunicação serial com uma
taxa de transmissão de 115200 bps, que é uma taxa comum para
comunicação entre o microcontrolador e o computador.

42
A função loop() é onde a mágica acontece. Primeiro, lemos os
valores dos três potenciômetros usando a função analogRead(AN_
Pot1). Em seguida, convertemos esses valores digitais em tensões
usando a fórmula familiar Volts = Resultado*3.3/4095.
Agora, para plotar esses valores no Serial Plotter, precisamos
enviá-los através da comunicação serial. Usamos a função Serial.
print() para enviar cada valor de tensão. Entre cada valor, adicio-
namos um espaço para separá-los. Finalmente, usamos Serial.
println() para enviar uma nova linha, indicando o fim de um con-
junto de leituras.
O delay(300) no final do loop garante que espere mos um pou-
co antes de fazer a próxima leitura, dando tempo para visualizar os
dados no Serial Plotter. Este código permite que você visualize em
tempo real as variações de tensão de três potenciômetros em um
gráfico. Ao girar os potenciômetros, você verá as linhas do gráfico
se movendo, refletindo as mudanças nas tensões.

#define AN_Pot1 2
#define AN_Pot2 4
#define AN_Pot3 35

int AN_Pot1_Resultado = 0;
int AN_Pot2_Resultado = 0;
int AN_Pot3_Resultado = 0;

double Volts1 = 0, Volts2 = 0, Volts3 = 0; //pode usar float


também

void setup()
{
Serial.begin(115200);
}

void loop()
{
AN_Pot1_Resultado = analogRead(AN_Pot1);

43
AN_Pot2_Resultado = analogRead(AN_Pot2);
AN_Pot3_Resultado = analogRead(AN_Pot3);

Volts1 = AN_Pot1_Resultado*3.3/4095;
Volts2 = AN_Pot2_Resultado*3.3/4095;
Volts3 = AN_Pot3_Resultado*3.3/4095;

Serial.print(Volts1);
Serial.print(“ “);

Serial.print(Volts2);
Serial.print(“ “);

Serial.print(Volts3);
Serial.println();
delay(300);
}

44
Figura 25 - Implementação prática do diagrama anterior.

45
Figura 26 - Exemplo de utilização do circuito anterior
com um monitor serial na tela, mostrando os três
gráficos da conversão analógica-digital.

46
3.5 Uso do Display OLED

Neste projeto, estamos explorando o uso de um display OLED,


especificamente o modelo SSD1306. O display OLED é um tipo de
tela que usa diodos orgânicos emissores de luz para exibir infor-
mações. Eles são conhecidos por sua nitidez e capacidade de exibir
informações em ambientes de baixa luminosidade.
Começamos incluindo as bibliotecas necessárias para traba-
lhar com o display OLED: <Wire.h>, <Adafruit_GFX.h> e <Ada-
fruit_SSD1306.h>. A biblioteca <Wire.h> é usada para comunica-
ção I2C, enquanto as bibliotecas da Adafruit fornecem funções
para desenhar e controlar o display OLED.
Definimos as dimensões do display com SCREEN_WIDTH e
SCREEN_WIDTH. Também definimos o pino onde um potenciô-
metro está conectado com AN_Pot1 e uma variável tensão para ar-
mazenar a tensão lida desse potenciômetro.
A linha Adafruit_SSD1306 display(SCREEN_WIDTH, SCRE-
EN_HEIGHT, &Wire, -1); cria um objeto display que usaremos para
controlar o display OLED.
Na função setup(), iniciamos a comunicação serial e tentamos
iniciar o display OLED com display.begin(). Se o display não ini-
ciar corretamente, uma mensagem de erro é exibida no monitor
serial.
Em seguida, configuramos o display para exibir uma série de
gráficos e texto. Usamos funções como display.drawRect(), display.
drawCircle(), display.fillRoundRect() e display.drawLine() para de-
senhar formas no display. Também exibimos o texto “Oi, Brasil!” e
“Prof. Marco” em diferentes posições e tamanhos.

47
A função loop() é onde lemos a tensão do potenciômetro e a
exibimos no display OLED. Primeiro, lemos a tensão e a exibimos
no monitor serial. Em seguida, limpamos o display com display.
clearDisplay(), exibimos o texto “Prof Marco” e mostramos o valor
da tensão no display OLED. Além disso, desenhamos uma barra
de progresso que representa a tensão lida, usando display.fillRou-
ndRect(). A largura da barra de progresso é proporcional à tensão
lida.
Em resumo, este código demonstra como usar um display
OLED para exibir informações de um potenciômetro em tempo
real. Ele combina gráficos e texto para criar uma interface visual
intuitiva. Ao girar o potenciômetro, você verá a barra de progresso
se mover e o valor da tensão mudar no display.

// Uso do Display OLED SSD1306


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display largura, em pixels


#define SCREEN_HEIGHT 64 // OLED display altura, em pixels
#define AN_Pot1 2
float tensao = 0;
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
&Wire, -1);

void setup() {
Serial.begin(115200);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address
0x3D for 128x64
Serial.println(F(“SSD1306 allocation failed”));
for(;;);
}
display.clearDisplay();
display.setTextSize(1); display.setTextColor(WHITE); display.
setCursor(33, 0);
display.println(“Oi, Brasil!”);

48
display.drawRect(10, 16, 106, 12, WHITE);
display.drawCircle(10, 16, 8, WHITE);
display.drawCircle(116, 16, 8, WHITE);
display.fillCircle(26, 16, 8, WHITE);
display.fillCircle(100, 16, 8, WHITE);

display.fillRoundRect(35, 19, 56, 6, 2, WHITE);


display.drawLine(0, 30, 127, 30, WHITE);

display.setCursor(3, 36); display.setTextSize(2); display.


println(“Prof Marco”);
display.display();
delay(4000);
}
void loop() {
tensao = analogRead(AN_Pot1)*3.3/4095;
display.clearDisplay();

Serial.print(“V : “);
Serial.println(tensao);

display.setCursor(2, 0); display.setTextSize(2); display.


println(“Prof Marco”);
// mostra o valor da tensão no display OLED
display.setCursor(5, 20); display.print(“V:”); display.
print(tensao);
display.fillRoundRect(5, 50, tensao*118/3.3, 10, 2, WHITE);
display.display();
delay(300);
}

49
Figura 27 - Diagrama de um circuito que converte um sinal analógico
vindo do potenciômetro para um valor digital e mostra na tela OLED.

Figura 28 - Implementação prática do diagrama anterior.

50
4.
SENSORES

Os sensores são dispositivos fundamentais no mundo da eletrô-


nica e automação, atuando como os olhos e ouvidos dos sistemas ele-
trônicos. Eles são responsáveis por capturar informações do ambiente,
convertendo-as em sinais elétricos que podem ser interpretados por
microcontroladores e outros dispositivos eletrônicos. Essa capacida-
de de perceber e responder às mudanças ambientais torna os sensores
essenciais em uma ampla variedade de aplicações, desde sistemas de
segurança doméstica até avançadas aplicações industriais e robóticas.
A importância dos sensores é ainda mais evidente no contexto
dos microcontroladores, como o ESP-32. Estes pequenos, mas po-
derosos dispositivos, são o cérebro por trás de muitos dos nossos
gadgets e sistemas eletrônicos modernos. No entanto, sem senso-
res, sua capacidade de interagir com o mundo externo seria extre-
mamente limitada. Os sensores fornecem aos microcontroladores
a capacidade de receber informações do ambiente, permitindo que
eles tomem decisões e executem ações com base nesses dados.
Dentro do vasto universo dos sensores, alguns se destacam
por sua utilidade e popularidade:

• Sensor de luminosidade - LDR (4.1): Este sensor varia sua


resistência com base na quantidade de luz que incide sobre ele.

51
É amplamente utilizado em sistemas de iluminação automá-
tica e dispositivos que precisam responder às mudanças nas
condições de iluminação.
• Ultrassom (4.2): Utilizado principalmente para medir distâncias,
os sensores de ultrassom emitem ondas sonoras e medem o tem-
po que levam para retornar após refletirem em um objeto. São
comuns em sistemas de estacionamento automático e robótica.
• NTC - Resistor sensível à temperatura (4.3): Como o pró-
prio nome sugere, sua resistência varia com a temperatura. É
frequentemente usado em termostatos e sistemas de monito-
ramento de temperatura.
• DHT22 - Sensor de umidade e temperatura (4.4): Este sen-
sor compacto é capaz de medir tanto a umidade relativa do
ar quanto a temperatura, tornando-o ideal para aplicações de
controle climático e estufas.
• MAX9814 - Sensor de som (4.5): Este é um sensor de som de
alta qualidade que pode detectar variações de pressão sonora
e convertê-las em sinal elétrico. É utilizado em aplicações que
requerem detecção de som ou gravação de áudio.

Os sensores são a “ponte” entre o mundo físico e o digital, permi-


tindo que os sistemas eletrônicos entendam e reajam ao ambiente ao
seu redor. Seja em aplicações domésticas, industriais ou de pesquisa,
a integração de sensores adequados é crucial para o funcionamento
eficaz e eficiente de qualquer sistema baseado em microcontroladores.

4.1 Sensor de Luminosidade – LDR

O LDR (Resistor Dependente de Luz) é um componente ele-


trônico que tem sua resistência variada de acordo com a intensida-

52
de da luz que incide sobre ele. Quanto mais luz, menor a resistência
e quanto menos luz, maior a resistência. Este código demonstra
como usar um LDR para medir a luminosidade do ambiente e, com
base nessa leitura, controlar a iluminação de diferentes LEDs.
Primeiro, definimos os pinos dos LEDs com cores diferentes:
vermelho, laranja, amarelo e branco. Também definimos o pino
onde o LDR está conectado, como o pino_SensorLuz. A variável
sensorLuz será usada para armazenar a leitura do LDR.

Na função setup(), inicializamos a comunicação serial com


uma velocidade de 115200 bps. Isso nos permite visualizar os va-
lores lidos do LDR no monitor serial. Também configuramos os
pinos dos LEDs como saída.
A função loop() é onde a mágica acontece. Primeiro, lemos o
valor do LDR usando analogRead(pino_SensorLuz) e armazena-
mos esse valor na variável sensorLuz. Em seguida, exibimos esse
valor no monitor serial.
Depois, com base no valor lido do LDR, decidimos quais LEDs
acender. Se a luminosidade for muito baixa (valor do LDR alto),
acendemos mais LEDs. Por exemplo, se o valor lido for menor ou
igual a 1500, acendemos o LED Branco. Se for menor ou igual a
1700, acendemos o LED Amarelo, e assim por diante. Isso significa
que, em ambientes mais escuros, mais LEDs serão acesos.
Finalmente, esperamos 700 milissegundos antes de fazer a
próxima leitura. Isso dá um pequeno intervalo entre as leituras e
evita que os LEDs pisquem muito rapidamente.
Em resumo, este código demonstra como usar um LDR para
medir a luminosidade do ambiente e controlar a iluminação de
LEDs com base nessa leitura. À medida que o ambiente fica mais
escuro, mais LEDs são acesos, proporcionando uma iluminação
adaptativa.

53
//Exemplo LDR (Light Dependent Resistor)

#define LedVermelho 26
#define LedLaranja 25
#define LedAmarelo 17
#define LedBranco 16

#define pino_SensorLuz 14
int sensorLuz;

void setup()
{
Serial.begin(115200); //Inicialização da porta serial
pinMode(LedVermelho, OUTPUT);
pinMode(LedLaranja, OUTPUT);
pinMode(LedAmarelo, OUTPUT);
pinMode(LedBranco, OUTPUT);
}

void loop()
{
sensorLuz = analogRead(pino_SensorLuz); // read analog input
pin 0
Serial.println(sensorLuz, DEC); // prints the value read

digitalWrite(LedBranco, sensorLuz <= 1500);


digitalWrite(LedAmarelo, sensorLuz <= 1700);
digitalWrite(LedLaranja, sensorLuz <= 1800);
digitalWrite(LedVermelho, sensorLuz <= 2000);

delay(700); // wait 100ms for next reading


}

54
Figura 29 - Diagrama do circuito que verifica a iluminação
do ambiente por meio do LDR e mostra o nível de
iluminação utilizando os LEDs como indicadores.

Figura 30 - Implementação prática do circuito do diagrama anterior.

55
4.2 Ultrassom

O sensor de ultrassom é uma ferramenta essencial em muitos


projetos de robótica e automação. Ele funciona emitindo ondas ul-
trassônicas e, em seguida, escutando o eco dessas ondas. Com base
no tempo que o eco leva para retornar, o sensor pode calcular a
distância até o objeto que refletiu a onda.
No código fornecido, começamos definindo os pinos trigPin e
echoPin para os números 27 e 26, respectivamente. O pino trigPin
é responsável por enviar o sinal ultrassônico, enquanto o echoPin
escuta o retorno desse sinal. Também temos os pinos para os LEDs
Verde e Vermelho, que servirão como indicadores visuais.
A velocidade do som, que é crucial para nossos cálculos, é
definida como 0.034 cm por microssegundo. Com essa constante,
podemos determinar a distância de um objeto com base no tempo
que o som leva para atingi-lo e voltar.
Na função setup(), configuramos a comunicação serial e defi-
nimos os modos dos pinos. O loop principal do programa começa
garantindo que o pino trigPin esteja desligado. Depois, um pulso
ultrassônico de 10 microssegundos é enviado. O tempo que esse
pulso leva para retornar é capturado e, com base nesse tempo e na
velocidade do som, calculamos a distância até o objeto.
A distância calculada é então exibida no monitor serial. Além
disso, dependendo da distância detectada, os LEDs são acionados:
se a distância estiver entre 12 e 20 cm, o LED Verde acende, indi-
cando uma distância segura. Se estiver fora desse intervalo, o LED
Vermelho é acionado, sinalizando que o objeto está muito próximo
ou muito distante. Com isso, o código demonstra como usar um
sensor de ultrassom para detectar a distância de um objeto e forne-
cer um feedback visual por meio de LEDs.

56
const int trigPin = 27;
const int echoPin = 26;

#define LedVerde 12
#define LedVermelho 13

//definindo a velocidade do som em cm/uS


#define SOUND_SPEED 0.034

long duration;
float distanceCm;
float distanceInch;

void setup() {
Serial.begin(115200); // Starts the serial communication
pinMode(trigPin, OUTPUT); // Sets the trigPin as an Output
pinMode(echoPin, INPUT); // Sets the echoPin as an Input
pinMode(LedVerde, OUTPUT);
pinMode(LedVermelho, OUTPUT);
}

void loop() {
// Clears the trigPin
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
// Sets the trigPin on HIGH state for 10 micro seconds
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
// Leitura do pino echoPin, tempo que demorou em ir e voltar
duration = pulseIn(echoPin, HIGH);

// Cálculo da Distância
distanceCm = duration * SOUND_SPEED/2;

// Mostra a distância através da comunicação Serial


Serial.print(“Distância (cm): “);
Serial.println(distanceCm);

digitalWrite(LedVerde, distanceCm>=12 && distanceCm<=20 );


digitalWrite(LedVermelho, distanceCm<12 || distanceCm>20);

delay(1000);
}

57
Figura 31 - Diagrama de um sensor de distância
utilizando ultrassom e indicadores com LEDs.

4.2.1 NTC – Resistor sensível à temperatura

Os termistores NTC (Negative Temperature Coefficient) são


resistores cuja resistência varia inversamente com a temperatura.
Ou seja, à medida que a temperatura aumenta, a resistência do
NTC diminui. Eles são comumente usados em aplicações para me-
dir temperatura.
Neste código, o termistor NTC B3950 é utilizado. A tempera-
tura é calculada com base em uma fórmula que relaciona a resis-
tência do termistor à temperatura em Kelvin. Esta fórmula é uma

58
adaptação da equação de Steinhart-Hart, que descreve a resistência
de um termistor em função da temperatura.
Inicialmente, o pino ao qual o termistor está conectado é defi-
nido como NTCPin = 26. Também são estabelecidos alguns valores
constantes: R1, que é o valor do resistor usado em um divisor de
tensão; Beta, uma constante específica do termistor; To, a tempera-
tura em Kelvin equivalente a 25°C; e Ro, a resistência do termistor
a 25°C.
Na função setup(), a comunicação serial é iniciada, permitin-
do que os resultados sejam visualizados no monitor serial. No loop
principal, o valor analógico do pino NTCPin é lido. Esse valor é
usado para calcular a tensão de saída e a resistência atual do ter-
mistor. Com essa resistência, a temperatura em Kelvin é calculada.
Depois, essa temperatura é convertida para Celsius e Fahrenheit.
Os resultados, ou seja, a temperatura em Celsius e o valor
ADC lidos, são então exibidos no monitor serial. O código verifica
se a temperatura em Celsius é positiva antes de imprimí -la, pos-
sivelmente para evitar mostrar valores inválidos. Entre cada leitura,
há um atraso de 1 segundo.
Em resumo, este código oferece uma maneira de medir a tem-
peratura usando um termistor NTC, convertendo a resistência do
termistor em uma leitura de temperatura e exibindo essa leitura. É
uma abordagem simples e eficaz para obter medições de tempera-
tura precisas.

// NTC B3950 Thermistor


// the formula for temp in kelvin is
// 1
// T = ----------------------------
// 1/To + (1/beta) * ln(Rt/Ro)
//
// https://en.wikipedia.org/wiki/Thermistor
int NTCPin = 26;

59
double R1 = 10000.0; // voltage divider resistor value
double Beta = 3950.0; // Beta value
double To = 273.15+25.0; // Temperature in Kelvin for 25 degree
Celsius
double Ro = 10000.0; // Resistance of Thermistor at 25 degree
Celsius

void setup() {
Serial.begin(115200);
}

void loop() {
double Vout, Rt = 0;
double T, Tc, Tf = 0;

double adc = 0;
adc = analogRead(NTCPin);
Vout = adc * 3.3/4095.0;
Rt = R1 * Vout / (3.3 - Vout);

T = 1/(1/To + log(Rt/Ro)/Beta); // Temperatura em Kelvin

Tc = T - 273.15; // Celsius
Tf = Tc * 9 / 5 + 32; // Fahrenheit
if (Tc > 0) Serial.println(Tc);
Serial.println(adc);

delay(1000);
}

Figura 32 - Diagrama de sensor NTC ligado ao ESP-32.

60
Figura 33 - Exibição dos dados de temperatura
na tela. A xícara com água aquecida foi utilizada
para variar abruptamente a temperatura.

61
4.2.2 NTC – Mostrando a temperatura num Display
OLED

O código mostrado abaixo é projetado para ler a temperatu-


ra de um termistor NTC B3950 e exibir essa informação n um
display OLED. A fórmula inicial, comentada no código, é usada
para calcular a temperatura em Kelvin com base na resistência do
termistor, uma adaptação da equação de Steinhart-Hart.
Para comunicar-se com o display OLED, o código incorpora
bibliotecas específicas que facilitam a comunicação I2C e a rende-
rização gráfica no display. Diversas constantes e variáveis são esta-
belecidas para definir parâmetros como as dimensões do display,
o pino ao qual o termistor está conectado e valores associados à
resistência e características do termistor.
Na função setup(), a comunicação serial é iniciada, permitin-
do que mensagens sejam enviadas para a porta serial do dispositi-
vo. O display OLED é então inicializado e, em caso de problemas,
uma mensagem de erro é enviada para a porta serial. Uma vez ini-
cializado com sucesso, o display é configurado para mostrar uma
mensagem de boas-vindas: “Oi, Brasil!” e “Prof Marco”.
A função loop() é onde a mágica acontece. A tensão de saí-
da do termistor é lida e convertida para calcular a resistência atual
do termistor. Com essa resistência, a temperatura em Kelvin é de-
terminada e, em seguida, convertida para Celsius e Fahrenheit. A
temperatura em Celsius é exibida no display OLED.
Aqui vem o detalhe interessante: para fornecer uma represen-
tação visual da leitura da temperatura, uma barra é desenhada no
display OLED. Esta barra é criada usando o comando display.fill-
RoundRect(). A largura da barra é proporcional à temperatura em
Celsius, e isso é feito multiplicando a temperatura atual por um
fator de escala, neste caso, 118/50. Isso significa que, para cada grau

62
Celsius, a barra cresce aproximadamente 2,36 pixels de largura. A
barra tem uma altura fixa de 10 pixels e cantos arredondados para
uma estética agradável. À medida que a temperatura aumenta, a
barra se expande horizontalmente, fornecendo uma representação
visual intuitiva da leitura da temperatura.
As variáveis utilizadas para armazenar e calcular os valores
de temperatura e resistência são essenciais para o funcionamento
correto do código. Em resumo, este código não apenas lê e exibe
a temperatura de um termistor num display OLED, mas também
fornece uma representação visual clara e intuitiva da temperatu-
ra, tornando-o ideal para aplicações que requerem monitoramento
contínuo da temperatura.

// NTC B3950 Thermistor


// the formula for temp in kelvin is
// 1
// T = ----------------------------
// 1/To + (1/beta) * ln(Rt/Ro)
//
// https://en.wikipedia.org/wiki/Thermistor
//Bibliotecas para o OLED display
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>

#define SCREEN_WIDTH 128 // OLED display largura, em pixels


#define SCREEN_HEIGHT 64 // OLED display altura, em pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
&Wire, -1);

int NTCPin = 26;

double R1 = 10000.0; // voltage divider resistor value


double Beta = 3950.0; // Beta value
double To = 273.15+25.0; // Temperature in Kelvin for 25 degree
Celsius
double Ro = 10000.0; // Resistance of Thermistor at 25 degree
Celsius

63
const double rx = Ro * exp(-Beta/To);

void setup() {
Serial.begin(115200);

if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address


0x3D for 128x64
Serial.println(F(“SSD1306 allocation failed”));
for(;;);
}
display.clearDisplay();

display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(33, 0);
// Oled siplay 128x64
display.println(“Oi, Brasil!”);

display.fillRoundRect(35, 19, 56, 6, 2, WHITE);


display.drawLine(0, 30, 127, 30, WHITE);

display.setCursor(3, 36);
display.setTextSize(2);
display.println(“Prof Marco”);
display.display();
delay(4000);
}

void loop() {

double Vout, Rt = 0;
double T, Tc, Tf = 0;

double adc = 0;
adc = analogRead(NTCPin);
Vout = adc * 3.3/4095.0;
Rt = R1 * Vout / (3.3 - Vout);

T = 1/(1/To + log(Rt/Ro)/Beta); // Temperature in Kelvin


//T = Beta/log(Rt/rx);
Tc = T - 273.15; // Celsius
Tf = Tc * 9 / 5 + 32; // Fahrenheit

64
if (Tc > 0) Serial.println(Tc);
Serial.println(adc);
display.clearDisplay();
display.setCursor(2, 0);
display.setTextSize(2);
display.println(“Prof Marco”);

display.setCursor(5, 20);
display.print(“T:”);
display.print(Tc);
display.fillRoundRect(5, 50, Tc*118/50, 10, 2, WHITE);
display.display();

delay(1000);
}

Figura 34 - Diagrama do circuito utilizando NTC para


medir a temperatura e um OLED como indicador
para mostrar o valor da temperatura.

4.3 O DHT22 – Sensor de Umidade e Temperatura

O DHT22 é um sensor confiável e de baixo custo utilizado


para medir tanto a umidade relativa do ar quanto a temperatura
ambiente. Ele se destaca por sua capacidade de fornecer leituras
precisas com uma resolução relativamente alta, tornando-o uma

65
escolha popular para projetos de automação residencial, estações
meteorológicas pessoais e diversas outras aplicações que requerem
monitoramento ambiental.
Comparado a outros sensores de umidade e temperatura,
como o DHT11, o DHT22 oferece uma faixa de medição mais am-
pla e uma precisão aprimorada. Ele pode medir temperaturas de
-40°C a 80°C com uma precisão de ±0,5°C e umidade de 0% a 100%
com uma precisão de ±2%.
Uma das características marcantes do DHT22 é sua simplici-
dade de uso. Ele requer apenas uma conexão de alimentação, ter-
ra e um único pino de dados para operar. A comunicação com o
sensor é realizada através de um protocolo serial proprietário, o
que permite que ele seja facilmente integrado a uma variedade de
microcontroladores, incluindo o ESP-32.
Nos subtópicos subsequentes, exploraremos como utilizar o
DHT22 em diferentes cenários, desde a configuração básica até a
integração com displays OLED para uma visualização mais intuiti-
va dos dados coletados.

4.3.1 Programa Básico do DHT22

O código apresentado é destinado a operar com o sensor


DHT22, um sensor amplamente utilizado para medir temperatura
e umidade. O DHT22 é conhecido por sua precisão e facilidade de
uso, sendo uma escolha popular para muitos projetos que envol-
vem monitoramento ambiental.
O código começa com um cabeçalho que indica sua origem
e fornece um link para instruções detalhadas e um diagrama de
fiação. Isso é útil para qualquer pessoa que queira replicar o projeto
ou entender melhor o contexto em que o código foi criado.

66
A biblioteca <DHT.h> é incluída no início do código. Esta bi-
blioteca contém funções e definições que facilitam a comunicação
com o sensor DHT22. Em seguida, são definidas duas constantes:
DHT_SENSOR_PIN, que indica o pino do ESP32 ao qual o sensor
está conectado, e DHT_SENSOR_TYPE, que especifica o tipo de
sensor DHT em uso (neste caso, DHT22).
Um objeto dht_sensor é então criado usando a classe DHT,
e os parâmetros previamente definidos são passados para o cons-
trutor. Este objeto será usado para interagir com o sensor e obter
leituras de temperatura e umidade.
Na função setup(), a comunicação serial é iniciada com uma
taxa de transmissão de 115200 bps, permitindo a comunicação
entre o ESP32 e um computador ou outro dispositivo. O sensor
DHT22 é então inicializado com o método begin().
A função loop() contém a lógica principal do programa. Aqui,
o código lê a umidade e a temperatura em Celsius e Fahrenheit
usando os métodos readHumidity() e readTemperature(), respec-
tivamente. O método readTemperature(true) é usado para obter
a temperatura em Fahrenheit, enquanto readTemperature() sem
parâmetros retorna a temperatura em Celsius.
Após a leitura dos valores, o código verifica se as leituras são
válidas usando a função isnan(). Se alguma das leituras for inválida
(por exemplo, devido a uma falha de comunicação com o sensor),
uma mensagem de erro é enviada para a porta serial. Caso contrá-
rio, as leituras de umidade e temperatura são enviadas para a porta
serial em um formato legível.
Por fim, o código pausa por 2 segundos usando o comando
delay(2000), permitindo um intervalo entre as leituras e evitando
a sobrecarga do sensor ou da porta serial.

67
Em resumo, este código oferece uma solução simples e eficaz
para ler e exibir valores de temperatura e umidade de um sensor
DHT22 usando um ESP32. A saída formatada e as verificações de
validade das leituras garantem que os dados apresentados sejam
precisos e confiáveis.

/*
* This ESP32 code is created by esp32io.com
*
* This ESP32 code is released in the public domain
*
* For more detail (instruction and wiring diagram), visit https://
esp32io.com/tutorials/esp32-temperature-humidity-sensor
*/
#include <DHT.h>
#define DHT_SENSOR_PIN 26 // ESP32 pin GIOP21 connected
to DHT22 sensor
#define DHT_SENSOR_TYPE DHT22

DHT dht_sensor(DHT_SENSOR_PIN, DHT_SENSOR_TYPE);

void setup() {
Serial.begin(115200);
dht_sensor.begin(); // initialize the DHT sensor
}

void loop() {
// read humidity
float humi = dht_sensor.readHumidity();
// read temperature in Celsius
float tempC = dht_sensor.readTemperature();
// read temperature in Fahrenheit
float tempF = dht_sensor.readTemperature(true);

// check whether the reading is successful or not


if ( isnan(tempC) || isnan(tempF) || isnan(humi)) {
Serial.println(“Failed to read from DHT sensor!”);
} else {
Serial.print(“Humidity: “);
Serial.print(humi);
Serial.print(“%”);

68
Serial.print(“ | “);

Serial.print(“Temperature: “);
Serial.print(tempC);
Serial.print(“°C ~ “);
Serial.print(tempF);
Serial.println(“°F”);
}

delay(2000); // wait a 2 seconds between readings


}

Figura 35 - Diagrama utilizando o sensor DHT22


para medição de temperatura e umidade. Note que
o sensor já envia o valor de forma digital.

Figura 36 - Implementação do DHT22 em um circuito prático.

69
4.3.2 Mostrando a umidade e temperatura medida
pelo DHT22 num display OLED

O código apresentado é uma extensão do programa anterior,


que lia a temperatura e a umidade do sensor DHT22. Nesta versão,
além de ler esses valores, o programa também exibe as informações
em um display OLED, proporcionando uma interface visual para o
usuário.
O código começa incluindo a biblioteca DHT.h, que facilita a
comunicação com o sensor DHT22. As constantes DHT_SENSOR_
PIN e DHT_SENSOR_TYPE são definidas para especificar o pino
de conexão e o tipo de sensor, respectivamente. Em seguida, um
objeto dht_sensor é criado para interagir com o sensor.
Para a comunicação e renderização no display OLED, são inclu-
ídas as bibliotecas Wire.h, Adafruit_GFX.h e Adafruit_SSD1306.h.
Estas bibliotecas contêm funções e definições que simplificam a
interação com displays OLED via comunicação I2C. As constan-
tes SCREEN_WIDTH e SCREEN_HEIGHT definem as dimensões do
display em pixels. Um objeto display é então criado para represen-
tar o display OLED.
Na função setup(), a comunicação serial é iniciada e o sensor
DHT22 é inicializado. O display OLED também é inicializado e,
em caso de falha, uma mensagem de erro é enviada para a porta
serial. Se o display for inicializado com sucesso, ele exibirá uma
mensagem de boas-vindas “Oi-Brasil!” e “Prof Marco”.
A função loop() contém a lógica principal do programa. Aqui,
o código lê a umidade e a temperatura em Celsius. Se as leituras fo-
rem inválidas, uma mensagem de erro é enviada para a porta serial.
Caso contrário, os valores de umidade e temperatura são exibidos
tanto na porta serial quanto no display OLED.

70
No display OLED, a umidade é precedida pela letra “U” e a tem-
peratura pela letra “T”. Além disso, uma barra visual é desenhada na
parte inferior do display, representando a temperatura atual. A lar-
gura desta barra é proporcional à temperatura em Celsius, crescendo
aproximadamente 2,36 pixels para cada grau Celsius. Esta barra ofe-
rece uma representação gráfica intuitiva da temperatura ambiente.
Por fim, o programa pausa por 2 segundos, permitindo um
intervalo entre as leituras.

#include <DHT.h>
#define DHT_SENSOR_PIN 26 //Pino de dados do Sensor DHT22
#define DHT_SENSOR_TYPE DHT22
DHT dht_sensor(DHT_SENSOR_PIN, DHT_SENSOR_TYPE);
//Bibliotecas para o OLED
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display largura, em pixels
#define SCREEN_HEIGHT 64 // OLED display altura, em pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
&Wire, -1);

void setup() {
Serial.begin(115200);
dht_sensor.begin(); // Inicializando o Sensor DHT
delay(500);
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address
0x3D for 128x64
Serial.println(F(“SSD1306 allocation failed”));
for(;;);
}
display.clearDisplay();
display.setTextSize(2); display.setTextColor(WHITE);
display.setCursor(0, 0); display.println(“Oi-Brasil!”);
display.setCursor(3, 36); display.setTextSize(2);
display.println(“Prof Marco”);
display.display();
delay(4000);
}

71
void loop() {
float humi = dht_sensor.readHumidity(); // Leitura de Umidade
float tempC = dht_sensor.readTemperature(); // Leitura de
temperatura em Celsius

if ( isnan(tempC) || isnan(humi)) { // Verificação da leitura


correta de umidade e temp.
Serial.println(“Failed to read from DHT sensor!”);
} else {
Serial.print(“Umidade: “); Serial.print(humi); Serial.print(“%”);
Serial.print(“ | “);
Serial.print(“Temperatura: “); Serial.print(tempC); Serial.
println(“°C”);

display.clearDisplay(); display.setCursor(5, 0); display.


println(“Prof Marco”);
display.print(“U: “); display.print(humi); display.println(“%”);
display.print(“T: “); display.print(tempC); display.println(“C”);
display.fillRoundRect(5, 50, tempC*118/50, 10, 2, WHITE);
display.display();
}
delay(2000); // Espera de 2 segundos entre as leituras
}

Figura 37 - Diagrama do circuito que mostra temperatura


e umidade na tela usando como sensor o DHT22.

72
Figura 38 - Implementação do circuito anterior na prática.

4.3.3 Medição da umidade e temperatura usando o


DHT22 e DHT11 num display OLED

O código apresentado é uma extensão do programa anterior, que


lia a temperatura e a umidade do sensor DHT22. Nesta versão, além
de ler esses valores, o programa também exibe as informações em um
display OLED, proporcionando uma interface visual para o usuário.
O código começa incluindo a biblioteca DHT.h, que facilita a
comunicação com o sensor DHT22. As constantes DHT_SENSOR_
PIN e DHT_SENSOR_TYPE são definidas para especificar o pino
de conexão e o tipo de sensor, respectivamente. Em seguida, um
objeto dht_sensor é criado para interagir com o sensor.
Para a comunicação e renderização no display OLED, são inclu-
ídas as bibliotecas Wire.h, Adafruit_GFX.h e Adafruit_SSD1306.h.
Estas bibliotecas contêm funções e definições que simplificam a
interação com displays OLED via comunicação I2C. As constan-
tes SCREEN_WIDTH e SCREEN_HEIGHT definem as dimensões do
display em pixels. Um objeto display é então criado para represen-
tar o display OLED.

73
Na função setup(), a comunicação serial é iniciada e o sensor
DHT22 é inicializado. O display OLED também é inicializado e,
em caso de falha, uma mensagem de erro é enviada para a porta
serial. Se o display for inicializado com sucesso, ele exibirá uma
mensagem de boas-vindas: “Oi-Brasil!” e “Prof Marco”.
A função loop() contém a lógica principal do programa. Aqui,
o código lê a umidade e a temperatura em Celsius. Se as leituras fo-
rem inválidas, uma mensagem de erro é enviada para a porta serial.
Caso contrário, os valores de umidade e temperatura são exibidos
tanto na porta serial quanto no display OLED.
No display OLED, a umidade é precedida pela letra “U” e a tem-
peratura pela letra “T”. Além disso, uma barra visual é desenhada na
parte inferior do display, representando a temperatura atual. A lar-
gura desta barra é proporcional à temperatura em Celsius, crescendo
aproximadamente 2,36 pixels para cada grau Celsius. Esta barra ofe-
rece uma representação gráfica intuitiva da temperatura ambiente.
Por fim, o programa pausa por 2 segundos, permitindo um
intervalo entre as leituras.

//Bibliotecas para o OLED


#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#define SCREEN_WIDTH 128 // OLED display largura, em pixels
#define SCREEN_HEIGHT 64 // OLED display altura, em pixels
Adafruit_SSD1306 display(SCREEN_WIDTH, SCREEN_HEIGHT,
&Wire, -1);

#include <DHT.h>
#define DHT22_SENSOR_PIN 26
#define DHT11_SENSOR_PIN 25

DHT dht22_sensor(DHT22_SENSOR_PIN, DHT22);


DHT dht11_sensor(DHT11_SENSOR_PIN, DHT11);

74
void setup() {
Serial.begin(115200);
dht22_sensor.begin(); // Inicializando o sensor DHT22
dht11_sensor.begin(); // Inicializando o sensor DHT11
if(!display.begin(SSD1306_SWITCHCAPVCC, 0x3C)) { // Address
0x3D for 128x64
Serial.println(F(“SSD1306 allocation failed”));
for(;;);
}
display.clearDisplay();

display.setTextSize(2); display.setTextColor(WHITE);
display.setCursor(0, 0); display.println(“Oi-Brasil!”);
display.setCursor(3, 36); display.println(“Prof Marco”);
display.display();
delay(4000);
}

void loop() {
// Leitura da umidade
float umid22 = dht22_sensor.readHumidity();
float umid11 = dht11_sensor.readHumidity();
// Leitura da temperatura em celsius
float tempC22 = dht22_sensor.readTemperature();
float tempC11 = dht11_sensor.readTemperature();

// Checagem da leitura correta da umidade e temperatura


if ( isnan(tempC22) || isnan(tempC11) || isnan(umid22)||
isnan(umid11)) {
Serial.println(“Erro na leitura dos sensores!”);
} else {
Serial.print(“Umid22: “); Serial.print(umid22); Serial.print(“%”);
Serial.print(“ | “);
Serial.print(“Umid11: “); Serial.print(umid11); Serial.print(“% “);

Serial.print(“Temp22: “); Serial.print(tempC22); Serial.


print(“°C ~ “);
Serial.print(“ | “);
Serial.print(“Temp11: “); Serial.print(tempC11); Serial.
println(“°C”);

display.clearDisplay();

75
display.setTextSize(2); display.setCursor(5, 0); display.
println(“Prof Marco”);
display.setCursor(3, 25); display.setTextSize(1);
display.print(“U1:”); display.print(umid11);
display.print(“ | U2:”); display.print(umid22); display.println(“%”);
display.fillRoundRect(5, 35, tempC11*118/50, 3, 2, WHITE);
display.setCursor(3, 50);
display.print(“T1:”); display.print(tempC11);
display.print(“ | T2:”); display.print(tempC22); display.
println(“C”);
display.fillRoundRect(5, 60, tempC22*118/50, 3, 2, WHITE);
display.display();
}
// Aguarda 2 segundos para a próxima leitura
delay(2000);
}

Figura 39 - Comparação entre os sensores DHT11


(azul) e DHT22 (branco) mostrados na tela.

76
Figura 40 - Diagrama esquemático do circuito
implementado na figura anterior.

4.4 O MAX9814 – Sensor de som

O MAX9814 é um microfone amplificador que pode ser usado


para detectar níveis de som. O código é projetado para ler o nível
de som através de uma entrada analógica e, com base em certos
limiares, controlar um LED.
No início do código, algumas definições são estabelecidas. A
constante AN_Pot1 é definida como 2, indicando que o pino 2 é
usado para ler o sinal analógico do MAX9814. A constante pinLed
é definida como 23, representando o pino ao qual um LED está
conectado. A variável SOM é usada para armazenar a leitura ana-
lógica do nível de som.
Na função setup(), a comunicação serial é iniciada com uma
taxa de transmissão de 115200 bps. O pino do LED é configurado
como saída usando a função pinMode().
A função loop() contém a lógica principal do programa. Aqui,
o nível de som é lido usando a função analogRead() e armazena-

77
do na variável SOM. Este valor é então enviado para a porta serial
usando o comando Serial.println().
Uma verificação condicional é feita para determinar se o valor
lido está acima de 2800 ou abaixo de 250. Se qualquer uma dessas
condições for verdadeira, o estado do LED é alternado usando a
combinação das funções digitalWrite() e digitalRead(). Isso signifi-
ca que, se o LED estiver aceso, ele será desligado e vice-versa. Após
alternar o estado do LED, o programa pausa por 300 milissegundos
usando delay(300).
Em resumo, este código monitora o nível de som através do
MAX9814 e, com base em certos limiares, controla o estado de um
LED. É uma implementação simples que pode ser usada em aplica-
ções onde a detecção de níveis de som é necessária, como sistemas
de alarme ou dispositivos interativos baseados em som.

//Bibliotecas para o OLED


# neste exemplo usamos o max 9814
#define AN_Pot1 2
#define pinLed 23
int SOM = 0;

void setup()
{
Serial.begin(115200);
pinMode(pinLed, OUTPUT);
}
void loop()
{
SOM = analogRead(AN_Pot1);
Serial.println(SOM);
delay(1);
if((SOM > 2800)||(SOM<250)){
digitalWrite(pinLed, !digitalRead(pinLed));
delay(300);
}
}

78
Figura 41 - Pinagem do ESP-32 modelo ESPWROOM32.

Figura 42 - Implementação do circuito que


acende e apaga o LED ao bater palma.

79
Figura 43 - Diagrama do circuito implementado na figura anterior.

Figura 44 - Exibição do circuito em funcionamento.


Note a captação de som na tela. Essa informação
é enviada via cabo USB para o computador.

80
5.
ATUADORES

Os atuadores desempenham um papel fundamental em sis-


temas embarcados e automação, servindo como a ponte entre o
mundo digital e o mundo físico. Eles transformam os comandos
e decisões tomados por um microcontrolador em ações concretas,
permitindo que nossos dispositivos interajam e respondam ao am-
biente ao seu redor.
No contexto do ESP-32, uma plataforma versátil e poderosa, os
atuadores como LEDs, servomotores, buzzers, relés e motores DC
são frequentemente utilizados para demonstrar e validar funciona-
lidades, bem como para construir aplicações práticas e inovadoras.

• LEDs: estes são, talvez, os atuadores mais básicos e amplamen-


te utilizados em eletrônica. Eles são frequentemente emprega-
dos como indicadores de status, sinalizadores ou até mesmo
para criar efeitos visuais impressionantes. No ESP-32, graças
à capacidade de modulação por largura de pulso (PWM), é
possível controlar a luminosidade de um LED, permitindo
uma ampla gama de aplicações, desde simples notificações até
iluminação ambiente sofisticada.

81
• Servomotores: estes pequenos e potentes motores são capa-
zes de mover-se a um ângulo específico com grande precisão.
Eles são amplamente utilizados em robótica, modelismo e em
qualquer aplicação que exija movimento controlado. Com o
ESP-32, é possível controlar vários servomotores simultanea-
mente, tornando-o ideal para projetos que exigem movimen-
tos coordenados.
• Buzzers: estes atuadores sonoros são utilizados para gerar tons
e melodias. Eles são frequentemente empregados em alarmes,
notificações sonoras e até mesmo em pequenos instrumentos
musicais. O ESP-32, com sua capacidade de gerar ondas sono-
ras de diferentes frequências, permite que os desenvolvedores
criem uma variedade de efeitos sonoros e melodias.
• Relés: são dispositivos eletromecânicos que funcionam
como interruptores. Eles permitem que o ESP-32 controle
dispositivos de alta potência, como lâmpadas e motores, de
forma segura e eficaz. São essenciais em projetos de automa-
ção residencial e industrial.
• Motores DC: estes são motores que operam com corrente
contínua e são amplamente utilizados em robótica e disposi-
tivos móveis. Com o ESP-32, é possível controlar a direção e a
velocidade dos motores DC, permitindo a criação de veículos
autônomos, robôs e outras máquinas móveis.

A capacidade de integrar e controlar esses atuadores com o


ESP-32 abre um mundo de possibilidades para desenvolvedores e
entusiastas. Desde a criação de pequenos robôs autônomos até sis-
temas de notificação inteligentes, os atuadores são essenciais para
dar vida às nossas invenções e ideias.

82
5.1. O PWM, modulação por largura de pulso

5.1.1. Controlando a luminosidade de um Led usan-


do o PWM

O código tem como objetivo controlar a luminosidade de um


LED usando a técnica de modulação por largura de pulso (PWM).
O PWM é uma técnica que permite controlar a potência entregue a
um dispositivo, como um LED, variando a largura do pulso de uma
onda quadrada. No caso de um LED, isso se traduz em controlar
seu brilho.
O código começa definindo o pino ao qual o LED está conec-
tado, usando a constante pinoLedPWM definida como 23.
Na função setup(), o pino do LED é configurado como saída
usando a função pinMode(). Em seguida, a função ledcAttachPin()
é usada para atribuir o pino 23 ao canal 0 do controlador PWM. A
função ledcSetup() é então usada para configurar o canal 0 com
uma frequência de 1000Hz e uma resolução de 10 bits. Isso signifi-
ca que o valor do duty cycle pode variar de 0 a 1023 ( ).
A função loop() contém a lógica principal do programa. Aqui,
dois loops for são usados para variar a luminosidade do LED. No
primeiro loop, o valor do duty cycle é incrementado de 0 a 1023,
fazendo o LED aumentar gradualmente seu brilho. No segundo
loop, o valor do duty cycle é decrementado de 1023 a 0, fazendo
o LED diminuir gradualmente seu brilho. A função ledcWrite() é
usada para definir o valor do duty cycle para o canal 0. Entre cada
alteração do duty cycle, há uma pausa de 4 milissegundos usando
a função delay().
Desta maneira, o código faz o LED brilhar gradualmente até
atingir sua luminosidade máxima e, em seguida, diminuir gradu-

83
almente até ficar completamente apagado. Esse ciclo de aumento
e diminuição da luminosidade é repetido continuamente, criando
um efeito de “respiração” para o LED. É uma implementação sim-
ples, mas eficaz, para demonstrar o controle de luminosidade de
um LED usando PWM no ESP32.

#define pinoLedPWM 23
void setup()

{
pinMode(pinoLedPWM, OUTPUT);

ledcAttachPin(pinoLedPWM, 0);//Atribuímos o pino 23 ao


canal 0.
ledcSetup(0, 1000, 10);//Atribuímos ao canal 0 a freq.de 1000Hz
com resolução de 10bits.
}

void loop()
{
for (int i = 0; i < 1024; i++)
{
ledcWrite(0, i);//Escrevemos no canal 0, o duty cycle “i”.
delay(4);
}

for (int i = 1023; i > 0; i--)


{
ledcWrite(0, i);
delay(4);
}
}

84
Figura 45 - Diagrama da ligação de um LED na ESP-32. O
código interno permite o controle do brilho por meio de PWM.

Figura 46 - Implementação prática do circuito


mostrado na figura anterior.

85
5.1 Usando o PWM e entradas Analógicas

5.1.1 Regular a luminosidade de um Led com PWM


usando um potenciômetro

O código tem como objetivo controlar a luminosidade de um


LED usando a técnica de modulação por largura de pulso (PWM),
mas, desta vez, a luminosidade é ajustada com base na leitura de
um potenciômetro.
O código começa definindo duas constantes: AN_Pot1, que re-
presenta o pino ao qual o potenciômetro está conectado (definido
como 2), e pinoLedPWM, que representa o pino ao qual o LED está
conectado (definido como 23). Além disso, uma variável AN_Pot1_
Result é declarada para armazenar o valor lido do potenciômetro.

Na função setup(), o pino do LED é configurado como saída


usando a função pinMode(). Em seguida, a função ledcAttachPin()
é usada para atribuir o pino 23 ao canal 0 do controlador PWM. A
função ledcSetup() é então usada para configurar o canal 0 com
uma frequência de 1000Hz e uma resolução de 12 bits. A comuni-
cação serial é iniciada com uma taxa de transmissão de 115200 bps
usando Serial.begin(115200).
A função loop() contém a lógica principal do programa. Aqui,
o valor do potenciômetro é lido usando a função analogRead() e
armazenado na variável AN_Pot1_Result. Esse valor é então envia-
do para a porta serial usando Serial.println(). A função ledcWrite()
é usada para definir o valor do duty cycle para o canal 0 com base
no valor lido do potenciômetro. Há uma pausa de 100 milissegun-
dos entre cada leitura usando a função delay().
Em resumo, o código permite que o usuário ajuste a luminosi-
dade de um LED girando um potenciômetro. À medida que o po-

86
tenciômetro é girado, a resistência varia, o que altera a leitura analó-
gica. Essa leitura é então usada para ajustar a luminosidade do LED.
É uma implementação prática que demonstra como um dispositi-
vo de entrada (neste caso, um potenciômetro) pode ser usado para
controlar um dispositivo de saída (o LED) em tempo real.

#define AN_Pot1 2
#define pinoLedPWM 23
int AN_Pot1_Result = 0;

void setup()
{
pinMode(pinoLedPWM, OUTPUT);
ledcAttachPin(pinoLedPWM, 0);//Atribuimos o pino 2 ao canal
0.
ledcSetup(0, 1000, 12);//Atribuimos ao canal 0 a frequencia de
1000Hz com resolucao de 12 bits.

Serial.begin(115200);
}

void loop()
{
AN_Pot1_Result = analogRead(AN_Pot1);
Serial.println(AN_Pot1_Result);
ledcWrite(0, AN_Pot1_Result);//Escrevemos no canal 0, o duty
cycle “i”.
delay(100);
}

87
Figura 47 - Diagrama do circuito que controla a luminosidade do
LED por meio de entrada analógica do potenciômetro e PWM.

Figura 48 - Circuito que controla a luminosidade do LED


via potenciômetro e PWM montado no protoboard.

88
5.2 Como usar um Led RGB

O código tem como objetivo demonstrar o uso de um LED


RGB. Um LED RGB é um dispositivo que contém três LEDs em
uma única embalagem: um vermelho (Red), um verde (Green) e
um azul (Blue). Combinando essas três cores em diferentes intensi-
dades, é possível criar uma ampla variedade de cores.
O código começa definindo três constantes: PIN_RED, PIN_
GREEN e PIN_BLUE, que representam os pinos aos quais os LEDs
vermelho, verde e azul estão conectados, respectivamente.
Na função setup(), cada pino LED é associado a um canal
PWM específico usando a função ledcAttachPin(). Por exemplo,
o pino 5 (LED vermelho) é associado ao canal 0. Em seguida, a
função ledcSetup() é usada para configurar cada canal com uma
frequência de 1000Hz e uma resolução de 8 bits.
A função loop() contém a lógica principal do programa. Aqui,
diferentes combinações de cores são criadas ajustando a intensida-
de dos três LEDs:

1.Vermelho: apenas o LED vermelho é ligado, enquanto os LEDs


verde e azul são desligados.
2.Verde: apenas o LED verde é ligado, enquanto os LEDs verme-
lho e azul são desligados.
3.Azul: apenas o LED azul é ligado, enquanto os LEDs vermelho
e verde são desligados.
4.Amarelo: os LEDs vermelho e verde são ligados ao mesmo
tempo, enquanto o LED azul é desligado. A combinação das
cores vermelho e verde cria a cor amarela.

89
Entre cada mudança de cor, há uma pausa de 1 segundo (1000
milissegundos) usando a função delay().
Com isso, o código demonstra como controlar um LED RGB
usando a técnica de modulação por largura de pulso (PWM) para
criar diferentes cores. Através da combinação das três cores básicas
em diferentes intensidades, é possível criar uma ampla gama de co-
res, tornando o LED RGB uma ferramenta versátil em projetos de
iluminação e sinalização.

#define PIN_RED 5 // GIOP19


#define PIN_GREEN 18 // GIOP18
#define PIN_BLUE 19 // GIOP05

void setup() {
ledcAttachPin(PIN_RED, 0);//Atribuímos o pino 5 ao canal 0.
ledcSetup(0, 1000, 8);//Canal 0 com f=1000Hz e resolucao de
8bits.

ledcAttachPin(PIN_GREEN, 1);//Atribuímos o pino 18 ao


canal 1.
ledcSetup(1, 1000, 8);//Canal 1 com f=1000Hz e resolução de
8bits.

ledcAttachPin(PIN_BLUE, 2);//Atribuímos o pino 18 ao canal 2.


ledcSetup(2, 1000, 8);//Canal 2 com f=1000Hz e resolução de
8bits.
}

void loop() {
//Mostrando primeiro o Vermelho
ledcWrite(0, 255);
ledcWrite(1, 0);
ledcWrite(2, 0);
delay(1000);

// Verde
ledcWrite(0, 0);
ledcWrite(1, 255);
ledcWrite(2, 0);
delay(1000);

90
// Azul
ledcWrite(0, 0);
ledcWrite(1, 0);
ledcWrite(2, 255);
delay(1000);

// Amarelo = Verde e Vermelho


ledcWrite(0, 255);
ledcWrite(1, 255);
ledcWrite(2, 0);
delay(1000);
}

Figura 49 - Diagrama de conexão do ESP-32 com um shield LED RGB.

91
Figura 50 - Foto com detalhe do shield LED RGB.

Figura 51 - Foto de outro ângulo do ESP-32 com o shield LED RGB.

92
5.3 Buzzer, Passivo, produzindo SOM

O código apresentado tem como objetivo controlar um buz-


zer passivo usando a técnica de modulação por largura de pulso
(PWM). O buzzer passivo é um dispositivo que pode produzir di-
ferentes tons de som com base na frequência e intensidade (duty
cycle) do sinal PWM fornecido.
No início do código, algumas constantes e variáveis são defini-
das para configurar o buzzer. A constante freq define, a frequência
inicial do sinal PWM, enquanto canal e resolução especificam o
canal PWM e a resolução do sinal, respectivamente.
A função setup() é responsável por inicializar a comunicação
serial e configurar o buzzer para uso com PWM. A função ledcSe-
tup() é usada para configurar o canal PWM, definindo sua frequ-
ência e resolução. A função ledcAttachPin() associa um pino espe-
cífico ao canal PWM.
A função loop() é o coração deste código, pois é onde a lógica
principal de controle do buzzer passivo é executada. Ela começa
variando o duty cycle de 0 a 255 em incrementos de 10. O duty
cycle representa a proporção de tempo que o sinal PWM está em
nível alto em relação ao período total do sinal. Para cada valor de
duty cycle, o código imprime o valor atual no monitor serial, define
o duty cycle para o buzzer, aguarda um segundo para que o som
seja audível e, em seguida, desliga o buzzer por um breve momento.
Após completar a variação do duty cycle, o código define um
duty cycle fixo de 125, garantindo que o som produzido tenha uma
intensidade constante. Em seguida, varia a frequência do som de
255Hz a 10kHz em incrementos de 250Hz. A frequência determina
o tom do som, com frequências mais altas produzindo tons mais
agudos e frequências mais baixas resultando em tons mais graves.
Para cada valor de frequência, o código imprime o valor atual no

93
monitor serial, define a frequência para o buzzer e aguarda um bre-
ve momento para que o tom seja audível.
Ao final de ambas as variações, a função loop() recomeça, re-
petindo o processo indefinidamente. Isso permite que o usuário
ouça continuamente as mudanças na intensidade e no tom do som
produzido pelo buzzer, demonstrando efetivamente o controle do
buzzer passivo usando PWM.

int freq = 2000;


int canal = 0;
int resolucao = 8;

void setup() {
Serial.begin(115200);
ledcSetup(canal, freq, resolucao);
ledcAttachPin(33, canal);
}

void loop() {

for (int dutyCycle = 0; dutyCycle <= 255;


dutyCycle=dutyCycle+10){

Serial.println(dutyCycle);

ledcWrite(canal, dutyCycle);
delay(1000);
ledcWrite(canal, 0);
delay(100);
}

ledcWrite(canal, 125);

for (int freq = 255; freq < 10000; freq = freq + 250){
Serial.println(freq);

ledcWriteTone(canal, freq);
delay(100);
}
}

94
Figura 52 - Diagrama para utilização do buzzer ativo com ESP-32.

5.4 Buzzer Passivo - construindo um mini piano

O código apresentado tem como objetivo transformar o ESP32


em um mini piano usando um buzzer passivo. Inicialmente, são defi-
nidos o pino do buzzer e algumas variáveis relacionadas ao controle do
buzzer usando a técnica de modulação por largura de pulso (PWM).
O pino do buzzer é definido como 4, a frequência inicial é definida
como 1000Hz, o canal do buzzer é o canal 0 e a resolução é de 10 bits.
Em seguida, são definidos os pinos dos botões que represen-
tam as teclas do piano e as notas associadas a cada botão. O array
buttonPins contém os pinos GPIO dos botões, enquanto o array
buttonTones contém as notas correspondentes. A constante num-
Tones indica o número total de notas disponíveis.

A função setup() inicializa a comunicação serial e configura


os pinos dos botões como entradas com resistores de pull-up inter-

95
nos. Isso significa que, por padrão, os pinos dos botões lerão HIGH
(alto) e mudarão para LOW (baixo) quando um botão for pressio-
nado. Além disso, o pino do buzzer é configurado como saída e o
buzzer é preparado para uso com PWM.
A função loop() é onde a lógica principal do minipiano é exe-
cutada. Ela começa verificando se algum dos botões foi pressiona-
do. Se um botão for pressionado, a nota correspondente é atribuída
à variável nota e a flag butApertou é definida como verdadeira.
Um pequeno delay de 10ms é adicionado para evitar leituras falsas
devido ao efeito de debounce dos botões.
Após verificar todos os botões, o código verifica se a flag bu-
tApertou é verdadeira. Se for, o buzzer toca a nota corresponden-
te ao botão pressionado usando a função ledcWriteNote(). Caso
contrário, o buzzer é desligado usando a função ledcWriteTone().
Por fim, o estado da flag butApertou é impresso no monitor se-
rial, permitindo que o usuário veja se um botão foi pressionado
ou não.
Desta maneira, este código permite que o usuário toque dife-
rentes notas em um buzzer passivo pressionando diferentes botões,
transformando o ESP32 em um minipiano.

//No esp32 30 pinos: com pull up interno são os GPIOs: 14, 16, 17,
18, 19, 21, 22 e 23
#define pinoBuzzer 4
int freq = 1000, canalBuzzer = 0, resolucao = 10;
const int buttonPins[] = { 18, 19, 21, 22, 23};
const note_t buttonTones[] = {
NOTE_C, NOTE_D, NOTE_E, NOTE_F, NOTE_G };
const int numTones = 5;
note_t nota;
void setup() {
Serial.begin(115200);
for (int i = 0; i < numTones; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}

96
pinMode(pinoBuzzer, OUTPUT);
ledcSetup(canalBuzzer, freq, resolucao);
ledcAttachPin(pinoBuzzer, canalBuzzer);
}

void loop() {
note_t nota; bool butApertou = 0;
for (int i = 0; i < numTones; i++) {
if (digitalRead(buttonPins[i]) == LOW) {
nota = buttonTones[i];
butApertou = 1;
delay(10);
}
}

if (butApertou) {
ledcWriteNote(canalBuzzer, nota, 5);
}
else {
ledcWriteTone(canalBuzzer, 0);
}
Serial.println(butApertou);
}

Figura 53 - Diagrama do piano usando ESP-32 e buzzer.

97
5.5 Buzzer Passivo, o hino de um time de futebol

O circuito a seguir mostra o ESP32 controlando um buzzer


para tocar o hino de um time de futebol. Para isso ser possível,
conecta-se no protoboard um buzzer passivo no circuito e este con-
trola a saída do pino para permitir que o som saia deste buzzer.

//Referência de música - https://www.youtube.com/


watch?v=Fcibr49E_HA
// https://espressif-docs.readthedocs-hosted.com/projects/
arduino-esp32/en/latest/api/ledc.html

#define pinoBuzzer 2
int freq = 2000, canalBuzzer = 0, resolucao = 10;
const int buttonPins[] = {14, 27, 16, 17, 25};
const note_t buttonTones[] = {NOTE_C, NOTE_D, NOTE_E,
NOTE_F, NOTE_G};
const int numTones = 5;
note_t nota;
bool butTocar = 0;

void setup() {
Serial.begin(115200);
for (int i = 0; i < numTones; i++) {
pinMode(buttonPins[i], INPUT_PULLUP);
}
pinMode(pinoBuzzer, OUTPUT);
ledcSetup(canalBuzzer, freq, resolucao);
ledcAttachPin(26, canalBuzzer);
}

//NOTE_C NOTE_Cs NOTE_D NOTE_Eb NOTE_E


//NOTE_F NOTE_Fs NOTE_G NOTE_Gs NOTE_A
//NOTE_Bb NOTE_B
void loop() {
if (digitalRead(buttonPins[0]) == LOW) butTocar =1;

if (digitalRead(buttonPins[1]) == LOW) {
butTocar =0; ledcWriteTone(canalBuzzer, 0);
}

98

if (butTocar){
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(1000);
ledcWriteNote(canalBuzzer, NOTE_A, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_A, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_A, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_A, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(1000);
ledcWriteNote(canalBuzzer, NOTE_A, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Gs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(2000);
ledcWriteNote(canalBuzzer, NOTE_Fs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Gs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Fs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Fs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Gs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Fs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Fs, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 5); delay(700);

ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(100);


ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(100);
ledcWriteNote(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(500);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);

99
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_E, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Fs, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(100);
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(500); //17s

ledcWriteNote(canalBuzzer, NOTE_Fs, 4); delay(200);


ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_Fs, 4); delay(200);
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_Fs, 4); delay(200);
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Fs, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(100);
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(500); //19s
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(150);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(100);
ledcWriteTone(canalBuzzer, 0); delay(500);

ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);


ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(250);
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(600);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(250);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(500);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(250);
ledcWriteTone(canalBuzzer, 0); delay(350);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(150);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(350);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(250);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(300);
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(300);
ledcWriteTone(canalBuzzer, 0); delay(500); //25 SEG

100
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(180);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(500);
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(500);
ledcWriteNote(canalBuzzer, NOTE_Eb, 5); delay(500);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(300);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteTone(canalBuzzer, 0); delay(500); //28 SEG
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(300);
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Eb, 5); delay(600);
ledcWriteTone(canalBuzzer, 0); delay(350);
ledcWriteNote(canalBuzzer, NOTE_D, 5); delay(250);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_D, 5); delay(400); //32 SEG
ledcWriteTone(canalBuzzer, 0); delay(350);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(450);
ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(300);
ledcWriteTone(canalBuzzer, 0); delay(400);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_C, 5); delay(450);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(400);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(400);
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(400);
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(400);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);

ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);


ledcWriteTone(canalBuzzer, 0); delay(20);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(250);

101
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(600);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(250);
ledcWriteNote(canalBuzzer, NOTE_Bb, 5); delay(500);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(250);
ledcWriteTone(canalBuzzer, 0); delay(200);
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(150);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(200); //42 SEG
ledcWriteNote(canalBuzzer, NOTE_Gs, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(200);
ledcWriteNote(canalBuzzer, NOTE_F, 4); delay(150);
ledcWriteNote(canalBuzzer, NOTE_Bb, 4); delay(400);
ledcWriteNote(canalBuzzer, NOTE_G, 4); delay(150);
ledcWriteNote(canalBuzzer, NOTE_Eb, 4); delay(400);
}
ledcWriteTone(canalBuzzer, 0);
butTocar =0;
delay(1000);
}

5.6 Como ligar um motor de corrente contínua


usando o LD298

O controle de motores de corrente contínua (motores DC –


Direct Current) é um item muito importante na robótica, visto que
tais motores são muito utilizados e, para controlá-los, é muito co-
mum utilizar circuitos conhecidos como ponte H. Eles têm esse
nome devido à configuração dos transistores utilizados para con-
trolar o sentido de rotação do motor. No caso do Shield que contém
o chip L298N (dupla ponte H mostrada na Figura 52), isso já está
todo integrado de forma que temos a entrada de alimentação de 6
a 35V, o GND e dois pares de saída.

102
Figura 54 - Shield L298N com dupla ponte H.

Tal configuração permite controlar dois motores de corrente


contínua. De forma complementar, o circuito ainda conta com um
regulador de 5V que disponibiliza essa tensão em um outro pino de
saída, que pode ser utilizada para alimentar algum circuito externo,
incluindo a própria ESP32 se essa não estiver já alimentada.
Além disso, há quatro pinos que devem vir da ESP32 que são
utilizados para controlar o sentido de rotação do motor. Dois pinos
são utilizados para o motor A e os outros dois pinos para o motor
B. Observe que é necessário habilitar com o jumper cada um dos
motores, bem como o regulador de tensão. Esses jumpers estão in-
dicados na Figura 53.

103
Figura 55 - Indicação dos jumpers para ativar os motores.

Desta maneira pode-se controlar motores DC de 6 até 35V,


tensões que sairão pelos bornes dos motores A e B respectivamen-
te. É importante ressaltar que a mesma tensão da alimentação será
passada para os motores, logo se for alimentar um motor de 12V,
por exemplo, é necessário colocar 12V na alimentação do Shield.

5.7 Ligando um servomotor – controlando a posi-


ção de uma haste

Servomotores são tipos de motores elétricos que podem ser


controlados para se moverem em posições ou ângulos específicos.
É especialmente útil nas aplicações de robótica, nas quais é neces-
sário que um robô mova seu braço, por exemplo, para um ponto
específico. Por meio dos servomotores, tais tarefas podem ser reali-
zadas, visto que exigem precisão.
A diferença do servomotor para um motor elétrico comum é
que ele possui um sistema de controle para garantir sua posição.
Em outras palavras, ao invés de apenas ligar e desligar ou girar con-
tinuamente, um servomotor pode ser direcionado para uma posi-

104
ção específica. Por exemplo, você pode dizer a um servomotor para
girar 90 graus e ele vai parar exatamente nessa posição.
Para isso os servomotores geralmente usam um sistema de fe-
edback, como um sensor, que informa ao controlador a posição
atual do motor. Com isso, o sistema ajusta o movimento para al-
cançar e manter a posição desejada com precisão. Devido a essas
características, os servomotores são muito úteis em aplicações
como robótica, aeronaves de controle remoto e sistemas automati-
zados em geral, onde é necessário controle preciso do movimento.

5.8 Ligando um servomotor – controlando sua ve-


locidade

Para o controle de velocidade em um servomotor, geralmen-


te se utiliza uma técnica conhecida por modulação por largura de
pulso (PWM, do inglês “Pulse Width Modulation”). Esta técnica
envolve enviar uma série de pulsos elétricos ao motor, sendo que
para controlá-lo, é feita uma variação na “largura” (ou duração) de
cada pulso. Em um tempo fixo, quanto maior a duração do pulso,
mais potência é entregue ao motor, e vice-versa.
Com isso, ao ajustar a largura dos pulsos, podemos controlar a
velocidade do motor. Por exemplo, pulsos mais longos podem fazer
o motor girar mais rápido, enquanto pulsos mais curtos o fazem
girar mais devagar. Para realizar o controle PWM, normalmente se
usa um controlador eletrônico (como um microcontrolador) para
gerar os sinais PWM. Desta maneira, você programa o controlador
para enviar os pulsos na frequência e largura desejadas, de acordo
com a velocidade que você quer que o motor atinja. Essa é uma
técnica de controle bastante eficaz e muito utilizada em diversas
aplicações, desde pequenos projetos de robótica até em sistemas
industriais mais complexos.

105
6.
PROJETOS FINAIS

6.1 Detector de linha

A ideia que vamos seguir neste capítulo é montar um seguidor


de linha e, posteriormente, uma garra. Inicialmente, para montar-
mos um seguidor de linha, precisamos fazer um circuito que detec-
te a linha utilizando infravermelho. O Shield usado para emitir e
detectar o infravermelho possui um LED infravermelho e um foto-
diodo que atua como receptor.
Especificamente, vamos utilizar o circuito TRCT5000, que é
conectado ao microcontrolador e envia o sinal que está detectando
ou não a linha. O funcionamento do TRCT5000 se baseia na detec-
ção da reflexão do infravermelho emitido pelo LED.
O LED infravermelho emite um pulso de luz e se o local onde está
apontado o LED tiver cor escura, a luz será absorvida pelo meio e não
será refletida para o receptor. Com isso o circuito sabe que o robô está
em cima de uma superfície escura (ou no nosso caso a linha que é feita
de fita isolante). De forma complementar, se for detectada a reflexão
da luz, significa que a superfície é clara e, no nosso caso, é a mesa. A
lógica inversa pode ser usada para uma mesa escura e uma linha clara.

106
Na Figura 54 é mostrada a ligação entre o circuito TRCT5000
(detector de linha) e o ESPDuíno.

Figura 56 - Diagrama do circuito que detecta a linha.


O sensor TRCT5000 consegue detectar a reflexão
da luz e assim saber onde está a linha.

A Figura 55 mostra uma montagem real do circuito:

Figura 57 - Circuito para detecção da linha,


que será usado no seguidor de linha.

107
O código implementado dentro do microcontrolador é o mos-
trado abaixo:

#define pinSenIV_DO 4
#define pinSenIV_AO 35
int Res_Analog = 0;

void setup() {
pinMode(pinSenIV_DO, INPUT);
Serial.begin(115200);
}

void loop() {
Res_Analog = analogRead(pinSenIV_AO);
Serial.print(“AO:”); Serial.print(Res_Analog);
Serial.print(“ “);
Serial.print(“DO:”);Serial.println(digitalRead(pinSenIV_DO));
delay(1000);
}

Por fim, temos a figura mostrando no Monitor Serial momen-


tos em que o circuito detecta a linha (fita isolante) e a mesa.

108
Figura 58 - Imagem do monitor serial mostrando
a saída do detector de linha.

6.2 Montagem de um robô móvel usando motores CC

O robô móvel a ser montado é um seguidor de linha, que ao


ser iniciado e colocado sobre um caminho feito de fita isolante, se-
gue este caminho da fita isolante. Desta maneira, este robô é cha-
mado de “robô seguidor de linha.” Ele utiliza motores de corrente
contínua e há outras versões que utilizam servomotores para fazer
o mesmo tipo de trabalho.
O robô precisa inicialmente identificar a linha, utilizando sen-
sores para detecção de linha que são compostos por um LED emis-

109
sor de infravermelho e um fotorreceptor (que recebe a luz infraver-
melha emitida). O funcionamento desse tipo de sensor se baseia
na reflexão da luz, ou seja, caso a luz bata na fita isolante, ela não
refletirá, visto que a cor escura da fita absorverá a luz. De forma
complementar, caso a luz bata na mesa será refletida, fazendo com
que o robô saiba onde está o caminho.
A partir desse ponto, pode ser feito o controle dos motores
via microcontrolador e ponte H, esta última representada pelo cir-
cuito vermelho na Figura. Através desse controle, é possível fazer o
controle de movimentação do robô para que ele ande em cima da
linha (caminho) feita com fita isolante.
O diagrama do circuito é apresentado na figura abaixo:

Figura 59 - Diagrama que exemplifica funcionamento de dois


motores DC com ponte H para controle do sentido de rotação.

110
O robô montado com as baterias encapsuladas em um case na
parte posterior é mostrado na Figura 57.

Figura 60 - Carrinho com o sistema seguidor de linha.

111
Agora vamos ao código, que é o que de fato indicará o com-
portamento do robô e será executado dentro do microcontrolador.

//DO_Direita 39 AO_Direita 36
//DO_Esquerda 35 AO_Esquerda 4
#define pinSDO_D 39
#define pinSDO_E 35

//Roda Esquerda
#define pin_ENA 5
#define pin_IN1 13
#define pin_IN2 12
//Roda Direita
#define pin_ENB 16
#define pin_IN3 14
#define pin_IN4 27

bool IR_D, IR_E;

void setup() {
Serial.begin(115200);

pinMode(pinSDO_D, INPUT);
pinMode(pinSDO_E, INPUT);

pinMode(pin_ENA, OUTPUT);
pinMode(pin_IN1, OUTPUT);
pinMode(pin_IN2, OUTPUT);
ledcAttachPin(pin_ENA, 0);//Atribuí mos o pino ao canal 0.
ledcSetup(0, 1000, 12);//canal 0 a frequência de 1000Hz com
resolucao de 12bits.

pinMode(pin_IN3, OUTPUT);
pinMode(pin_IN4, OUTPUT);
pinMode(pin_ENB, OUTPUT);
ledcAttachPin(pin_ENB, 1);//Atribuímos o pino ao canal 1
ledcSetup(1, 1000, 12);//canal 1 a frequência de 1000Hz com
resolução de 12bits.
}
void vaiReto(){
ledcWrite(0, 1300); //Roda Esquerda
digitalWrite(pin_IN1, LOW);

112
digitalWrite(pin_IN2, HIGH);

ledcWrite(1, 1300);//Roda Direita


digitalWrite(pin_IN3, LOW);
digitalWrite(pin_IN4, HIGH);
}
void sentHorario(){
ledcWrite(0, 1300);//Roda Esquerda
digitalWrite(pin_IN1, LOW);
digitalWrite(pin_IN2, HIGH);

ledcWrite(1, 800);//Roda Direita


digitalWrite(pin_IN3, HIGH);
digitalWrite(pin_IN4, LOW);
}
void sentAntiHorario(){
ledcWrite(0, 800); //Roda Esquerda
digitalWrite(pin_IN1, HIGH);
digitalWrite(pin_IN2, LOW);

ledcWrite(1, 1300); //Roda Direita


digitalWrite(pin_IN3, LOW);
digitalWrite(pin_IN4, HIGH);
}
void loop() {
IR_D = digitalRead(pinSDO_D);
IR_E = digitalRead(pinSDO_E);

Serial.print(“IR_D: “); Serial.print(IR_D);


Serial.print(“ IR_E: “); Serial.println(IR_E);

if(!IR_E && !IR_D) // frente com fita


vaiReto();

if(IR_D) //Sentido horário


sentHorario();

if(IR_E) //Sentido anti horário


sentAntiHorario();

delay(60);
}

113
6.3 Montagem de um robô móvel usando servomo-
tores

Da mesma forma que podemos fazer o robô seguidor de linha


utilizando motores de corrente contínua, também podemos fazer
por meio de servomotores, que são motores de corrente contínua
que possuem controle de posição e/ou velocidade.
O que muda, em essência, é a lógica que roda dentro do micro-
controlador. Com isso o algoritmo que estará dentro do circuito é:

#include <ESP32Servo.h>

#define pinIR_D 23
#define pinIR_E 35

bool IR_D, IR_E;

Servo Roda_Direita;
Servo Roda_Esquerda;
int servoPin_D = 15;
int servoPin_E = 12;

void setup() {
Serial.begin(115200);
Roda_Direita.attach(servoPin_D); // Inicializa os objetivos Servo
com os pinos respectivos
Roda_Esquerda.attach(servoPin_E);
pinMode(pinIR_D, INPUT);
pinMode(pinIR_E, INPUT);
}

void loop() {
IR_D = digitalRead(pinIR_D);
IR_E = digitalRead(pinIR_E);

Serial.print(“IR_D: “); Serial.print(IR_D);


Serial.print(“ IR_E: “); Serial.println(IR_E);

114
if(!IR_E && !IR_D){ // frente com fita
Roda_Direita.write(85);
Roda_Esquerda.write(95);
}

if(IR_D){ //Sentido horário


Roda_Direita.write(92);
Roda_Esquerda.write(94);
}

if(IR_E){ //Sentido anti horário


Roda_Direita.write(85);
Roda_Esquerda.write(89);
}

delay(60);
}

6.4 Exemplo do ensino de robótica - Montagem


de um robô que mexe cabeça e braços e pisca os
olhos.

Um projeto interessante realizado pela equipe da GainTech/


RoboTech foi um robô que mexe cabeça e braços e possui olhos
que podem piscar. Com isso, foi possível criar um efeito de dança
com os robôs. Esses robôs foram feitos em parceria com escolas de
ensino fundamental do município de Serra, Espírito Santo.

115
Figura 61 - Exemplos dos robôs dançantes que
mexem a cabeça e “piscam” os olhos.

Figura 62 - Robô que mexe a cabeça e botões para controle.

116
O robô conta com servomotores que comandam os movimen-
tos de acordo com os botões. A parte interna possui uma eletrônica
padrão para todos os robôs, contendo servomotores e a placa ele-
trônica responsável por controlar os movimentos e os LEDs dos
olhos. Já a parte externa, foi pintada pelos alunos. Com isso, cada
grupo pode fazer seu próprio robô personalizado.

6.5 Exemplo prático de aplicação - montagem de


uma garra que separa bolas de isopor de cores di-
ferentes

Esse projeto se baseia na montagem de uma garra que faz a


leitura da cor de uma bolinha de isopor que pode ser preta ou bran-
ca e as redireciona para um local pré-determinado. Para isso ser
possível, inicialmente há uma estrutura física onde as bolinhas são
localizadas e há um leitor como o do seguidor de linha na parte
inferior dessa estrutura.
Caso a bolinha seja branca, a garra redirecionará para o pote
azul, caso a bolinha seja preta, redirecionará para o pote rosa. Isso é
definido pelo código e tem como input a cor da bolinha e como ou-
tput o movimento para esquerda ou direita que será feito pela garra.

117
Figura 63 - Sequência mostrando a garra que pega a bola da
rampa azul, analisa a cor e leva para a caixa correspondente.

O código a seguir exemplifica como é feita a lógica do movi-


mento da garra:

#include <ESP32Servo.h>
#define pinSenIV_DO 32
#define pinSenIV_AO 35
int Res_Analog = 0;
Servo Garra, BaseGarra, Giro; // cria um objeto Servo para a
Roda Direita

118
int pos = 0; // variable to store the servo position
// Recommended PWM GPIO pins on the ESP32 include 2,4,12-
19,21-23,25-27,32-33
int pinServoGarra = 21;
int pinServoGira = 5;
int pinServoBase = 19;
char valorRecebido;
bool ativado;
void setup() {
pinMode(pinSenIV_DO, INPUT);
Serial.begin(115200);
Garra.attach(pinServoGarra); // attaches the servo on pin 18 to
the servo object
BaseGarra.attach(pinServoBase); // attaches the servo on pin
18 to the servo object
Giro.attach(pinServoGira);
ativado=1;
}

void loop() {
Res_Analog = analogRead(pinSenIV_AO);
Serial.print(“AO:”); Serial.print(Res_Analog);
Serial.print(“ “);
Serial.print(“DO:”);Serial.println(digitalRead(pinSenIV_DO));

valorRecebido = (char)Serial.read();
if (valorRecebido == ‘0’)
ativado = 0;

if (valorRecebido == ‘1’)
ativado = 1;

if (ativado){//sobe depois de pegar bola


if(Res_Analog>3000){ //Bola Branca
Garra.write(0); delay(500);
BaseGarra.write(90); delay(1000);
Giro.write(90); delay(2000);

BaseGarra.write(21); delay(2000);
Garra.write(27); delay(500);//Segura

BaseGarra.write(90); delay(1000);

119
Giro.write(0); delay(500);
BaseGarra.write(20); delay(1000);
Garra.write(0); //Solta
}
if(Res_Analog<200){//Bola preta
Garra.write(0); delay(500);
BaseGarra.write(90); delay(1000);
Giro.write(90); delay(2000);

BaseGarra.write(21); delay(2000);
Garra.write(27); delay(500);

BaseGarra.write(90); delay(1000);
Giro.write(180); delay(500);
BaseGarra.write(20); delay(1000);
Garra.write(0);
}
delay(3000);
}
}

Este é um exemplo prático de uma aplicação que pode ser fa-


cilmente aplicada em processos industriais. Um exemplo seria uma
máquina onde passam vários produtos em que seja necessário se-
pará-los por cor. Nesse caso, o sistema funciona de forma simi-
lar, detectando a característica desejada (cor) e tomando uma ação
com base nessa característica.

120
SOBRE OS AUTORES

Igor Rodrigues Cassimiro. Formado em Engenharia de Controle e


Automação pelo IFES Campus Serra, Igor possui expertise em
microcontroladores e experiência em ministrar aulas de robótica no
ensino fundamental. Ele também é responsável pelo
desenvolvimento de kits didáticos em robótica e atua como
conteudista na RoboTech.

João Guilherme Lourenço. Engenheiro de Controle e Automação


formado pelo Instituto Federal do Espírito Santo Campus Serra,
João Guilherme tem amplo conhecimento em redes, banco de
dados e programação com microcontroladores. Ele também tem
experiência em lecionar aulas de robótica para alunos do ensino
fundamental.

Caio Lopes de Oliveira. Engenheiro de Controle e Automação pelo


Instituto Federal do Espírito Santo Campus Serra, tem experiência
em inteligência artificial e microcontroladores. Ele também atuou
como professor de robótica para o ensino fundamental e é
conteudista na Robotech.
Carlos Torturella Valadão. Doutor em Engenharia Elétrica pela
Universidade Federal do Espírito Santo, Carlos Torturella Valadão
é um especialista em robôs para interação social e interfaces
humano-robô. Além de seu trabalho acadêmico, ele é professor e
conteudista na RoboTech.

Marco Antonio de Souza Leite Cuadros. Doutor em Engenharia


Elétrica pela UFES, é formado em Engenharia Elétrica pela
Universidad Nacional del Centro del Perú. Atualmente, é professor
no IFES - Campus Serra, lecionando em cursos técnicos e de
mestrado em Automação e Engenharia de Controle. Sua
especialidade abrange Eletrônica Industrial, Sistemas e Controles
Eletrônicos, focando em controle de processos e robótica móvel.

Marcelo de Souza Gomes Veloni. Formado em Engenharia


Elétrica pela Universidade Federal do Rio de Janeiro. Atualmente,
é empresário na Efficiency On, que presta serviços e realiza
consultoria na área de marketing para diversas empresas. Sua
especialidade abrange estratégias de marketing, vendas e gestão de
tráfego pago.

Você também pode gostar