Curso Arduino – #10 – Gráficos, Números Aleatórios e Condições

 

 

Chegamos ao último artigo do Curso Arduino! Neste, vamos abordar alguns aspetos que vão melhorar a programação: combinação de condições e números aleatórios. Também vamos ver como é fácil apresentar a informação enviada para o PC na forma de um gráfico!

Desenho de Gráficos

O Arduino IDE possui uma característica muito conveniente que permite desenhar rapidamente diagramas a partir das informações enviadas via UART. Para usar esta ferramenta, tem de ter o IDE atualizado. Se não tiver, atualize-o antes de continuar. Deverão aparecer, na secção Ferramentas, as seguintes opções: Monitor Série e Plotter Série.

curso arduino - #10 - graficos

Para desenhar um gráfico, devemos, de preferência, enviar os números para o computador em diferentes linhas. Primeiramente, vamos criar um sistema que desenhe um gráfico da tensão medida na entrada A5, à qual ligamos um potenciómetro.

Material necessário:

O diagrama de ligação é o seguinte:

curso arduino - #10 - gráfico

A versão normal do programa a enviar informações para o monitor série seria a seguinte:

int dadosRecebidos = 0;

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

void loop() {
dadosRecebidos = analogRead(A5); //Leitura do valor da tensão
Serial.println(dadosRecebidos); //Envio para o monitor série
delay(200); //Atraso para melhor efeito
}

Ao usar a opção “Monitor Série”, quando rodar o seu potenciómetro verá o seguinte efeito:

Pouco legível, não acha? Agora abra o “Plotter Série”. Muito melhor, certo? Os dados recebidos são apresentados num gráfico, como podemos ver no vídeo abaixo:

Quando é que esta opção é útil na prática? Quando usamos sensores (distância, temperatura, etc.), claro! No artigo anterior abordamos o sensor de distância ultrassónico HC-SR04. Vamos tentar desenhar um gráfico da distância medida!

Exercício Prático – Gráfico da Distância de um Obstáculo

Para isto, voltamos ao diagrama do artigo anterior:

curso arduino - #9 - hc-sr04

Também executamos o código escrito no artigo anterior. Só precisa fazer duas alterações. A primeira é exibir o resultado numa nova linha sem referência à unidade de medida. A segunda é aumentar a frequência das medições – graças a isso, o gráfico será mais fluido.

#define trigPin 12
#define echoPin 11

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

void loop() {
long tempo, distancia;

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

tempo = pulseIn(echoPin, HIGH);
distancia = tempo / 58;

Serial.println(distancia);
delay(100);
}

Vamos então desenhar o gráfico! Este às vezes funciona bem, mas outras vezes não. Quando usamos este tipo de sensores, corremos o risco de receber alguma interferência. Neste caso, pode causar o envio de medições incorretas para o computador. A imagem abaixo mostra medições acima dos 2400cm, o que é impossível, sendo que o fabricante indica que o sensor tem como valor de medição máximo 400cm.

curso arduino - #10 - gráficos

Isto resulta da seleção automática da escala do gráfico. Como solucionar o problema? Vamos adicionar uma condição que irá verificar o valor enviado para o computador:

if (distancia > 400) { //Se a distância medida for maior do que 400cm
distancia = 400; //Definir distância como 400cm (valor máximo indicado pelo fabricante)
}

Graças a esta função, nunca mais será enviada uma medição acima do valor máximo do sensor. Vejamos o programa completo:

#define trigPin 12
#define echoPin 11

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

void loop() {
long tempo, distancia;

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

tempo = pulseIn(echoPin, HIGH);
distancia = tempo / 58;

if (distancia > 400) { //Se a distância medida for maior do que 400cm
distancia = 400; //Definir distância como 400cm (valor máximo indicado pelo fabricante)
}

Serial.println(distancia);
delay(100);
}

Agora, o gráfico apresentará sempre valores dentro da faixa de medição do sensor:

Exercício Prático – Gráficos com Vários Valores

Esta característica de desenho de gráficos também permite incluir diversos valores de uma só vez. Para usufruir desta opção, deve enviar números na mesma linha separados por um caracter tab. O caracter para início de uma nova linha, deverá aparecer no final.

Na prática, o código é este:

Serial.print(valor1);
Serial.print("\t"); // Tab
Serial.print(valor2);
Serial.print("\t"); // Tab
Serial.print(valor3);
Serial.print("\t"); // Tab
Serial.print(valor4);
Serial.println(""); // Transição para nova linha

Trabalho de Casa nº32

Use, na prática, a capacidade de desenhar vários gráficos ao mesmo tempo. Ligue dois sensores LDR ao Arduino. De seguida, meça o nível de luz que cada um deles recebe. Ambos os valores devem ser apresentados num gráfico.

