Curso Arduino – #3 – UART e Variáveis

 

 

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

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

Como é que o UART funciona?

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

artigo #3

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

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

  • Tx – envio de dados (pino 1);
  • Rx – receção de dados (pino 0).

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

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

Resta-nos a comunicação USB. Infelizmente, esta é uma tarefa bem difícil. Desta forma, geralmente são usados conversores USB-UART, o que simplifica bastante o trabalho. A boa notícia é que não precisa de se preocupar com isso na utilização do Arduino, o conversor já vem integrado na placa.

artigo #3

Portanto, tudo o que precisa de fazer é ligar o Arduino ao computador através do cabo USB (o mesmo que é usado na programação).

Vamos passar para os exemplos práticos. Os dois primeiros apenas requerem ligar o Arduino via USB ao computador. Só iremos adicionar periféricos ao sistema mais tarde.

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

Material necessário:

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

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

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

artigo #3 curso arduino

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

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

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

Trabalho de Casa nº3

Verifique o que acontece quando escolhe velocidades diferentes da configurada no Arduino, no monitor série. Quando é que aparecem erros? Como é que se evidenciam? Como poderá verificar, os erros são bastante característicos, vale a pena fazer a experiência.

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

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

Usando o conhecimento adquirido anteriormente, poderá escrever um sketch que ativa um LED quando uma janela está aberta. É claro que não vamos usar um sensor de abertura de janelas, vamos simular utilizado componentes mais simples. Um botão de pressão vai substituir o sensor e dois LEDs servirão para sinalização.

Material necessário:

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

artigo #3 curso arduino

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

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

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

digitalWrite(8, LOW); //Desligar LEDs
digitalWrite(9, LOW);
}

void loop() {
if (digitalRead(10) == LOW) { //Se o botão for pressionado
digitalWrite(9, HIGH); //Liga o LED verde
digitalWrite(8, LOW); //Desliga o LED vermelho
} else { //Se o botão não for pressionado
digitalWrite(9, LOW); //Desliga o LED verde
digitalWrite(8, HIGH); //Liga o LED vermelho
Serial.println("Atenção! Alarme! A janela está aberta!");
}
}

Vamos verificar como é que o programa está a funcionar! Infelizmente, não está muito bem. A informação de alarme é enviada o tempo todo. Preferimos que seja enviada apenas uma vez. Sabe como mudar isso? Claro, inserindo a função while!

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

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

digitalWrite(8, LOW); //Desligar LEDs
digitalWrite(9, LOW);
}

void loop() {

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

while (digitalRead(10) == HIGH) {
//Criação de um loop vazio para a janela voltar a fechar
delay(25); //Atraso de 25ms dentro do loop para minimizar interferências
}

}
}

Podemos melhorar alguma coisa neste código? Não, mas podemos torná-lo mais elegante!

Instrução #define

Com o tempo, os nossos programas vão aumentar consideravelmente. E se for necessário alterar a conexão física de, por exemplo, um LED ou um botão? Alterar o número do pino de todo o código seria bastante difícil.

A instrução #define ajuda nesse aspeto. Permite que defina um símbolo para um determinado pino, que será substituído pelo número deste antes da compilação, em qualquer local do código. Por exemplo:

#define ledPin 8

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

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

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

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

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

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

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

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

digitalWrite(LEDvermelho, LOW); //Desligar LEDs
digitalWrite(LEDverde, LOW);
}

void loop() {

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

while (digitalRead(Botão) == HIGH) {
//Criação de um loop vazio para a janela voltar a fechar
delay(25); //Atraso de 25ms dentro do loop para minimizar interferências
}

}
}

De agora em diante, só precisará de fazer a alteração de mudança de pino uma vez em todo o código!

Variáveis

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

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

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

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

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

int numero = 30000; //Int - números inteiros no intervalo de -32768 a 32767
long numeroGrande = 2000000; //Long - números inteiros no intervalo de -2147483648 a 2147483647

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

char caractere = 'a'; //Char - caracteres
String frase = "Bem-vindo ao blog ElectroFun!"; //String - sequência de caracteres

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

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

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

Declaração de Variáveis

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

tipo nome = 0;

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

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

int variavel = 0; //Variável global - pode ser usada em qualquer parte do programa

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

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

