Entrada e Saída - Manipulando Registradores

Entrada e Saída - Manipulando Registradores

Para determinar os estados de suas entradas e saídas o microcontrolador possui registradores na qual esses dados são armazenados. Ao chamar as funções de entrada e saída fornecidas pela biblioteca padrão do Arduino o que fazemos é nada mais que modificar tais registradores. Então porque acessar estes registradores diretamente?

A manipulação direta de registradores permite que:

  • A leitura e escrita em pinos seja feita muito mais rápida.
  • Ler e escrever em mais de um pino de uma mesma porta por vez.
  • O código produzido é menor, em alguns casos esse fator pode fazer a diferença entre seu código caber na memória flash ou não.

Essa técnica também possuí desvantagens:

  • O código produzido é menos portável, difícil de debbugar e de ser mantido.

Na abordagem dos conceitos a seguir o microcontrolador atmega328 presente na placa Arduino Uno será utilizado. Para acompanhar esse tutorial é necessário algum conhecimento de lógica digital.

Todos os registradores desse microcontrolador possuem 8 bits. Os pinos de entrada e saída são divididos em PORTs. O atmega328 possui 3 PORTs, como podemos observar no diagrama a seguir:

Cada PORT possui 3 registradores com diferentes funções:

DDR

Os registradores do tipo DDR (Data Direction Register) são responsáveis por determinar se os pinos de um determinado PORT se comportarão como entrada ou saída. Cada bit do registrador DDR controla o estado do respectivo pino. Por exemplo: O bit 1 do registrador DDRB (DDB1) controlará o estado do pino PB1 e consequentemente o pino D9 do Arduino Uno como mostrado no mapa.

Para definir um pino como saída devemos setar seu respectivo bit do registrador DDR como 1 e  para defini-lo como entrada seta-lo para 0.

/* Equivalente:
pinMode(9,OUTPUT);
pinMode(9,INPUT);
*/

DDRB |= (1 << DDB1);
DDRB &= ~(1 << DDB1);

PORT

Os registradores do tipo PORT são responsáveis por determinar se um pino está definido como alto (HIGH) ou baixo (LOW).

portb

Para definir um pino como alto devemos setar seu respectivo bit do registrador PORT como 1 e para defini-lo como baixo seta-lo para 0.

 

/* Equivalente:
pinMode(9,OUTPUT);
digitalWrite(9,LOW);
*/
 
DDRB |= (1 << DDB1);
PORTB &= ~(1 << PORTB1);

Outro exemplo:

/* Equivalente:
digitalWrite(8,HIGH);
digitalWrite(9,HIGH);
digitalWrite(10,HIGH);
digitalWrite(11,HIGH);
digitalWrite(12,HIGH);
digitalWrite(13,HIGH);
*/
 
PORTB = 0xFF;

 

PIN

Os registradores do tipo PIN são responsáveis por guardar o estado lógico de um pino.

/* Equivalente:
pinMode(9,INPUT);
digitalWrite(9,HIGH); //Nesse contexto, ativa o pull-up interno.
bool x = digitalRead(9);
*/
 
DDRB &= ~(1 << DDB1);
PORTB |= (1 << PORTB1);
bool x = (PINB & (1 << PINB1));
Todo o conteúdo apresentado pode ser encontrado no datasheet do microcontrolador.

Arduino - Entradas e Saídas Digitais - Pinos digitais

Arduino - Entradas e saídas digitais - Pinos digitais

Nesse tutorial daremos prosseguimento aos conceitos básicos para aqueles que desejam aprender como utilizar uma placa Arduino. Este conteúdo será voltado para ensinar como configurar e manipular as entradas e saídas digitais em uma placa Arduino, de modo que, no decorrer deste material você aprenderá a desenvolver programas capazes de fazer com que o seu Arduino realize o acionamento de um led e também com que ele consiga saber se um botão, por exemplo, foi pressionado. Entretanto, sugerimos que, antes de acompanhar este conteúdo, você veja nosso tutorial sobre grandezas digitais, analógicas e PWM, para que então, possa extrair o máximo de informação daqui. 

[toc]

Pinos de entrada e saída digital