Números Aleatórios

Às vezes pretendemos que um programa funcione de forma imprevisível. Um exemplo? Um robot que, depois de detetar um obstáculo, roda para um lado de forma aleatória.

Neste tipo de situações, uma função que envia um valor aleatório é bastante útil. A função random () é responsável por enviar um valor aleatório, e pode conter dois argumentos. Graças a eles, definimos o intervalo dos números a serem enviados. Na prática, a função usada frequentemente de duas formas. Indicação do limite superior:

random(500); //Número aleatório no intervalo de 0 a 499

Indicação dos limites inferior e superior:

random(100, 500); //Número aleatório no intervalo de 100 a 499

Vamos agora verificar a função na prática. Para isso, copie o seguinte código. O seu objetivo é enviar números aleatórios para o monitor série a cada segundo.

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

void loop() {
Serial.println(random(300));
delay(1000);
}

Como esperado, no monitor série verá o seguinte:

curso arduino - #10 - números aleatórios

Vamos fazer uma experiência: reinicie o programa várias vezes e veja o que acontece. Já deve ter reparado que os números são sempre iguais. Infelizmente, recebemos a mesma string de números de todas as vezes que reiniciamos o programa. Neste sentido, a “aleatoriedade não é totalmente aleatória”. O microcontrolador da placa Arduino é um sistema muito preciso que realiza operações programadas. Não existem valores aleatórios no seu mundo.

A fim de melhorar o funcionamento do algoritmo de aleatoriedade, vamos utilizar uma nova função: randomSeed (). Com esta função, os números gerados vão ser determinados pelo valor inicial – seed. Vejamos a utilização desta:

randomSeed(valor_inicial);

No argumento, que está indicado como valor_inicial, deve inserir um número aleatório. É um pouco confuso… Para gerar valores aleatórios, é necessário um valor aleatório. Sabe como obtê-lo? Se não, reveja o artigo sobre o Conversor Analógico-Digital.

O que é que acontece se nenhum sinal estiver ligado à entrada a ser lida? Recebe interferências do ambiente, que são aleatórias. Até agora, era um problema para nós, mas encontramos um propósito para isso. Desta forma, para recebermos números “mais aleatórios”, vamos colocar a seguinte linha:

randomSeed(analogRead(A0));

Graças a ela, cada vez que o programa é iniciado, existe uma medição da tensão na entrada A0. De seguida, esse valor será fornecido como seed ao gerador de números pseudoaleatórios.

Aqui está o código completo. Vamos testá-lo.

void setup() {
Serial.begin(9600);
randomSeed(analogRead(0));
}

void loop() {
Serial.println(random(300));
delay(1000);
}

De agora em diante, de cada vez que iniciar o programa, obterá valores diferentes:

Claro que ainda não é um gerador de números aleatórios perfeito, mas é suficiente para o uso em projetos Arduino.

Trabalho de Casa nº33

Verifique o que acontece se, em vez de fornecer a leitura da entrada analógica como seed, fornece um valor fixo. Como é que o gerador de números pseudoaleatórios vai reagir?

Trabalho de Casa nº34

Escreva um programa que funciona como um dado eletrónico. Ligue um botão de pressão ao Arduino. Cada vez que pressionar o botão, deve enviar para o computador (via UART) um valor compreendido entre 1 e 6.

Exercício Prático – Piscar do LED Aleatório

Vamos usar o conhecimento adquirido anteriormente para escrever um programa, que tenha como objetivo piscar o LED do pino 13 de forma aleatória. Vamos assumir que o tempo que o LED está ligado varia entre 100ms e 990ms. E o tempo que está desligado entre 50ms e 490ms. Ambos os valores devem mudar em intervalos de 10ms. Para isto, vamos precisar de dois valores aleatórios:

int tempoLigado = random(100, 1000);
int tempoDesligado = random(50, 500);

Poderíamos colocar estes valores na função delay, mas o atraso poderia assumir qualquer valor de 100 a 999, ou seja, não íamos respeitar os intervalos de 10ms. Como solucionar? Tudo o que temos de fazer é inserir valores 10 vezes menores, que serão multiplicados por 10 antes de substituí-los pela função delay:

int tempoLigado = random(10, 100); //Valor varia entre 10 e 99
int tempoDesligado = random(5, 50); //Valor varia entre 5 e 49

tempoLigado = tempoLigado * 10; //Valor varia entre 100 e 990, a cada 10ms
tempoDesligado = tempoDesligado * 10; //Valor varia entre 50 e 499, a cada 10ms

Assim, podemos finalizar o código:

void setup() {
pinMode(13, OUTPUT);
randomSeed(analogRead(0));
}

