Você está na página 1de 57

v.

Linguagem de
Programação

Prof. Rodrigo Rech


Sumário

Capítulo 01: Algoritmos, fluxogramas e lógica de programação ............. 2


Capítulo 02: Introdução à linguagem C com Arduino (Olá Mundo) .... 10
Capítulo 03: Variáveis e Operações Aritméticas ...................................... 20
Capítulo 04: Estruturas condicionais e entradas digitais ..................... 25
Capítulo 05: Estrutura condicional 2 – Comando switch ...................... 30
Capítulo 06: Entradas e Saídas Analógicas .......................................... 34
Capítulo 07: Laços de repetição ............................................................... 39
Capítulo 08: Arrays (Vetores e Matrizes) ............................................... 45
Capítulo 09: Criando Funções ................................................................. 52
Prof. Rodrigo Rech v.1

Capítulo 01: Algoritmos, fluxogramas e lógica de programação

Para quê programar?

Quando falamos sobre programação, geralmente, a primeira coisa que vem à nossa cabeça
são computadores e equipamentos relacionados à área de informática. Porém, não paramos para
observar que a maioria dos equipamentos que usamos diariamente são de alguma forma
“programados” e funcionam graças a “dispositivos programáveis” como microprocessadores,
microcontroladores, FPGAs, DSPs etc. Podemos citar como exemplos de equipamentos que se
utilizam de alguma forma de programação: máquina de lavar roupas, televisores, carros,
celulares, máquinas industriais, entre vários outros.

Em adição a isso, há de se considerar também que, dentro da área das ciências exatas, existe
uma grande demanda no uso de algoritmos e linguagens de programação para solução de
problemas numéricos, simulação de sistemas dinâmicos, métodos não convencionais para controle
de sistemas (redes neurais artificiais, por exemplo), otimização de processos industriais etc., que
nos motivam ainda mais a buscarmos compreender melhor esse importante campo de
desenvolvimento!

Mas, afinal o que é um algoritmo?

De forma simplificada, podemos definir o algoritmo como uma sequência de etapas que são
necessárias para a resolução de uma determinada tarefa ou problema. Praticamente tudo o que
fazemos em nosso dia a dia pode ser escrito na forma de algoritmo. Por exemplo, vamos pensar na
sucessão de tarefas para se fazer café:

Inicio_Algoritmo
1 – Colocar água na panela
2 – Ferver a água
3 - Acrescentar o açúcar à água
4 - Pegar o bule, o coador e a caneca
5 - Colocar o café em pó no coador
6 – Encaixar o coador no bule
7 - Despejar água fervente no bule
8 - Retirar o coador
9 - Despejar o café na caneca
10 - Beber
Fim Algoritmo

Uma vez observado o exemplo acima, podemos tirar algumas conclusões sobre a forma de
se desenvolver um algoritmo:

1. Utilizar somente 1 verbo por etapa do algoritmo;


2. Usar frases curtas e simples;
3. Ser objetivo na sequência de tarefas;

Obs: Um algoritmo é independente de qualquer tipo de linguagem de programação.

2
Prof. Rodrigo Rech v.1

Com base no que discutimos até agora, como seria, por exemplo, um algoritmo para
solucionar uma equação do segundo grau na forma 𝒂𝒙𝟐 + 𝒃𝒙 + 𝒄 = 𝟎?

Primeiramente, torna-se necessário acrescentarmos mais algumas informações ao que


discutimos até agora. Essas informações estão relacionadas àquilo que está “antes” e “após” a
sequência de etapas que vimos anteriormente, ou seja, os “dados de entrada” e os “dados de saída”
do algoritmo. Portanto, podemos dividir o algoritmo em três etapas fundamentais:

1. Entrada: dados (informações) de entrada necessários para o algoritmo;


2. Processamento: procedimentos utilizados para chegar ao resultado a partir dos dados de
entrada;
3. Saída: o resultado obtido a partir do processamento dos dados de entrada;

Assim, poderíamos usar o algoritmo a seguir para a solução da equação de forma:


𝒂𝒙𝟐 + 𝒃𝒙 + 𝒄 = 𝟎:

Inicio_Algoritmo
1 – Entrar com os valores a, b e c.
2 – Calcular Delta = b²-4.a.c
3 – Se Delta < 0
então: exibir mensagem: “não há raízes reais”
se não: exibir os valores de 𝒙𝟏 = -𝒃 + √𝑫𝒆𝒍𝒕𝒂/(𝟐. 𝒂) e 𝒙𝟐 = -𝒃 - √𝑫𝒆𝒍𝒕𝒂/(𝟐. 𝒂)
Fim Algoritmo

Uma forma alternativa de representarmos um algoritmo é o fluxograma. Para o exemplo


acima, podemos desenvolver o fluxograma de várias formas, desde uma mais completa por meio
de símbolos dedicados a cada função (Figura 1), até um fluxograma mais simplificado com foco
na resolução do problema (Figura 2).

Figura 1: Fluxograma para as raízes da equação do 2° grau (forma completa)


3
Prof. Rodrigo Rech v.1

Figura 2: Fluxograma para as raízes da equação do 2° grau (forma simplificada)

Embora a forma de representação do fluxograma seja uma escolha do desenvolvedor, deve


ficar claro que existem símbolos padronizadas e uma variedade de blocos a serem utilizados (a
Figura 3 apresenta alguns desses blocos). Porém, considerando que em nosso caso o objetivo final
não é o desenvolvimento do fluxograma, mas sim, a solução do problema, e o fato de ser comum
observarmos essa forma minimalista nas bibliografias voltadas à programação de dispositivos
eletrônicos, buscaremos representá-lo de forma simplificada a fim de focarmos na solução do
problema. A seguir observam-se os significados dos símbolos de um fluxograma.

Figura 3: Símbolos usados em fluxogramas e suas funções

4
Prof. Rodrigo Rech v.1

Erros comuns em Fluxogramas

Ao se utilizar fluxogramas como representação gráfica de um programa é necessário que


este siga um fluxo de execução semelhante ao de um processador e, por isso, não podem ocorrer
execuções de tarefas de forma paralela. Como exemplo, observe o fluxograma da figura 4.

Figura 4: Fluxograma Incorreto

A figura 4 ilustra um fluxograma que indica o recebimento de três variáveis em paralelo,


o que não pode ocorrer pois, em um processador, este processo é executado de forma sequencial,
semelhante ao mostrado na figura 1.

Lógica de Programação

Vimos, no tópico anterior, que um algoritmo é uma sequência de etapas que são necessárias
para a resolução de uma determinada tarefa. Vimos também que praticamente tudo o que fazemos
em nosso dia a dia pode ser escrito por meio de um algoritmo, desde que observemos o problema ou
atividade a ser executada de forma a encontrarmos a sequência correta de ações a serem
desenvolvidas para alcançarmos o objetivo. É justamente nesse ponto que nos deparamos com a
lógica de programação.

A palavra lógica faz parte do nosso vocabulário cotidiano, especialmente quando nos
deparamos com a necessidade de solucionarmos um problema. Sua origem é atribuída a Aristóteles
(discípulo de Platão que viveu na cidade grega de Atenas aproximadamente três séculos antes de
Cristo), que a definia, em poucas palavras, como a “ciência que descreve as leis que regem o
pensamento objetivando descobrir algo de novo sem possibilidade de erro”(dado que em seu conceito
somente a verdade absoluta é aceita).

Sendo assim, podemos então pensar que a lógica de programação é o “modo pelo qual, a
partir das ferramentas disponíveis para a realização de uma tarefa, estabelecemos a sequência de
etapas necessárias para a sua resolução”. Portanto, podemos inferir que é algo abstrato e
individual, afinal, podemos chegar a um mesmo objetivo por meio de variados caminhos.
Consequentemente, a lógica de programação não é algo a ser “aprendido” de fato, mas sim, a ser
estimulado por meio da resolução de tarefas “lógicas”. Existem inúmeras ferramentas que têm
como objetivo de estimular o desenvolvimento de lógica de programação. Dentre elas, o aplicativo
Light-bot apresenta, em forma de um jogo, uma ótima maneira de estimular o desenvolvimento
de pequenos algoritmos para solucionar determinadas tarefas (figura 5).

5
Prof. Rodrigo Rech v.1

Figura 5: Interface do aplicativo Light-bot

O objetivo do aplicativo é a construção de algoritmos – por meio dos comandos no canto


superior direito (Figura 6) – que permitam o robô iluminar os ladrilhos azuis da fábrica referentes
a cada etapa.

Figura 6: Em destaque a barra de comandos disponíveis para a solução dos problemas

Esses comandos são implementados: clicando sobre eles, arrastando-os e encaixando-os nas
lacunas. Você deve encaixá-los nos espaços já na sequência correta pensada para a locomoção do
robô. Caso não seja feito assim, o robô irá desenvolver uma trajetória aleatória (que estará
relacionada ao que você preencheu). A etapa referente à “iluminação dos ladrilhos” deve ser
executada por meio do comando representado por uma lâmpada.

Tomemos o exemplo da primeira fase. Nessa etapa, partindo-se do ponto inicial, é necessário
que o robô realize dois passos à frente e, posteriormente, “acenda o ladrilho azul”. A sequência de
comandos necessários para a conclusão dessa etapa pode observada na Figura 7.

6
Prof. Rodrigo Rech v.1

Figura 7: Sequência dos comandos implementada

Após a finalização do preenchimento das lacunas deve-se pressionar o botão “Go!”. O


resultado ao final da movimentação pode ser observado na Figura 8.

Figura 8: Objetivo alcançado com sucesso!

7
Prof. Rodrigo Rech v.1

Instruções para a execução do light-bot:

Modo online:

Acesse o link https://www.minijogos.com.br/jogo/light-bot e siga os passos da imagem a


seguir para iniciar o jogo.

Link alternativo: https://www.gameflare.com/online-game/light-bot/

Aplicativos mobile:

Pesquise pelo aplicativo “Lightbot: Hour of Code” na loja do Android ou IOS para a versão
gratuita ou simplesmente “Lightbot” para a versão paga.

8
Prof. Rodrigo Rech v.1

Exercícios:

1. Descreva com detalhes a sequência lógica para trocar um pneu de um carro;

2. Identifique os dados de entrada, processamento e saída no algoritmo abaixo:

• Receba código da peça;


• Receba valor da peça;
• Receba Quantidade de peças;
• Calcule o valor total da peça (Quantidade * Valor da peça);
• Mostre o código da peça e seu valor total.

3. Construa um fluxograma que:

• Receba duas notas;


