Robótica Com ESP32 e Arduino
Robótica Com ESP32 e Arduino
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)
24-200117 CDD-372.358
Índices para catálogo sistemático:
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
5
Figura 1 - Exemplo de placa de desenvolvimento baseada
em ESP-32 com formato similar ao Arduino.
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
7
2. Clique em Criar uma conta pessoal.
Figura 3 - Página do Tinkercad para criar uma conta pessoal.
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.
9
6. Parabéns! Você criou sua conta.
10
2. Clique no link indicado na Figura 8.
11
1.5 Circuitos simples de bateria e resistores Tinkercad
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, .
13
Figura 14 - Circuito com 2 resistores.
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.
15
2.
REVISÃO, LEDS E BOTÕES
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.
18
2.1.2 Pisca-pisca de dois Leds sem 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;
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();
Contador = Contador + 1;
Serial.println(Contador);
}
20
2.2 Como usar botões no Esp32
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
*/
//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
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;
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
*/
//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);
27
Serial.println(“ Vezes “);
digitalWrite(LedPino2, ledState);
delay(50);
}
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.
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);
30
}
/*
31
#include <ezButton.h>
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
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.
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);
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.
36
3.2 Controlando a velocidade de um sequencial de
5 leds usando uma entrada analógica
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.
39
3.3 Ligando 5 leds em função do nível de tensão de
uma entrada analógica
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);
delay(500);
}
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;
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
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.
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);
Serial.print(“V : “);
Serial.println(tensao);
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.
50
4.
SENSORES
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.
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.
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
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.
55
4.2 Ultrassom
56
const int trigPin = 27;
const int echoPin = 26;
#define LedVerde 12
#define LedVermelho 13
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;
delay(1000);
}
57
Figura 31 - Diagrama de um sensor de distância
utilizando ultrassom e indicadores com LEDs.
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.
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);
Tc = T - 273.15; // Celsius
Tf = Tc * 9 / 5 + 32; // Fahrenheit
if (Tc > 0) Serial.println(Tc);
Serial.println(adc);
delay(1000);
}
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
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.
63
const double rx = Ro * exp(-Beta/To);
void setup() {
Serial.begin(115200);
display.setTextSize(1);
display.setTextColor(WHITE);
display.setCursor(33, 0);
// Oled siplay 128x64
display.println(“Oi, Brasil!”);
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);
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);
}
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.
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
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);
68
Serial.print(“ | “);
Serial.print(“Temperature: “);
Serial.print(tempC);
Serial.print(“°C ~ “);
Serial.print(tempF);
Serial.println(“°F”);
}
69
4.3.2 Mostrando a umidade e temperatura medida
pelo DHT22 num 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
72
Figura 38 - Implementação do circuito anterior na prática.
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.
#include <DHT.h>
#define DHT22_SENSOR_PIN 26
#define DHT11_SENSOR_PIN 25
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();
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);
}
76
Figura 40 - Diagrama esquemático do circuito
implementado na figura anterior.
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.
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.
79
Figura 43 - Diagrama do circuito implementado na figura anterior.
80
5.
ATUADORES
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.
82
5.1. O PWM, modulação por largura de pulso
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);
void loop()
{
for (int i = 0; i < 1024; i++)
{
ledcWrite(0, i);//Escrevemos no canal 0, o duty cycle “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.
85
5.1 Usando o PWM e entradas Analógicas
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.
88
5.2 Como usar um Led RGB
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.
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.
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);
91
Figura 50 - Foto com detalhe do shield LED RGB.
92
5.3 Buzzer, Passivo, produzindo SOM
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.
void setup() {
Serial.begin(115200);
ledcSetup(canal, freq, resolucao);
ledcAttachPin(33, canal);
}
void loop() {
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.
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);
}
97
5.5 Buzzer Passivo, o hino de um time de futebol
#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);
}
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);
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
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);
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);
}
102
Figura 54 - Shield L298N com dupla ponte H.
103
Figura 55 - Indicação dos jumpers para ativar os motores.
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.
105
6.
PROJETOS FINAIS
106
Na Figura 54 é mostrada a ligação entre o circuito TRCT5000
(detector de linha) e o ESPDuíno.
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);
}
108
Figura 58 - Imagem do monitor serial mostrando
a saída do detector de linha.
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:
110
O robô montado com as baterias encapsuladas em um case na
parte posterior é mostrado na Figura 57.
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
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);
delay(60);
}
113
6.3 Montagem de um robô móvel usando servomo-
tores
#include <ESP32Servo.h>
#define pinIR_D 23
#define pinIR_E 35
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);
114
if(!IR_E && !IR_D){ // frente com fita
Roda_Direita.write(85);
Roda_Esquerda.write(95);
}
delay(60);
}
115
Figura 61 - Exemplos dos robôs dançantes que
mexem a cabeça e “piscam” os olhos.
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.
117
Figura 63 - Sequência mostrando a garra que pega a bola da
rampa azul, analisa a cor e leva para a caixa correspondente.
#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;
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);
}
}
120
SOBRE OS AUTORES