Buscar

Aula 5

Prévia do material em texto

AULA 5 
 
 
 
 
 
 
 
 
 
 
LÓGICA E 
MICROCONTROLADORES 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
Prof. Charles Way Hun Fung 
 
 
 
2 
TEMA 1 – VETORES OU ARRAY 
Durante o desenvolvimento de um projeto com o Arduino e sensores, é 
comum armazenar muitos dados em variáveis de mesmo tipo para um mesmo 
propósito. Um exemplo é fazer a leitura de um sensor de temperatura: imagine 
que esse sensor será lido uma vez a cada hora, então no final de um dia seriam 
necessárias 24 variáveis para armazenar todas as leituras. Além disso, seria 
necessário fazer o gerenciamento de todas essas variáveis com nomes diferentes. 
Soluções para o problema apresentado são as novas estruturas para 
armazenamento de dados. Nesta aula vamos introduzir o uso de vetores e 
matrizes que consistem em variáveis unidimensionais ou multidimensionais, 
respectivamente. 
Segundo Oliveira (2017), vetor ou array é uma estrutura unidimensional que 
armazena diversos valores de mesmo tipo. A figura a seguir ilustra um vetor. 
Figura 1 – Estrutura de um vetor 
 
Perceba que, na Figura 1, dentro de cada quadrado há o conteúdo de uma 
variável que está contida no vetor. O número que se encontra sobre esses 
quadrados são os índices, que indicam a posição de cada variável. Pode-se dizer 
que a posição zero do vetor possui conteúdo ou valor igual a 5. Da mesma forma, 
pode-se dizer que a posição 1 possui o valor 8, e assim por diante. 
O vetor da Figura 1 possui um tipo; no caso, o que melhor se enquadra na 
figura é o tipo inteiro, mas da mesma forma que as variáveis, os vetores possuem 
um tipo dentre os possíveis na linguagem C/C++. A declaração de um vetor segue 
o formato 
<tipo> <nome vetor>[<tamanho do vetor>]. 
Por exemplo: 
int numeros[10]; 
Esse exemplo declara um vetor com o nome de “numeros” do tipo inteiro 
de 10 posições. 
 
 
3 
Para atribuir um valor para uma posição do vetor, é necessário usar o nome 
do vetor, a posição entre colchetes – “[ ]” – seguido do operador de atribuição e o 
valor, como mostrado no exemplo a seguir. 
numeros[2] = 5; 
Além disso, é possível inicializar um vetor com valores específicos fazendo 
uma atribuição direta da seguinte forma. 
int vet[] = {1, 5, 10, 7, 4, 2, 2, 9, 20, 15}; 
Nessa atribuição, não é necessário adicionar o tamanho do vetor, apenas 
o conteúdo entre chaves e cada elemento separado por vírgulas. 
Quando o vetor é do tipo caractere, a atribuição no momento da declaração 
é um pouco diferente: 
char frase[] = “Ola mundo”; 
Perceba que, nessa declaração, o vetor recebe o texto entre aspas duplas. 
Cada caractere vai ocupar uma posição específica no vetor, como na figura a 
seguir. 
Figura 2 – Vetor de caracteres 
 
Um vetor de caracteres é conhecido como Strings; vamos abordá-lo em um 
tema adiante sobre esse tipo de vetor. Como se pode ver na Figura 2, a frase da 
declaração é colocada no vetor caractere por caractere até um finalizador ‘\0’, que 
indica o termo nulo dessa linguagem. Esse caractere nulo é importante como 
finalizador de String, já que variáveis caracteres podem assumir qualquer valor. 
TEMA 2 – USANDO VETORES NO ARDUINO 
Para exemplificar o uso de vetores com o Arduino, serão realizadas 
diversas leituras de uma distância utilizando um sensor de ultrassom. Para isso, 
será feito o uso de um sensor ultrassônico HC-SR04, que possui alcance de 
2 cm a 4 m. Esse sensor é apresentado na figura a seguir. 
 
 
4 
Figura 3 – Sensor de ultrassom 
 
Crédito: Pozdeyev Vitaly/Shutterstock. 
O sensor de ultrassom HC-SR04 possui quatro pinos: VCC, Trigger, Echo 
e GND. O primeiro pino corresponde aos 5 V e GND representa o terra. O pino 
Trigger indica o som deve ser enviado, enquanto o Echo é usado para receber o 
dado quando retorna. O cálculo da distância se baseia no tempo que a onda 
sonora demora para ir e voltar ao objeto da medição da distância. 
A Figura 4 apresenta o sensor de ultrassom com o Arduino. No Tinkercad, 
o sensor ultrassônico possui apenas um pino de sinal, que, no nosso exemplo, 
está conectado ao pino digital 7. Nesse exemplo, é realizada uma medição da 
distância a cada 10 s; após um minuto, apresenta-se a média dos valores no 
terminal serial. 
Figura 4 – Circuito com ultrassom 
 
 
 