É normal que, para já, esteja tudo ainda um pouco verde, mas com tempo aprenderá tudo na prática. De início, para facilitar a aprendizagem, usaremos apenas variáveis globais. Os programadores experientes podem não gostar, no entanto, chegaremos a tudo, pouco a pouco.

Há mais um aspeto importante a apontar – denominar as variáveis. Lembre-se de dar nomes às variáveis que determinem o seu propósito. Por exemplo, em vez de:

string xx = "Manuel";

Coloque antes um nome único que identifique a variável:

string nomePessoa = "Manuel";

O problema poderá surgir quando o propósito das variáveis for mais complicado de definir. Não tenha receio de criar nomes como:

int vMotorEsquerdo = 100; //Velocidade do motor esquerdo

O mais importante é tornar o código legível e inteligível!

Exercício Prático – Variáveis

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

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

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

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

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

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

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

Passaremos a explicar o ponto 2, que é o aumento do valor da variável. A instrução utilizada foi a seguinte:

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

Do ponto de vista matemático, onde o sinal “=” significa igualdade, a linha acima não deveria funcionar. No entanto, na programação, o sinal “=” significa atribuição. Na prática, o código acima deve ser entendido como a seguinte operação:

  1. Ir buscar o valor da variável contador;
  2. Somar 1 ao valor recebido;
  3. Receber o resultado da operação e atribuí-lo à própria variável.

Faça o download do programa para o Arduino e confira se está tudo a funcionar corretamente. É claro que, para ver os resultados, deverá abrir o monitor série.

curso arduino

Trabalho de Casa nº4

O que é que acontece quando a declaração de variável é incluída na função loop ()?

Trabalho de Casa nº5

Como mencionado, as variáveis têm as suas limitações. Mude a declaração de variável do contador de int para byte (pode conter números entre 0 e 255). O que é que acontece quando esse valor é excedido?

Transmissão Bidirecional do Arduino

É claro que a comunicação, para ser útil, deve ocorrer de forma bidirecional. Até agora, tem sido o Arduino a enviar-nos informações. Está na hora de lhe respondermos!

O objetivo do primeiro programa é “ouvir” o nosso nome. Quando lhe enviarmos o nome, o Arduino deverá responder com a seguinte mensagem “Olá, Nome!”, onde, obviamente, o nome será o anteriormente enviado.

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

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

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

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

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

curso arduino #3

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

Material necessário:

Neste exercício vamos usar capacidade de enviar texto para o Arduino para controlar LEDs. Para isso, ligue dois LEDs de acordo com o esquema abaixo (LEDs nos pinos 8 e 9):

curso arduino #3

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

#define verde 8
#define vermelho 9

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

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

digitalWrite(verde, LOW); //Desligar LEDs
digitalWrite(vermelho, LOW);
}

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

if (dadosRecebidos == "verde") { //Se escrever a palavra "verde"
digitalWrite(verde, HIGH); //Liga o LED verde
delay(1000); //Espera 1 segundo
digitalWrite(verde, LOW); //Desliga o LED verde
}

if (dadosRecebidos == "vermelho") { //Se escrever a palavra "vermelho"
digitalWrite(vermelho, HIGH); //Liga o LED vermelho
delay(1000); //Espera 1 segundo
digitalWrite(vermelho, LOW); //Desliga o LED vermelho
}
}
}

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

Trabalho de Casa nº6

Edite o código acima, de forma a que, quando é inserida uma cor errada (ex. laranja, azul, preto,…), seja enviada uma mensagem apropriada através do monitor série. Envie-nos a sua solução nos comentários abaixo!

Trabalho de Casa nº7

Este TPC é mais complexo! Escreva um programa que, depois de enviar a cor do LED, mude o seu estado para o oposto. Se o LED estiver aceso, será desligado e vice-versa.

Sumário

Este artigo possui informações fundamentais para programar com Arduino. As variáveis são elementos de programação utilizados em praticamente todos os códigos. Por sua vez, a comunicação UART costuma ser utilizada para exibir informações reunidas e alterar configurações do programa. Também é muito útil para procurar erros nos nossos códigos!

Apesar da grande quantidade de informação, foi uma lição relativamente fácil, mas se ainda tem algumas dificuldades não se preocupe. Com o tempo irá perceber tudo muito melhor!

Para treinar e consolidar alguns conhecimentos, é imperativo que realize os trabalhos de casa propostos! Estamos à espera das suas soluções e dúvidas nos comentários!

___________

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