Você está na página 1de 56

ÍNDICE

O que é o Arduíno?..........................................................................................................................................................2
Constituição do Arduíno UNO R3...................................................................................................................................2
O Básico da Programação do Arduíno.............................................................................................................................3
Funções – o que é que significam?..................................................................................................................................3
Arduíno UNO – pinagem.................................................................................................................................................4
Exercício Prático de Saídas – LED..................................................................................................................................4
Exercício Prático de Delays – LED a Piscar....................................................................................................................5
Exercício Prático de Entradas – Instrução Condicional (if).............................................................................................6
Exemplo – Interruptor de Luz com “Temporizador”.......................................................................................................7
Exemplo – Semáforo.......................................................................................................................................................7
Como é que o UART funciona?.....................................................................................................................................12
Exercício Prático – Comunicação UART......................................................................................................................13
Exercício Prático – Interação com o programa..............................................................................................................14
Instrução #define...........................................................................................................................................................15
Variáveis........................................................................................................................................................................ 16
Declaração de Variáveis................................................................................................................................................17
Exercício Prático – Variáveis.........................................................................................................................................17
Transmissão Bidirecional do Arduíno...........................................................................................................................18
Exercício Prático de Interação com o Sistema – Controlo de LEDs via UART.............................................................19
Conversor Analógico-Digital.........................................................................................................................................20
Exercício Prático com ADC – Seleção de LEDs............................................................................................................23
Exercício Prático com ADC – Ativar um LED quando está escuro...............................................................................25
Exercício Prático com ADC – Ativar um LED quando está escuro v2..........................................................................26
O que é o sinal PWM?...................................................................................................................................................27
Para que é que o sinal PWM é usado?...........................................................................................................................28
Exercício Prático de PWM – Controlo do brilho de um LED........................................................................................28
Servo Motor................................................................................................................................................................... 30
Como é que o servo funciona?.......................................................................................................................................30
Alimentação do servo....................................................................................................................................................30
Exercício Prático – Servomecanismo.............................................................................................................................30
Representação Numérica no Monitor Série...................................................................................................................32
Precisão dos Números Não Inteiros...............................................................................................................................32
Função Serial.print()......................................................................................................................................................33
Exercício Prático – Novas informações UART.............................................................................................................34
Função Switch().............................................................................................................................................................35
Porquê juntar motores ao Arduíno?...............................................................................................................................37
Novas Funções............................................................................................................................................................... 43
Sensor de Distância Ultrassónico HC-SR04..................................................................................................................50
Exercício Prático – Alarme............................................................................................................................................54
O que é o Arduíno?
De forma geral, o Arduíno é uma plataforma de prototipagem eletrónica, que integra o popular microcontrolador AVR, e
permite o desenvolvimento de controlo de sistemas interativos. É um dispositivo de baixo custo e acessível a todos.
Algumas características são:

 Não requer um programador externo;


 Interage, sem problemas, com um compilador dedicado;
 É compatível com inúmeras de placas de expansão (por exemplo: controladores de motor, displays, módulos,
sensores, etc.).

No entanto, o verdadeiro poder do Arduíno está na sua linguagem de programação baseada em C/C++.

A programação é realizada através de livrarias, graças às quais até a criação de um programa complicado está ao alcance
de um programador iniciante.

Constituição do Arduíno UNO R3


O coração do Arduíno é o popular microcontrolador Atmel de 8 bits, o AVR ATmega328 que opera a 16MHz. Trabalhar
com tal frequência, de forma muito simples, significa que o microcontrolador é capaz de realizar 16 milhões de operações
por segundo!
Os conectores localizados nas laterais da placa, são as saídas dos sinais mais importantes. Aí encontramos 14
entradas/saídas (I/O) digitais programáveis. Seis delas podem ser usadas como saídas PWM (ex.: controlo de motores) e
outras 6 como entradas analógicas. Também encontramos um botão de reset e um conector para a alimentação da placa.

O Arduíno pode ser alimentado de várias formas. Os métodos mais populares são:
 Alimentação via cabo USB;
 Alimentação através de uma fonte de alimentação externa (baterias ou plug-in).
Os constituintes mais importantes estão sinalizados na imagem seguinte:

Conector USB – usado para alimentação, programação e comunicação com o