5 
Figura 5 – Código para leitura do ultrassom 
 
 
 
 
 
6 
No código apresentado na Figura 5 (linha 8), é feito uso da função 
“distanciaUltrassom”, que calcula o tempo que o sinal ultrassônico levou para ir 
do sensor até o objeto. Essa configuração, que estabelece o pino de Trigger como 
saída na linha 11, serve para tornar flexível o uso desse pino; na prática, podemos 
colocar qualquer pino digital como Trigger. Da mesma forma, o pino de Echo que 
é como entrada (INPUT), na linha 19. As linhas 12, 13, 15, 16 e 17 fazem a 
transmissão de um pulso de 10 µs pelo Trigger, o qual é representado pelas linhas 
15 e 16, que deixam o pino de Trigger em HIGH. 
O retorno desse pulso é registrado na linha 22, que possui a função 
“pulseIn”, que retorna o tempo para receber esse sinal em Echo. Esse tempo é 
retornado por essa função e será usado para determinar a distância até o objeto 
por meio de uma equação de conversão para centímetros. 
Na função “loop()”, na linha 33, temos a conversão do valor do tempo para 
centímetros. Essa equação foi retirada da documentação fornecida pelo fabricante 
do sensor de ultrassom. 
Na linha 34, o valor da distância em centímetros é colocado no vetor, na 
posição determinada por “pos”. Essa variável serve para controlar em qual 
posição do vetor será armazenado o valor da medição. As linhas de 36 a 41 
mostram essa medição no terminal serial. Após o armazenamento dos dados, a 
variável “pos” é incrementada na linha 42, que indica que a próxima posição do 
vetor está pronta para receber um novo valor. 
Na linha 43, há uma verificação quanto ao “pos” ter chegado ao valor 6. 
Como o vetor tem apenas 6 posições e as posições no vetor vão de 0 a 5, não 
seria possível armazenar dados na sexta posição, logo, deve-se fazer o cálculo 
da média desses valores. Para realizar esse cálculo, foi usado um “loop for” na 
linha 44, que usa uma variável de controle i, que começa em 0 e vai até o valor 5; 
quando chega ao valor 6, encerra o “loop”. Nesse laço, é realizada a soma dos 
valores das medições e colocado na variável “media”, na linha 45. Perceba que a 
variável “media” acumula os valores das medições: 
media = media + medidas[i]; 
Essa equação diz que “media vai receber o valor de media mais o valor da 
posição do vetor determinada por i”. A variável “media” começa com o valor zero 
e, com o passar das iterações, vai acumulando o valor de medidas. 
Quando o “loop” termina, o valor de “media” é dividido por 6 e mostrado no 
terminal nas linhas 49 a 51, como mostrado na figura a seguir. 
 
 
7 
Figura 6 – Resultado apresentado pelo terminal serial 
 
 
Após a apresentação desse resultado, o valor da variável “media” é zerado 
na linha 52. Para que a leitura seja feita a cada 1s, é usado um “delay” na linha 
55. 
TEMA 3 – VETOR DE CARACTERES OU STRINGS 
Os vetores de caracteres precisam de atenção especial por possuir um tipo 
próprio, o tipo String. Toda vez que se desejar escrever uma frase ou palavra na 
linguagem wiring, deve-se fazer uso de formas específicas dos comandos. 
Primeiramente, a forma que é escrita uma sequência de caracteres nessa 
linguagem é entre aspas duplas: 
“<Texto>” 
Exemplo: 
char nome[] = “José”; 
char frase[] = “Ola mundo!”; 
Um detalhe importante na linguagem é a diferença entre um caractere e 
uma String; o primeiro é representado entre aspas simples, por exemplo, ‘A’, ‘c’, 
‘3’, indicando o caractere A maiúsculo, c minúsculo e o caractere 3, 
respectivamente. No caso da String, é representada entre aspas duplas, como 
mencionado anteriormente, por exemplo: “Teste”, “Ola mundo” e “A”. Uma dúvida 
comum do estudante dessa linguagem é diferenciar ‘A’de “A”, porque 
aparentemente parecem ser a mesma coisa, mas não são. O primeiro é o 
caractere A maiúsculo, o segundo é uma String que contém o A maiúsculo, mas 
não é só isso, a String é composta pelo seu conteúdo seguido pelo caractere nulo 
(‘\0’), como mostrado na figura a seguir. 
 
 
8 
Figura 7 – Exemplo de String com o nulo para finalização 
 
 
 O formato do caractere nulo pode parecer estranho, mas é exatamente 
