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

 

 

Neste artigo, vamos abordar vários tópicos. Em primeiro, voltaremos à interface UART, e também discutiremos novas instruções de controlo. Por fim, vamos mostrar uma aplicação prática para o servo.

Antes de ler este artigo, certifique-se que domina os conteúdos presentes nos capítulos anteriores deste curso Arduino gratuito!

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

No terceiro capítulo do curso, usamos a interface UART para comunicação com o computador. Havia funções usadas para transmitir e receber informações. No entanto, não abordamos todas as possibilidades que a função println oferece. Nos exemplos dados até agora, foi usada de uma forma muito simples, com apenas um argumento – número ou frase.

Todos os valores que enviamos para o monitor série nas tarefas propostas, enquadravam-se no sistema decimal. E se nos interessasse enviar, por exemplo, números binários? Temos de criar as nossas próprias funções que alterem a representação de valores para outros sistemas? Claro que não!

Felizmente, as bibliotecas do Arduino contêm vários recursos para os utilizadores. Incluindo suporte para vários sistemas de representação numérica. Quando enviamos um valor através da função println, podemos decidir como é que é exibido no computador:

[...]
int numero = 2345;

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

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

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

Precisão dos Números Não Inteiros

Como discutido no terceiro capítulo do curso, é possível declarar uma variável que armazena um número não inteiro, por exemplo: 3.141592. Até agora, não usamos essa variável, porque é uma boa prática evitar números com uma parte fracionária no uso com microcontroladores.

De qualquer das formas, vamos supor que queremos exibir um número não inteiro. Vejamos o seguinte programa:

void setup() {
float numeroPI = 3.1415; //Declaração de variável

Serial.begin(9600); //Configuração da taxa de transmissão
Serial.println(numeroPI, 4); //4 Casas decimais
Serial.println(numeroPI, 0); //0 Casas decimais

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

void loop() {
}

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

curso arduino - #6 - uart e servos

Como pode ver, existe um parâmetro adicional para definir a precisão dos valores enviados (número de casas decimais). Lembre-se que as variáveis float podem ser representadas com um máximo de 7 dígitos. Por exemplo:

  • float numero1 = 0.123456 
  • float numero2 = 12345.6 
  • float numero3 = 123.456 
  • float numero4 = 1234567.8 ×

Vamos voltar ao código acima por um momento, especificamente para a seguinte linha misteriosa:

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

Por que é que este comando enviou o número 3,14? Nós não declaramos tal variável em lugar nenhum. A verdade é que o valor do número Pi é tão usado que, em muitas linguagens pode encontrar constantes “prontas”. Neste caso, qualquer local do código com “PI” escrito, será transformado no valor apropriado da constante.

Se precisar de uma maior precisão no seu programa, pode sempre escrever a seguinte função:

Serial.print(PI, 25);

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

3.1415927410125732421875000

De qualquer das formas, voltemos à precisão máxima que os microcontroladores oferecem. A constante PI possui propriedades da variável float, ou seja, aceita, no máximo, 7 dígitos! Cada dígito subsequente está errado, porque o registo mais preciso de valores não inteiros no sistema binário, não permite obter o verdadeiro valor de Pi.

Vejamos o valor exibido anteriormente e o verdadeiro valor de Pi:

Valor exibido = 3.1415927410125732421875000

π = 3,1415926535897932384626433

Função Serial.print()

Até agora, cada valor enviado para o monitor série, apareceu em diferentes linhas. Tornou o programa claro, mas nem sempre é útil. E se quisermos exibir várias variáveis e textos lado a lado? Usamos a função que temos usado – Serial.println() – mas sem o “ln” no final – Serial.print().

Tem exatamente a mesma função que a anterior, com a diferença de não mudar de linha. Exemplo:

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

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

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

curso arduino - #6 - uart e servos

Como é que pode criar uma nova linha quando pretendido? Existem 3 formas:

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

OU

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

OU

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

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

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

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

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

Material necessário:

De início, faça todas as conexões necessárias. Vamos usar o potenciómetro para regular a tensão.

curso arduino - #6 - uart e servos

Esperamos que não tenha sido demasiada informação de uma vez, e que tenha percebido tudo. De qualquer das formas, preparamos o código para o ajudar. O que é pretendido é que analise e compreenda o programa e, depois, escreva um semelhante!

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

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

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

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

Depois de executar o programa, no monitor série, deve observar os valores dados pelo ADC bem formatados e em diferentes sistemas numéricos:

curso arduino - #6 - uart e servos

Encorajamos-vos a criar o vosso próprio programa. Também é uma ótima oportunidade para praticar a conversão manual de números para vários sistemas.

Acabámos o conteúdo UART. Vamos continuar para a parte seguinte!

Trabalho de Casa nº17

Escreva um programa que leia a informação de dois LDR e de um potenciómetro. Depois de pressionar um botão, deverá enviar uma linha com a seguinte informação:

“LDR 1: XXX, LDR 2: XXX, Potenciómetro: XXX, Botão pressionado XX vezes”

Os X deverão indicar os valores apropriados.

Função Switch()

Vamos agora abordar a função de controlo switch, usada muito frequentemente. É aplicada em situações em que, com base numa variável, são realizadas várias ações diferentes, dependendo do valor fornecido.

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

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

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

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

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

if(Serial.available() > 0) { //Se o Arduino recebeu dados
dadosRecebidos = Serial.readStringUntil('\n'); //Lê até ao final da linha
}

if (dadosRecebidos == "d") {
Serial.println(potenciometro, DEC);
} else if (dadosRecebidos == "h") {
Serial.println(potenciometro, HEX);
} else if (dadosRecebidos == "o") {
Serial.println(potenciometro, OCT);
} else if (dadosRecebidos == "b") {
Serial.println(potenciometro, BIN);
}

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

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

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

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

[...]

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

No início, escrevemos a palavra-chave switch e, dentro dos parênteses, indicamos a variável que queremos verificar. Em seguida, abrimos chavetas. Dentro delas, pode inserir qualquer número de condições que serão verificadas sucessivamente. Fazemos isso ao escrever a palavra case. Depois do espaço colocamos um valor, que deve ser igual à variável que pretendemos verificar. Terminámos com dois pontos “:”.

Se a condição for atendida, o código será executado até ao break seguinte. Quando a condição não é atendida, parte do código é ignorada e o microcontrolador passa a verificar a próxima condição (case).

No final, opcionalmente, podemos colocar um código entre default e break. Este será executado quando nenhuma das condições anteriores tiver sido verificada.

Percebemos que possa parecer complicado, e é por isso que vamos passar para o exemplo prático e vamos transformar o programa anterior.

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

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

if(Serial.available() > 0) { //Se o Arduino receber dados
dadosRecebidos = Serial.read(); //Se sim, lê apenas 1 sinal
}

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

delay(1000);
}

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

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

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

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

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