• Calcule a média entre elas;
• Apresente o texto “Aluno aprovado” se a média for maior ou igual a 6;
• Apresente o texto “Aluno em recuperação” se a média for maior ou igual a 4 e menor do
que 6;
• Apresente o texto “Aluno reprovado” se a média for menor do que 4.

4. Acrescente, no exercício 5 (Aprovado ou reprovado), a comparação do número de faltas. Caso

o aluno ultrapasse 25 faltas fica reprovado independente da sua nota.


5. Tente resolver as tarefas de algumas fases do aplicativo “lightbot”.

9
Prof. Rodrigo Rech v.1

Capítulo 02: Introdução à linguagem C com Arduino (Olá Mundo)

As ferramentas que vimos até agora (algoritmo e fluxograma) buscam auxiliar a resolução
de alguma situação-problema na qual iremos aplicar uma determinada linguagem de
programação para programar o dispositivo responsável por controlar o processo. Mas, o que vem a
ser uma linguagem de programação?

Para definirmos linguagem de programação, antes vamos falar sobre o que é um programa
de computador, que nada mais é do que uma “sequência de comandos enviados ao processador
para a realização de uma determinada tarefa”. Assim, de forma resumida, podemos falar que a
Linguagem de Programação é uma ferramenta computacional que se utiliza de palavras ou
símbolos padronizados que nos possibilitam a escrita de um programa de computador para
implementação de um determinado algoritmo.

Embora em nosso curso utilizaremos somente a linguagem de programação denominada


“C”, existem diversas outras linguagens de programação disponíveis e, em princípio, podemos
escolher qualquer uma delas na hora de implementarmos um algoritmo. Elas podem ser
classificadas como:

• Não estruturada (linear): nessa concepção não temos a organização do programa em “blocos de
instruções” e, sendo assim, os comandos de decisão são baseados em “desvios”, condicionais ou
incondicionais. São exemplos: Assembly, Basic, Cobol etc.;

• Estruturada: tem como objetivo deixar o código mais intuitivo, utilizando blocos estruturados.
Deste modo, torna-se mais fácil entender a sintaxe (regras que regem a composição de textos com
significados em uma linguagem de programação) e o fluxo do programa. Na linguagem
estruturada, o comando “ir para” costuma ser usado somente em casos específicos e deve sempre
que possível ser evitado, pois é considerado um comando de desestruturação. São exemplos de
linguagem estruturada: C, Clipper, Pascal, etc.;

• Orientada a objeto: é baseado na composição e interação entre diversas unidades chamadas


“objetos”. São exemplos: C++, Visual Basic, Visual C#, Java etc.;

Linguagem C

Foi desenvolvida nos anos 1970 por Dennis M. Ritchie e Ken Thompson nos laboratórios
da BELLTelephone e, como dito anteriormente, é da categoria “estruturada”, significando que seu
código pode ser separado em sub-rotinas que podem ser reutilizadas em toda a programação,
deixando o código mais enxuto e simples de se efetuar manutenção.

10
Prof. Rodrigo Rech v.1

A linguagem C possui características que possibilitam maior facilidade na interpretação


dos comandos do que linguagens de baixo nível (categorização atribuída a linguagens mais
próximas ao código binário ou linguagem de máquina). Ou seja, é considerada de “alto nível” em
relação a outras que surgiram antes de seu desenvolvimento como a linguagem Assembly, criada
em meados dos anos 1950 e considerada baixo nível. Contudo, outras linguagens de programação
possuem “nível mais alto” em relação à linguagem C, ou seja, são ainda mais fáceis de serem
interpretadas. São exemplos: Basic, Pascal, entre outras.

Já linguagem C++ é derivada da linguagem C e foi desenvolvida na década de 1980 por


Bjarne Stroustrup, também nos laboratórios BELL, como um adicional à linguagem C. Sendo
assim, todas as instruções contidas na linguagem C também fazem parte da linguagem C++.
Entretanto, essa última possui vários diferenciais, dentre eles, a possibilidade de criação e
manipulação de objetos, dentre vários outros recursos implementados ao longo das décadas
seguintes durante suas revisões.

Compiladores, IDE’s e editores de texto

Para os exemplos apresentados durante nosso curso utilizaremos o IDE Arduino. Uma IDE
(Integrated Development Environment ou Ambiente Integrado de Desenvolvimento) é um
programa computacional que fornece diversas ferramentas para o desenvolvedor em um único
ambiente, tais como: compilador, depurador (debugger) e editor de texto.

Um compilador é programa computacional capaz de converter a linguagem de programação


utilizada (em nosso caso, a linguagem C) em linguagem de máquina (código binário) por meio
de um arquivo .exe, por exemplo, para posterior execução. Ou seja, com o auxílio dessa ferramenta
podemos programar em “alto nível” que, posteriormente, o compilador executa a tarefa de “traduzir”
o código desenvolvido para linguagem de máquina. Uma ressalva que se faz é que, para o caso de
algumas outras linguagens como o Python, por exemplo, ao invés de um compilador se usa um
“interpretador”, que ao invés de transformar todo o código para somente depois executá-lo, realiza
a execução linha a linha do programa. Para que um compilador funcione corretamente são
necessárias algumas extensões específicas de arquivos:

Extensão Função
.c Código fonte do programa. No Arduino a principal extensão utilizada é a .ino
.h Arquivo “header”, utilizado para armazenar os cabeçalhos das bibliotecas
Arquivo compilado e pronto para ser executado. No Arduino e outros sistemas embarcados
.exe
essa extensão é a .hex

Já o depurador ou debugger é um programa usado para testar e fazer a depuração de outro


programa. Ou seja, uma de suas principais funções é facilitar a localização de erros e observação
do comportamento do programa. Alguns depuradores podem oferecer funções mais sofisticadas
como: execução linha a linha de um determinado programa, paralização da execução para
observação do estado atual por meio de breakpoints (pontos de parada), acompanhamento do valor
de variáveis etc.

11
Prof. Rodrigo Rech v.1

Por fim, o editor de texto é a ferramenta que nos permite digitar e editar texto sem
formatação (de forma análoga ao bloco de notas do Windows) e que também está incorporado ao
IDE. Assim como no caso do debugger, no caso no editor de texto algumas funções mais avançadas
podem estar incorporadas, tais como: verificação de sintaxe durante a escrita do código, gerando
sinalizações instantâneas na ocorrência de erros de digitação para variáveis ou determinados
comandos básicos ou mais utilizados.

Conceitos básicos de linguagem C

Um programa escrito em linguagem C possui uma estrutura básica constituída por:

1. Inclusão de arquivos externos: funções externas ao programa, por exemplo, a biblioteca stdio.h;
2. Declaração de variáveis globais: variáveis que podem ser utilizadas em qualquer trecho do
programa;
3. Declaração de protótipos de funções: funções criadas pelo próprio programador;
4. Função principal (main): determina o ponto onde o programa começa a ser executado;
5. Funções: criadas pelo programador no decorrer do código.

Vamos observar um exemplo para essa estrutura básica a seguir.

1 /*Inclusão dos arquivos externos:*/


2 #include <stdio.h>
3 #include <stdlib.h>
4 /*Função principal:*/
5 void main()
6 {
7 /*Função utilizada para escrever um texto na tela
8 Retirada da biblioteca “stdio.h” declarada no
9 início da programação.*/
10 printf("Este é um programa em linguagem C...");
11 }

Um ponto importante de ser observado é a presença de /* no início e */ no final de todos os


comentários digitados no programa. Os comentários são de extrema relevância para que façamos
observações pertinentes às funções ou ao programa, a fim de registrá-las para posterior consulta.
Uma vez digitado um texto com /* no início e */ no final de sua digitação, não ocorre interferência
deste na compilação do código. Ou seja, por meio destes dois delimitadores, podemos escrever várias
linhas de comentários. Caso deseje escrever um comentário de somente 1 linha, pode ser empregado
// antes de seu início, tendo o mesmo efeito do anterior.

12
Prof. Rodrigo Rech v.1

O Arduino

A plataforma “Arduino” foi desenvolvida com o intuito de tornar ferramentas eletrônicas


mais acessíveis e fáceis de se trabalhar, tanto por profissionais quanto por leigos. Consiste em
hardware e software livres, isto é, podem ser utilizados sem nenhuma restrição em qualquer projeto.
Sua programação é oriunda da Linguagem Wiring, que basicamente é C/C++.

Figura 1: Arduino Uno Figura 2: Shields para Arduino

Existem várias placas Arduino, porém, o Arduino Uno (Figura 1) é o mais comum. E para
o desenvolvimento de projetos com Arduino são utilizados os Shields (Figura 2), que são placas
eletrônicas com finalidades diversas (Displays, acionamento de motores, comunicação sem fio,
etc.).

O software programação é chamado de Arduino IDE, e seu download pode ser realizado no
site oficial do Arduino: https://www.arduino.cc/en/Main/Software. Para iniciar a programação é
importante conhecer como funciona o programa.

12

Figura 3: Arduino IDE

13
Prof. Rodrigo Rech v.1

1. Botão “Compilar”: Verifica os erros de sintaxe do código;


2. Botão “Carregar”: Grava o programa na placa Arduino;
3. Função “Setup”: Trecho do código que será executado uma única vez. Utilizado para
configurações iniciais;
4. Função “loop”: Trecho do código que ficará sendo repetido.

Configuração da placa

• Para configurar o modelo da placa que


será utilizada, deve ser usado o menu
“Ferramentas -> Placa:” e selecionar
“Arduino/Genuino Uno”.

• Depois, é necessário escolher em qual


porta USB está conectada. Para isso, o
menu “Ferramentas -> Porta”.

Figura 4: Configuração da Placa

Para inserir uma biblioteca nova deve ser utilizado o menu “Ferramentas -> Gerenciar
Bibliotecas” (Figura 5). Caso ocorra algum problema para carregar uma biblioteca por meio deste
menu, é possível copiar a pasta da biblioteca (Deve ser feito o download previamente) no caminho:
Sketch-> Incluir Biblioteca -> Adicionar Biblioteca .ZIP. Como teste, faça o download da
biblioteca “ArduinoSTL” pelo gerenciador de bibliotecas.

14
Prof. Rodrigo Rech v.1

Figura 5: Gerenciador de Bibliotecas

15
Prof. Rodrigo Rech v.1

Caso não seja possível realizar o download por causa de limitações da internet, baixe o
arquivo pelo seguinte caminho e faça a instalação da forma manual:

https://sites.google.com/view/rodrigorechifsp/lipj5 -> Programas -> ArduinoSTL-1.1.0.zip

Primeiro Exemplo: “Olá Mundo”