esse formato, com um caractere barra seguido do caractere zero. O nulo tem uma 
representação na linguagem que não deve ser confundida com o zero. Ambos 
possuem significados diferentes. 
No Arduino, as Strings são utilizadas principalmente na comunicação serial, 
na qual se pode mostrar mensagens e valores de variáveis. No decorrer do curso, 
já usamos diversas vezes a comunicação serial, mas fundamentalmente essa 
comunicação funciona da seguinte forma. 
1. Configuração da taxa de comunicação. 
2. Envio de mensagens. 
A configuração é realizada na função “setup()”, na qual é chamada a função 
“Serial.begin”, como mostrado no exemplo a seguir. 
Serial.begin(9600); 
Entre parênteses se encontra a taxa de comunicação, esta deve ser igual 
tanto no Arduino como no receptor, no caso, o monitor serial. 
Nas mensagens enviadas na serial, há duas funções básicas: 
• Serial.print: escreve a String que está determinada entre parênteses. Por 
exemplo: 
Serial.print(“Ola mundo”); 
Essa função não pula para a próxima linha do monitor serial assim que 
finaliza sua execução; 
• Serial.println: escreve a String que está determinada entre parênteses, 
pulando de linha no monitor serial após sua execução. Por exemplo: 
Serial.println(“Teste”); 
Além disso, as Strings podem ser usadas para converter diversos tipos de 
dados: 
 
 
9 
1. Converter um caractere para uma String: 
String teste = String(‘a’); 
2. Converter um constante inteiro: 
String teste = String(12); 
3. Converter um número inteiro para uma base numérica: 
a. Base decimal: String teste = String(x, DEC); em que x é uma variável; 
b. Base hexadecimal: String teste = String(32, HEX); 
c. Base binária: String teste = String(255, BIN); 
4. Converter um float com casas decimais: 
String teste = String(1.523, 3); 
5. Concatenar duas Strings: 
String s = “ola”; 
String teste = String(s+” mundo”); 
TEMA 4 – MATRIZES 
Da mesma forma que vetores, as matrizes são um conjunto de dados de 
mesmo tipo, porém possuem duas dimensões: linhas e colunas. Elas são formas 
bidimensionais de armazenar dados. A figura a seguir ilustra o formato de uma 
matriz 4x5 (4 linhas e 5 colunas). 
Figura 8 – Exemplo de matriz 
 
 
A matriz da Figura 8 mostra como os dados se distribuem na matriz. 
Perceba que as linhas e colunas são numeradas: linhas vão de 0 a 3 e colunas 
de 0 a 4, formando a matriz 4x5. 
 
 
10 
A forma de declaração de uma matriz segue um modelo parecido ao vetor, 
porém com duas dimensões: 
<tipo> <nome matriz>[<linhas>][<colunas>]; 
Exemplo: 
int leituras[4][5]; 
Nesse exemplo, é declarada uma matriz inteira com o nome de leituras com 
quatro linhas e cinco colunas. As matrizes aceitam todos os tipos de dados: inteiro 
(int), float (real), char (caractere), double (real com maior precisão). 
Também é possível declarar os valores de uma matriz diretamente na 
declaração, por exemplo: 
int leituras[][] = {{1,2,3},{4,5,6},{7,8,9}}; 
Para atribuir um valor para uma determinada posição de uma matriz, deve-
se especificar a linha e a coluna dessa posição e usar o operador de atribuição, 
como no exemplo a seguir. 
leituras[2][3] = 5; 
Essa linha significa que a variável inteira que se encontra no cruzamento 
entre a linha 2 e a coluna 3 receberá o valor de 5. Isso pode ser ilustrado mudando 
o valor da posição de linha 2 e coluna 3 para 5, na Figura 8. 
Figura 9 – Matriz da Figura 8 modificada com novo valor da posição 2x3 
 
 
Em uma matriz, é comum fazer uma varredura por todos os componentes. 
Isso é útil tanto para atribuir valores para todas as posições da matriz como para 
procurar algum valor específico. Por exemplo: 
Contar quantas posições na matriz da figura 9 têm valor superior a 10. 
 
 
11 
Para resolver esse problema, devemos criar duas variáveis para contar a 
quantidade de linhas e colunas. 
int linha; 
int coluna; 
Nesse caso, essa matriz tem quatro linhas e cinco colunas, então, para 
cada coordenada, devemos fazer um “loop for” da seguinte forma. 
for(linha=0;linha<4;linha++){ 
for(coluna=0;coluna<5;coluna++){ 
 
} 
} 
O funcionamento desse código é baseado na mecânica dos “loops”. A ideia 
é bem simples, fixa um valor da linha e preenche os valores na respectiva linha. 
Em seguida, incrementa o valor da linha e preenche os valores da linha, processo 
que se repete até finalizar as linhas. 
No código, a variável “linha” começa com um valor zero, e verifica-se a 
condição de linha<4; esta é verdadeira. Sendo assim, vai executar os comandos 
dentro do primeiro “for”. Nos comandos, há um novo “for”, nesse caso a variável 
de controle é coluna, que começa com zero e também tem uma condição 
verdadeira – em breve comentaremos sobre os códigos no interior desse “for” que 
vão ser executados. Assim que esse “for” interno terminar, a variável “linha” será 
incrementada em uma unidade; nesse caso, vai para o valor 1. A condição do “for” 
externo ainda continua sendo verdadeira, reiniciando o “for” interno. Essa 
repetição desse código vai continuar até que todas as linhas sejam verificadas. 
Perceba que cada posição da matriz é explorada com esse código, na seguinte 
ordem. 
[0][0], [0][1], [0][2], [0][3], [0][4], [1][0], [1][1], [1][2], [1][3], [1][4], [2][0], [2][1], [2][2], 
[2][3], [2][4], [3][0], [3][1], [3][2], [3][3], [3][4]. 
Perceba que, como mencionado anteriormente, o valor da linha é fixado 
para, em seguida, suas posições de coluna serem verificadas. 
 
 
12 
No problema proposto, deve-se contar a quantidade de posições da matriz 
que possui valor superior a 10. Para isso, devemos criar uma variável para realizar 
essa contagem; chamaremos essa variável de contador, que deverá começar 
zerada para que não ocorra nenhum erro na contagem das posições da matriz. 
int contador = 0; 
O resto do código é apresentado a seguir. 
for(linha=0;linha<4;linha++){ 
for(coluna=0;coluna<5;coluna++){ 
 if(leituras[linha][coluna]>10){ 
 contador++; 
 } 
} 
} 
Serial.println(“A quantidade de valores é ”+contador); 
No “loop” interno, temos um comando de comparação que verifica se a 
posição analisada possui um conteúdo com valor superior a 10. Caso isso seja 
verdade, o comando “contador++”, que incrementa o contador em uma unidade, 
é executado. No final, o valor de contador é mostrado na serial. 
TEMA 5 – EXEMPLO DO USO DE MATRIZ COM O ARDUINO 
Nesse exemplo, faremos a leitura de três sensores de temperatura e vamos 
armazenar as leituras em uma matriz. Nesse caso, serão feitas 
10 leituras e serão mostradas as médias das leituras na serial. 
O esquemático do circuito para realizar a leitura das temperaturas é 
apresentado a seguir. 
 
 
13 
 Figura 10 – Leitura de três sensores de temperatura 
 
 