Graças a isto, pudemos comparar comandos transmitidos e realizar operações apropriadas. Esperamos que a função switch esteja mais clara agora!

Trabalho de Casa nº18

Volte ao trabalho de casa nº6, que se encontra no terceiro capítulo do curso, e faça o mesmo exercício utilizando a função switch.

Exercício Prático de Servomecânica – Indicador de luz

Vamos agora passar ao exercício prático prometido com uso do servo motor. Atualmente, há cada vez mais informações apresentadas em formato digital, ou seja, no display. No entanto, alguns valores, como temperatura, intensidade de luz, etc., ficam melhor apresentados em indicadores analógicos. Por exemplo:

curso arduino - #6 - uart e servos

Portanto, vamos construir um indicador de luz usando um micro servo. O braço do servo irá indicar a quantidade de luz que o sensor recebe.

Material necessário:

O diagrama de montagem do sistema é o seguinte:

curso arduino - #6 - uart e servos

É um pouco confuso, mas consiste em dois esquemas simples. O primeiro é ligar o servo ao regulador de tensão. Além disso, são colocados dois condensadores ao lado do LM7805. Pode encontrar esquema semelhante no capítulo anterior do curso.

A segunda parte do diagrama é a ligação do sensor de luz e da resistência. Pode encontrar mais informações sobre esta ligação no artigo #4.

Está na hora de pensar no design do indicador de luz! Pode fazer uma escala em cartão como a da imagem abaixo.

curso arduino - #6 - uart e servos

O programa é relativamente simples. O seu objetivo é medir periodicamente a luz incidente no LDR e controlar o movimento do servo em função disso. Neste código foram usadas, principalmente, as funções aprendidas anteriormente.

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

Servo servomecanismo; //Declaração do servo como servomecanismo
byte posicao = 0; //Posição atual do servo entre 0 e 180 graus
int posicaoAnterior = 0;

void setup() {
servomecanismo.attach(11); //Servo ligado ao pino 11
Serial.begin(9600);
}

void loop()
{
int leituraSensor = analogRead(A5); //Ler valor do sensor LDR
posicao = map(leituraSensor, 0, 900, 0, 180); //Dividir escala

if (abs(posicao-posicaoAnterior) > 5) { //Se diferir em mais de 5 graus
servomecanismo.write(posicao); //Realiza movimento
posicaoAnterior = posicao; //Declarar a posição atual como a anterior
}

Serial.println(leituraSensor); //Enviar valor da leitura para o monitor série
delay(300); //Atraso para melhor efeito
}

Passamos a explicar a função abs (). É muito útil em situações como esta, porque envia um valor absoluto. Portanto, dará sempre um resultado positivo.

O efeito do código pode ser observado na imagem abaixo. O sensor foi tapado e, depois, iluminado gradualmente com uma lanterna.

curso arduino

Trabalho de Casa nº19

Aperfeiçoe o sistema acima e encontre outras aplicações para ele!

Trabalho de Casa nº20

Insira nos comentários uma fotografia do indicador que realizou.

Sumário

Esta parte complementar foi bastante longa. No entanto, esperamos que tenha sido útil. Ficámos à espera que nos enviem as fotografias do vosso indicador de luz!

___________

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