Para este primeiro exemplo, copie o código abaixo no Arduino IDE, compile e grave no
Arduino. Para verificar seu funcionamento, abra o menu “Ferramentas->Monitor Serial”.
Obs: A linguagem C é sensível ao tamanho do caractere, se maiúsculo ou minúsculo. Esta
característica se chama “case sensitive”. Por isso, preste atenção na hora de digitar os comandos,
pois poderá ocorrer erros de compilação.

#include <ArduinoSTL.h>

void setup() {
Serial.begin(9600);
}
void loop() {
Serial.print("Olá Mundo\n");
}

Analisando o código:

#include <ArduinoSTL.h>
O comando “#include” é chamado de diretiva do compilador, isto é, esta linha avisa para o
compilador incluir naquele código uma biblioteca externa. Neste caso, a biblioteca é a
“ArduinoSTL”. Ela é responsável por permitir o uso de funções padrões da linguagem C Console
no Arduino, como a função printf e a função scanf. Funções básicas do Arduino, como a
“Serial.begin” e outras não necessitam de uma biblioteca externa. As funções básicas podem ser
acessadas neste link: https://www.arduino.cc/reference/en/.

void setup() {
Serial.begin(9600);
}
Aqui, as palavras “void setup ( )” criam uma função. Neste caso, os comandos inseridos
entre as chaves ({ e }) serão executados uma única vez pelo Arduino e, ao seu término, a função
loop começa a ser executada. Já a função “Serial.begin (9600);” é utilizada para configurar a
comunicação USB entre o Arduino e o Computador. Todos os comandos que são inseridos dentro
de uma função devem, obrigatoriamente, serem finalizados com um ponto e vírgula (;).

void loop() {
Serial.print("Olá Mundo\n");
}
Novamente as palavras “void loop ( )” criam uma função, porém, desta vez, os comandos
inseridos entre as chaves dela serão repetidos infinitas vezes ou, até o Arduino ser desligado. A
função “Serial.print(“Texto”)” envia para o computador o texto escrito dentro dos parênteses e aspas.

16
Prof. Rodrigo Rech v.1

Este texto é denominado “String”. Para ver este texto no computador deve ser utilizado o Monitor
Serial do Arduino IDE (Figura 6).

Figura 6: Monitor serial

Note que, no exemplo do código do Arduino, a estrutura básica da linguagem C está diferente da
apresentada no início desta aula. Isso se dá pelo fato de o Arduino abstrair funções para facilitar a
programação. As duas funções que programamos: a setup e a loop, na verdade estão dentro de uma função
“main”, mas que não é visível para o programador. De forma resumida, a função main do Arduino pode ser
apresentada da seguinte forma:

1 /*Inclusão dos arquivos externos:*/


2 #include <Arduino.h>
3
4 /*Função principal:*/
5 void main()
6 {
7 setup();
8 for( ; ; ){
9 loop();
10 }
11 }

Segundo Exemplo: Acionando saídas digitais e temporização

Por se tratar de um computador de baixa performance, o Arduino é muito utilizado para


projetos simples de automação, onde é necessário realizar o acionamento de cargas. Para o primeiro
exemplo de acionamento de cargas será utilizado um LED.

Para acionar um LED é necessário que exista uma tensão entre seus pinos, Anodo e Catodo
(Figura 7). No Anodo deve ser inserido o potencial mais positivo, enquanto no catodo, o mais
negativo. Os pinos do Arduino podem fornecer dois níveis de tensão (0V ou GND e 5V). A tensão
5V também é definida como nível lógico alto (HIGH ou ‘1’), enquanto 0V pode ser definido como
nível lógico baixo (LOW ou ‘0’). Analisando o esquema eletrônico do shield utilizado (Figura 8)
é possível observar que os leds estão com os catodos ligados diretamente ao 0V (GND), enquanto

17
Prof. Rodrigo Rech v.1

os anodos estão nos pinos do Arduino (D0 à D7). Logo, para acionar um LED é necessário enviar
um nível lógico alto (HIGH) para o pino anodo.

Figura 7: Light Emitter Diode (LED) Figura 8: Ligação dos leds no Shield

Copie o código abaixo no Arduino IDE, envie para o Arduino e observe o comportamento dos
LEDs na placa:

void setup() {
Serial.begin(9600); //Configura a comunicação entre o Arduino e o Computador
pinMode(2,OUTPUT); //Configura o pino D2 como saída
pinMode(3,OUTPUT); //Configura o pino D3 como saída
}

void loop() {
Serial.print("Olá Mundo\n"); //Envia uma string para o computador
digitalWrite(2,HIGH); //Aciona o pino D2 com nível baixo (0)
digitalWrite(3,LOW); //Aciona o pino D3 com nível alto (1)
delay(500); //Aguarda um tempo de 500ms
digitalWrite(2,LOW); //Aciona o pino D2 com nível alto (1)
digitalWrite(3,HIGH); //Aciona o pino D3 com nível baixo (0)
delay(500); //Aguarda um tempo de 500ms
}

Analisando o código:

Na função “setup” foi incluída a função “pinMode( )”, ela é utilizada para configurar o
pino do Arduino como entrada de sinal ou saída de sinal. Basicamente um pino de entrada recebe
um sinal de um elemento externo, que pode ser um botão, sensor, etc. Já um pino configurado como
saída tem a capacidade de mudar seu nível lógico e fornecer corrente elétrica para algum
componente, neste caso, um LED. A sintaxe da função pinMode é:

pinMode(número do pino, funcionamento).

18
Prof. Rodrigo Rech v.1

Na função loop foram adicionadas três novas funções:

Serial.print("Olá Mundo\n");

Tem a mesma finalidade da função printf(), porém, não tem a necessidade de se incluir
uma biblioteca específica para seu funcionamento.

digitalWrite(3,LOW);

Tem a função de alterar o nível lógico de um pino definido como saída anteriormente. Sua
sintaxe é:

digitalWrite(número do pino, nível lógico)

delay(500);

Gera um atraso no código de acordo com o valor inserido nos parênteses. Este tempo é dado
em milissegundos e só são aceitos números inteiros.

Traduzindo este código para um fluxograma, fica da seguinte forma:

Exercícios:

1. Utilizando os 4 últimos leds ligados na placa, desenvolva um deslocador de bits. A cada 0,5
segundos o led atual apaga e acende o próximo. Ao apagar o último LED, aparece a frase
“Recomeçando...” no monitor serial e o ciclo começa novamente.

2. Ainda no programa do exercício anterior, ao finalizar o ciclo, o LED D3 deve piscar 3 vezes com
intervalos de 200ms, recomeçando o ciclo após o término.

19
Prof. Rodrigo Rech v.1

Capítulo 03: Variáveis e Operações Aritméticas

Tipos de dados

Entende-se por variáveis em linguagem de programação, o espaço reservado na memória


para que o programador possa armazenar informações, as modificando quando necessário.
Diferente de um computador padrão PC, um microcontrolador possui uma quantidade de memória
de dados muito inferior, na ordem de poucos kilobytes. Por exemplo: uma variável do tipo float
ocupa na memória um total de 4 bytes (32 bits), para um computador que possui 4GB de RAM,
este valor não representa problema algum, porém, para um microcontrolador que possua 128 bytes
de RAM, já é significativo.

Assim como na linguagem C ANSI, o Arduino também trabalha com tipos de dados de
diferentes tamanhos, utilizando o mesmo padrão (byte, char, int, float). Além dos tipos de
variáveis, existem também os modificadores de tipo, que alteram a forma na qual o compilador
enxerga aquela variável (signed, unsigned, long, short), e os modificadores de acesso, que
determinam de qual forma o compilador pode acessar determinada variável (const, volatile).
Alguns tipos de tamanhos e modificadores estão listados na tabela 1.

Tipo Tamanho Faixa


byte 8 bits (1 byte) 0 a 255
char, signed char, unsigned char 8 bits (1 byte) -128 a +127, -128 a +127, 0 a 255
int, signed int, unsigned int 16 bits (2 bytes) -32768 a 32767, -32768 a 32767, 0 a 65535
Ponto flutuante (números reais) com até seis dígitos de
float 32 bits (4 bytes)
precisão
long int, unsigned long int 32 bits (4 bytes) -2.147.483.648 a 2.147.483.647, 0 a 4.294.967.295
Tabela 1: Tipos e modificadores de variáveis

O modificador const declara uma constante, isto é, uma variável que não pode ser
modificada durante a execução do programa. Já o modificador volatile indica ao compilador que a
variável pode ser modificada de forma não explícita, ou seja, o compilador pode alterar a variável
para otimizações de código.

Para mais informações ou para verificar outros tipos de variáveis e modificadores aceitos
pelo Arduino, acesse: https://www.arduino.cc/reference/en/#variables.

Declaração de variáveis

Para reservar um espaço de memória é necessário fazer a declaração de variável. Este é o


momento no qual são indicados os tamanhos e os nomes das variáveis. Sintaxe:

int variavel_1; //Cria uma variável de 16 bits


unsigned char variavel_2; //Cria uma variável positiva de 8 bits
long int variavel_3; //Cria uma variável positiva de 32 bits
float var_4, var_5; //Cria duas variáveis de 32 bits

20
Prof. Rodrigo Rech v.1

Escopo das variáveis

O escopo define quais as funções do programa enxergam a variável. No caso do Arduino,


na maioria das vezes as variáveis terão um escopo chamado global, no qual ela poderá ser lida e
modificada por qualquer função do programa. É possível, também, definir variáveis que poderão
ser alteradas somente pela função onde foi criada, neste caso a variável terá um escopo chamado
de local.

Exemplo:

int var_global = 0; //Esta variável pode ser acessada por qualquer função do programa