Primeiramente, deve-se ter em mente que, quando falamos em entradas ou saídas digitais em uma placa Arduino, estamos falando de elementos que trabalham apenas dois níveis de tensão definidos. No caso do Arduino UNO, por exemplo, estes são:

  • Um nível lógico alto, correspondente a 5V;
  • Um nível lógico baixo, correspondente a 0V.

É importante ressaltar que na prática existem faixas de valores próximos a esses números em que o circuito digital entende como nível alto ou baixo e da mesma forma, existe também uma faixa intermediária não definida que pode gerar resultados inesperados e que, portanto, deve ser evitada.

Em um Arduino UNO, as entradas e saídas digitais estão localizadas desde pino 0 até o pino 13. Note que, estes pinos devem ser configurados previamente para que atuem como entradas ou saídas (é importante ressaltar que alguns destes pinos possuem funções especiais, no entanto, isto será tratado em outros tutoriais. Neste momento basta salientar a função destes enquanto entradas e saídas digitais).


Hardware para o desenvolvimento dos projetos

Nas próximas seções deste tutorial serão desenvolvidos 3 exemplos à respeito da utilização das entradas e saídas digitais. Para simplificar, iremos propor o mesmo hardware para executar todas as propostas de projetos citadas, pois, desta forma o leitor poderá aprender os conceitos de maneira mais fácil. Os projetos que serão desenvolvidos são:

  • Acionando um led através de uma saída digital
  • Piscando um led
  • Realizando a leitura de um botão através de uma entrada digital

Componentes utilizados

Montagem do projeto

Placa Arduino Uno - Uso de entradas e saídas digitais
Esquema de montagem da placa Arduino para desenvolvimento do projeto

Veja o nosso como ficou:

Placa Arduino Uno - Uso de entradas e saídas digitais
Circuito montado com uma Placa Arduino Uno

Entendendo o hardware

A função do hardware apresentado anteriormente consiste em criar o cenário propicio para que possamos ensinar o básico que você precisa aprender para poder utilizar um Arduino UNO.

Primeiramente, perceba que, na montagem em questão, temos um led ligado através de um resistor ao pino 10 do Arduino UNO, de modo que, este resistor é colocado para limitar a corrente que passa pelo led, evitando assim, um eventual problema com os componentes. Observe que quando o pino 10 disponibiliza um potencial de 5V em seu terminal, o circuito será fechado, proporcionando o acionamento do led.

Pino digital do Arduino Uno trabalhando como saída
Pino digital do Arduino Uno trabalhando como saída

Em seguida, lembre-se que o hardware utilizado também possui um botão que ao ser pressionado estabelecerá um potencial de 5V no pino 9 do Arduino UNO. Em contrapartida, caso o botão permaneça sem ser pressionado a porta de entrada digital estará com um potencial de 0V. Dessa forma é importante usarmos aqui um resistor de pull-down de 10kΩ(explicado com mais detalhes no nosso artigo sobre grandezas digitais, analógicas e PWM).

Pino digital do Arduino Uno trabalhando como entrada
Pino digital do Arduino Uno trabalhando como entrada

Projeto 1: Acionando um led através de uma saída digital

Neste projeto ensinaremos a você como proceder para utilizar uma saída digital para acionar algum dispositivo através da mesma.

Código do projeto

Segue o código para ser utilizado no Arduino para realizar o acionamento de uma saída digital

void setup() 
{ 
    pinMode(10,OUTPUT);
    digitalWrite(10,HIGH); 
} 

void loop() 
{
 
}

Entendendo o software

- Definindo as configurações iniciais

O primeiro passo para realizar qualquer tipo de interação utilizando um dos pinos de entrada/saída digital consiste em determinar o modo de operação do mesmo. Como queremos acender um led, devemos fazer com que o pino em que o mesmo está conectado se comporte como uma saída digital. Para isso, dentro da função setup() (lembre-se que a esta função é executada somente quando o Arduino UNO é iniciado e apenas uma vez) utiliza-se a função pinMode(), onde os parâmetros passados para a mesma são: o número do pino a ser utilizado e o modo de operação do mesmo (neste caso, definimos o pino 10 como uma saída digital através da palavra OUTPUT).