void loop() {
int tempoLigado = random(10, 100); //Valor varia entre 10 e 99
int tempoDesligado = random(5, 50); //Valor varia entre 5 e 49

tempoLigado = tempoLigado * 10; //Valor varia entre 100 e 990, a cada 10ms
tempoDesligado = tempoDesligado * 10; //Valor varia entre 50 e 499, a cada 10ms

digitalWrite(13, HIGH);
delay(tempoLigado);
digitalWrite(13, LOW);
delay(tempoDesligado);
}

Na prática, o piscar do LED será totalmente aleatório!

Combinação de Funções Condicionais

No início do curso Arduino, abordamos a função condicional if, que é usada para controlar o programa dependendo de uma determinada condição. Na maioria das vezes, utilizamos apenas uma condição, por exemplo: “O botão foi pressionado?”. Todavia, na prática, pode acontecer que queira verificar duas condições simultaneamente. O exemplo mais simples é verificar se o utilizador pressionou mais do que um botão. É claro que, pode fazê-lo tradicionalmente:

if (digitalRead(7) == LOW) { //Se o primeiro botão for pressionado, verificar...
if (digitalRead(8) == LOW) { //... se o segundo botão foi pressionado
//Realizar determinada ação
}
}

A solução é eficaz, mas terá alguns problemas em perceber o código, principalmente se quiser incluir mais condições. Portanto, é muito mais fácil quando utilizamos os seguintes operadores lógicos:

  • Produto lógico – &&
  • Soma lógica – ||

Usamos o primeiro quando queremos verificar se a primeira e a segunda condição foram atendidas:

if (condicao1 ==1 && condicao2 ==1)

O segundo é usado quando queremos verificar se a primeira condição foi atendida ou se a segunda condição foi atendida (ou as duas):

if (condicao1 == 1 || condicao2 == 1)

Exercício Prático – Combinação de Condições

Material necessário:

Para este propósito, ligue dois LEDs (vermelho e verde) e dois botões ao Arduino. O diagrama de montagem é o seguinte:

curso arduino - #10 - combinação de condições

Agora, escreva um programa que ligue o LED verde quando pressiona um dos botões de pressão. O código poderá ser o seguinte:

void setup() {
pinMode(10, INPUT_PULLUP); //Botão como entrada
pinMode(9, INPUT_PULLUP); //Botão como entrada

pinMode(8, OUTPUT); //LED como saída
pinMode(7, OUTPUT); //LED como saída

digitalWrite(8, LOW); //Desligar LED verde
digitalWrite(7, LOW); //Desligar LED vermelho
}

void loop() {
if (digitalRead(9) == LOW || digitalRead(10) == LOW) { //Se o primeiro ou o segundo botão forem pressionados
digitalWrite(8, HIGH); //LED verde liga
} else {
digitalWrite(8, LOW); //LED verde desliga
}
}

A parte mais importante deste código é a função que verifica os estados dos dois botões. Se pelo menos um deles for pressionado, o LED verde acende.

Vamos expandir o programa e criar uma condição que ligue o LED vermelho quando os dois botões forem pressionados simultaneamente:

void setup() {
pinMode(10, INPUT_PULLUP); //Botão como entrada
pinMode(9, INPUT_PULLUP); //Botão como entrada

pinMode(8, OUTPUT); //LED como saída
pinMode(7, OUTPUT); //LED como saída

digitalWrite(8, LOW); //Desligar LED verde
digitalWrite(7, LOW); //Desligar LED vermelho
}

void loop() {
if (digitalRead(9) == LOW || digitalRead(10) == LOW) { //Se o primeiro ou o segundo botão forem pressionados
digitalWrite(8, HIGH); //LED verde liga
} else {
digitalWrite(8, LOW); //LED verde desliga
}

if (digitalRead(9) == LOW && digitalRead(10) == LOW) { //Se os dois botões forem pressionados simultaneamente
digitalWrite(7, HIGH); //LED vermelho liga
} else {
digitalWrite(7, LOW); //LED vermelho desliga
}
}

 

Exercício Prático – Sensor de Distância Ultrassónico

Os exemplos acima mostraram o funcionamento do sistema, mas não são exemplos propriamente úteis. Vamos tentar fazer algo mais prático. Ligue ao Arduino um botão de pressão, um sensor de distância ultrassónico HC-SR04 e um buzzer. O sistema irá emitir um som se um obstáculo estiver entre 20 e 40 cm do sensor ou se pressionar o botão de pressão.

Material necessário:

Primeiro, temos de fazer as conexões necessárias. Para tornar o exercício mais complexo, desta vez não vamos fornecer diagrama de montagem. Vamos sim, indicar uma lista de conexões a realizar e mostrar uma imagem auxiliar. Por esta altura do curso, já todos devem conseguir fazer as ligações sem qualquer problema.