O sensor de temperatura utilizado é o TMP36, que possui três pinos; o pino 
da direita é a alimentação de 5 V, na esquerda é o GND (Terra), o qual está 
conectado ao GND do Arduino. O pino do meio é uma saída analógica que está 
conectada às entradas analógicas do Arduino. Nesse exemplo, utilizaremos as 
entradas A0, A1 e A2. 
O código para resolver esse problema será separado em partes, para 
melhorar a compreensão. 
Figura 11 – Declaração e variáveis e função setup 
 
 
Na Figura 11, as declarações de variáveis são apresentadas. As variáveis 
declaradas na linha 1, temperatura1, temperatura2 e temperatura3 serão usadas 
para receber diretamente a medição de temperatura dos sensores, porém será 
realizada uma conversão para que na variável esteja o valorem graus Celsius. 
 
 
14 
Temp_media1, temp_media2, temp_media3 são as médias das 
temperaturas dos sensores que serão mostradas na serial. 
A variável “num_medida” será usada para indicar quantas leituras foram 
realizadas; caso esse número chegue a 10, deverá ser realiza a média dos 
valores. 
A matriz medidas[3][10] será onde os dados das medições serão 
armazenados. Cada linha dessa matriz registra os dados de um único sensor, 
sendo a linha zero o primeiro sensor, a linha 1 o segundo sensor e a linha 2 o 
terceiro sensor. Como o total de medidas é dez, foram criadas dez colunas de 
dados. Em uma matriz dessas dimensões, não é possível armazenar mais valores 
que dez em cada linha; caso seja necessário armazenar mais dados, deve-se 
declarar a matriz com dimensões maiores. 
A função “setup” é usada apenas para configurar a comunicação serial com 
uma taxa de comunicação de 9.600 bps (bits por segundo). 
 Figura 12 – Aquisição e armazenamento dos dados 
 
 