pinMode(10,OUTPUT);

- Realizando o acionamento

Depois de definirmos o pino 10 como saída digital, deve-se fazer com que o Arduino UNO coloque o mesmo em nível alto, ou seja, que disponibilize 5V na saída em questão. Para realizar este procedimento, utiliza-se a função digitalWrite() (assim como a função pinMode(), esta também possui dois parâmetros, onde o primeiro corresponde ao pino que terá seu estado alterado e o segundo corresponde ao nível que será disponibilizado na saída, HIGH para nível alto e LOW para nível baixo).

digitalWrite(10,HIGH);

Neste projeto não é necessário utilizar a função loop() (apesar de vazia, ela deve estar presente no código), pois, o conteúdo da função setup() é suficiente para cumprir o objetivo proposto.


Projeto 2: Piscando um led

Assim como no projeto anterior, este terá como objetivo acionar um led, porém, de maneira temporizada, fazendo com que o mesmo permaneça aceso somente por alguns instantes.

Código do projeto

Segue o código a ser utilizado no Arduino para piscar um led.

void setup() 
{ 
    pinMode(10,OUTPUT);
} 

void loop() 
{
    digitalWrite(10,HIGH); 
    delay(1000);
    digitalWrite(10, LOW);
    delay(1000);
}

Entendendo o software

- Definindo as configurações iniciais

Assim como no projeto anterior, o primeiro procedimento a ser realizado neste momento consiste em configurar o modo de operação do pino utilizado, de modo que, para isso, utiliza-se a função pinMode() para definir o mesmo como uma saída digital. Como dito anteriormente, este é apenas um procedimento de configuração, portanto, está inserido na função setup().

void setup() 
{ 
    pinMode(10,OUTPUT);
}

- Realizando o ciclo de acionamentos do led

Como sabemos, o conteúdo da função loop() executado repetidamente do início ao fim. A primeira linha de código existente no conteúdo citado consiste na função digitalWrite(), que por sua vez, é utilizada para acionar o led.

digitalWrite(10,HIGH);

Em seguida, utiliza-se a função delay() para fazer com que o programa espere um determinado tempo (este tempo é passado como parâmetro da função e é no formato de milissegundos) antes de prosseguir com a execução das próximas linhas de código.

delay(1000);

Posteriormente, voltamos a utilizar a função digitalWrite(), porém para desligar o led.

digitalWrite(10, LOW);

E por fim, recorremos uma segunda vez à função delay() para que o ciclo não seja reiniciado de maneira abrupta.

delay(1000);

Veja como ficou nossa função loop():

void loop() 
{
    digitalWrite(10,HIGH); 
    delay(1000);
    digitalWrite(10, LOW);
    delay(1000);
}

Projeto 3: Realizando a leitura de um botão através de uma entrada digital

Neste projeto será demonstrado como você deve proceder para realizar a leitura do estado de uma entrada digital. Nestes casos torna-se possível, por exemplo, determinar o estado de um push-button, ou seja, através da leitura do pino (configurado como uma entrada digital) no qual o mesmo está conectado, pode-se determinar se este foi pressionado ou não.

Código do projeto

Segue o código a ser utilizado no Arduino para ler o estado de uma entrada digital, acender um led caso o botão seja pressionado e mantê-lo aceso por 2 segundos.

void setup() 
{ 
  pinMode(10,OUTPUT);
  pinMode(9,INPUT); 
}

void loop() {
  
  if(digitalRead(9) == HIGH)
  {
      digitalWrite(10, HIGH);
      delay(2000);
      digitalWrite(10, LOW);
  }

}

Entendendo o software

- Definindo as configurações iniciais

Primeiramente, na função setup(), deve-se determinar os modos de operação dos pinos que serão utilizados, sendo assim, definimos o pino 10 como uma saída digital (utilizando OUTPUT no segundo parâmetro da função pinMode()), pois, este será responsável por alimentar o led em questão. Além disso, determinamos também que o pino 9 servirá como uma entrada digital, por isso, utilizamos a palavra INPUT no segundo parâmetro da função pinMode()).

  pinMode(10,OUTPUT);
  pinMode(9,INPUT);