Lista de conexões:

  1. Ligar pino trigger do sensor ao pino 12 do Arduino;
  2. Ligar pino echo do sensor ao pino 9 do Arduino;
  3. Ligar buzzer ao pino 11 do Arduino;
  4. Ligar botão ao pino 10 do Arduino.

Adicionalmente, deverá fazer as ligações para alimentação e GND. Vejamos a imagem ilustrativa:

Curso Arduino - #10 - Gráficos, números aleatórios e condições

Vamos passar à programação. Nós já conseguimos ler a distância e verificar o status do botão já não é um problema. Portanto, vamos focar-nos na análise da condição. Como foi referido, pretendemos ativar o buzzer quando um obstáculo estiver entre 20 e 40 cm do sensor. Para isso, temos de verificar se o valor lido pelo sensor é maior do que 20 cm e, ao mesmo tempo, menor do que 40 cm. Fazemo-lo numa condição:

if (distancia > 20 && distancia < 40) {
digitalWrite(11, HIGH); //Ativar buzzer
} else {
digitalWrite(11, LOW); //Desativar buzzer
}

Vamos passar para o botão. É claro que podemos utilizar duas condições:

if (distancia > 20 && distancia < 40) {
digitalWrite(11, HIGH); //Ativar buzzer
} else {
digitalWrite(11, LOW); //Desativar buzzer
}

if (digitalRead(10) == LOW) { //Se o botão for pressionado
digitalWrite(11, HIGH); //Ativar buzzer
} else {
digitalWrite(11, LOW); //Desativar buzzer
}

Mas, para quê? Se o objetivo das duas condições é igual, não as podemos juntar? Claro que podemos! Assim, o que pretendemos verificar é:

(a distância medida é maior do que 20 cm e menor do que 40 cm) ou (o botão é pressionado)

Traduzindo isto para a linguagem C:

if ((distancia > 20 && distancia < 40) || digitalRead(10) == LOW) {
digitalWrite(11, HIGH); //Ativar buzzer
} else {
digitalWrite(11, LOW); //Desativar buzzer
}

O código completo é o seguinte:

#define trigPin 12
#define echoPin 9

void setup() {
pinMode(trigPin, OUTPUT); //Definição do pino 12 como saída
pinMode(echoPin, INPUT); //Definição do pino 9 como entrada

pinMode(10, INPUT_PULLUP); //Botão como entrada
pinMode(11, OUTPUT); //Buzzer como saída

digitalWrite(11, LOW); //Desligar buzzer
}

void loop() {
long tempo, distancia;

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

tempo = pulseIn(echoPin, HIGH);
distancia = tempo / 58;

if ((distancia > 20 && distancia < 40) || digitalRead(10) == LOW) {
digitalWrite(11, HIGH); //Ativar buzzer
} else {
digitalWrite(11, LOW); //Desativar buzzer
}
}

Na prática, o programa funciona exatamente como previsto.

Trabalho de Casa nº35

Escreva um programa que escolha aleatoriamente um número de 0 a 100, e verifique se esse valor é/está:

  1. Menor do que 10 ou maior do que 90;
  2. Maior do que 50, mas que não se encontre dentro do intervalo 70-85;
  3. Igual a 20, 30, 40 ou 50;
  4. Incluído no intervalo 10-40 ou 60-100.

Em cada alínea, envie o número escolhido para o monitor série e indique se cumpriu ou não a condição.

Sumário do Curso Arduino!

É verdade, chegamos ao fim do curso. Tudo o que tínhamos planeado abordar, já foi mencionado. Esperamos que os conhecimentos adquiridos ao longo do curso sejam de grande utilidade para os vossos próximos projetos. Mal podemos esperar por ver as vossas invenções! Obrigado por frequentarem o nosso curso e continuação de bons projetos!

___________

O que achou deste artigo? Deixe o seu comentário abaixo, e partilhe nas Redes Sociais que certamente será útil e interessante para os seus amigos!

 

 

 

 Curso Arduino – #0 – Introdução

 Curso Arduino – #1 – O Básico do Arduino e o Software de Programação

 Curso Arduino – #2 – O Básico da Programação e as Portas I/O

 Curso Arduino – #3 – UART e Variáveis

 Curso Arduino – #4 – Conversor Analógico-Digital

 Curso Arduino – #5 – PWM, Servomecanismos e Bibliotecas

 Curso Arduino – #6 – UART (continuação) e Servos

 Curso Arduino – #7 – Displays

 Curso Arduino – #8 – Controlo de Motores DC

 Curso Arduino – #9 – Sensor de Distância Ultrassónico HC-SR04 e Novas Funções

 Curso Arduino – #10 – Gráficos, Números Aleatórios e Condições