computador;
Conector Jack DC – usado para alimentação (recomendado 7V a 12V);
Estabilizador de Tensão – transforma a tensão de entrada em 5V;
Botão de Reset – reinicia a placa Arduino;
Microcontrolador responsável pela comunicação com o computador via USB;
Terminais para Programação para microcontrolador #5;
Pinos Digitais I/O (8 a 13) e GND Digital (terra);
Pinos Digitais I/O (3 a 7) e TX e RX (saída de série e entrada de série
respetivamente);
LED – indica se a placa está ligada;
Pinos para Programação Série – permite programar o microcontrolador (pino
#13) via comunicação série.
Pinos de Entrada Analógicos (0 a 5);
Pinos de Alimentação e Reset da placa;
Microcontrolador AVR ATmega328 – o coração da placa arduino;
LEDs – indicam a transmissão do/para o computador;
LED – ligado ao pino #13, está à disposição do utilizador;
Cristal 16MHz – faz com que o microcontrolador funcione a uma frequência
de 16MHz.

O Básico da Programação do Arduíno


Na linguagem C, todas as instruções que queremos dar, colocamos na função principal.

O símbolo “//” indica um comentário. É uma informação, de uma linha, que ajuda as pessoas a entender o programa.
Durante a compilação, todos os comentários são omitidos. Se quiser escrever um comentário mais longo, deve colocá-lo
entre “*/“.

No Arduíno, há aspetos que estão simplificados. Existem duas funções: uma delas executa a instrução uma vez, a outra
executa a instrução definida em loop. Vejamos:

void setup() {
//Instruções que são executadas apenas uma vez
}

void loop() {
//Instruções que são executadas em loop
}

Na prática, a primeira função geralmente contém as configurações. Por exemplo: a definição dos pinos como entradas ou
saídas. Nesta função, depois de ligar a placa, serão realizadas ações que é suposto só acontecerem uma vez.

Na segunda função, coloca-se o código que pretende executar o tempo todo (em loop). Vai perceber isto muito melhor
nos exemplos práticos mais abaixo.

Funções – o que é que significam?


Os códigos podem ser escritos por si, ou pode usar um pré-feito, fornecido por programadores que compartilham o seu
próprio código. No início do tutorial, vamos concentrar-nos nas funções fornecidas pelas livrarias, juntamente com o
compilador Arduíno.

Existe um conceito de função na linguagem C. Uma função, nas linguagens de programação, é um bloco (lista) de certos
comandos extraídos do código principal, cujo desempenho fornece um resultado.

Cada função pode integrar vários argumentos e enviar um resultado. O programador pode determinar quais valores serão
o resultado e os dados de entrada. Cada função tem o seu próprio tipo de resultado enviado (prefixos ex.: int, string, etc.)
– pode ser um número, um sinal ou outra coisa. Há também um tipo específico de função – não envia qualquer valor
(prefixo void).

Vamos concentrar-nos nas principais funções dos programas Arduíno.

void setup() {
}

O procedimento setup, como já vimos, é indicado para executar as instruções definidas uma só vez. Como o nome
sugere, é destinado principalmente a configurações gerais. Neste, o processador é iniciado, os periféricos são
configurados, etc.

void loop() {
}

A função (procedimento) loop é, como o nome indica, um loop infinito. É indicado para instruções que devem ser
executadas o tempo todo.
Arduíno UNO – pinagem
Abaixo pode ver um esquema com os principais pinos do Arduíno UNO:
A verde escuro (#0 a #19) estão indicados os pinos digitais de entrada/saída (I/O). Quando usados como saídas, podemos
definir como sendo 0V (nível lógico 0, low) ou 5V (nível lógico 1, high). Quando são configurados como entradas, são
capazes de detetar se o pino em questão possui tensão de 0V ou 5V.

As entradas analógicas (A0-A5) estão destacadas a verde claro. Estes são pinos únicos que permitem medir a tensão (0-
5V). Como pode ver, a numeração destes pinos coincide com os pinos universais (#14 a #19). Trabalhar no modo
analógico é uma função adicional deles.

Em azul, foram destacados pinos com funções alternativas. Isto significa que, além de serem pinos I/O normais, podem
executar funções mais complexas. Vamos trabalhar com eles posteriormente, mas para já só precisamos de uma
explicação básica:

o SDA, SCL – barramentos I2C usados, por exemplo, para comunicação com sensores mais avançados. Existem dois
pinos SDA e dois pinos SCL, no canto inferior esquerdo e superior direito da placa;
o TX, RX – interface UART, usados principalmente para comunicação com o computador;
o PWM – saídas nas quais é possível gerar um sinal retangular (variável). É função muito útil, por exemplo, no
controlo de servos;
o LED – LED permanentemente instalado no Arduino, que está diretamente ligado ao pino #13.

A cor-de-laranja estão saídas que não são programáveis. Estas são responsáveis, principalmente, pela alimentação do
sistema. Serão discutidas mais detalhadamente quando chegar a hora de as usar.

Os conectores indicados na imagem como ICSP são usados para programação direta de dois microcontroladores, que
estão localizados na placa Arduíno UNO. Esses conectores são usados em casos muito específicos e, não há necessidade
de falarmos sobre eles para já.

Exercício Prático de Saídas – LED


Vamos começar a prática com algo muito simples: ligar um LED. De acordo com a descrição anterior, qualquer pino de
I/O pode ser usado nessa ligação. Para já, escolha a saída digital #8. Saída digital é a saída que pode ser definida num de
dois estados (high ou low). No caso do Arduíno, será 5V ou 0V.

Material necessário:
 1x Placa Arduino UNO e cabo USB;
 1x Breadboard;
 1x LED;
 1x Resistência 330Ω;
 2x Cabos jumper macho-macho.
O sistema deve ser ligado de acordo com esquema apresentado abaixo. O LED é ligado em série com uma resistência
(330RΩ). De seguida, ligue o pino mais longo do LED (ânodo) na mesma coluna do jumper ligado ao pino #8. O segundo
pino, deverá estar na mesma coluna de uma das pernas da resistência. A outra perna deve estar na mesma coluna que o
jumper ligado ao pino terra (GND). Existem 3 pinos GND na placa, pode escolher qualquer um.

void setup() {
pinMode(8, OUTPUT);
digitalWrite(8, HIGH);
}

void loop() {
}

A programação da inclusão do LED é muito simples. Ligue o Arduíno ao computador com o cabo USB. Abra o Arduíno
IDE e escreva o código abaixo. De seguida, faça o upload para a placa.

A função pinMode (Pin, Mode) permite selecionar se o pino é uma entrada ou uma saída. O pino é um número inteiro
entre 0 e 13 e o modo pode ser:

o INPUT
o OUTPUT
o INPUT_PULLUP.

Se queremos controlar uma saída, usamos o modo OUTPUT.

Graças a esta configuração, pode definir o estado lógico na saída e, assim, ativar o LED. A função digitalWrite (Pin,
Status) é usada para este propósito. O estado é um estado lógico que pode ser HIGH ou LOW (alto ou baixo).

Depois de definir o pino num único estado, o seu valor não será alterado até definir um valor diferente. Portanto, o
programa acima fará com que o LED permaneça ligado o tempo todo.

Exercício Prático de Delays – LED a Piscar


Neste exercício, queremos colocar o LED a piscar. Para isso, é necessária uma nova função para inserir o delay. O
esquema de ligação é exatamente igual ao anterior. O código deverá ficar assim:

void setup() {
pinMode(8, OUTPUT); //Definir o pino 8 como saída
}

void loop() {
digitalWrite(8, HIGH); //Ligar o LED
delay(1000); //Esperar 1 segundo
digitalWrite(8, LOW); //Desligar o LED
delay(1000); //Esperar 1 segundo
}

Na função loop, o estado é constantemente alternado. Foram adicionados atrasos ao programa através da função delay.
Esta função assume um determinado número de milissegundos a atrasar.
Se não introduzisse os atrasos, o sistema mudaria de estado tão rapidamente que seria impossível ver a alternância a olho
nu. Pode realizar esta experiência ao colocar 0ms como delay.

Exercício Prático de Entradas – Instrução Condicional (if)


Muitas vezes é pretendido que o sistema reaja a sinais externos. Desta vez vamos ligar o botão de pressão ao Arduíno,
para além do LED.

Material necessário:

 1x Arduino UNO e cabo USB;


 1x Breadboard;
 1x LED;
 1x Botão de Pressão;
 1x Resistência de 330Ω;
 5x Cabos jumper.

A ligação deverá ser realizada de acordo com o esquema abaixo. De um lado, o botão foi ligado à terra (menos) e do outro
lado ao pino 7.
O objetivo é criar um programa que ligue o LED quando
o botão é pressionado. A tarefa é muito simples, mas
vamos inserir algo novo – instruções condicionais.

Queremos que o programa esteja permanentemente num


dos dois estados – o LED está ligado ou desligado. De
início, é necessário ler o estado lógico do pino de entrada
do botão.

Lembre-se do modo INPUT_PULLUP mencionado


anteriormente. A primeira parte do nome (input)
obviamente significa entrada, enquanto o segundo
(pullup) sugere a inclusão de uma resistência interna que
verifica o estado do interruptor. Vamos usá-lo sempre que
ligarmos um botão ao Arduíno.
Como já foi referido, é preciso ler o estado do pino de entrada. Para isso, é necessária a função digitalRead (pin), que
envia a informação HIGH ou LOW, dependendo do estado. No entanto, apenas ler o estado da entrada não é o suficiente,
devemos fazer com que o programa trabalhe em função dessa informação. Daí a instrução condicional (if). Graças a esta,
pode executar uma determinada parte do código se houver o cumprimento de determinados requerimentos ou se se
verificarem certas condições. Por exemplo, se pressionar um botão.

Ao combinar o conhecimento, pode criar um programa que realize a tarefa proposta. Analise o código e faça o upload
para o Arduíno.

void setup() {
pinMode(8, OUTPUT); //LED como saída
pinMode(7, INPUT_PULLUP); //Botão como entrada
digitalWrite(8, LOW); //Desliga o LED
}

void loop()
{
if (digitalRead(7) == LOW) { //Se o botão for pressionado
digitalWrite(8, HIGH); //Ligar o LED
} else { //Se o botão não for pressionado
digitalWrite(8, LOW); //Desligar LED
}
}

Todavia, este programa é de pouca utilidade. Por que é que precisamos de um botão que só funciona quando o estamos a
pressionar? Não seria melhor se o LED estivesse aceso por um determinado período de tempo após o botão ser
pressionado?

Exemplo – Interruptor de Luz com “Temporizador”


Neste exemplo queremos que, tendo em conta o exemplo anterior, o LED esteja ligado por 10 segundos após pressionar o
botão.

void setup() {
pinMode(8, OUTPUT); //LED como saída
pinMode(7, INPUT_PULLUP); //Botão como entrada
digitalWrite(8, LOW); //Desliga o LED
}

void loop()
{
if (digitalRead(7) == LOW) { //Se o botão for pressionado
digitalWrite(8, HIGH); //Ligar o LED
delay(10000); //Esperar 10 segundos
digitalWrite(8, LOW); //Desligar LED
}
}

Exemplo – Semáforo
O próximo exemplo é um sistema de semáforo sequencial. O principal objetivo é escrever um programa que, depois do
botão ser pressionado, mostre uma sequência correta de luzes. Vamos assumir o seguinte ciclo:

[…] Verde -> Amarelo -> Vermelho -> Amarelo+Vermelho […]


Material necessário:

 1x Arduino UNO e cabo USB;


 1x Breadboard;
 1x Botão de pressão;
 1x LED vermelho;
 1x LED amarelo;
 1x LED verde;
 3x Resistências de 330Ω;
 6x Cabos jumper.

Quando pressionar o botão, o sistema deve iniciar a sequência. Vamos fazê-lo por etapas. Primeiro, ligue os 3 LEDs
conforme o esquema abaixo:
Vamos preparar um programa que serve apenas para configurar as entradas e saídas. Agora que estão os LEDs e o botão
configurados, vamos escrever um programa que mude as luzes automaticamente, a cada 1 segundo. O sketch completo
deverá ficar assim:
void setup() {
pinMode(10, OUTPUT); //LED vermelho
pinMode(9, OUTPUT); //LED amarelo
pinMode(8, OUTPUT); //LED verde

pinMode(7, INPUT_PULLUP); //Botão

digitalWrite(10, LOW); //Desligar os LEDs


digitalWrite(9, LOW);
digitalWrite(8, LOW);
}

void loop()
{
digitalWrite(10, LOW); //Vermelho
digitalWrite(9, LOW); //Amarelo
digitalWrite(8, HIGH); //Verde

delay(1000); //Esperar 1 segundo

digitalWrite(10, LOW); //Vermelho


digitalWrite(9, HIGH); //Amarelo
digitalWrite(8, LOW); //Verde

delay(1000); //Esperar 1 segundo

digitalWrite(10, HIGH); //Vermelho


digitalWrite(9, LOW); //Amarelo
digitalWrite(8, LOW); //Verde

delay(1000); //Esperar 1 segundo

digitalWrite(10, HIGH); //Vermelho


digitalWrite(9, HIGH); //Amarelo
digitalWrite(8, LOW); //Verde

delay(1000); //Esperar 1 segundo


}

Faça o upload do programa no Arduíno e verifique se está tudo a funcionar na perfeição.

Até agora, usamos apenas o loop principal e obrigatório (função void loop). Agora é hora de conhecer um loop que
podemos usar dentro dos nossos programas.

Agora vamos abordar o loop while (), que funciona enquanto uma certa condição for cumprida (verdadeira). O seu
funcionamento é apresentado no seguinte código:

Para uma maior clareza, a função while apenas executa o código que fica entre as suas chavetas {}. O restante código não
é executado naquele momento.

Vamos aproveitar o sistema de semáforo que foi montado anteriormente, para escrever um programa que fará piscar um
LED de cada vez quando o botão for pressionado. Este exercício é uma tarefa mais difícil do que a anterior.

Confira o código proposto:


void setup() {
pinMode(10, OUTPUT); //LED vermelho
pinMode(9, OUTPUT); //LED amarelo
pinMode(8, OUTPUT); //LED verde

pinMode(7, INPUT_PULLUP); //Botão

digitalWrite(10, LOW); //Desligar LED


digitalWrite(9, LOW);
digitalWrite(8, LOW);
}

void loop() {

while (digitalRead(7) == LOW) { //Quando o botão é pressionado


digitalWrite(10, LOW); //Vermelho desligado
delay(1000);
digitalWrite(10, HIGH); //Vermelho ligado
delay(1000);
}
}

Se entender o código acima, pode prosseguir e completar a tarefa original: comutação automática das luzes.

Desta vez, as sequências devem ser exibidas até pressionar o botão. Assumimos que o botão é pressionado e largado
muito rapidamente. O programa finalizado deve ter este aspeto:

void setup() {
pinMode(10, OUTPUT); //LED vermelho
pinMode(9, OUTPUT); //LED amarelo
pinMode(8, OUTPUT); //LED verde

pinMode(7, INPUT_PULLUP); //Botão

digitalWrite(10, LOW); //Desligar LED


digitalWrite(9, LOW);
digitalWrite(8, LOW);
}

void loop()
{
digitalWrite(10, LOW); //Vermelho
digitalWrite(9, LOW); //Amarelo
digitalWrite(8, HIGH); //Verde

while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado

digitalWrite(10, LOW); //Vermelho


digitalWrite(9, HIGH); //Amarelo
digitalWrite(8, LOW); //Verde

while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado

digitalWrite(10, HIGH); //Vermelho


digitalWrite(9, LOW); //Amarelo
digitalWrite(8, LOW); //Verde

while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado

digitalWrite(10, HIGH); //Vermelho


digitalWrite(9, HIGH); //Amarelo
digitalWrite(8, LOW); //Verde

while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado


}

Neste caso, o loop foi usado de uma maneira bastante estranha. Como pode verificar não há nada dentro das chavetas!
Então, como é que o programa está a funcionar? Isso ocorre porque o programa usa loops para parar.

Como é que está a funcionar?

1. Começamos a iluminar os LEDs de acordo com uma sequência;


2. Entramos na função loop while (), que está imediatamente abaixo;
3. As chavetas estão vazias, portanto, o programa está sempre em loop, sem fazer nada;
4. Somente depois do botão ser pressionado (a condição passa a ser falsa) o programa sai do loop;
5. A sequência seguinte é acionada e a situação repete-se.

Vamos agora verificar o programa na prática!

O que é que está a acontecer? Está tudo a funcionar como suposto? Claro que não! Mesmo quando o botão é pressionado
por um curto período de tempo, às vezes o programa funciona corretamente, e outras vezes, salta algumas posições. Por
que é que isso acontece?

O processador, de forma simplificada, realiza cerca de 16 milhões de operações por segundo. Portanto, ao pressionar o
botão, o processador será capaz de ter acesso a todos os estados da nossa sinalização. Posto isto, depois de largar o botão
poderá haver uma escolha aleatória na sequência.

Como resolver este problema? Muito simples! É suficiente alterar o programa, para que a mudança de luz não ocorra com
mais frequência do que, por exemplo, a cada segundo. Para isso, podemos usar a função delay () já conhecida.

void setup() {
pinMode(10, OUTPUT); //LED vermelho
pinMode(9, OUTPUT); //LED amarelo
pinMode(8, OUTPUT); //LED verde

pinMode(7, INPUT_PULLUP); //Botão

digitalWrite(10, LOW); //Desligar LED


digitalWrite(9, LOW);
digitalWrite(8, LOW);
}

void loop(){
digitalWrite(10, LOW); //Vermelho
digitalWrite(9, LOW); //Amarelo
digitalWrite(8, HIGH); //Verde

delay(1000); //Parar o programa durante 1 segundo


while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado

digitalWrite(10, LOW); //Vermelho


digitalWrite(9, HIGH); //Amarelo
digitalWrite(8, LOW); //Verde

delay(1000); //Parar o programa durante 1 segundo


while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado

digitalWrite(10, HIGH); //Vermelho


digitalWrite(9, LOW); //Amarelo
digitalWrite(8, LOW); //Verde
delay(1000); //Parar o programa durante 1 segundo
while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado

digitalWrite(10, HIGH); //Vermelho


digitalWrite(9, HIGH); //Amarelo
digitalWrite(8, LOW); //Verde

delay(1000); //Parar o programa durante 1 segundo


while (digitalRead(7) == HIGH) {} //Quando o botão é pressionado
}

Agora já deve funcionar perfeitamente!

É importante ressaltar que as condições na função while () podem ser combinadas e muito mais complexas, mas
voltaremos a este tópico quando conhecermos as variáveis.

Como é que o UART funciona?


O Arduíno permite a utilização de inúmeras interfaces de comunicação. Graças a estas, os projetos desenvolvidos podem
comunicar com outros sistemas, sensores ou com o computador.

Vamos abordar o UART, que é uma interface série simples e muito utilizada. Especialmente quando se trata de uma
comunicação com o computador.

O seu princípio de funcionamento baseia-se no envio série de uma sequência de bits, que são transformados em
informação. Um conjunto de dados (data frame) é transmitido da seguinte forma:

A transmissão começa com o start bit, marcado como BS na figura. É sempre um bit que é zero lógico. Depois,
dependendo da configuração, existem 7, 8 ou 9 data bits (marcados de B0-B7) que são as informações a ser enviadas. O
stop bit (indicado como BK) é um bit um lógico – finaliza a transmissão.

Ao usar o UART no Arduíno, devemos ter em consideração dois pinos:

o Tx – envio de dados (pino 1);


o Rx – receção de dados (pino 0).

Para que a transmissão funcione corretamente, deve ser definida a mesma velocidade de transferência de dados em ambos
os sistemas – conhecida como baud-rate ou taxa de transmissão. Esta especifica o número de bits transmitidos por
segundo. Os valores mais utilizados são: 9.600 e 112.500.

O computador com o qual pretendemos estabelecer comunicação também deve estar equipado com a interface apropriada.
Infelizmente, os fabricantes de PCs pararam de inserir a porta série RS-232, que há alguns anos fazia parte do
equipamento básico da maioria dos computadores.

Resta-nos a comunicação USB. Infelizmente, esta é uma tarefa bem difícil. Desta forma, geralmente são usados
conversores USB-UART, o que simplifica bastante o trabalho. A boa notícia é que não precisa de se preocupar com isso
na utilização do Arduíno, o conversor já vem integrado na placa.
Portanto, tudo o que precisa de fazer é ligar o Arduíno ao computador através do cabo USB (o mesmo que é usado na
programação).

Exercício Prático – Comunicação UART


Material necessário:
o 1x Arduíno UNO e cabo USB.

O objetivo do programa abaixo é muito simples: enviar um texto para o computador:

void setup(){
Serial.begin(9600); //Configuração da velocidade de transmissão
Serial.println("Bem-vindo!"); //Envio de texto único
}
void loop() {
delay(5000);
Serial.println("Passaram 5 segundos"); //Envio de texto em loop
}

Após o upload do programa acima, aparentemente nada acontece. Para verificar o seu funcionamento, precisa de
selecionar no menu do Arduíno: Ferramentas -> Monitor Série. Depois disso, vai abrir uma nova janela. Aqui, podemos
observar o que é enviado para/do Arduíno através da porta COM, que é o nosso UART. Vejamos a operação em prática:

Vamos agora analisar o programa. A primeira coisa ser feita foi a definição da baud-rate. A função Serial.begin () é usada
para este propósito, onde entre parênteses se encontra a velocidade de transmissão. Nesse caso, é 9600 baud/seg. Por
outro lado, a função Serial.println () é usada para enviar uma informação (frase ou números).

O texto “Bem-vindo!” é exibido apenas uma vez, porque está inserido na função void setup e, como se deve lembrar do
capítulo anterior do curso, as instruções inseridas nessa função são realizadas apenas uma vez.

A transmissão também pode ser observada nos LEDs integrados no Arduíno (Tx e Rx)! Estes acendem quando os dados
estão a ser transferidos para/da placa.

Exercício Prático – Interação com o programa


É claro que as informações não precisam de ser sempre enviadas por UART, a transmissão e receção também podem
ocorrer uma vez num momento escolhido. Isto é muito útil, por exemplo, para diagnosticar a operação do sistema ou
sinalizar diferentes ocorrências.

Usando o conhecimento adquirido anteriormente, poderá escrever um sketch que ativa um LED quando uma janela está
aberta. É claro que não vamos usar um sensor de abertura de janelas, vamos simular utilizado componentes mais simples.
Um botão de pressão vai substituir o sensor e dois LEDs servirão para sinalização.
Material necessário:
o 1x Arduíno UNO e cabo USB;
o 1x Breadboard;
o 1x LED vermelho;
o 1x LED verde;
o 1x Botão de pressão;
o 2x Resistências de 330Ω;
o 5x Cabos jumper.

Faça a ligação da seguinte forma:

Quando a janela está fechada (botão pressionado), o LED verde está aceso. Quando abrimos o circuito (paramos de
carregar no botão) o LED vermelho acende e no monitor série vamos ler a mensagem “Atenção! Alarme! A janela está
aberta!”.

void setup(){
Serial.begin(9600); //Configuração da velocidade de transmissão

pinMode(8, OUTPUT); //LED vermelho


pinMode(9, OUTPUT); //LED verde
pinMode(10, INPUT_PULLUP); //Botão

digitalWrite(8, LOW); //Desligar LEDs


digitalWrite(9, LOW);
}

void loop() {

if (digitalRead(10) == LOW) { //Se o botão for pressionado


digitalWrite(9, HIGH); //Liga o LED verde
digitalWrite(8, LOW); //Desliga o LED vermelho

} else { //Se o botão não for pressionado


digitalWrite(9, LOW); //Desliga o LED verde
digitalWrite(8, HIGH); //Liga o LED vermelho
Serial.println("Atenção! Alarme! A janela está aberta!");

while (digitalRead(10) == HIGH) { //Criação de um loop vazio para a janela voltar a fechar
delay(25); //Atraso de 25ms dentro do loop para minimizar interferências
}
}
}
Instrução #define
Com o tempo, os nossos programas vão aumentar consideravelmente. E se for necessário alterar a conexão física de, por
exemplo, um LED ou um botão? Alterar o número do pino de todo o código seria bastante difícil.
A instrução #define ajuda nesse aspeto. Permite que defina um símbolo para um determinado pino, que será substituído
pelo número deste antes da compilação, em qualquer local do código. Por exemplo:

#define ledPin 8

void setup() {
pinMode(ledPin, OUTPUT); //Configuração do pino 8 como saída
}

void loop() {
digitalWrite(ledPin, HIGH); //Liga o LED
delay(1000); //Espera 1 segundo
digitalWrite(ledPin, LOW); //Desliga o LED
delay(1000); //Espera 1 segundo
}

Colocando a linha: #define ledPin 8 no início do código, fazemos com que, antes da compilação, qualquer parte do
programa que possua como pino o “ledPin”, seja automaticamente transformada no número definido para este,
nomeadamente 8. É claro que o nome do pino pode ser diferente, o importante é estabelecer um nome único, que o ajude
a escrever programas longos.

IMPORTANTE: Depois da instrução #define não se coloca ponto e vírgula (;).

De seguida, está a nova e melhorada versão do código do sensor de abertura de janelas:

#define LEDvermelho 8
#define LEDverde 9
#define Botão 10

void setup(){
Serial.begin(9600); //Configuração da velocidade de transmissão

pinMode(LEDvermelho, OUTPUT); //LED vermelho como saída


pinMode(LEDverde, OUTPUT); //LED verde como saída
pinMode(Botão, INPUT_PULLUP); //Botão

digitalWrite(LEDvermelho, LOW); //Desligar LEDs


digitalWrite(LEDverde, LOW);
}

void loop() {

if (digitalRead(Botão) == LOW) { //Se o botão for pressionado


digitalWrite(LEDverde, HIGH); //Liga LED verde
digitalWrite(LEDvermelho, LOW); //Desliga LED vermelho
} else { //Se o botão não for pressionado
digitalWrite(LEDverde, LOW); //Desliga LED verde
digitalWrite(LEDvermelho, HIGH); //Liga LED vermelho
Serial.println("Atenção! Alarme! A janela está aberta!");

while (digitalRead(Botão) == HIGH) { //Criação de um loop vazio para a janela voltar a fechar
delay(25); //Atraso de 25ms dentro do loop para minimizar interferências
}
}
}
De agora em diante, só precisará de fazer a alteração de mudança de pino uma vez em todo o código!

Variáveis
Antes de passarmos para outros programas (incluindo envio de informações para o Arduíno via UART), temos que saber
o que são variáveis, e como é que estas funcionam.

As variáveis, de forma geral, são declarações de algum tipo de informação necessária para o código. Podem ser
caracteres, palavras ou números. Na maioria das vezes, vamo-nos deparar com variáveis numéricas.

Quando é que as variáveis são necessárias? Quando queremos guardar um valor e executar vários tipos de operações com
ele. Uma variável, assim como uma função, pode ter um tipo específico de informação, acerca de que tipo de dados pode
armazenar.

Abaixo pode encontrar uma lista dos tipos de variáveis mais importantes:

boolean logica = false; //Boolean - verdadeiro (true) ou falso (false)

int numero = 30000; //Int - números inteiros no intervalo de -32768 a 32767


long numeroGrande = 2000000; //Long - números inteiros no intervalo de -2147483648 a 2147483647

float numeroRacional = 6.28; //Float - números racionais que ocupem até 4 bytes de memória

char caractere = 'a'; //Char - caracteres


String frase = "Bem-vindo!"; //String - sequência de caracteres

NOTA: Os valores máximos que podem ser gravados numa variável dependem da placa Arduíno utilizada. Os valores
acima são apropriados para o Arduíno UNO.

De início, iremos usar mais frequentemente as seguintes variáveis:

o Boolean – como mencionado, é usado para armazenar valores verdadeiros ou falsos. Este tipo de variável, geralmente
é usado para sinalizar ocorrências ou condições de controlo;
o Int – é a variável mais comum para o armazenamento de números inteiros. Pode armazenar informações como o
número de toques no teclado, quantas vezes ocorreu uma determinada situação ou um valor dado pelo sensor de
distância (será realizado no final do curso). E, claro, pode realizar operações matemáticas nas variáveis – mais nos
exemplos práticos;
o String – é um conjunto de caracteres, ou seja, de forma simplificada, podemos guardar uma
palavra/frase/legenda/mensagem/etc.

Declaração de Variáveis
De forma a usar uma variável, é necessário declará-la, isto é, informar o compilador sobre o seu tipo e o seu nome. O
nome de cada variável começa sempre com uma letra, nunca com um número, e não pode conter espaços. A declaração de
uma variável deve ser feita da seguinte forma:

tipo nome = 0;

IMPORTANTE: Note que o símbolo = é usado para atribuir um valor de variável, e o símbolo == serve para comparar a
igualdade entre variáveis e valores.

Também é importante referir que se uma variável for colocada dentro de uma função, instrução ou subprograma, esta
ficará invisível (não poderemos usá-la) noutras funções. Vejamos:

int variavel = 0; //Variável global - pode ser usada em qualquer parte do programa
void setup() {
int variavel2 = 0; //Variável local - só pode ser utilizada dentro da função setup()
}

void loop() {
int variavel3 = 0; //Variável local - só pode ser utilizada dentro da função loop()
}

Exercício Prático – Variáveis


A teoria já passou, agora é hora de praticar o que aprendeu. Vamos começar com algo muito simples. De início, deixe o
nosso código escrever um valor de variável, que vai aumentando, em cada ciclo de loop.

int contador = 0; //Declaração da variável

void setup() {
Serial.begin(9600); //Configuração da velocidade de transmissão
}

void loop() {
Serial.println(contador); //Enviar o valor da variável
contador = contador + 1; //Somar 1 ao valor do contador
delay(100); //Atraso para tornar o programa mais percetível
}

Obviamente, a declaração de variável foi colocada no início, fora de qualquer função. Graças a isso, podemos ter acesso à
variável em qualquer parte do programa.

Primeiro, a taxa de transmissão é definida e inicializada e, de seguida, a função loop () executa 3 ações:

1. Invoca o local da memória, no qual declaramos uma variável denominada “contador”, e envia o valor encontrado via
UART;
2. Aumenta +1 no valor recebido do contador;
3. Espera 100ms (para uma melhor perceção) e volta ao início do loop.

contador = contador + 1; //Somar 1 ao valor do contador

Do ponto de vista matemático, onde o sinal “=” significa igualdade, a linha acima não deveria funcionar. No entanto, na
programação, o sinal “=” significa atribuição. Na prática, o código acima deve ser entendido como a seguinte operação:
1. Ir buscar o valor da variável contador;
2. Somar 1 ao valor recebido;
3. Receber o resultado da operação e atribuí-lo à própria variável.

Faça o download do programa para o Arduíno e confira se está tudo a funcionar corretamente. É claro que, para ver os
resultados, deverá abrir o monitor série.
Transmissão Bidirecional do Arduíno
É claro que a comunicação, para ser útil, deve ocorrer de forma bidirecional. Até agora, tem sido o Arduíno a enviar-nos
informações. Está na hora de lhe respondermos!
O objetivo do primeiro programa é “ouvir” o nosso nome. Quando lhe enviarmos o nome, o Arduíno deverá responder
com a seguinte mensagem “Olá, Nome!”, onde, obviamente, o nome será o anteriormente enviado.
String dadosRecebidos = ""; //Conjunto vazio de dados recebidos

void setup() {
Serial.begin(9600); //Configuração da velocidade de transmissão
}

void loop() {
if(Serial.available() > 0) { //Se o Arduino receber dados
dadosRecebidos = Serial.readStringUntil('\n'); //Lê os dados recebidos e guarda na própria variável
Serial.println("Bem-vindo " + dadosRecebidos + "!"); //Mostrar a mensagem
}
}

Primeiramente, declaramos a variável dadosRecebidos, para a qual o conjunto de caracteres recebido (nome) será copiado. De
seguida, como de costume, definimos a taxa de transmissão e iniciámo-la. Depois introduzimos uma nova função:
Serial.available (). Esta envia o número de bytes que foram recebidos e que estão a aguardar suporte do Arduíno.

No caso dos dados já estarem disponíveis (maior que 0), são enviados para a variável dadosRecebidos. Isto é feito através da
função .readStringUntil (término) que copia os dados do buffer até encontrar um caractere de finalização (neste caso, “\n”).

Exercício Prático de Interação com o Sistema – Controlo de LEDs via


UART
Material necessário:
o 1x Arduino UNO e cabo USB;
o 1x Breadboard;
o 1x LED verde;
o 1x LED vermelho;
o 2x Resistências de 330Ω;
o 3x Cabos jumper.
Neste exercício vamos usar capacidade de enviar texto para o Arduíno para controlar LEDs. Para isso, ligue dois LEDs de
acordo com o esquema abaixo (LEDs nos pinos 8 e 9):

O objetivo do programa é ligar o LED verde ou vermelho por 1 segundo, quando é enviado um comando apropriado para
o Arduíno. O código final é o seguinte:

#define verde 8
#define vermelho 9

String dadosRecebidos = ""; //Conjunto vazio de dados recebidos

void setup() {
Serial.begin(9600); //Configuração da velocidade de transmissão
pinMode(verde, OUTPUT); //Configuração dos LEDs como saídas
pinMode(vermelho, OUTPUT);

digitalWrite(verde, LOW); //Desligar LEDs


digitalWrite(vermelho, LOW);
}

void loop() {
if(Serial.available() > 0) { //Se o Arduíno receber dados
dadosRecebidos = Serial.readStringUntil('\n'); //Lê os dados recebidos e guarda na própria variável

if (dadosRecebidos == "verde") { //Se escrever a palavra "verde"


digitalWrite(verde, HIGH); //Liga o LED verde
delay(1000); //Espera 1 segundo
digitalWrite(verde, LOW); //Desliga o LED verde
}

if (dadosRecebidos == "vermelho") { //Se escrever a palavra "vermelho"


digitalWrite(vermelho, HIGH); //Liga o LED vermelho
delay(1000); //Espera 1 segundo
digitalWrite(vermelho, LOW); //Desliga o LED vermelho
}
}
}

Vamos agora analisar o funcionamento do programa. Inicialmente, os números dos pinos com LEDs são definidos e a
variável para a qual os dados recebidos são copiados é declarada. No loop, é verificado se o Arduíno recebeu os dados. Se
sim, é averiguado se esses dados correspondem a uma das cores. Depois disto, é ligado o LED da cor indicada.

Conversor Analógico-Digital
O mundo que nos rodeia não é só digital, e, às vezes, 2 estados (high e low) não são suficientes para realizar o projeto
pretendido.
Por isso é que, vamos falar do conversor analógico-digital, abreviado como ADC (analog-to-digital converter).

Introdução Teórica

A eletrónica divide-se em dois tipos de sinais: digital e analógico. Os sinais digitais estão limitados a dois estados: High
(1) ou Low (0). Na prática, significa que o Arduíno reconhecerá uma de duas tensões: 5V ou 0V, respetivamente.

Infelizmente, nem tudo em nosso redor pode ser descrito de uma forma tão simples. Por exemplo, ao usarmos um sensor
de distância, provavelmente pretendemos saber a distância exata de um obstáculo, e não apenas informações básicas
como: obstáculo detetado/sem obstáculo.

Tal sensor, na sua saída, pode fornecer uma tensão proporcional à distância do obstáculo. Então, a medição consiste em
ler a tensão numa faixa de 0 a 5V. Esta é a abordagem analógica. Portanto, nos exemplos seguintes, vamos usar os
periféricos apropriados do Arduíno, que permitem medir a tensão fornecida às entradas especiais do sistema.

ATENÇÃO: Lembre-se que as entradas do Arduíno só são compatíveis com tensões incluídas na seguinte faixa: 0-5V.
Outras tensões poderão danificar a placa e até o computador ao qual ligar o circuito.

Para o processamento de sinais analógicos, é utilizado o chamado ADC: conversor analógico-digital. Este é um dos
periféricos mais populares encontrados em microcontroladores. O seu trabalho é converter uma tensão aplicada numa
entrada do sistema num formato digital. Por exemplo (transdutor linear):

Tensão => Valor lido no ADC [V] (arredondado)


0 => 0
1 => 51
2 => 102
3 => 154
4 => 205
5 => 255

Neste caso, apresentamos um conversor de 8 bits, já que o valor lido poderia ter 256 combinações (começando em 0). Na
verdade, podemos encontrar vários transdutores, por exemplo de 12 ou 16 bits. O conversor que possui mais bits é o mais
preciso, porque seu o valor máximo é maior (funciona no mesmo intervalo, mas com uma resolução mais alta).

Como curiosidade, é interessante saber que os conversores analógico-digitais operam de forma relativamente lenta.
Naturalmente, não vai verificar isso nos seus programas, pois, mesmo sendo “lentos” são inacreditavelmente rápidos (até
10.000 medições por segundo). No entanto, comparando o ADC a outros periféricos do microcontrolador, é a “ovelha
negra”.
Os ADCs são, também, muito caros de produzir. Como se deve lembrar, na segunda lição do curso, verificamos que o
Arduíno UNO possui 6 entradas analógicas (A0-A5). De facto, na placa, existe apenas um conversor analógico-digital,
que consegue medir a tensão das seis entradas.

Exercício Prático – ADC

Material necessário:

o 1x Arduíno UNO e cabo USB;


o 1x Breadboard;
o 1x Potenciómetro;
o 5x Cabos jumper.

É hora de verificar como é que o ADC funciona na prática. Para isso, faça a montagem do circuito de acordo com a figura
abaixo.
O uso de software do ADC é trivial e limitado ao uso de apenas uma função analogRead (canal ADC), onde o canal ADC
é o pino analógico utilizado (A0-A5).

int valorLido = 0;

void setup() {
Serial.begin(9600); //Configuração da velocidade de transmissão
}

void loop() {
valorLido = analogRead(A5); //Ler valor da tensão na entrada A5
Serial.println(valorLido); //Enviar sinal para o monitor série
delay(200);//Esperar 200ms
}

Ao girar o potenciómetro, obtemos valores de 0 a 1023 no monitor série. Isto significa que o conversor analógico-digital
integrado no Arduíno UNO, é de 10 bits.

Exercício Prático – Voltímetro


Esta tarefa é fácil, basta usar o circuito criado anteriormente. O exercício consiste apenas na conversão apropriada do
valor lido. Sabemos que a tensão de entrada varia numa faixa de 0 a 5V, e o maior número que podemos obter do ADC é
1023. Portanto, eis o cálculo:

Simplificando, qualquer aumento na tensão de entrada de ~0.005V aumentará a leitura do ADC em um. Assim, para obter
um resultado em volts basta adicionar uma linha:

int valorLido = 0; //Ler valor do ADC


float tensão = 0; //Valor convertido em volts (V)

void setup() {
Serial.begin(9600); //Configuração da taxa de transmissão
}

void loop() {
valorLido = analogRead(A5); //Ler valor da tensão na entrada A5
tensão = valorLido * (5.0/1023.0); //Converter valores em volts
Serial.println(tensão); //Enviar tensão medida para monitor série
delay(200); //Esperar 200ms
}
Note que a declaração de tensão foi feita através de uma variável float, para que seja possível armazenar valores/números
racionais.
Deverá conseguir ver no monitor série valores entre 0 e 5V. Acabamos de construir um voltímetro muito simples!

Exercício Prático com ADC – Regulação do funcionamento do programa

O exemplo anterior pretendia apenas demonstrar o funcionamento do conversor. Agora vamos usar o potenciómetro para
influenciar o funcionamento do programa.

Material necessário:
o 1x Arduíno UNO e cabo USB;
o 1x Breadboard;
o 1x Potenciómetro;
o 1x LED;
o 1x Resistência de 330Ω;
o 6x Cabos jumper.

Faça a ligação do circuito de acordo com o esquema abaixo:

O que é que será que acontece se o valor lido do ADC determinar o delay do programa? Este é o exemplo mais rápido
para construir um dispositivo com um LED, que pisca a uma frequência controlada por um potenciómetro:

int valorLido = 0; //Variável para armazenar leituras do ADC

void setup() {
pinMode(2, OUTPUT); //Configuração do LED como saída
}

void loop() {
valorLido = analogRead(A5); //Ler valor do ADC
digitalWrite(2, HIGH); //Ligar o LED
delay(valorLido); //Tempo de espera igual ao valor lido pelo ADC
digitalWrite(2, LOW); //Desligar o LED
delay(valorLido); //Tempo de espera igual ao valor lido pelo ADC
}

Exercício Prático com ADC – Seleção de LEDs


Neste exemplo, dependendo da posição em que o potenciómetro se encontre, um LED vai ser ligado.

Material necessário:

 1x Arduino UNO e cabo USB;


 1x Breadboard;
 1x Potenciómetro;
 1x LED amarelo;
 2x LEDs verdes;
 2x LEDs vermelhos;
 5x Resistências de 330Ω;
 11x Cabos jumper.

Primeiro, necessita de ligar todo o circuito. O nosso está disposto da seguinte forma:

A tarefa é simples, basta dividir o valor máximo que podemos ler do ADC (1023) por 5 e, com base nisso, criar condições
para a ativação individual dos LEDs. Mas, para isso, podemos usar a função map (), que nos facilita muito o trabalho!

O seu uso, na prática, é assim:


valorEscala = map(valorLido, 0, 1023, 1, 5);
Esta função permite, rapidamente, dividir por escalas um determinado valor. O primeiro argumento, é o valor a ser
dividido, que neste caso, são informações dadas pelo ADC. O segundo e terceiro parâmetros são o intervalo do valor de
entrada, enquanto os dois últimos são o intervalo do valor de saída (após divisão).

Como resultado da linha de código acima, obtém-se sempre um valor no intervalo compreendido entre 1 e 5. Vejamos o
código completo:

int valorLido = 0;

void setup() {
pinMode(8, OUTPUT); //Configuração dos LEDs como saídas
pinMode(9, OUTPUT);
pinMode(10, OUTPUT);
pinMode(11, OUTPUT);
pinMode(12, OUTPUT);
}

void loop() {
valorLido = analogRead(A5); //Ler valor do ADC
valorLido = map(valorLido, 0, 1023, 1, 5); //Valores para divisão

if (valorLido == 1) { //Primeiro intervalo


digitalWrite(8, HIGH);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
} else if (valorLido == 2) { //Segundo intervalo
digitalWrite(8, LOW);
digitalWrite(9, HIGH);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
} else if (valorLido == 3) { //Terceiro intervalo
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, HIGH);
digitalWrite(11, LOW);
digitalWrite(12, LOW);
} else if (valorLido == 4) { //Quarto intervalo
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, HIGH);
digitalWrite(12, LOW);
} else { //Quinto intervalo
digitalWrite(8, LOW);
digitalWrite(9, LOW);
digitalWrite(10, LOW);
digitalWrite(11, LOW);
digitalWrite(12, HIGH);
}
delay(50); //Atraso para o ADC não ler demasiado rápido
}

Verifique o que acontece aos LEDs quando roda o potenciómetro. Se tudo estiver a funcionar corretamente, e se estiver tudo
bem ligado, quando roda o potenciómetro deverá acender um LED diferente que estava aceso anteriormente.

Exercício Prático com ADC – Ativar um LED quando está escuro


Vamos agora inserir um novo elemento e criar algo prático. Neste exercício, vamos usar um sensor de luz (LDR), um
elemento cuja resistência muda sob a influência da luz incidente (quanto maior a quantidade de luz, menor a resistência).
Material necessário:
 1x Arduino UNO e cabo USB;
 1x Breadboard;
 1x LED;
 1x Sensor de luz LDR;
 1x Resistência de 330Ω;
 1x Resistência de 1KΩ;
 7x Cabos jumper.
A resistência de 1KΩ deve estar ligada ao LDR. Faça as ligações do circuito da seguinte forma:

Quando uma grande quantidade de luz incide sobre o LDR, a sua resistência é mínima e se estiver ligado ao Arduíno
possui uma tensão relativamente alta. Quando escurece, a resistência do LDR aumenta e a tensão é baixa.

Com este programa, será capaz de criar uma lâmpada que liga quando está escuro. O código é muito simples:

int valorLido = 0; //Variável para armazenar leituras do ADC

void setup() {
pinMode(8, OUTPUT); //Configuração do LED como saída
}

void loop() {
valorLido = analogRead(A5); //Ler valor do ADC

if (valorLido < 100) {


digitalWrite(8, HIGH); //Ligar LED
} else {
digitalWrite(8, LOW); //Desligar LED
}
delay(50);
}

Existe uma condição que é responsável por ligar/desligar o LED. A questão é: como escolher o valor de mudança? O
melhor é fazê-lo à mão, mas é pouco prático… Digamos que quer mudar o projeto de local, para uma sala com condições
mínimas muito diferentes. Teremos de reconfigurar o código novamente? Sim, a menos que…

Exercício Prático com ADC – Ativar um LED quando está escuro v2


Desta vez o exercício é óbvio. Como antes, pretendemos que crie uma lâmpada que ligue após escurecer. No entanto, tem
de ser muito mais fácil de regular. Faz ideia de como fazer isso?

Usamos o potenciómetro ligado à entrada analógica seguinte (A4):

Em vez de tornar o LED dependente de uma faixa muito específica, o objetivo é ajustar suavemente o limite de
comutação com o potenciómetro. A alteração do código é muito fácil e consiste em editar 3 linhas de código:

int valorLido = 0; //Variável para armazenar leituras do ADC


int valorComutacao = 0; //Valor limite para ligar o LED - definido pelo potenciómetro

void setup() {
pinMode(8, OUTPUT); //Configuração do LED como saída
}

void loop() {
valorLido = analogRead(A5); //Ler valor do ADC
valorComutacao = analogRead(A4); //Ler valor do ADC

if (valorLido < valorComutacao) { //Se for mais escuro do que o limite encontrado
digitalWrite(8, HIGH); //Liga o LED
} else {
digitalWrite(8, LOW); //Desliga o LED
}

delay(50);
}

De agora em diante, pode ajustar o limite como preferir!

O que é o sinal PWM?


Suponha que liga um LED ao microcontrolador e programa-o para piscar em loop. O LED fica ligado por um segundo, no
próximo permanece desligado e assim em diante:

void setup() {
pinMode(3, OUTPUT); //Configuração do LED como saída
}

void loop() {
digitalWrite(3, HIGH); //Liga o LED
delay(1000); //Espera 1 segundo
digitalWrite(3, LOW); //Desliga o LED
delay(1000); //Espera 1 segundo
}

Se desenhássemos um gráfico que demonstrasse a mudança de tensão em função do tempo do pino 3, obteríamos a
seguinte onda:

O valor marcado como x é o tempo em que o LED está ligado. De forma oposta, T é o período de tempo em que o LED
está desligado. Por sua vez, o seu inverso, isto é, 1/T, indica a frequência. A relação entre o tempo que o LED está ligado
e o tempo que o LED está desligado é 1:1. Por outras palavras, o LED está ativo durante 50% da operação do programa.
Este aspeto é denominado duty cycle.

Para resumir as informações do sinal acima:


o Amplitude (valor máximo): 5V;
o Período (ciclo): 2 segundos;
o Frequência: 1/2 = 0,5 Hz;
o Duty cycle: 50%.

Agora outro exercício semelhante. No entanto, com um duty cycle diferente, ainda que mantendo o período. Como fazê-
lo? Basta prolongar o tempo de operação do LED, reduzindo o tempo em que desligado. Por exemplo:

void setup() {
pinMode(3, OUTPUT); //Configuração do LED como saída
}

void loop() {
digitalWrite(3, HIGH); //Ligar o LED
delay(1667);
digitalWrite(3, LOW); //Desligar o LED
delay(333);
}

Desta vez, o LED fica ligado cerca de 5/6 do tempo. Então o duty cycle é cerca de 83%. Apresentando a situação num
gráfico obtemos:

De forma oposta, se trocarmos os delays, o duty cycle do sinal fica cerca de 17%. Vejamos:
Dê uma vista de olhos nos exemplos acima. Qual dos parâmetros mudou em cada exemplo? A resposta é fácil: o duty
cycle. A frequência permaneceu igual.

Agora imagine que os delays inseridos nos códigos acima eram muito mais pequenos, graças aos quais a frequência do
sinal é muito maior… Parabéns! Acabou de entender o princípio do PWM. É um método de modular um sinal retangular
através do ajuste da largura de pulso.

Para que é que o sinal PWM é usado?


Este sinal é usado com muita frequência. Com este, pode controlar o brilho de um LED, a posição de um servo e a
velocidade à qual um motor funciona! Como terá oportunidade de ver, possui inúmeras aplicações em robótica, bem
como noutros projetos DIY.

Exercício Prático de PWM – Controlo do brilho de um LED


Está na hora do primeiro exemplo prático de aplicação do PWM. Para já, vamos criar um programa muito simples, cujo
objetivo será colocar regular o brilho de um LED.

Material necessário:
 1x Arduino UNO e cabo USB;
 1x Breadboard;
 1x LED;
 1x Resistência de 330Ω;
 2x Cabos jumper.

Como já vimos no segundo artigo do curso, o Arduíno está equipado com 6 canais PWM. Cada saída, na qual podemos
obter o sinal PWM, foi marcada na placa com um til “~”.

Cada canal PWM disponível no Arduíno UNO é de 8 bits. Isto significa que, o sinal que queremos receber na sua saída,
pode ser definido por um número de 0 a 255, onde 255 significa 100% de duty cycle.

Para realizar o primeiro exercício, é necessário ligar o LED ao pino 3 da seguinte forma:

Agora vamos escrever o código. O objetivo é o LED acender lentamente.

#define pinoLED 3

int dutyCycle = 0;
int mudanca = 5;
void setup() {
pinMode(pinoLED, OUTPUT); //Configuração do LED como saída
}

void loop() {
analogWrite(pinoLED, dutyCycle); //Gerar um sinal com determinado duty cycle

if (dutyCycle < 255) { //Se o duty cycle for menor do que 100%
dutyCycle = dutyCycle + mudanca; //Aumenta o duty cycle
} else {
dutyCycle = 0; //Se o duty cycle for igual a 100%, volta ao início
}

delay(50); //Pequeno atraso para tornar o efeito visível


}

Esperamos que tenha ficado claro. Podemos agora discutir a nova função inserida: analogWrite (pino, duty cycle). O seu
objetivo é gerar o sinal PWM no pino selecionado com o duty cycle indicado.

O programa acima pretende aumentar periodicamente o duty cycle de zero para o momento em que o seu valor é
imediatamente menor do que 255 (100%). Quando é alcançado o duty cycle máximo, o LED desliga e o processo é
repetido.

Servo Motor
Um servomecanismo é um motor, caixa de velocidades e controlador num só dispositivo. No entanto, estes motores não
são projetados para executar rotações completas. Na maioria das vezes, os servos possuem um ângulo de rotação de 0-
180º. É importante saber que eles conhecem a sua posição atual, por isso não precisa de se preocupar com erros de
posição.

Os princípios mais importantes da utilização dos servos:

1. Não se deve girar manualmente a posição do eixo, sem necessidade. Pode danificar as delicadas engrenagens de
plástico;
2. Não se deve alimentar o servo diretamente da fonte de alimentação usada no restante sistema. Cada motor recebe
uma corrente relativamente alta, especialmente no início do movimento. Isso pode perturbar o funcionamento dos
outros dispositivos e, em casos extremos, danificá-los.

Como é que o servo funciona?


Como é que o servomecanismo sabe para qual posição girar? Graças ao driver integrado. É ele que, com base no sinal
PWM fornecido, controla o motor.

Um padrão aceitável é o envio de um sinal com um período de 20ms para o servo. O duty cycle é interpretado como a
posição para a qual o servo deve ser movido. O duty cycle do sinal gerado deve encontrar-se entre 5 e 10%. Estes valores
serão convertidos em duas posições extremas no servo (máximo esquerdo e máximo direito).

Fios de ligação do servo:

o Vermelho – alimentação;
o Amarelo ou laranja – controlo do sinal;
o Preto ou castanho – GND.

Dependendo do fabricante, as cores dos fios podem variar. No entanto, dois serão definitivamente preto/castanho e
vermelho. O restante será o fio de sinal.
Alimentação do servo
Como foi referido anteriormente, não deve alimentar o servo diretamente da mesma fonte que alimenta o
microcontrolador. Portanto, devido ao fato de o motor consumir uma grande corrente, deve ser utilizada uma fonte
adequada para alimentação do sistema.

Infelizmente, a alimentação a partir da porta USB, como havíamos feito até agora, não é suficiente. Portanto, pela
primeira vez, vamos alimentar a placa com uma bateria de 9V!

Exercício Prático – Servomecanismo


Vamos passar ao primeiro programa com o servo motor. Para isto, ligue o sistema de acordo com o diagrama de
montagem abaixo.

Material necessário:
o 1x Arduino UNO e cabo USB;
o 1x Breadboard;
o 1x Servo Motor SG90;
o 1x Regulador de tensão LM7805;
o 1x Bateria de 9V;
o 1x Ligador para bateria de 9V;
o 7x Cabos jumper.

Em primeiro lugar, é necessário ligar a bateria. Em segundo, é preciso incluir um regulador de tensão LM7805.

Agora o código que fará o servo mover-se gradualmente:

#include <Servo.h> //Biblioteca responsável pelo servo motor

Servo servomecanismo; //Declaração do servo como servomecanismo


int posicao = 0; //Posição atual do servo de 0-180 graus
int mudanca = 6; //Qual deve ser a posição do servo?

void setup(){
servomecanismo.attach(9); //Servo ligado ao pino 9
}

void loop(){
if (posicao < 180) { //Se a posição for inferior a 180 graus
servomecanismo.write(posicao); //Move-se
} else { //Caso contrário, volta ao início
posicao = 0;
}
posicao = posicao + mudanca; //Aumentar a posição atual do servo
delay(200); //Atraso para melhor efeito
}

Desta vez, adicionámos uma biblioteca que vai expandir as capacidades do programa com as nossas funções. O comando
usado é:

#include Servo.h

Neste caso, adicionamos o arquivo Servo.h, que contém instruções adicionais do servo. Graças a este, não precisámos de
ser nós a controlar o sinal PWM. É suficiente indicar as posições (ângulo) para as quais queremos que o servo gire.
Para controlar o servo, é necessário declará-lo:
Servo servomecanismo;

A função attach (pino) – para o objeto Servo – funciona de maneira semelhante ao pinMode. A partir desta instrução, será
gerado, na saída indicada (neste caso 9), um sinal PWM.
Depois de iniciar o programa, o servo deve mover-se suavemente de uma posição extrema para a outra em loop. A
instrução chave é:
servomecanismo.write(posição);

A posição deverá ser um ângulo entre 0 e 180º.

Representação Numérica no Monitor Série


Neste ponto usamos a interface UART para comunicação com o computador. Havia funções usadas para transmitir e
receber informações. No entanto, não abordamos todas as possibilidades que a função println oferece. Nos exemplos
dados até agora, foi usada de uma forma muito simples, com apenas um argumento – número ou frase.
Todos os valores que enviamos para o monitor série nas tarefas propostas, enquadravam-se no sistema decimal. E se nos
interessasse enviar, por exemplo, números binários? Temos de criar as nossas próprias funções que alterem a
representação de valores para outros sistemas? Claro que não!
Felizmente, as bibliotecas do Arduíno contêm vários recursos para os utilizadores. Incluindo suporte para vários sistemas
de representação numérica. Quando enviamos um valor através da função println, podemos decidir como é que é exibido
no computador:

[...]
int numero = 2345;

Serial.println(numero); //Exibir no sistema decimal


Serial.println(numero, DEC); //Exibir no sistema decimal

Serial.println(numero, HEX); //Exibir no sistema hexadecimal


Serial.println(numero, OCT); //Exibir no sistema octal
Serial.println(numero, BIN); //Exibir no sistema binário
[...]

Como pode perceber, nos exemplos anteriores, a representação numérica foi realizada, por padrão, na forma decimal. No
entanto, pode escolher o sistema pretendido de entre quatro: hexadecimal, octal, binário e, claro, decimal. Na prática,
provavelmente só usará o sistema decimal e o binário.

Precisão dos Números Não Inteiros


É possível declarar uma variável que armazena um número não inteiro, por exemplo: 3.141592. Até agora, não usamos
essa variável, porque é uma boa prática evitar números com uma parte fracionária no uso com microcontroladores.
De qualquer das formas, vamos supor que queremos exibir um número não inteiro. Vejamos o seguinte programa:
void setup() {
float numeroPI = 3.1415; //Declaração de variável

Serial.begin(9600); //Configuração da taxa de transmissão


Serial.println(numeroPI, 4); //4 Casas decimais
Serial.println(numeroPI, 0); //0 Casas decimais

Serial.println(PI); //Mistério
}

void loop() {
}

Ao enviar o programa para o Arduíno e abrir o monitor série, deverá aparecer a seguinte sequência:

Como pode ver, existe um parâmetro adicional para definir a precisão dos valores enviados (número de casas decimais).
Lembre-se que as variáveis float podem ser representadas com um máximo de 7 dígitos. Por exemplo:
float numero1 = 0.123456 √
float numero2 = 12345.6 √
float numero3 = 123.456 √
float numero4 = 1234567.8 ×
Vamos voltar ao código acima por um momento, especificamente para a seguinte linha misteriosa:
Serial.println(PI); //Mistério

Por que é que este comando enviou o número 3,14? Nós não declaramos tal variável em lugar nenhum. A verdade é que o
valor do número Pi é tão usado que, em muitas linguagens pode encontrar constantes “prontas”. Neste caso, qualquer
local do código com “PI” escrito, será transformado no valor apropriado da constante.
Se precisar de uma maior precisão no seu programa, pode sempre escrever a seguinte função:
Serial.print(PI, 25);

Para sua satisfação, irá aparecer um número muito preciso no ecrã:


3.1415927410125732421875000
De qualquer das formas, voltemos à precisão máxima que os microcontroladores oferecem. A constante PI possui
propriedades da variável float, ou seja, aceita, no máximo, 7 dígitos! Cada dígito subsequente está errado, porque o
registo mais preciso de valores não inteiros no sistema binário, não permite obter o verdadeiro valor de Pi.
Vejamos o valor exibido anteriormente e o verdadeiro valor de Pi:
Valor exibido = 3.1415927410125732421875000
π = 3,1415926535897932384626433
Função Serial.print()
Até agora, cada valor enviado para o monitor série, apareceu em diferentes linhas. Tornou o programa claro, mas nem
sempre é útil. E se quisermos exibir várias variáveis e textos lado a lado? Usamos a função que temos usado –
Serial.println() – mas sem o “ln” no final – Serial.print().
Tem exatamente a mesma função que a anterior, com a diferença de não mudar de linha. Exemplo:
void setup() {
Serial.begin(9600); //Configuração da taxa de transmissão
}

void loop() {
Serial.print("Bem-vindo! "); //Enviar texto
delay(1000); //Atraso de 1 segundo para melhor efeito
}

O resultado não é impressionante, mas mostra o que é pretendido: não há linhas novas.

Como é que pode criar uma nova linha quando pretendido? Existem 3 formas:
Serial.print("Primeira linha");
Serial.println();
Serial.print("Segunda linha");

OU
Serial.println("Primeira linha");
Serial.print("Segunda linha");

OU
Serial.print("Primeira linha \n Segunda linha");

A forma mais interessante é, definitivamente, a última. É incluído um novo símbolo “\n“. Não é único do Arduíno e
significa transição para uma nova linha. Como pode ver, é muito conveniente porque permite passar a uma nova linha em
qualquer momento.

Existem outros símbolos úteis como este? Sim! Para formatar o texto, também é útil usar o Tab. Se quiser mover o texto
para a direita, deve usar o \t – é muito mais prático do que inserir uma quantidade absurda de espaços.

Exercício Prático – Novas informações UART


Está na hora de usar os conteúdos acima na prática. O objetivo do programa será medir o valor de tensão no pino A5 e
depois enviá-lo para o monitor série. No entanto, desta vez, não é suficiente exibir o número no sistema decimal.
Adicionalmente – numa linha – deverão ser exibidos os valores em HEX, OCT e BIN. E, claro, tem de estar tudo bem
formatado!

Material necessário:
 1x Arduino UNO e cabo USB;
 1x Breadboard;
 1x Potenciómetro;
 5x Cabos jumper.

De início, faça todas as conexões necessárias. Vamos usar o potenciómetro para regular a tensão.
Esperamos que não tenha sido demasiada informação de uma vez, e que tenha percebido tudo. De qualquer das formas,
preparamos o código para o ajudar. O que é pretendido é que analise e compreenda o programa e, depois, escreva um
semelhante!
void setup() {
Serial.begin(9600); //Configuração da taxa de transmissão
}

void loop() {
int potenciometro = analogRead(A5); //Ler valores do ADC

Serial.print("Ler: ");
Serial.print(potenciometro, DEC);
Serial.print("[DEC]\t");
Serial.print(potenciometro, HEX);
Serial.print("[HEX]\t");
Serial.print(potenciometro, OCT);
Serial.print("[OCT]\t");
Serial.print(potenciometro, BIN);
Serial.print("[BIN]\n");

delay(1000); //Atraso de 1 segundo para melhor efeito


}

Depois de executar o programa, no monitor série, deve observar os valores dados pelo ADC bem formatados e em
diferentes sistemas numéricos:
Função Switch()
Vamos agora abordar a função de controlo switch, usada muito frequentemente. É aplicada em situações em que, com
base numa variável, são realizadas várias ações diferentes, dependendo do valor fornecido.

Para entender esta função, vamos usar um exemplo, que será resolvido de duas maneiras – de forma tradicional e através
de um novo método. Portanto, vamos supor que queremos escrever um programa que leia o valor ADC e, de seguida, o
envie para o monitor série na forma de números decimais, hexadecimais, octais ou binários. Tudo depende da nossa
escolha.

Com os conhecimentos que já detemos, podemos escrever o seguinte código:


String dadosRecebidos = ""; //Conjunto vazio de dados recebidos

void setup() {
Serial.begin(9600); //Configuração da taxa de transmissão
}

void loop() {
int potenciometro = analogRead(A5); //Ler valores do ADC

if(Serial.available() > 0) { //Se o Arduíno recebeu dados


dadosRecebidos = Serial.readStringUntil('\n'); //Lê até ao final da linha
}

if (dadosRecebidos == "d") {
Serial.println(potenciometro, DEC);
} else if (dadosRecebidos == "h") {
Serial.println(potenciometro, HEX);
} else if (dadosRecebidos == "o") {
Serial.println(potenciometro, OCT);
} else if (dadosRecebidos == "b") {
Serial.println(potenciometro, BIN);
}
delay(1000); //Atraso de 1 segundo para melhor efeito
}

Exequível? Sim. Prático? Mais ou menos. Não seria ideal se, por exemplo, houvesse muito mais condições, ou se fosse
necessário mudá-las. É aqui que a nova função switch entra para ajudar! Possui este aspeto:

switch (ValoraVerificar) {
case valor_1:
//O código é executado se a função for atendida
break;

case valor_2:
//O código é executado se a função for atendida
break;

[...]
default:
//Código a ser executado se a condição não foi satisfeita
break;
}

No início, escrevemos a palavra-chave switch e, dentro dos parênteses, indicamos a variável que queremos verificar. Em
seguida, abrimos chavetas. Dentro delas, pode inserir qualquer número de condições que serão verificadas
sucessivamente. Fazemos isso ao escrever a palavra case. Depois do espaço colocamos um valor, que deve ser igual à
variável que pretendemos verificar. Terminámos com dois pontos “:”.
Se a condição for atendida, o código será executado até ao break seguinte. Quando a condição não é atendida, parte do
código é ignorada e o microcontrolador passa a verificar a próxima condição (case).
No final, opcionalmente, podemos colocar um código entre default e break. Este será executado quando nenhuma das
condições anteriores tiver sido verificada.
Percebemos que possa parecer complicado, e é por isso que vamos passar para o exemplo prático e vamos transformar o
programa anterior.

int dadosRecebidos = 0;
void setup() {
Serial.begin(9600);
}

void loop() {
int potenciometro = analogRead(A5); //Ler valores do ADC

if(Serial.available() > 0) { //Se o Arduíno receber dados


dadosRecebidos = Serial.read(); //Se sim, lê apenas 1 sinal
}

switch (dadosRecebidos) {
case 'd':
Serial.println(potenciometro, DEC);
break;
case 'h':
Serial.println(potenciometro, HEX);
break;
case 'o':
Serial.println(potenciometro, OCT);
break;
case 'b':
Serial.println(potenciometro, BIN);
break;
}
delay(1000);
}

Uma pequena nota, a função switch funciona somente com base na comparação de números. Portanto, neste exemplo, as
letras que estamos a controlar: d, h, o, b devem ser tratadas não como letras, mas como códigos ASCII. Escrever uma
letra dentro de apóstrofos, depois de case, faz com que estas sejam tratadas como códigos ASCII.

Além disso, em vez da função de leitura de dados usada anteriormente:

dadosRecebidos = Serial.readStringUntil('\n');

Foi usada uma função mais simples, que apenas lê o primeiro byte (sinal) dos dados:

dadosRecebidos = Serial.read(); //Se sim, lê apenas 1 sinal


Porquê juntar motores ao Arduíno?
Controlar o sentido da rotação e a velocidade do motor abre a porta a muitas possibilidades. Com essas novas
capacidades, podemos construir um robot móvel simples, que vagueie pela casa e evite obstáculos. Também podemos
criar um veículo controlado remotamente através do nosso telemóvel. As possibilidades são, realmente, inúmeras!

Porque é que não podemos ligar o motor diretamente ao Arduíno?

O Arduíno, mais especificamente o microcontrolador integrado, controla os sinais. A eficiência de cada saída é
relativamente pequena (cerca de 20mA). É fácil supor que, 99,999% dos motores que encontrar, vão precisar de muito
mais corrente. Posto isto, ao ligar um motor ao Arduíno corre o risco de danificar irreversivelmente a placa.

Introdução às Pontes H

Portanto, nos exercícios seguintes, os motores vão ser substituídos por LEDs. Será na mesma capaz de observar a
mudança de direção da rotação (através do LED que acender) e a mudança da velocidade (através do brilho do LED).

Neste ponto precisará dos seguintes materiais:

 1x Arduino UNO e cabo USB;


 1x Breadboard;
 1x Bateria de 9V;
 1x Ligador para bateria de 9V;
 1x Chip L293D;
 1x Resistência de 1KΩ;
 1x Condensador Cerâmico 10-220uF;
 1x Condensador Eletrolítico 10-220uF;
 2x LEDs;
 Cabos jumper.

São necessários componentes intermédios entre o Arduíno e os motores. Estes são frequentemente denominadas pontes
H. Estes drivers podem ser construídos a partir de vários transístores ou pode simplesmente usar um circuito integrado
ponte H. Como é iniciante, o melhor é recorrer a um chip já pronto a utilizar.

O principal objetivo das pontes H é ler e converter os sinais enviados pelo microcontrolador em tamanhos compatíveis
com o controlo do motor. Por exemplo, o Arduíno, cujos sinais podem funcionar a um máximo de 5V/20mA, após a
aplicação da ponte H, pode facilmente controlar um motor que requer 12V/1A para funcionar.

A sua primeira ponte H – L293D


No curso, vamos utilizar o chip L293D, que apesar de antigo, é barato e muito comum. A sua principal vantagem é o
facto de possuir uma montagem THT, ou seja, podemos conectá-lo diretamente à breadboard.

Este sistema possui 16 pinos. Vejamos a legenda de cada um deles:


Uma das principais informações acerca da ponte H que devem ser verificadas é seu desempenho. Especificamente, a
corrente que o motor poderá utilizar. O L293D possui uma corrente média por canal de 0,6A-1,2A. O que é que isso
significa? Significa que, idealmente, os motores podem consumir até 0.6A, mas se, por um momento, a corrente aumentar
para 1.2A, nada de mal irá acontecer. Desde que seja por um período de tempo reduzido!
Vamos agora abordar cada um dos pinos. Primeiro, os pinos de alimentação:
Terra (GND) – 4, 5, 12, 13;
Alimentação da Parte Lógica 5V (Arduíno) – 16;
Alimentação para os Motores até 36V – 8.
Lembre-se que cada ponte tem uma queda de tensão. Isso significa que, por exemplo, se fornecer uma alimentação de 9V,
o L293D gasta parte dela e, os motores recebem, no máximo, 7V. Este sistema é antigo, por isso possui uma grande queda
de tensão. Outras pontes mais recentes (por exemplo: TB6612) possuem uma queda menor.

Pinos de controlo dos motores:


o Entradas que definem a direção de rotação do 1º motor – 2, 7;
o Entradas que definem a direção de rotação do 2º motor – 10, 15;
o Entrada que define a velocidade do 1º motor – 1;
o Entrada que define a velocidade do 2º motor – 9.

Para parar ou mudar a direção de rotação do motor, deverá definir os sinais de acordo com o diagrama seguinte,
denominada tabela verdade:

Pinos dos motores:


o Saídas do 1º motor – 3, 6;
o Saídas do 2º motor – 11, 14.

Programação – Controlo da direção de rotação

Vamos agora programar, tendo por base o esquema ligado anteriormente. No início, vamos abordar o controlo da rotação
do motor. Deixaremos a regulação da velocidade para mais tarde. Como pode verificar, os pinos do Arduíno responsáveis
pelo motor são os seguintes:
o 6 (PWM) – regulação da velocidade;
o 7, 8 – Controlo do sentido de rotação.

Se não quisermos controlar a velocidade do motor, precisamos de definir o pino 6 como high. Também podíamos ligar o
cabo diretamente a 5V. No entanto, como já temos as ligações feitas, vamos usar o Arduíno:

void setup() {
pinMode(6, OUTPUT); //Sinal PWM do motor para controlo da velocidade
digitalWrite(6, HIGH); //Definir permanentemente o estado high no pino 6 - velocidade máxima

pinMode(7, OUTPUT); //Pino que controla a direção da rotação do motor


pinMode(8, OUTPUT);
}

void loop() {
//Restante programa
}

Se o sistema foi ligado corretamente, depois de fazer o upload do programa não deverá acontecer nada! Agora é hora de
adicionar o restante código à função loop.

Vamos supor que gostaríamos de rodar o motor 3 segundos num sentido e 3 segundos no sentido oposto (velocidade
máxima). Para este fim, devemos adicionar uma parte muito simples ao programa:

void setup() {
pinMode(6, OUTPUT); //Sinal PWM do motor para controlo da velocidade
digitalWrite(6, HIGH); //Definir permanentemente o estado high no pino 6 - velocidade máxima

pinMode(7, OUTPUT); //Pino que controla a direção da rotação do motor


pinMode(8, OUTPUT);
}
void loop() {
digitalWrite(7, LOW); //Rodar para a esquerda
digitalWrite(8, HIGH);
delay(3000); //Durante 3 segundos

digitalWrite(7, HIGH); //Rodar para a direita


digitalWrite(8, LOW);
delay(3000); //Durante 3 segundos
}

De acordo com a tabela verdade apresentada anteriormente, sabemos que o sistema funciona se uma das entradas tiver no
estado low “0” e a outra no estado high “1”. O sentido da rotação depende do sinal de entrada.

Depois de fazer o upload do programa para o Arduino, os dois LEDs devem começar a piscar alternadamente. Concentre-
se e entenda por que é que isso está a acontecer. Os LEDs brilham alternadamente porque, a corrente flui da saída 1 para a
saída 2, e vice-versa. O piscar é possível porque estes foram inseridos inversamente.

Programação – Controlo da velocidade

Para poder continuar, é necessário dominar os conteúdos abordados no ponto PWM, Servomecanismos e Bibliotecas.
Como pode adivinhar, basta ligar um sinal PWM ao pino ENABLE1 (circuito L293D) para controlar a velocidade do
motor!

Vamos agora escrever um programa simples, que rode os motores alternadamente, de forma mais lenta ou mais rápida.
Lembre-se que o brilho do LED apenas é visível acima de um certo limite de duty cycle do sinal PWM. O mesmo
acontece com os motores. Toda a gente terá um valor diferente.

void setup() {
pinMode(6, OUTPUT); //Sinal PWM do motor para controlo da velocidade

pinMode(7, OUTPUT); //Pino que controla a direção da rotação do motor


pinMode(8, OUTPUT);
}
void loop() {
analogWrite(6, 100); //Baixa velocidade
digitalWrite(7, LOW); //Rodar para a esquerda
digitalWrite(8, HIGH);
delay(3000); //Durante 3 segundos

analogWrite(6, 255); //Velocidade máxima


digitalWrite(7, LOW); //Rodar para a direita
digitalWrite(8, HIGH);
delay(3000); //Durante 3 segundos
}

Deve verificar que um LED muda claramente o seu brilho – mas faz isso rapidamente! Agora inserir uma mudança suave
na velocidade do motor.

Função for()

Vamos agora discutir uma função loop extremamente útil. A função for() permite executar uma determinada instrução,
um determinado número de vezes. Vamos usá-la quando, por exemplo, pretendermos que escreva 10 números naturais
consecutivos, pisque um LED 5 vezes, etc. No entanto, antes passarmos ao exemplo, vamos mostrar a sintaxe:

for (declaração de variável; condição; operação da variável) {


}

Parece complicado, mas felizmente é muito simples. Depois da palavra for, abrimos parênteses e declaramos três aspetos
muito importantes. O primeiro é a declaração da variável. Como o código vai ser executado um determinado número de
vezes, deverá ser guardado num local o número de vezes que já foi realizado.

Depois do ponto e vírgula, indicamos a condição. O loop é executado até que a condição deixe de ser verificada. Após o
ponto e vírgula seguinte, inserimos a operação a ser executada na variável durante cada ciclo. Por fim, fechamos
parênteses.

Exercício Prático – Função For()

Vamos utilizar o loop for para escrever uma saudação, 25 vezes, através de UART.

void setup() {
Serial.begin(9600); //Configuração da velocidade de transmissão

for (int i = 0; i < 25; i++) { //Executar ciclo 25 vezes


Serial.println("Bem-Vindo!"); //Escrever texto indicado numa nova linha
delay(200); //Atraso de 200ms para melhor efeito
}
}

void loop() {
}

O efeito visível no terminal deverá ser o seguinte:


Vamos agora explicar a seguinte linha do código:

for (int i = 0; i < 25; i++) { //Executar ciclo 25 vezes

O int i = 0 significa que declaramos uma nova variável local denominada “i“, do tipo int, em que o seu valor inicial é 0.
Se tiver dificuldades em perceber esta declaração, volte novamente ao artigo #3 do curso.

Neste caso, a condição é i < 25. Ou seja, enquanto a variável for menor do que 25, a instrução será repetida.

O último elemento, i++, é a soma de 1 à variável, de forma a que esta tenha registo do número de vezes que o ciclo foi
realizado. Este registo também pode ser substituído por i = i + 1.

Para facilitar a compreensão da função, veja esta versão do programa:

void setup() {
Serial.begin(9600); //Configuração da velocidade de transmissão

for (int i = 0; i < 25; i++) { //Executar ciclo 25 vezes


Serial.print("Valor da variável i: ");
Serial.print(i); //Exibir valor no monitor série
Serial.print("\n"); //Passar para uma nova linha
delay(200); //Atraso para melhor efeito
}
}
void loop() {
}

Agora pode verificar facilmente os valores que a variável (0-24) assume.

Para além desta disposição, existem outras que possuem exatamente o mesmo efeito:

for (int i = 0; i <= 24; i++) { //Executar ciclo 25 vezes

ou

for (int i = 1; i <= 25; i++) { //Executar ciclo 25 vezes

ou
for (int i = 1; i < 26; i++) { //Executar ciclo 25 vezes

ou

for (int i = 0; i < 50; i = i + 2) { //Executar ciclo 25 vezes

ou

for (int i = 25; i > 0; i--) { //Executar ciclo 25 vezes

Como pode ver, existem muitas possibilidades! Mas é claro que, a que nós utilizamos no exemplo é a mais frequente.
Agora podemos voltar à questão dos motores, isto é, à regulação suave da velocidade.

Aceleração suave do motor

Como já conhecemos o ciclo for, podemos usá-lo para acelerar suavemente o motor. É suficiente para alterar o sinal
PWM suavemente, por exemplo, a cada 25 ms.

O código é simples e a variável i é responsável pelo duty cycle do sinal PWM:

void setup() {
pinMode(6, OUTPUT); //Sinal PWM do motor para controlo da velocidade

pinMode(7, OUTPUT); //Pino que controla a direção da rotação do motor


pinMode(8, OUTPUT);

digitalWrite(7, LOW); //Rodar para a esquerda


digitalWrite(8, HIGH);
}

void loop() {
for (int i = 0; i <= 255; i++) {
analogWrite(6, i); //Aceleração suave do motor
delay(25);
}
}

Muitas vezes, os iniciantes têm problemas porque o robot não quer andar. Na maioria das vezes, verifica-se que, ou a
fonte de alimentação utilizada é muito fraca, ou o sinal PWM tem pouco duty cycle. Se algum dia tiver algum problema,
lembre-se de verificar estes dois aspetos!

Novas Funções
O Sensor de Distância Ultrassónico HC-SR04, que é muito comum nos projetos Arduíno. Também, está na hora de
começar a escrever suas próprias funções. No final, vamos apresentar um outro elemento – buzzer.

Esperamos que esta parte seja interessante para os construtores de robots e para todos aqueles que gostariam de usar um
sensor de distância nos seus projetos. Porém, antes de introduzirmos o sensor, vamos abordar novos truques de
programação, que vão tornar os seus programas ainda melhores!

Funções sem argumentos


Até agora, incluímos o nosso código nas funções setup () {} ou loop () {}. A primeira define configurações, e a segunda é
um loop infinito, realizado o tempo todo. Por exemplo, para colocarmos o LED do pino 13 a piscar, escrevemos um
programa deste género:

void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
}

void loop() {
digitalWrite(13, HIGH); //Liga o LED
delay(1000); //Espera 1 segundo
digitalWrite(13, LOW); //Desliga o LED
delay(1000); //Espera 1 segundo
}

Imagine uma situação em que o seu programa é muito extenso e quer usar este piscar como confirmação de operações
selecionadas. Vai rapidamente reparar que a repetição do código responsável por ligar/desligar o LED consome muito do
seu tempo. O que é pior é que também torna todo o programa muito mais difícil de analisar.

Ao declarar uma variável, podemos utilizá-la inúmeras vezes de uma forma muito simples. Se pudéssemos escrever
sequências de operações sob um nome fácil, os programas seriam muito mais legíveis. Quaisquer alterações que
pretendêssemos fazer, também seriam mais fáceis de realizar. As funções ajudam neste aspeto, já que podemos criá-las
nós próprios.

Vamos voltar ao exemplo anterior do LED a piscar. O fragmento de código seguinte é responsável por essa operação:

digitalWrite(13, HIGH); //Liga o LED


delay(1000); //Espera 1 segundo
digitalWrite(13, LOW); //Desliga o LED
delay(1000); //Espera 1 segundo

Podemos retirar este fragmento da função loop e criar uma função própria com ele. Como é que o fazemos? No início, à
semelhança de uma variável, é necessário declarar o tipo e o nome da função. Fazemo-lo depois da função loop () {}.

void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
}

void loop() {
}

void piscarLED() {
//Conteúdo da função
}

Como pode ver, antes do nome da função (piscarLED) vem o tipo de função. Não é nada mais do que informação acerca
da função, se envia algum valor/mensagem/etc. após o término da atividade. Se fosse esse o caso, então deveria ser
colocado o tipo apropriado de função (de acordo com os tipos de variáveis). Por exemplo, um inteiro (int), um caracter
(char), um número não inteiro (float), etc. Neste caso, o tipo de função é void. Isto significa que a função não retorna
qualquer valor/mensagem/etc. Porque é que escolhemos este tipo? O objetivo da função é piscar o LED, esta operação
não envia nenhum resultado, além do que é visível.

Após o nome da função deverá aparecer parênteses. Para já, vamos assumir que não há nada dentro deles. Depois abrimos
chavetas e colocámos o código pretendido. Fechámos chavetas e está pronto. Na prática será assim:

void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
}
void loop() {
piscarLED();
}

void piscarLED() {
digitalWrite(13, HIGH); //Liga o LED
delay(500); //Espera meio segundo
digitalWrite(13, LOW); //Desliga o LED
delay(500); //Espera meio segundo
}

Por favor, note que na função loop () {} inserimos o nome da nossa função (sem o prefixo void). Isto é intitulado
chamada de função. Faça o upload do programa e verifique se o LED da porta 13 está a pisca.
Graças a esta função, se pretendermos alterar algum aspeto no código em questão, só o precisamos de fazer uma vez e
num só sítio.

Funções com argumentos

Vamos agora descobrir novos segredos das funções. Lembra-se de uma das funções mais comuns que utilizamos na
programação com Arduíno? É, provavelmente, a mudança de estado num determinado pino, por exemplo:

digitalWrite(13, HIGH);

Em contraste com a nossa função piscarLED (); , existem dados dentro dos parênteses. Podem ser um número de pino,
um estado ou duty cycle do sinal PWM. Essas informações são usadas posteriormente na função, na execução de
determinadas operações.

Agora vamos escrever a nossa própria função, com um argumento. Vamos supor que queremos editar a função piscarLED
de tal forma que, durante a chamada, seja possível alterar a velocidade do piscar. Na declaração da função, devemos a
informação pretendida para o argumento. Fazemo-lo dentro dos parênteses da função:

//Versão original
void piscarLED(){

//Nova versão
void piscarLED(int tempo){

Na prática, a função terá este aspeto:

void piscarLED(int tempo){


digitalWrite(13, HIGH); //Ligar o LED
delay(tempo); //Esperar determinado tempo
digitalWrite(13, LOW); //Desligar o LED
delay(tempo); //Esperar determinado tempo
}

Vamos agora inserir um último elemento. Não é nada surpreendente. Simplesmente colocámos um número entre
parênteses, que vai indicar o tempo que o LED vai estar ligado e desligado. Vejamos o código:

void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
}

void loop() {
piscarLED(50);
}
void piscarLED(int tempo){
digitalWrite(13, HIGH); //Ligar o LED
delay(tempo); //Esperar determinado tempo
digitalWrite(13, LOW); //Desligar LED
delay(tempo); //Esperar determinado tempo
}

Verifique como consegue alterar a frequência do piscar, ao alterar o valor entre parênteses.

Exemplo nº2

Até agora, o LED piscava constantemente, porque fizemos a chamada da função na função loop. Se transferimos a
chamada da função para a função setup, veremos apenas um flash após o início do programa.

void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
piscarLED(50);
}

void loop() {

void piscarLED(int tempo){


digitalWrite(13, HIGH); //Ligar LED
delay(tempo); //Esperar determinado tempo
digitalWrite(13, LOW); //Desligar LED
delay(tempo); //Esperar determinado tempo
}

É hora de transformar a função de tal forma que, além de alterar o tempo que o LED pisca, também é possível influenciar
o número de piscas. Para isso, temos de alterar a declaração da função:

//Versão anterior
void piscarLED(int tempo){

//Nova versão
void piscarLED(int tempo, int quantidade){

Adicionamos o argumento “quantidade”, que será responsável pelo número de piscas. Como pode verificar, foi inserido
após a vírgula, precedido, obviamente, pelo seu tipo (int). Este parâmetro pode ser de um tipo diferente, não há qualquer
problema. O importante é que a declaração seja apropriada.

Esperamos que já saiba qual loop usar para controlar a quantidade de piscas. Se não, aconselhamo-lo a visitar o nosso
artigo #8 que aborda o assunto. No entanto, vamos presumir que já domina este conteúdo e apresentar a nova função
piscarLED:

void piscarLED(int quantidade, int tempo){


for (int i=0; i < quantidade; i++) {
digitalWrite(13, HIGH); //Ligar LED
delay(tempo); //Esperar determinado tempo
digitalWrite(13, LOW); //Desligar LED
delay(tempo); //Esperar determinado tempo
}
}

Agora vejamos o código completo:


void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
piscarLED(100, 5);
}

void loop() {
}

void piscarLED(int tempo, int quantidade){


for (int i=0; i < quantidade; i++) {
digitalWrite(13, HIGH); //Ligar o LED
delay(tempo); //Esperar determinado tempo
digitalWrite(13, LOW); //Desligar o LED
delay(tempo); //Esperar determinado tempo
}
}

Tudo deverá funcionar na perfeição. Agora, após o início do programa, o LED deve piscar exatamente 5 vezes. Mas como
é que o Arduíno sabe distinguir, das informações contidas entre parênteses, qual o tempo e qual a quantidade de piscas?
Bem, é muito simples – valores subsequentes separados por vírgulas, são atribuídos aos argumentos seguintes descritos na
declaração da função. No caso acima, o primeiro número será sempre tratado como tempo e o segundo como a quantidade
de vezes que o LED pisca.

Exercício prático – Funções com argumentos

O pino ao qual o LED está ligado é um número no código. Costumamos usá-lo em dois sítios: na declaração do pino
como saída/entrada e na definição do estado high/low. Portanto, esse número pode ser um outro argumento da nossa
função!

Material necessário:

o 1x Arduino UNO e Cabo USB;


o 1x Breadboard;
o 1x LED;
o 1x Resistência de 330Ω;
o 2x Cabos jumper.

Primeiramente, conecte o segundo LED a outro pino (exemplo: 8):

O código será o seguinte:

void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
piscarLED(100, 5, 13);
piscarLED(150, 4, 8);
}

void loop() {
}

void piscarLED(int tempo, int quantidade, int pino){


for (int i=0; i < quantidade; i++) {
digitalWrite(pin, HIGH); //Ligar o LED
delay(tempo); //Esperar determinado tempo
digitalWrite(pin, LOW); //Desligar o LED
delay(tempo); //Esperar determinado tempo
}
}

Funciona? Nem por isso, certo? Apenas o LED do pino 13 pisca. O LED do pino 8 não quer dar sinal de vida. Mas,
porquê? Bem, cometemos um erro muito simples, que é fácil de fazer ao escrever este tipo de funções. Não indicamos em
lugar nenhum que, além do pino 13, podem existir outras saídas. Verifique a função setup:

void setup() {
pinMode(13, OUTPUT); //Configuração do pino 13 como saída
piscarLED(100, 5, 13);
piscarLED(150, 4, 8);
}

Podemos corrigir este problema facilmente. Basta mover a configuração do pino para dentro da nossa função, como pode
ver abaixo:

void setup() {
piscarLED(100, 5, 13);
piscarLED(150, 4, 8);
}

void loop() {
}

void piscarLED(int tempo, int quantidade, int pino){


pinMode(pino, OUTPUT); //Configuração de saídas

for (int i=0; i < quantidade; i++) {


digitalWrite(pino, HIGH); //Ligar o LED
delay(tempo); //Esperar determinado tempo
digitalWrite(pino, LOW); //Desligar o LED
delay(tempo); //Esperar determinado tempo
}
}

Agora tudo deve funcionar como pretendido. No entanto, devemos admitir que esta não é uma solução propriamente
elegante. Portanto, não aconselhamos a utilização deste tipo de solução em projetos profissionais. Como se trata de um
projeto simples, não há qualquer problema, até nos facilita a vida.

Funções que enviam um resultado

Até aqui, apenas usamos funções que realizavam algumas operações, sem qualquer retorno de resultado. Agora vamos
introduzir uma nova função que nos envia um valor. O objetivo da função será calcular a área de um quadrado, através do
valor de um dos lados, e enviar o resultado. Para começar, é necessário declarar a função:
int area(int a) {

Como pode ver, existe a expressão int antes do nome da função. Isto significa que o resultado enviado será um número
(área do quadrado).
A função deverá ficar desta forma:

int area(int a) {
int resultado = 0;
resultado = a * a;

return resultado;
}

Deve estar a perguntar-se para onde é enviado o resultado. Vamos verificar o exemplo seguinte:

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

void loop() {
int resultado = area(4);
Serial.println(resultado); //Enviar resultado para monitor série
delay(500);
}

int area(int a) {
int resultado = 0;
resultado = a * a;

return resultado;
}

Execute o exemplo. O resultado da operação deverá aparecer no monitor série.

À semelhança do que está no exemplo acima, podemos estabelecer o envio do resultado para o monitor série de uma outra
forma:

//Versão anterior
int resultado = area(4);
Serial.println(resultado); //Enviar resultado para monitor série

//Nova versão
Serial.println(area(4)); //Enviar resultado para monitor série

A cereja no topo do bolo será enviar o valor do lado do quadrado para o Arduíno via computador. Se já não se lembra
como se faz, reveja o artigo do curso sobre comunicação via UART. O programa ficará assim:

String dadosRecebidos = ""; //Conjunto vazio de dados recebidos


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

void loop() {
if(Serial.available() > 0) { //Se o Arduino receber dados
dadosRecebidos = Serial.readStringUntil('\n'); //Ler dados e salvá-los na variável
int resultado = area(dadosRecebidos.toInt());
Serial.println(resultado); //Enviar resultado para monitor série
}
}
int area(int a) {
int resultado = 0;
resultado = a * a;

return resultado;
}

A novidade aqui é a linha:

int resultado = area(dadosRecebidos.toInt())

Como se deve lembrar, durante a comunicação UART, todos os caracteres são enviados na forma de códigos ASCII.
Assim, não podemos simplesmente enviar números para o Arduíno. Terá de haver um conversor que transforme o número
enviado como texto, num número tipo int. É exatamente isto que a linha anterior faz.

Sensor de Distância Ultrassónico HC-SR04


Vamos passar agora à parte mais desejada do artigo: a introdução do sensor de distância HC-SR04. Este sensor consiste
num transmissor, num recetor ultrassónico e em vários circuitos integrados. Graças a ele, tendo em conta a propagação e
reflexão de uma onda sonora, podemos determinar, com precisão, a distância entre o sensor e um obstáculo. De forma
semelhante à ecolocalização dos morcegos!

Mas vamos voltar ao Arduino e ao sensor de distância. Para começar, vamos concentrar-nos nos seus quatro pinos. Dois
deles são usados para alimentação (Vcc e GND) e os outros dois (trigger e echo) para realizar medições.

O Trigger é o pino que desencadeia a ação. Quando lhe atribuímos um estado high (por pelo menos 10 microssegundos),
a medição da distância começa. No entanto, é a partir do pino Echo que vamos obter a distância medida. O alcance
máximo deste sistema é 4 metros.

Exercício Prático – Medição de distância

Material necessário:

 1x Arduino UNO e cabo USB;


 1x Breadboard;
 1x Sensor de distância ultrassónico HC-SR04;
 5x Cabos jumper.
Vamos criar um sistema que mede distâncias em intervalos regulares e exibe as medições no monitor série. Para isso, é
necessário montar o sistema de acordo com o seguinte diagrama:

A descrição dos pinos do sensor está indicada no próprio diagrama. No entanto, para que não haja dúvidas, criamos uma
tabela com a ordem dos pinos e com as conexões com o Arduíno:

Também pode conferir a imagem abaixo, que mostra as nossas ligações:

Como podemos verificar na tabela, o trigger está conectado ao pino 12 e o echo ao pino 11 do Arduino. Isso deve estar
bem claro no código. Portanto, sugerimos que defina os pinos:

#define trigPin 12
#define echoPin 11

Vamos agora escrever o código que estabeleça o desencadeamento da medição da distância:

#define trigPin 12
#define echoPin 11

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída
pinMode(echoPin, INPUT); //Definição do pino 11 como entrada
}
void loop() {
digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);
//Medição feita
}

Observe a nova função delayMicroseconds (). Esta é equivalente à função delay (). A diferença é óbvia: a nova função
conta o tempo em microssegundos. A função mais comum, conta o tempo em milissegundos.

A sequência que inicia a medição é muito simples. No início, definimos o estado do pino ligado ao trigger como low.
Colocamos um atraso de dois microssegundos, que são suficientes, e definimos o estado high durante 10 microssegundos.
O sensor realiza a medição e envia os resultados através do pino echo.

A questão é como é que vamos ler esse valor? Existe UART ou outra interface de comunicação para isso? Não,
felizmente este sensor é muito simples e a distância medida é representada pelo pulso (estado high) no pino echo. O seu
tamanho é proporcional à distância, ou seja, quanto maior for o pulso, maior é a distância medida.

Medição da duração de um pulso no Arduíno

Felizmente, no Arduino existe uma função muito simples que consegue medir a duração do pulso em qualquer entrada. A
sua duração deve ser compreendida entre 10 microssegundos e 3 minutos. O início da medição ocorre quando é detetada
uma mudança de estado no pino.

A sua representação é muito simples:

int resultado = 0;
resultado = pulseIn(11, HIGH);

A função apenas aceita dois argumentos muito simples: o número do pino a ser verificado e o nível lógico (high/low) a
ser medido.

Então, para medir a distância, temos de executar a seguinte operação:

#define trigPin 12
#define echoPin 11

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída
pinMode(echoPin, INPUT); //Definição do pino 11 como entrada
}

void loop() {
long tempo;

digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

tempo = pulseIn(echoPin, HIGH);


Serial.print(tempo);
delay(500);
}

Ao executar este programa, vão aparecer números no monitor série. Quanto mais perto de um obstáculo o sensor estiver,
menor será o valor que aparece. No entanto, são impercetíveis para nós. Para que a medição seja legível, o resultado deve
ser dividido por um “número mágico”.

Verifique o funcionamento do seguinte programa.

#define trigPin 12
#define echoPin 11

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída
pinMode(echoPin, INPUT); //Definição do pino 11 como entrada
}

void loop() {
long tempo, distancia;

digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

tempo = pulseIn(echoPin, HIGH);


distancia = tempo / 58;

Serial.print(distancia);
Serial.println(" cm");

delay(500);
}

Agora, o resultado deve estar apresentado em centímetros. É claro que o número (58) pelo qual dividimos o valor não é
“mágico”. Resulta do tempo que o som viaja numa distância de 1cm e da distância padrão indicada pelo fabricante.

Função que envia a distância detetada pelo sensor em cm

int medicaoDistancia() {
long tempo, distancia;

digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

tempo = pulseIn(echoPin, HIGH);


distancia = tempo / 58;

return distancia;
}

Agora, no local certo, coloque a chamada da função:

#define trigPin 12
#define echoPin 11

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída
pinMode(echoPin, INPUT); //Definição do pino 11 como entrada
}

void loop() {
Serial.print(medicaoDistancia());
Serial.println(" cm");

delay(500);
}

int medicaoDistancia() {
long tempo, distancia;

digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

tempo = pulseIn(echoPin, HIGH);


distancia = tempo / 58;

return distancia;
}

Exercício Prático – Alarme


Neste exercício, vamos adicionar um buzzer ao nosso sistema, ou seja, um elemento sonoro. Possui o seguinte aspeto:

Este elemento possui duas entradas: VCC e GND. Quando ligamos as duas, o buzzer emite um som alto, não muito
agradável.

Material necessário:

o 1x Arduino UNO e cabo USB;


o 1x Breadboard;
o 1x Sensor de distância ultrassónico HC-SR04;
o 1x Buzzer;
o 6x Cabos jumper.

Para utilizar o buzzer, deverá fazer as ligações ao Arduíno da seguinte forma:


A imagem do buzzer utilizada no diagrama não é exatamente igual ao buzzer que indicamos acima. No entanto, isso não é
relevante, o efeito será o mesmo. O importante é fazer a ligação dos fios (VCC e GND) corretamente!

Agora vamos escrever código cujo objetivo será verificar se um objeto se encontra a uma certa distância do sensor. Se se
verificar, o buzzer irá emitir som.

Para tal, utilizamos o código anteriormente utilizado para medir a distância e acrescentamos a seguinte função:

void alcance(int a, int b) {


int limiteDistancia = medicaoDistancia();

if ((limiteDistancia > a) && (limiteDistancia < b)) {


digitalWrite(3, HIGH); //Ligar o buzzer
} else {
digitalWrite(3, LOW); //Desligar o buzzer quando objeto está fora do alcance
}
}

Como argumento da função, indicamos dois valores inteiros. De seguida, verificamos se a distância medida é maior do
que o valor inicial da nossa faixa (a) e menor que o valor máximo (b).

Nota: O símbolo && combina duas condições numa.

O programa completo terá este aspeto:


#define trigPin 12
#define echoPin 11

void setup() {
Serial.begin (9600);
pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída
pinMode(echoPin, INPUT); //Definição do pino 11 como entrada
pinMode(3, OUTPUT); //Definição do pino 3, ligado ao buzzer, como saída
}

void loop() {
alcance(10, 25); //Ligar o alarme se houver um objeto a uma distância de 10 a 25cm do sensor
delay(100);
}

int medicaoDistancia() {
long tempo, distancia;

digitalWrite(trigPin, LOW);
delayMicroseconds(2);
digitalWrite(trigPin, HIGH);
delayMicroseconds(10);
digitalWrite(trigPin, LOW);

tempo = pulseIn(echoPin, HIGH);


distancia = tempo / 58;

return distancia;
}

void alcance(int a, int b) {


int limiteDistancia = medicaoDistancia();
if ((limiteDistancia > a) && (limiteDistancia < b)) {
digitalWrite(3, HIGH); //Ligar o buzzer
} else {
digitalWrite(3, LOW); //Desligar o buzzer quando objeto está fora do alcance
}
}

Verifique como é que o programa funciona na prática. Na nossa opinião, este é um ótimo primeiro passo na criação de um
sistema de alarme.
https://www.electrofun.pt/blog/curso-arduino-3-uart-e-variaveis/

Você também pode gostar