void setup() {
char var_local = 0; //Esta variável funciona apenas na função "setup()"

void loop() {
float var_local = 0; //Esta variável funciona apenas na função "loop()"

Observe que o nome escolhido para as variáveis locais é o mesmo, o que não acarreta em
nenhum problema, já que estão declaradas em funções diferentes. Este mesmo nome não poderia
ser utilizado em uma variável global, pois o compilador define, como preferência, as variáveis
locais.

Operações aritméticas

Os operadores aritméticos básicos já são nativos da linguagem C, logo, não é necessário


utilizar uma biblioteca externa para incluí-los ao programa. Outras funções, como raiz quadrada,
funções trigonométricas, entre outras, estão alocadas na biblioteca math.h. No caso do Arduino,
estas funções mais complexas já estão incorporadas na IDE, então não é necessário incluir a
biblioteca math. As operações básicas estão listadas na tabela 2.

Operador Ação
Atribuição de valor em uma
=
variável
- Subtração
+ Adição
* Multiplicação
/ Divisão
% Módulo da divisão (resto)
-- Decremento
++ Incremento
Tabela 2: Operadores aritméticos

Para verificar todas as funções matemáticas disponíveis no Arduino, consulte:


https://www.arduino.cc/reference/en/.

21
Prof. Rodrigo Rech v.1

Programa de exemplo:

Para o programa de exemplo, iremos trabalhar com as funções scanf( ) e printf( ) para
capturar os valores pela comunicação serial e enviar os resultados para a tela do computador. Para
isso, não esqueça de instalar e incluir a biblioteca ArduinoSTL.h no programa.

Código fonte:
#include <ArduinoSTL.h>

//Declaração as variáveis globais


unsigned int num_1, num_2, num_3;

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

void loop() {
printf("Digite um número inteiro:\n");
scanf("%d", &num_1); //Recebe um número inteiro e armazena na variável num_1
printf("Digite outro número inteiro:\n");
scanf("%d", &num_2); //Recebe um número inteiro e armazena na variável num_2

num_3 = num_1 + num_2; //Realiza a soma e armazena o resultado em num_3

//Apresenta o resultado da soma


printf("%d + %d = %d \n",num_1, num_2, num_3);
//Apresenta o resultado da multiplicação
printf("%d x %d = %d \n", num_1, num_2, (num_1*num_2));
//Apresenta o resultado da divisão
printf("%d / %d = %d \n", num_1, num_2, (num_1/num_2));
//Apresenta o resto da divisão
printf("O resto da divisão é %d \n", (num_1 % num_2));

/* Apresenta o resultado da exponenciação


* Como a função printf do arduino não aceita variáveis do tipo float
* Usaremos a função Serial.println */
printf("O número 1 elevado ao quadrado é : ");
Serial.println(pow(num_1, 2), 1);
}

22
Prof. Rodrigo Rech v.1

Considere os fluxogramas das figuras 1 e 2 para analisar o programa.

Loop

1 2
Setup

Receber o primeiro Apresentar


número multiplicação
Cria as variáveis
globais: num_1,
num_2 e num_3
Receber o segundo
Apresentar divisão
número

Configura
comunicação Serial Somar número 1 e Apresentar o resto
número 2 da divisão

Apresentar o
FIM Apresentar
resultado da
resultado da soma
exponenciação

Figura 1: Fluxograma da função setup


2 1

Figura 2: Fluxograma da função loop

Neste programa foi utilizada a função scanf( ) para capturar os valores digitados no
computador. Sua sintaxe é:

scanf(formato da variável, &variável);

O formato da variável indica para a função qual o tipo da variável que está sendo lida. Na
biblioteca ArduinoSTL são aceitos apenas os formatos “%d”, que se refere a um número inteiro, e
“%c”, que se refere a um caractere. O & indica para a função o endereço em que se encontra a
variável, para que o valor lido seja armazenado nele.

Além do scanf, também foi utilizado o caractere especial “\n”. Ele é chamado de caractere
de controle. No caso dele, sua função é de pular uma linha. Na tabela 3 segue a descrição de alguns
caracteres de controle:

Caractere Ação
\b Retrocesso (“back”);
\t Tabulação horizontal (“tab”);
\” Aspas dupla;
\? Aspas simples;
\0 Nulo (0 em decimal) –Terminador;
\\ Barra invertida;
\v Tabulação vertical;
Tabela 3: Caracteres de controle

23
Prof. Rodrigo Rech v.1

Também foi utilizada neste programa a função Serial.println( ) para enviar um valor para
o computador e pular uma linha na sequência. Sua sintaxe é:

Serial.println(Variável ou texto que se deseja imprimir, formato ou número de casas decimais);

Esta é uma função nativa do Arduino e não é necessária a inclusão de bibliotecas para sua
utilização. A grande vantagem é que podem ser impressas variáveis de qualquer tipo,
diferentemente da função printf da biblioteca ArduinoSTL. É importante notar que, para se enviar
um texto, é necessário que ele esteja entre aspas dupla, por exemplo:

Serial.println(“Texto que será enviado.”);

No caso de uma variável não é necessário utilizar as aspas dupla, mas é importante
informar o número de casas decimais que se deseja visualizar ou então o formato, se decimal,
binário, hexadecimal, etc.

Para mais informações sobre esta função, acesse:

https://www.arduino.cc/reference/en/language/functions/communication/serial/println/

Exercícios:

1. Desenvolva um programa que receba três números inteiros e apresente na tela o resultado das
seguintes equações: Obs: Para imprimir o número utilize a função Serial.println( ).

𝒏𝟏 + 𝒏𝟐
𝒙= 𝒙 = 𝒏𝟏𝟐 ∗ 𝒏𝟑 𝒙 = (𝒏𝟏 + 𝒏𝟐)𝟐
𝒏𝟑
2. Elabore um programa que receba 4 números inteiros e apresente sua média aritmética;

3. Crie um programa que receba um valor de temperatura em Celsius e converta para Kelvin e
Fahrenheit;

4. Crie um programa que, a partir de um número digitado pelo usuário, apareça na tela este número
sendo incrementado a cada 500ms infinitamente.

5. Elabore um programa onde seja digitado um número em decimal e ele seja apresentado na tela em:
hexadecimal, octal e binário;

6. Desenvolva um programa que apresente na tela os caracteres da tabela ASCII da posição 33 até a
126. Para isso utilize a função Serial.write( ):

https://www.arduino.cc/reference/en/language/functions/communication/serial/

24
Prof. Rodrigo Rech v.1

Capítulo 04: Estruturas condicionais e entradas digitais

É comum, em qualquer algoritmo ou linguagem de programação, realizar uma ação que


depende de uma determinada condição ocorrida previamente. Para isso são utilizadas as
estruturas condicionais. Com elas, é possível executar um trecho de código caso uma condição
tenha ou não sido atendida. O fluxograma apresentado na figura 1 ilustra seu funcionamento.

Figura 1: Fluxograma de uma estrutura condicional

A condição que realiza o controle de fluxo pode assumir apenas dois valores: verdadeiro ou
falso. Na linguagem C ANSI estes valores também podem ser considerados 0 (zero) para falso e
qualquer coisa diferente de zero para verdadeiro. No Arduino também são aceitas as constantes
“true” ou “false”.

Além dos valores e constantes utilizados para definir o controle do fluxo, também é comum
a utilização de operadores relacionais e lógicos para realização de comparações com variáveis. Eles
estão apresentados na figura 2.

Operadores relacionais
Operador Ação
> Maior que
>= Maior que ou igual
< Menor que
<= Menor que ou igual
== Igual
!= Diferente
Operadores lógicos
Operador Ação
&& AND
|| OR
! NOT
Figura 2: Operadores relacionais e lógicos

25
Prof. Rodrigo Rech v.1

Comandos if( ) e else

Traduzindo de forma literal, estes comandos são os “se( )” e o “senão”. O comando “if”
executa um bloco de código caso a condição inserida nele seja verdadeira. Caso a condição seja
falsa, o bloco executado será o “else”.

if(condição) //Se a condição for verdadeira, executa...


{
//Trecho do código que será executado caso a condição seja verdadeira
}

else //Caso seja falsa, executa o else...


{
//Trecho do código que será executado caso a condição seja falsa
}

Uma condição dita como verdadeira em linguagem C pode ser dada de duas formas:

1. Por meio do resultado de uma operação relacional. Por exemplo:

• Se (5 > 3); neste caso o número 5 é maior do que 3, logo, a condição é verdadeira!
• Se (‘a’ == ‘b’); agora é fácil de observar que as letras são diferentes, logo, a condição é
falsa!

2. Ou caso o valor colocado no comando for diferente de 0:

• Se (10); aqui a condição é verdadeira, pois o valor utilizado no comando é diferente de 0!


• Se (0); agora a condição é falsa, pois o valor é igual a 0!

Utilizando as entradas digitais

Assim como as saídas digitais, no Arduino também é possível realizar a leitura de valores
de elementos externos a ele. Quando os valores lidos possuem apenas dois estados lógicos, tais
como: 0 ou 1, 0V ou 5V, falso ou verdadeiro, estes são ditos como digitais. Quando um valor lido
assume três ou mais níveis diferentes, consideramos este como analógico.

Elementos ditos como digitais em eletrônica podem ser, entre outros, botões e alguns tipos
de sensores. O funcionamento de um botão juntamente com um microcontrolador pode ser de
diversas formas, as mais comuns são apresentadas na figura 3.

Neste caso, a posição da chave Neste caso, o resistor mantém o


Aqui o resistor mantém o nível alto
define o nível lógico no pino do nível baixo no pino do
no pino do microcontrolador até que
microcontrolador. microcontrolador até que o botão seja
o botão seja pressionado.
pressionado.

26
Prof. Rodrigo Rech v.1

Figura 3: Esquemas de ligações de chaves em entradas digitais

No Arduino, para realizar a leitura de um botão é necessário utilizar as estruturas


condicionais, além de definir os pinos como entrada.

Na placa que estamos utilizando os botões estão ligados como demonstra na figura 4.

Figura 4: Esquema de ligação dos botões

É fácil notar que os botões estão ligados no esquema de pull-up, isto é, enquanto o botão
estiver solto teremos nível alto (1) nos pinos do Arduino. Ao pressioná-los, os pinos ficarão com
nível baixo (0).

Programa de Exemplo:

Para o programa de exemplo, considere os fluxogramas da figura 5.

Setup Loop 2

1
Botões 1 e 2
Declara a variável pressionados
globla contador SIM
simultâneamente
?
Botão 1 foi
NÃO SIM
pressionado? Envia o texto:
Lógica AND
Configura a NÃO
Envia o texto:
comunicação serial Envia o texto:
Botão 1
Botão 1 solto
pressionado

Configura os pinos Acende o LED;


A1 e A2 como Incrementa a
entradas variável contador
Apaga o LED Atraso de 300ms
Apresenta o valor
de contador na
tela

Configura o pino 10
como saída 2 1

Fim

Figura 5: Fluxograma de funcionamento do exemplo 1

27
Prof. Rodrigo Rech v.1

Código Fonte:

unsigned int contador=0;

void setup()
{
//Inicia a comunicação serial
Serial.begin(9600);
//Define os pinos de entrada
pinMode(A2, INPUT_PULLUP);
pinMode(A3, INPUT_PULLUP);
//Define os pinos de saída
pinMode(7, OUTPUT);
}

void loop()
{
//Se o botão S1 foi pressionado, executa...
if(digitalRead(A2) == 0)
{
Serial.println("Botão 1 pressionado!");
digitalWrite(7, LOW); //Acende o LED
contador++; //Incrementa a variável contador
Serial.print("Contador = ");//Envia a palavra "contador =" para o PC
Serial.println(contador); //Apresenta o valor atual de contador no PC
}
//Caso não tenha sido pressionado...
else
{
Serial.println("Botão 1 solto!");
digitalWrite(7, HIGH); //Apaga o LED
}

//Realiza a leitura dos dois botões simultâneamente


if(digitalRead(A2) == 0 && digitalRead(A3) == 0)
{
Serial.println("Lógica AND!");
}

delay(300);
}

Analisando o código

O primeiro comando condicional utilizado dentro da função loop verifica a condição do


pino A2. Caso este esteja em nível zero, indica que o botão foi pressionado, senão, que ele está solto.
Note que aqui foi utilizado o comando relacional “==” e por isso que, neste caso, o valor 0 é
considerado verdadeiro. Caso contrário, se não existisse o comando relacional questionando se o
pino A2 é IGUAL à zero, esta condição seria falsa.

Caso a condição seja falsa, isto é, o pino esteja com um nível lógico alto, é sinal de que o
botão está solto e, por isso, o bloco que será executado é o “else”.

Já na segunda condição é utilizado um operador lógico para testar se os dois botões (S1 e
S2) foram pressionados simultaneamente. Observe que, aqui, a condição será verdadeira somente
quando os dois pinos do Arduino (A2 e A3) estiverem em nível 0 ao mesmo tempo. Caso apenas
um botão esteja pressionado, esta condição será falsa.

28
Prof. Rodrigo Rech v.1

Exercícios:

1. Desenvolva um programa que receba dois números, verifique qual é o maior e:


a. Apresente na tela do computador o maior número digitado;
b. Acenda o LED do pino 3 caso seja o número 1, e o LED do pino 4 caso seja o número 2.
Obs: Utilize a função scanf para receber os números.

2. Crie um programa que faça a leitura de um número inteiro e verifique se é par ou ímpar. Indique
por meio de um LED e, também, por meio de um texto na tela;

3. Elabore um programa que calcule a área do quadrado, triângulo e círculo,


porém, no início do programa deve se escolher uma opção indicando qual será a
forma a ser calculada. Por exemplo: Caso o usuário digite o caractere ‘a’, é calculada a área do
quadrado, caso digite ‘b’, calcula-se a área do triângulo.

4. Desenvolva um programa que apresente, por meio dos leds e um texto enviado para o computador,
as seguintes lógicas:
a. LED1 = (S1 && S2) || S3;
b. LED2 = (S1 || S3) && S2;

5. Crie um programa que conte a quantidade de vezes que o botão S1 foi pressionado e solto, e apresente
o valor na tela cada vez que o acionamento ocorrer.

29
Prof. Rodrigo Rech v.1

Capítulo 05: Estrutura condicional 2 – Comando switch

Uma forma alternativa ao comando if para se trabalhar com condições dentro de um


programa, é utilizando o comando switch.

Nele e possível testar uma série de condições utilizando apenas um comando, evitando,
desta forma, trabalhar com vários if e else encadeados, com a diferença de que, com este comando,
apenas valores constantes inteiros e caracteres são aceitos. Logo, não é possível trabalhar com
variáveis tipo float ou double e, também, com operadores relacionais. Para exemplificar seu
funcionamento, observe o seguinte pseudocódigo e fluxograma:

Início

Recebe um valor
para uma variável

Escolha(variável)
Início: Variável = 1? Sim Instruções
Caso (valor1)
Execute...; Não

Caso (valor2)
Variável = 2? Sim Instruções
Execute...;
Caso (padrão) Não
Execute...;
Fim; Instruções

FIM

O comando switch segue a seguinte sintaxe:

switch(variável)
{
case 1: {
//ações realizadas caso a variável seja 1
break;
}
case 2: {
//ações realizadas caso a variável seja 2
break;
}
default: {
//ações realizadas caso a variável não seja nenhuma das opções
}
}

30
Prof. Rodrigo Rech v.1

A variável escolhida não pode ser do tipo float ou double, apenas números inteiros ou
caracteres são aceitos. A palavra reservada “case” determina qual o bloco que será executado, de
acordo com o valor da variável escolhida. Já a palavra reservada “break”, finaliza o comando switch,
evitando que os blocos que estão após ele sejam executados. Caso o comando break não seja
utilizado, todos os blocos abaixo do case selecionado serão executados. A palavra “default” indica
que a variável não possui nenhum dos valores indicados nos cases, então este bloco é executado.

Exemplo:

Para testar o funcionamento do comando switch, analise o fluxograma e o código a seguir:

Setup Loop

Escreve o menu de
Cria variável global
funcionamento dos
led LEDs

Configura a Recebe o valor pela


comunicação serial serial

Define os pinos dos


leds como saída

led = 1? Sim Liga LED 1


Fim
Não

Led = 2? Sim Desliga LED 1

Não

Led = 6? Sim Desliga LED 3

Não

31
Prof. Rodrigo Rech v.1

Código:

#include <ArduinoSTL.h>

//Declara a variável que irá receber o valor do LED


int led = 0;

void setup() {
Serial.begin(9600);
pinMode(3, OUTPUT);
pinMode(4, OUTPUT);
pinMode(5, OUTPUT);
}

void loop() {
//Cria o menu
Serial.println("1 - Acende LED3\n2 - Apaga LED3\n3 - Acende LED4\n4 - Apaga
LED4\n5 - Acende LED5\n6 - Apaga LED5");
//recebe o valor do led
scanf("%d", &led);

//Define qual a condição verdadeira


switch(led)
{
case 1: {digitalWrite(3,LOW); break;}
case 2: {digitalWrite(3,HIGH); break;}
case 3: {digitalWrite(4,LOW); break;}
case 4: {digitalWrite(4,HIGH); break;}
case 5: {digitalWrite(5,LOW); break;}
case 6: {digitalWrite(5,HIGH); break;}
default:{Serial.println("O número digitado está incorreto");}
}
}

Analisando o código:

Na função setup() foi configurada a comunicação serial e os pinos dos leds foram definidos
como saída.

Na função loop() temos:

Serial.println("1 - Acende LED1\n2 - Apaga LED1\n3 - Acende LED2\n4 -


Apaga LED2\n5 - Acende LED3\n6 - Apaga LED3");

Nesta função é gerado o menu que indica para o usuário a ação correspondente de cada
número digitado no monitor serial;

scanf("%d", &led);

O scanf() é responsável por ler e armazenar o valor digitado pelo usuário no monitor serial.
Neste caso o valor armazenado é do tipo inteiro.

32
Prof. Rodrigo Rech v.1

switch(led){

O comando switch( ) define qual a variável que será utilizada para o teste condicional.
Neste caso, a variável é a “led”, que possui o valor digitado pelo usuário e recebido pela função
scanf( ).

case 1: {digitalWrite(3,LOW); break;}

O comando switch é complementado pela palavra reservada “case”, que possui a função de
escolher a condição correta de acordo com o valor contido na variável “led”. Aqui o bloco foi escrito
em apenas uma linha, porém, é possível escrever normalmente em linhas separadas, desde que, ao
final do bloco, seja inserido o comando “break”.

default:{Serial.println("O número digitado está incorreto");}

Para finalizar foi utilizada a condição “default”. Ela entra em ação após nenhum dos casos
anteriores ser atendido. Nela não é necessário incluir o comando break, pois se trata do último
bloco que será executado.

Exercícios:

1. Desenvolva um programa que apresente na tela o nome e o preço de um produto de acordo


com seu código numérico, de acordo com a tabela a seguir: Obs: Faça isso para 6 opções de
produtos diferentes.
Código Produto
150 Produto 1 – R$5,00
151 Produto 2 – R$9,50

2. Crie um programa que receba 2 números e, a partir de uma escolha do usuário execute uma
das funções abaixo:
Opção Operação
1 Média entre os números
2 Apresente qual é o maior
3 Número 1 elevado ao número 2

3. Faça um programa que acenda a quantidade de leds de acordo com o número enviado pelo
usuário. Caso o número seja maior do que a quantidade de leds disponível, deve aparecer
uma mensagem de erro no monitor serial;

4. Desenvolva um programa no qual o usuário escolha quantas vezes um LED irá piscar.
Considere os intervalos de 150ms.

33
Prof. Rodrigo Rech v.1

Capítulo 06: Entradas e Saídas Analógicas

Enquanto as entradas digitais do Arduino conseguem assumir apenas dois valores (0V
ou 5V), as entradas analógicas possuem a capacidade de realizar a leitura de infinitos valores
dentro de uma faixa pré-estabelecida. Variáveis analógicas são comuns para medir grandezas
físicas, como temperatura, vazão, pressão, entre outras.

O Arduino e qualquer outro sistema que possua um microprocessador trabalha


internamente apenas com dados digitais, ou seja, os valores analógicos lidos por um pino devem
ser convertidos para um valor digital que o represente. Este trabalho é feito por meio de um
conversor Analógico-Digital (conversor A/D ou ADC). Este tipo de conversor é encontrado tanto na
forma de circuitos integrados quanto já embutidos dentro de microcontroladores, como é o caso do
Arduino. Nele, existem 6 pinos (A0 – A5) que podem realizar a leitura de uma tensão máxima de
5V.

Um conversor A/D quantifica o valor analógico conforme a quantidade de bits da sua


resolução. A resolução de um conversor A/D é dada pela seguinte equação:

𝑉𝑟𝑒𝑓
𝑟𝑒𝑠𝑜𝑙𝑢çã𝑜 =
2𝑛 − 1
onde Vref é a tensão de referência do conversor A/D (normalmente 5V) e n é o número de bits do
conversor. (https://www.embarcados.com.br/arduino-entradas-analogicas/)

O conversor A/D do Arduino possui 10 bits de resolução, a sua tensão de entrada pode variar
de 0V até o valor de VCC. Dessa forma, o menor valor que pode ser lido será:

5𝑉
𝑅𝑒𝑠𝑜𝑙𝑢çã𝑜 = = 4,88𝑚𝑉
210−1
Este é o valor que representa o degrau para uma conversão em 10 bits com referência em 5V.

Como exemplo, vamos considerar um conversor A/D de 3 bits.

Figura 1: Funcionamento de um conversor A/D de 3 bits

34
Prof. Rodrigo Rech v.1

No gráfico da figura 1 é possível observar que, conforme a tensão da entrada analógica


varia, o valor da saída digital, isto é, o valor lido no Arduino também aumenta de forma
proporcional. Podemos notar também que, quanto maior o número de bits de um conversor A/D,
menor será o degrau entre um nível e outro, aumentando dessa forma, a resolução.

A função que deve ser utilizada para efetuar a leitura de um pino analógico do Arduino é:

Var = analogRead(pino);

Esta função retorna um valor inteiro, entre 0 e 1023, que representa a conversão do sinal
analógico lido no pino (A0 a A5). “Var” é a variável criada para receber o valor da conversão e deve
possuir um tamanho de 16 bits.

Saídas analógicas

As saídas analógicas seguem o mesmo conceito das entradas analógicas, isto é, possuem
infinitos valores dentro de uma faixa pré-estabelecida. Com isso, é possível realizar o controle de
cargas que não são binárias, como por exemplo, aumentar ou diminuir a intensidade de luz de
um LED ou controlar a velocidade de um motor de corrente contínua.

No Arduino Uno e na grande maioria dos microcontroladores, as saídas analógicas não


fornecem um sinal DC no nível desejado (estes são obtidos por meio de conversores Digital-
Analógicos ou DACs), eles utilizam uma técnica denominada PWM (Pulse Width Modulation),
na qual é possível obter valores médios de tensão a partir do chaveamento de um pino em alta
frequência. A figura 2 ilustra como este controle é realizado.

Figura 2: Funcionamento do PWM


Fonte: http://tot.eng.br/controlar-brilho-led-arduino-pwm/

35
Prof. Rodrigo Rech v.1

É possível notar na figura 2 que, quanto maior o tempo ativo, isto é, ligado, maior é a
intensidade do LED. Esse efeito ocorre porque a frequência de chaveamento (ligado-desligado) é
alta e o componente “enxerga” este sinal como uma tensão média sobre ele.

Da mesma forma das entradas analógicas, estas saídas também são calculadas a partir
de sua resolução. No Arduino, a resolução das saídas com PWM é de 8 bits, ou seja, é possível obter
255 valores de tensão média diferentes nestes pinos, entre 0 e 5V.

Para calcular o valor exato da tensão de saída pode ser utilizada a equação:

(5 ∗ 𝑉𝑎𝑙𝑜𝑟𝑃𝑊𝑀)
𝑣𝑚𝑒𝑑𝑖𝑎 (𝑉) =
255
Onde ValorPWM é um número inteiro entre 0 e 255.

A função do Arduino utilizada para controlar um pino com PWM é:

analogWrite(pino, ValorPWM);

Exemplo: Controle de intensidade do LED com potenciômetro

Neste exemplo será lido um valor analógico na entrada A0 do Arduino e com ele será
controlada a intensidade de luz no LED do pino 0. Além de realizar a leitura do pino, teremos que
efetuar um ajuste de escala, já que a entrada analógica funciona com 10 bits (0 a 1023) e a saída
analógica, com 8 bits (0 a 255). O ajuste é feito a partir de uma regra de três simples:

𝐸𝑛𝑡𝑟𝑎𝑑𝑎𝐴𝑛𝑎𝑙ó𝑔𝑖𝑐𝑎 ∗ 255
𝑆𝑎í𝑑𝑎 =
1023
Para facilitar, o Arduino possui uma função de ajuste de escala que retorna o valor de uma
regra de três, assim como apresentado:

map(valor, de_mínimo, de_máximo, para_mínimo, para_máximo);

É importante destacar que, esta função realiza a conversão apenas para números inteiros.
Para números reais é necessário realizar um cálculo de regra de três utilizando os operadores
aritméticos apresentados na aula 03.

36
Prof. Rodrigo Rech v.1

Para este exemplo, considere os fluxogramas:

Loop
Setup

Declara variáveis
globais:
valor_analógico e
Realiza a leitura do
valor_pwm pino A0

Configura
comunicação com o Envia o valor lido
PC para o computador

Ajusta o valor lido


Define o pino para a escala do
PWM
0 como saída

Envia o valor
ajustado para o
computador
FIM

Atualiza o valor do
pino 0

Atraso de 500ms

Código:

//Declara as variáveis que serão utilizadas no programa


int valor_analogico=0;
int valor_pwm = 0;

void setup() {
Serial.begin(9600);
pinMode(3, OUTPUT);
}

void loop()
{
//Faz a leitura do pino analógico
valor_analogico = analogRead(A0);

//Envia o valor lido para o computador


Serial.print("Valor lido do pino A0 = ");
Serial.println(valor_analogico);

//Faz o ajuste de escala para o PWM


valor_pwm = map(valor_analogico, 0, 1023, 0, 255);

//Envia o valor convertido para o computador


Serial.print("Valor convertido para o PWM = ");
Serial.println(valor_pwm);

//Atualiza o valor do pino 10


analogWrite(3, valor_pwm);
delay(500);
}

37
Prof. Rodrigo Rech v.1

Analisando o código:

A leitura do valor analógico emitido pelo potenciômetro é realizada pela função


“analogRead(A0)”, que armazena o resultado na variável “valor_analogico”.

valor_pwm = map(valor_analogico, 0, 1023, 0, 255);

Esta função realiza o ajuste de escala da variável “valor_analogico”, que possui uma faixa
de 0 a 1023, para uma escala de faixa entre 0 e 255. Dessa forma é possível utilizar a variável
“valor_pwm” para atualizar o nível de tensão média no pino 0.

analogWrite(3, valor_pwm);

Depois que a escala é ajustada, ela já pode ser utilizada para alterar o valor da tensão média
no pino 10. A partir desta função é possível ver a intensidade do LED aumentado ou diminuindo
de acordo com a posição do potenciômetro.

Exercícios:

1. Converta o valor digital lido em uma entrada analógica em tensão e apresente na tela do
computador. Utilize 2 casas decimais para a apresentação.

2. Desenvolva um bargraph com 4 leds, funcionando da seguinte forma:


a. LD4 acende se A0 > 0;
b. LD5 acende se A0 > 250;
c. LD6 acende se A0 > 500;
d. LD7 acende se A0 > 750.

3. Crie um programa que altere a intensidade de luz de um LED a partir da escolha do


usuário. O programa deverá receber através da função scanf um número inteiro entre 0 e
100%, e este valor deve ser convertido para a escala do PWM.

4. Desenvolva um programa que realize a comparação entre duas entradas analógicas (A0 e
A1), apresente a diferença na tela e acenda o LED1 caso A0>A1, LED2 caso A0<A1 ou
LED3 caso A0=A1.

5. Crie um programa que apresente na tela a conversão de um nível de tensão (0 a 5V) em


temperatura (0 a 100ºC).

38
Prof. Rodrigo Rech v.1

Capítulo 07: Laços de repetição

São utilizados para criar blocos que serão repetidos no programa enquanto uma
condição, testada periodicamente pelo bloco do laço de repetição, é verdadeira. Quando
esta condição atingir um valor e ser considerada falsa, o programa para de executar o
laço. No Arduino, a função “loop” pode ser considerada um laço de repetição, porém, incondicional.
Isso significa que a função loop é repetida infinitas vezes sem depender de uma condição.

Em linguagem C existem três tipos básicos de laços: laço “while”, laço “do-while” e laço “for”.

Laço “while”:

O laço while pode ser representado pelo fluxograma da figura 1:

Início

Instruções...

Condição
Sim Instruções...
verdadeira?

Não

Fim

Figura 1: Fluxograma do laço while

Neste fluxograma é possível observar que as instruções contidas no laço de repetição só serão
executadas se o teste condicional for verdadeiro. Do contrário, as instruções não serão realizadas.
O critério adotado para que uma condição seja verdadeira ou não é o mesmo utilizado nas
estruturas condicionais, com operadores relacionais e lógicos.

A sintaxe do laço “while” é:

while(condição)
{
//Instruções realizadas caso a condição seja verdadeira
}

39
Prof. Rodrigo Rech v.1

Exemplo 1:

#include <ArduinoSTL.h>

//Declara variáveis globais


int maximo=0;
int contador = 0;

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

void loop() {
Serial.println("Digite o numero de repeticoes:");
scanf("%d",&maximo);

//Verifica se a variável “contador” é menor do que o valor digitado


//Se for, entra no laço...
while(maximo !=0 && contador <= maximo) //Enquanto verdadeiro, faça...
{
Serial.println(contador);
contador++; //Incrementa a variável de controle
delay(1000);
}

//Zera a variável de controle para executar o programa novamente


contador = 0;
Serial.println("A contagem terminou...");
}

Laço “do-while”:

A figura 2 ilustra o fluxograma equivalente de um laço “do-while”:

Início

Instruções...

Sim
Instruções...

Condição
verdadeira?

Não

Fim

Figura 2: Fluxograma do laço do-while

40
Prof. Rodrigo Rech v.1

Diferente do laço “while”, as instruções que estão dentro do bloco do “do-while” são
executadas antes da verificação da condição. Esta é feita somente ao final da primeira execução
das instruções, fazendo com que o bloco seja executado ao menos uma vez, mesmo se a condição
for falsa.

Sintaxe do laço “do-while”:

do{

//Instruções do laço

}while(condição);

Exemplo 2:

Neste exemplo a aplicação será idêntica à apresentada no exemplo 1, porém, utilizando o


laço do-while.

#include <ArduinoSTL.h>

int maximo=0;
int contador = 0;

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

void loop() {

Serial.println("Digite o numero de repeticoes:");


scanf("%d",&maximo);

do{

Serial.println(contador);
contador++;
delay(1000);

}while(maximo !=0 && contador <= maximo);

contador = 0;
Serial.println("A contagem terminou...");
}

Laço “for”:

O laço “for” trabalha de uma forma semelhante a um contador. Nele, o programador


determina qual a condição para que a execução do laço seja mantida e, também, qual a operação
que deve ser realizada ao final do laço para que a condição se torne falsa em algum momento.

41
Prof. Rodrigo Rech v.1

A sintaxe do comando “for” é:

for(inicialização da variável; condição; operação realizada no final do laço)


{
//Instruções realizadas no laço

Na figura 3 é possível observar o fluxograma de funcionamento do laço “for”:

Início

Instruções...

Inicialização do laço
for

Instruções...

Sim

Operação de
controle do laço
for

Condição
verdadeira?

Não

Fim

Figura 3: Fluxograma do laço for

42
Prof. Rodrigo Rech v.1

Exemplo 3:

#include <ArduinoSTL.h>

int maximo=0;
int contador = 0;

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

void loop() {

Serial.println("Digite o numero de repeticoes:");


scanf("%d",&maximo);

/*Inicializa o laço "for", a cada iteração a variável "contador" é incrementada.


Enquanto a variável "contador" for menor do que "maximo", o laço continua sendo
executado*/
for(contador = 0; contador <= maximo; contador++)
{
Serial.println(contador);
delay(1000);
}

Serial.println("A contagem terminou...");


}

A operação de controle do laço é definida pelo programador e pode assumir qualquer tipo de
operação aritmética. Ela será executada automaticamente ao final de cada iteração do laço.

Utilizando o comando “break” para finalizar um laço:

É comum que, em algumas situações, um laço de repetição tenha que ser finalizado antes
que sua condição se torne verdadeira. Um bom exemplo para isso seria em uma emergência, na
qual no meio de uma contagem um botão de “stop” tenha sido pressionado. Para que isso funcione
e o laço pare de ser executado, deve ser utilizado o comando “break”. Por exemplo:

for(i = 1; i <= 10; i++)


{
if(i == 5)
break;
Serial.print("Indice: ");
Serial.println(i);
}

Neste trecho de programa, o laço imprime na tela o valor atual da variável “i”. Normalmente
o laço seria finalizado apenas quando a variável fosse maior do que 10, porém, a condição do
comando “if” é verdadeira quando ela atinge o valor 5, executando, dessa forma, o comando
“break”. A partir daí o laço “for” deixa de ser executado.

43
Prof. Rodrigo Rech v.1

Utilizando o comando “continue” para reiniciar um laço:

De forma contrária ao comando “break”, o comando “continue” tem a função de reiniciar a


execução de um laço antes que ele seja finalizado. Observe o seguinte exemplo:

for(i = 0; i <= 10; i++)


{
if(i == 5 || i == 7)
continue;

Serial.print("Indice: ");
Serial.println(i);
}

Aqui, a finalidade é imprimir o valor atual da variável “i” na tela. O comando “if” é
verdadeiro em duas condições: quando a variável atingir o valor 5 ou o valor 7. Em ambos os casos
será executado o comando “continue”, fazendo com que o laço seja reiniciado a partir daquele ponto.
Como resultado, aparecerá na tela a faixa de valores de 0 a 10, porém, sem apresentar os números
5 e 7.

0 1 2 3 4 6 8 9 10

Exercícios:

1. Faça um programa no qual o usuário digite o número de vezes que um LED deve piscar.
Considere um intervalo de 1s. Obs: Desenvolva o mesmo programa para os três tipos de laço.

2. Desenvolva um programa que apresente a tabuada de um número escolhido pelo usuário.


Utilize o formato tradicional. Exemplo: “5 x 0 = 0; 5 x 1 = 5...”;

3. Utilizando como base o programa anterior, receba dois números inteiros, no qual o primeiro
é o valor mínimo e o segundo o valor máximo da tabuada que deverá ser apresentada. Para
isso, utilize dois laços “for” aninhados. Obs: Crie um algoritmo que não permita que o
usuário digite o segundo número menor do que o primeiro.

4. Desenvolva um programa que aumente a intensidade de um LED de forma gradativa, com


intervalos de 50ms. Ao chegar na luminosidade máxima, a intensidade deve diminuir
também de forma gradativa.

5. Desenvolva um contador de 0 a 5, apresentando o valor no display de 7 segmentos.


Considere o intervalo de tempo para incremento de 1 segundo.

44
Prof. Rodrigo Rech v.1

Capítulo 08: Arrays (Vetores e Matrizes)

O arrays, também chamados de vetores e/ou matrizes, são variáveis que armazenam uma
quantidade “n” de valores do mesmo tipo e de forma indexada. Na prática, temos uma série de
valores organizados em posições sequenciais, sendo mais simples acessá-los.

Um exemplo prático para este tipo de variável é um datalogger. A função de um datalogger


é armazenar a mudança de uma variável (determinada pelo usuário) em função do tempo. Assim,
é possível obter um gráfico da variável desejada versus o tempo.

Imagine que é necessário medir a variação de temperatura de uma sala dentro de um período
de 10 horas para verificar em que horário a sala se encontra mais quente. Podemos, para este caso,
montar uma tabela com 10 posições, nas quais serão armazenados os valores a cada 1 hora:

Hora 9h00 10h00 11h00 12h00 13h00 14h00 15h00 16h00 17h00 18h00
Temperatura
17,5 19,8 22,2 25,1 26,0 26,6 26,9 26,3 25,5 24,7
(ºC)

Figura 1: Temperatura vs Tempo

Com estes valores é possível realizar diversas análises, tais como: Qual o horário em que a
sala está com a menor temperatura? E a maior? Quais horários o ar-condicionado irá gastar mais
energia? Qual a média de temperatura da sala durante este horário? Em que período houve a menor
variação de temperatura?

Observe que, para realizar estas observações é necessário que se tenha o histórico dos valores
lidos pelo sensor de temperatura, e não apenas o último valor. Em programação, para se obter um
histórico dessa forma é necessário utilizar os arrays.

Pensando no exemplo dado, vamos criar um array de 10 posições seguindo a sintaxe:

tipo_da_variável nome [quantidade_de_posições];

float temperatura[10];

45
Prof. Rodrigo Rech v.1

Aqui foram reservadas 10 posições da memória para armazenamento dos valores referentes
à variável “temperatura”. Para acessar cada uma das posições devem ser utilizados os índices
referentes a cada uma, começando no 0:

Índice 0 1 2 3 4 5 6 7 8 9
Temperatura
17,5 19,8 22,2 25,1 26,0 26,6 26,9 26,3 25,5 24,7
(ºC)

É possível atribuir os valores referentes a cada posição do vetor durante sua declaração ou
no decorrer do programa:

1- Durante a declaração:

unsigned int numero[5] = {32,56,13,22,9};

2- Na execução do programa:

numero[0] = 32;
numero[1] = 56;
numero[2] = 13;
numero[3] = 22;
numero[4] = 9;

Além de vetores, também é possível declarar matrizes com 2 ou mais dimensões utilizando
a seguinte sintaxe:

unsigned char nome_da_matriz [n_linhas] [n_colunas];


unsigned char matriz_xy [3] [3];

O acesso aos seus dados é feito de forma semelhante aos vetores, e seus índices também
iniciam com 0. Abaixo é mostrado como fica organizada uma matriz 3x3:

Linha Coluna 0 1 2
0 Valor_00 Valor_01 Valor_02
1 Valor_10 Valor_11 Valor_12
2 Valor_20 Valor_21 Valor_22

A sintaxe para criação de matrizes com mais dimensões é semelhante à utilizada na


matriz bidimensional.

O acesso às posições das linhas e colunas de uma matriz de 2 ou mais dimensões segue o
mesmo padrão de um vetor. Os valores podem ser inicializados já na declaração ou durante a
execução do programa:

1- Durante a declaração:

unsigned int matriz[3][3] = {{32,56,13},{22,12,65},{10,8,1}};

2- Na execução do programa:

46
Prof. Rodrigo Rech v.1

matriz[0][0] = 32;
matriz[0][1] = 56;
matriz[0][2] = 13;
matriz[1][0] = 22;
matriz[1][1] = 12;
matriz[1][2] = 65;
matriz[2][0] = 10;
matriz[2][1] = 8;
matriz[2][2] = 1;

Exemplo 1: Neste exemplo serão armazenados 5 números digitados pelo usuário em um vetor. Ao
final, eles deverão ser apresentados na tela:

#include <ArduinoSTL.h>

//Declaração do vetor
unsigned int numeros[5];

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

void loop() {
Serial.println("Este programa armazena 5 valores em um vetor: ");

//Laço para receber os valores e armazenar no vetor


for(int indice=0; indice<5; indice++){

Serial.print("Digite o numero da posicao ");


Serial.println(indice+1);

//Armazena o número digitado na posição indicada por "indice"


scanf("%d", &numeros[indice]);
}

//Laço para apresentar o conteúdo do vetor


for(int indice=0; indice<5; indice++){

Serial.print("Numero ");
Serial.print(indice+1);
Serial.print(" :");

//Apresenta o número armazenado na posição indicada por "indice"


Serial.println(numeros[indice]);
}
}

47
Prof. Rodrigo Rech v.1

Exemplo 2: Neste exemplo será mostrado como preencher e apresentar os valores de uma matriz
3x3.

#include <ArduinoSTL.h>

//Declaração da matriz
unsigned int matriz[3][3];

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

void loop() {
Serial.println("Este programa armazena 9 valores distribuídos em uma matriz 3x3: ");

//Laço para receber os valores e armazenar na matriz


for(int linha=0; linha<3; linha++){
//Mostra a linha atual
Serial.print("Digite os valores da linha ");
Serial.println(linha+1);

for(int coluna=0; coluna<3; coluna++){


//Mostra a coluna atual
Serial.print(" Coluna: ");
Serial.println(coluna+1);

//Armazena o número digitado na posição indicada por "linha" e "coluna"


scanf("%d", &matriz[linha][coluna]);
}
}

//Laço para apresentar o conteúdo da matriz


for(int linha=0; linha<3; linha++){
//Mostra a linha atual
Serial.print("Linha: ");
Serial.println(linha+1);

for(int coluna=0; coluna<3; coluna++){


//Mostra a coluna atual
Serial.print(" Coluna ");
Serial.print(coluna+1);
Serial.print(" :");

//Apresenta na tela os valores da matriz indicados por "linha" e "coluna"


Serial.println(matriz[linha][coluna]);
}
}
}

48
Prof. Rodrigo Rech v.1

Utilizando matrizes para acionar displays de 7 segmentos

Os displays de 7 segmentos são formados por LEDs dispostos de uma forma que,
dependendo da sequência acionada, formam um número de 0 a 9 ou 0 a F. Podem ser encontrados
displays de anodo comum ou catodo comum (figura 2).

Figura 2: Displays de 7 segmentos

Em um display de catodo comum, é necessário nível lógico ‘1’ nos segmentos para que eles
acendam. Já no display de anodo comum, é necessário nível ‘0’.

No circuito que iremos trabalhar os segmentos estão ligados nos pinos 0 a 7 do Arduino,
sendo o pino 0 o seguimento ‘a’ e o pino 7 o ponto decimal (figura 3).

Figura 3: Ligação do display

O display utilizado neste circuito é catodo comum, isto é, para acionar os segmentos é
necessário que os pinos do Arduino estejam em nível lógico ‘1’.

Para facilitar o acionamento do display com os dígitos de 0 a F, é criada uma tabela com o
estado lógico de cada segmento para cada dígito.

49
Prof. Rodrigo Rech v.1

Exemplo 3: Acionando o display de 7 segmentos

#include <ArduinoSTL.h>

//Declaração da matriz do display


// e d c P g f a b
char display_7seg[16][8] = { { 1,1,1,0,0,1,1,1 }, // = Digito 0
{ 0,0,1,0,0,0,0,1 }, // = Digito 1
{ 1,1,0,0,1,0,1,1 }, // = Digito 2
{ 0,1,1,0,1,0,1,1 }, // = Digito 3
{ 0,0,1,0,1,1,0,1 }, // = Digito 4
{ 0,1,1,0,1,1,1,0 }, // = Digito 5
{ 1,1,1,0,1,1,1,0 }, // = Digito 6
{ 0,0,1,0,0,0,1,1 }, // = Digito 7
{ 1,1,1,0,1,1,1,1 }, // = Digito 8
{ 0,0,1,0,1,1,1,1 }, // = Digito 9
{ 1,0,1,0,1,1,1,1 }, // = Digito A
{ 1,1,1,0,1,1,0,0 }, // = Digito B
{ 1,1,0,0,0,1,1,0 }, // = Digito C
{ 1,1,1,0,1,0,0,1 }, // = Digito D
{ 1,1,0,0,1,1,1,0 }, // = Digito E
{ 1,0,0,0,1,1,1,0 } // = Digito F
};

int num = 0;
int pino = 0;

void setup() {
Serial.begin(9600);
pinMode (8, OUTPUT);
//Define os pinos 0 - 7 como saídas
for(int i=0; i<8; i++){
pinMode(i, OUTPUT);
}

digitalWrite(8, HIGH); //Liga o Transistor do display


}

void loop() {
Serial.println("Digite o numero que deseja ver no display: ");
scanf("%d", &num);

//inicia a contagem do primeiro pino (segmento a)


pino = 0;

//Preenche todos os segmentos de acordo com o número digitado pelo usuário


for(int seg=0; seg<8; seg++){
//Liga ou desliga o segmento de acordo com a tabela criada
digitalWrite(pino, display_7seg[num][seg]);

//Muda o pino para o próximo segmento


pino++;
}
}

50
Prof. Rodrigo Rech v.1

Exercícios:

1. Faça a leitura de 10 valores, armazene-os em um vetor e apresente sua média aritmética;

2. Crie um programa onde um vetor já é inicializado com 5 caracteres, depois, peça para que
o usuário digite outros 5 caracteres e os armazene em um outro vetor. Caso todos os
caracteres forem iguais, apresenta uma mensagem de correto, caso diferente, incorreto.

3. Desenvolva um programa que preencha uma matriz 3x3 e calcule sua determinante.

4. Crie um contador de 0 a 9 que deve ser incrementado e decrementado pelos botões ligados
em A2 e A3 (ao pressionar e soltar o botão).

Dica: Utilize como base o exercício 5 da aula de estruturas condicionais e não esqueça de
ativar os resistores de pullup dos pinos.

5. Faça um programa que armazene os valores lidos de uma entrada analógica cada vez que
um botão é pressionado e solto. O total de valores lidos deve ser de 10. Ao finalizar as
leituras o programa deve enviar pela serial: A0[número da leitura] = valor lido; Ex. A0[3]
= 234;

51
Prof. Rodrigo Rech v.1

Capítulo 09: Criando Funções

Funções são sub-rotinas que executam determinadas tarefas e podem ser chamadas sempre
que necessário, alguns exemplos são as funções printf(), scanf() e pow(), estas já criadas e
utilizadas nos programas, desde que as bibliotecas que as possuem sejam inseridas no cabeçalho.

A utilização das funções em um código auxilia na organização e otimização do programa,


já que tarefas que são repetidas no não precisam ser reescritas e sim, chamadas novamente.

Toda função criada pode receber ou retornar um valor da função principal, para isso, basta
informar o tipo de dado que irá enviar, receber ou ambos. Abaixo é demonstrada a sintaxe de criação
de uma função:

Tipo_do_retorno nome_da_função (tipo_do_argumento)

OBS: Uma função pode receber quantos argumentos forem necessários, separados por vírgula,
porém, pode retornar apenas um valor.

Abaixo são mostradas as sintaxes para a criação de alguns tipos de funções:

1- Função que não envia e não recebe dado:

void nome_da_função (void);

2- Função que retorna um valor do tipo inteiro positivo:

unsigned int nome_da_função (void);

3- Função que recebe um ou mais argumentos e não retorna nenhum valor:

void nome_da_função (int arg1, char arg2,...);

4- Função que envia e recebe dados do tipo char:

unsigned char nome_da_função (char arg1, char arg2);

As funções podem ser criadas diretamente no arquivo do projeto, junto da função main, ou
então, em outros arquivos .c ou .h. Na segunda opção é necessário adicionar a biblioteca no
cabeçalho do arquivo principal com a diretiva #include “endereço do arquivo .h”, neste caso não
foram utilizados os símbolos < e >, pois o arquivo .h está em alguma pasta do computador e não
é nativo do compilador.

Outro detalhe importante se dá pelo fato de ser necessário criar os protótipos das
funções, que nada mais é do que inserir os nomes das funções com “;” no final para indicar
ao compilador que aquela função existe naquele arquivo. Estes protótipos não precisam
ser adicionados caso as funções sejam criadas antes da função “main”.

52
Prof. Rodrigo Rech v.1

Como exemplo, será criada uma função responsável por receber quatro argumentos e
retornar a média aritmética para o programa principal:

float media(float valor_1, float valor_2, float valor_3, float valor_4)


{
float resultado=0;
resultado = (valor_1 + valor_2 + valor_3 + valor_4)/4;
return resultado;
}

Caso seja necessário utilizar esta função dentro da “main”, basta colocar seu nome e os
argumentos necessários:

void main()
{
float nota_1, nota_2, nota_3, nota_4, media_final;
media_final = media(nota_1,nota_2,nota_3,nota_4);
}

Variáveis globais

A melhor forma para enviar valores de variáveis para uma função é por meio dos
argumentos, porém, como foi visto neste tópico, uma função tem a capacidade de retornar apenas
um valor, então, se fosse necessário retornar dois ou mais valores, ou então receber um vetor como
argumento? A forma mais simples para resolver estes problemas é utilizando variáveis globais.

As variáveis globais são criadas fora de qualquer função, por isso podem ser lidas e
modificadas em qualquer parte do programa. Ao criar uma variável global deve se prestar atenção
em alguns detalhes:

a. Não poderá existir outra variável com o mesmo nome no programa inteiro, se existir, o
compilador definirá a prioridade para a variável local;

b. Variáveis locais (aquelas criadas dentro da própria função) são apagadas da memória
sempre que a função acaba de ser executada, liberando espaço da memória RAM. Já as
variáveis globais não são apagadas, ou seja, possuem um endereço fixo na memória durante
toda a execução do programa. Este detalhe não é extremamente impactante em programas
pequenos para computadores, porém, em dispositivos com uma capacidade de memória
menor é um agravante, por isso a recomendação de se evitar variáveis globais sempre que
possível;

c. Variáveis globais podem ser modificadas a qualquer momento e em qualquer função, por
isso deve se tomar cuidado para não alterar seus valores em momentos indesejáveis.

53
Prof. Rodrigo Rech v.1

Exemplo 1:

#include <ArduinoSTL.h>

/* prototipos - declaracoes das funcoes */


int quadrado(int);
char maiusculo(char);
void mostra_dobro(double);

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

void loop() {
int a;
char b;

for(a = 1; a <= 10; a++){


Serial.print(quadrado(a)); //Retorna o quadrado da variável
Serial.print(" ");
}

Serial.println();

for(b = 'a'; b <= 'z'; b++){


Serial.print(maiusculo(b)); //Retorna as letras maiúsculas
Serial.print(" ");
}

Serial.println();
mostra_dobro(3.5); //Apresenta o resultado do dobro na tela

while(1); //Para a execução do programa


}

/* definicoes das funcoes */


int quadrado(int x)
{
return x * x;
}

char maiusculo(char l)
{
if(l >= 'a' && l <= 'z')
return l - 32; //Ajusta o valor de acordo com a tabela ASCII
else
return l;
}

void mostra_dobro(double v)
{
Serial.print("O valor do dobro e: ");
Serial.println(2*v);
}

54
Prof. Rodrigo Rech v.1

Exemplo 2:

#include <ArduinoSTL.h>

/* prototipos - declaracoes das funcoes */


int maximo(int, int, int);
void imprime_vetor(double [], int);
double media(double [], int);

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

void loop() {
int x = 7, y = 10, z = 9, maior;
double vetor[] = {1.2, 3.1, 4.6, 8.9, 7.5, 2.2};

maior = maximo(x, y, z); //Retorna o maior valor entre x,y e z


Serial.print("Maior valor: ");
Serial.println(maior); //Apresenta o maior valor

imprime_vetor(vetor, 6); //Mostra o vetor na tela

Serial.print("Media = ");
Serial.println(media(vetor, 6),2); //Mostra a media dos valores do vetor

while(1);
}
/* definicoes das funcoes */
int maximo(int a, int b, int c)
{
if(a > b && a > c)
return a;
else if(b > a && b > c)
return b;
else
return c;
}

void imprime_vetor(double v[], int n)


{
int i;

for(i = 0; i < n; i++){


Serial.print(v[i],2); //Mostra os valores do vetor
Serial.print(" ");
}
Serial.println("");
}

double media(double v[], int n)


{
int i;
double soma = 0;

for(i = 0; i < n; i++)


soma += v[i]; //Soma os valores do vetor

return soma/n; //Retorna o valor da média


}

55
Prof. Rodrigo Rech v.1

Exemplo 3:

//Protótipo da função
float calcula_temperatura(unsigned int valor_AD);

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

void loop() {
float temperatura;

//Retorna o valor convertido da temperatura


temperatura = calcula_temperatura(analogRead(A0));
Serial.print("Temperatura = ");
Serial.println(temperatura,2); //Apresenta o valor da temperatura
delay(1000);
}

//Converte o valor lido do conversor AD em temperatura (0 - 100ºC)


float calcula_temperatura(unsigned int valor_AD){
float resultado;

resultado = (valor_AD/1023.0)*100;
return resultado;
}

Exercícios:

1. Desenvolva uma função que verifique se um número é par ou ímpar. Ela deve retornar “0”
caso seja par, e “1” caso seja ímpar;

2. Agora, crie uma função que retorne “1” caso um número seja primo e “0”, caso não seja;

3. Faça uma função que receba por parâmetro o raio de uma esfera e retorne o seu volume;

4. Crie uma função que retorne o número do botão pressionado (1, 2 ou 3). Caso nenhum
tenha sido pressionado, a função deve retornar o valor 0.

5. Desenvolva uma função que retorne a diferença de tensão entre as duas entradas
analógicas (A0 e A1).

56

Você também pode gostar