Desta forma, a função setup() terá o seguinte conteúdo:

void setup() 
{ 
  pinMode(10,OUTPUT);
  pinMode(9,INPUT); 
}

- Realizando os acionamentos

Neste momento, antes de prosseguirmos com a explicação do conteúdo função loop(), devemos apresentar o funcionamento da função if(), que pos sua vez, consiste em um elemento muito importante para que esta parte do código possa ser entendida de maneira clara.

Entendendo a função IF

Constantemente, ao nos depararmos com um determinado problema, temos que tomar uma ou várias decisões para que o mesmo possa ser resolvido ou amenizado. Sendo assim, quanto mais informações tivermos, ou seja, quanto mais e melhores forem os resultados coletados sobre uma determinada situação, mais fácil será de tomar uma decisão sobre quais ações devem ser realizadas quando nos encontrarmos naquele tipo de situação. É neste cenário que entra a utilização da função if().

Imagine que o Vida de Silício, além produzir os melhores conteúdos e vender os melhores componentes, esteja se aventurando no meio gastronômico, mais especificamente, no ramo da confeitaria. Obviamente, como dominamos este assunto, temos uma grande variedade de receitas bolos que vão de A a Z, no entanto, somente alguns bolos possuem cobertura, os de aniversário. Sendo assim, internamente, elaboramos um algoritmo, ou passo-a-passo, para que nossa equipe esteja atenta a esta situação, veja:

Função bolo(){
 Faça o bolo;
 Se o bolo é de aniversário {
     Faça uma cobertura;
 }Senão
     Não faça uma cobertura
 }
fim

Para ficar mais fácil de visualizar esta situação, preparamos um fluxograma para você. Veja que utilizamos um parâmetro para decidir se iremos ou não executar a atividade.

Operadores lógicos

É importante ressaltar que os recursos de tomadas de decisão, como por exemplo, a função if(), devem ser utilizados juntamente com os operadores lógicos (como veremos a seguir), os quais, são responsáveis por criar as condições de execução de uma estrutura lógica de tomada de decisão.

Agora que já aprendemos o conceito da função if() e que a mesma é responsável por conferir se uma determinada sentença é verdadeira ou falsa e tomar as providências necessárias com base nesta resposta, neste código, desejamos testar se a entrada digital na qual o botão está conectado, está em nível alto, ou seja, queremos saber se o botão está pressionado (isso pode ser feito colocando o elemento, o operador de igualdade "==" e o que queremos saber se é verdade, no argumento da estrutura condicional if()).

if(digitalRead(9) == HIGH)
{
   //****** CONTEÚDO DA ESTRUTURA CONDICIONAL IF() ******
}

Caso a sentença testada anteriormente seja verdadeira, o código parte para a execução do conteúdo da mesma. Logo, caso o botão seja pressionado, ocorrerá uma situação semelhante a do exemplo 2, onde o led será aceso através da função pinMode() e permanecerá assim por 2 segundos até que seja apagado pela mesma função.

   digitalWrite(10, HIGH);
   delay(2000);
   digitalWrite(10, LOW);

Após o led ser apagado, o programa deve ficar esperando por um novo pressionamento do botão. Isto é possível pois esta parte do código está dentro da função loop(), portanto, será executada repetidamente. Veja como ficou a função loop().

void loop() {
  
  if(digitalRead(9) == HIGH)
  {
      digitalWrite(10, HIGH);
      delay(2000);
      digitalWrite(10, LOW);
  }

}

Nota: Nada irá acontecer caso o botão seja pressionado novamente entre o intervalo onde o led permanece aceso, pois, neste momento, o programa estará parado por conta da função delay().


Considerações finais

Produzimos este conteúdo para auxiliar o leitor na manipulação das entradas e saídas digitais encontradas em uma placa Arduino. Esperamos que você tenha gostado deste conteúdo, sinta-se à vontade para nos dar sugestões, críticas ou elogios. Lembre-se de deixar suas dúvidas nos comentários abaixo.

 

Apostila Arduino Básico