A Figura 12 mostra o começo da função “loop”; nela são apresentadas as 
linhas 14 a 16, em que há aquisição dos dados pelas entradas analógicas. A 
função “map” converte os valores recebidos, que seriam de 0 a 1.023, para -40 a 
125, que é o intervalo de temperatura que o sensor TMP36 opera. 
Após a aquisição, o valor de temperatura é colocado nas variáveis 
temperatura1, temperatura2 ou temperatura3, dependendo da entrada analógica 
que o sensor está conectado. Nas linhas 18 a 20, os dados de temperatura são 
armazenados, sendo a linha 0 para o primeiro sensor, linha 1 para o segundo 
sensor e linha 3 para o terceiro sensor, organizando, dessa forma, uma linha para 
 
 
15 
cada sensor de temperatura. Após o armazenamento desses dados, a variável 
“num_medida” é incrementada para que seja possível armazenar a próxima leitura 
dos sensores que ocorrerá após um segundo, devido ao “delay(1000)” na linha 
24. 
Figura 13 – Cálculo da média das medições, apresentação no terminal serial e 
zeramento das variáveis 
 
 
Quando a variável “num_medida” atingir o valor 10, indicará que já foram 
realizadas dez medições; nesse caso, o cálculo da média deverá ser realizado. A 
média é calculada por meio do somatório das medições dividido pela quantidade 
de medidas. Por isso o somatório das medidas dos sensores é realizado nas 
linhas 30 a 34. Na linha 30, tem um “loop for” que faz a variável i variar de 0 a 9; 
nas linhas seguintes, temos as variáveis “temp_media1”, “temp_media2” e 
“temp_media3”, tendo seu valor acrescido de uma nova medição – essas linhas à 
linha 31 serão explicadas com mais detalhes para facilitar o entendimento. 
Na linha 31, a variável “temp_media1” está na sentença: 
temp_media1 +=medidas[0][i]; 
 
 
16 
O operador “+=” pode ser traduzido na sentença a seguir. 
temp_media1 = temp_media1+medidas[0][i]; 
Essa sentença indica que a variável “temp_media1” receberá o valor atual 
dela mais o valor de medidas[0][i]. O valor de medidas[0][i] dependerá do valor de 
i; isso indica que o valor dessa variável será na matriz na linha 0 e coluna i. Esse 
valor será adicionado ao valor atual de “temp_media1” e substituirá o valor atual 
da variável. 
Após esse somatório, ocorrerá a divisão por 10 em cada uma das variáveis 
que guarda a média nas linhas de 36 a 38. Em seguida, os valores de média são 
mostrados no terminal serial usando as funções “print” e “println” nas linhas de 41 
a 46. Esse resultado pode ser visto na figura a seguir. 
Figura 14 – Resultado no terminal serial 
 
 
Para finalizar, as variáveis de média “temp_media1”, “temp_media2” e 
“temp_media3”, em conjunto com a variável “num_medida”, foram zeradas para 
que o processo de medição recomece. 
 
 
 
17 
REFERÊNCIAS 
ALVES, W. P. Linguagem e lógica de programação. São Paulo: Érica, 2014. 
ASCENCIO, A. F. G. Fundamentos da programação de computadores. São 
Paulo: Prentice Hall, 2002. 
FORBELLONE, A. L. V. Lógica de programação: a construção de algoritmos e 
estrutura de dados. 3. ed. São Paulo: Prentice Hall, 2005. 
MCROBERTS, M. Arduino básico. São Paulo: Novatec, 2011. 
OLIVEIRA, C. L. V. Arduino descomplicado: aprenda com projetos de eletrônica 
e programação. São Paulo: Érica, 2017.

Continue navegando