Os contadores são amplamente utilizados em muitos sistemas eletrônicos, como máquinas-ferramentas, processos industriais, acesso a sistemas de transporte, bancos, páginas da Web, programas de computador, algoritmos matemáticos etc. Daí a sua importância de saber como eles funcionam em microcontroladores. Neste artigo, aprenderemos a construir um contador de 2 dígitos com a placa Arduino Uno.

Na Figura 1 podemos ver a placa do Arduino Uno e na Figura 2 a IDE ou Interface de Desenvolvimento para escrever programas no Arduino Uno, comumente chamado de Sketch. Esse IDE pode ser baixado no site do Arduino.

 

Figura 1
Figura 1

 

 

 

Figura 2
Figura 2

 

Para o desenvolvimento do contador de 2 dígitos, usaremos os pinos: 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, A0, A1 e A2. O primeiro dígito, ou seja, o que representa as unidades, é conectado aos pinos: 2, 3, 4, 5, 6, 7 e 8. O segundo dígito, ou seja, o que representa as dezenas, é conectado ao pinos: 9, 10, 11, 12, A0, A1 e A2. Nos diagramas deste artigo, os pinos A0, A1 e A2 são mostrados, conectados aos pinos e1, f1 e g1 do display. É necessário interconectar esses pinos aos respectivos pinos no display.

Na Figura 3, podemos ver as letras atribuídas a cada segmento no visor.

 


 

 

São eles: a, b, c, d, e, f e g. Os displays usados neste artigo têm 2 dígitos e na Figura 4 podemos ver os pinos e suas conexões com os respectivos segmentos.

 

Figura 4
Figura 4

 

A Figura 5 já mostra os pinos usados na placa Arduino Uno para controlar o display de 7 segmentos.

 

Figura 5
Figura 5

 

 

A ordem dos pinos é a seguinte:

Pino 2 - Segmento a2

Pino 3 - Segmento b2

Pino 4 - Segmento c2

Pino 5 - Segmento d2

Pino 6 - Segmento e2

Pino 7 - Segmento f2

Pino 8 - Segmento g2

Pino 9 - Segmento a1

Pino 10 - Segmento b1

Pino11 - Segmento c1

Pino12 - Segmento d1

Pino A0 - Segmento e1

Pino A1 - Segmento f1

Pino A2 - Segmento g1

 

 

CONTADOR INCREMENTAL POR PROGRAMA.

Neste sketch, implementamos um contador incremental por programa. O contador começa em zero e incrementa até 99, depois para por 10 segundos, contando novamente até atingir 99. Assim, o mesmo loop é repetido infinitamente. A Figura 6 mostra o circuito eletrônico para implementar este contador.

 


 

 

 

O código para o contador incremental é o seguinte:

const int display_1_Pinout[7] = { 2, 3, 4, 5, 6, 7, 8 };
const int display_2_Pinout[7] = { 9, 10, 11, 12, A0, A1, A2 };
const byte anodeDisplay[10] =
 {
   0b1000000, //0
   0b1111001, //1
   0b0100100, //2
   0b0110000, //3
   0b0011001, //4
   0b0010010, //5
   0b0000010, //6
   0b1111000, //7
   0b0000000, //8
   0b0010000, //9
 };/*************************************************/
void setup()
 {
   for(int i = 0; i < 7; i++)
    {
       pinMode(display_1_Pinout[i], OUTPUT);
       pinMode(display_2_Pinout[i], OUTPUT);
    }
 }/******************************************************/
void Display_2_Write(int number)
 {
   byte numberBit = anodeDisplay[number];
   for (int i = 0; i < 7; i++)
    {
      int bit = bitRead(numberBit, i);
      digitalWrite(display_2_Pinout[i], bit);
    }
 }/******************************************************/
void Display_1_Write(int number)
 {
   byte numberBit = anodeDisplay[number];
   for (int i = 0; i < 7; i++)
    {
      int bit = bitRead(numberBit, i);
      digitalWrite(display_1_Pinout[i], bit);
    }
 }/*********************************************/
void Display_Show(int number)
 {
   int units = number % 10;
   int tens = number / 10;
   Display_1_Write(units);
   Display_2_Write(tens);
 }/*************************************************/
void loop()
 {
   for(int cnt=0; cnt<100; cnt++)
    {
      Display_Show(cnt);
      delay(1000);
    }
    delay(10000);
 }

 

O incremento é feito por programa usando um loop for(). A seguinte linha de código é responsável pela execução desse loop:

     for (int cnt = 0; cnt <100; cnt ++)

A variável inteira cnt é inicializada com zero e, para cada etapa que a instrução for() executa, é verificado se a variável cnt é menor que 100. Se for menor, o loop for() é executado, aumentando a variável cnt. Se for maior ou igual a 100, o loop for() é encerrado e a instrução delay(10000) é executada, o que atrasa o programa por 10 segundos.

A função Display_Show() recebe um parâmetro inteiro e é responsável por extrair as unidades (unidades) e dezenas (dezenas). Então chamamos as funções: Display_1_Write(units); e Display_2_Write(dezenas); para exibir esses valores na tela de 7 segmentos.

 

CONTADOR DECREMENTAL POR PROGRAMA.

Neste sketch, implementamos um contador decrescente por programa. O contador começa em 99 e diminui para zero, depois para por 10 segundos, diminuindo novamente até chegar a zero. Assim, o mesmo loop é repetido infinitamente. A Figura 6 mostra o circuito eletrônico para implementar este contador. O código para o contador decremental é o seguinte:

 

const int display_1_Pinout[7] = { 2, 3, 4, 5, 6, 7, 8 };const int display_2_Pinout[7] = { 9, 10, 11, 12, A0, A1, A2 };const byte anodeDisplay[10] =
 {
   0b1000000, //0
   0b1111001, //1
   0b0100100, //2
   0b0110000, //3
   0b0011001, //4
   0b0010010, //5
   0b0000010, //6
   0b1111000, //7
   0b0000000, //8
   0b0010000, //9
 };
 /************************************************************/void setup()
 {
   for(int i = 0; i < 7; i++)
    {
      pinMode(display_1_Pinout[i], OUTPUT);
      pinMode(display_2_Pinout[i], OUTPUT);
    }
 }
 /************************************************************/void Display_2_Write(int number)
 {
    byte numberBit = anodeDisplay[number];
    for (int i = 0; i < 7; i++)
     {
        int bit = bitRead(numberBit, i);
        digitalWrite(display_2_Pinout[i], bit);
     }
 }
 /*************************************************************/void Display_1_Write(int number)
 {
   byte numberBit = anodeDisplay[number];
   for (int i = 0; i < 7; i++)
    {
      int bit = bitRead(numberBit, i);
      digitalWrite(display_1_Pinout[i], bit);
    }
 }
 /************************************************************/void Display_Show(int number)
 {
   int units = number % 10;
   int tens = number / 10;
   Display_1_Write(units);
   Display_2_Write(tens);
 }
 /*************************************************************/void loop()
 {
   for(int cnt=99; cnt >= 0; cnt--)
    {
      Display_Show(cnt);
      delay(1000);
    }
   delay(10000);
 }

 

Basicamente, o código neste sketch é o mesmo que no exemplo anterior. A função responsável pela diminuição é:

for (int cnt = 99; cnt> = 0; cnt--)

Esse loop for () inicializa a variável cnt para 99 e verifica se é maior ou igual a zero. Nesse caso, ele entra no loop, diminuindo a variável cnt. Se for menor que zero, o loop for() sai e o programa é temporizado por 10 segundos. As outras funções funcionam da mesma forma que no exemplo anterior.

 

CONTADOR DECREMENTAL INCREMENTAL POR PROGRAMA.

Neste sketch, implementamos um contador crescente-decrescente por programa. Este esboço é a combinação dos dois exemplos anteriores. A entrada digital A3 está configurada para selecionar para aumentar ou diminuir o contador. Essa seleção tem efeito quando o loop for() sai do loop.

 


 

 

A Figura 7 mostra o circuito eletrônico para testar este exemplo. O código é o seguinte:

 

int incDecPinin = A3;const int display_1_Pinout[7] = { 2, 3, 4, 5, 6, 7, 8 };const int display_2_Pinout[7] = { 9, 10, 11, 12, A0, A1, A2 };const byte anodeDisplay[10] =
 {
   0b1000000, //0
   0b1111001, //1
   0b0100100, //2
   0b0110000, //3
   0b0011001, //4
   0b0010010, //5
   0b0000010, //6
   0b1111000, //7
   0b0000000, //8
   0b0010000, //9
 };
 /**************************************************/void setup()
 {
   pinMode(incDecPinin, INPUT_PULLUP);
   for(int i = 0; i < 7; i++)
    {
      pinMode(display_1_Pinout[i], OUTPUT);
      pinMode(display_2_Pinout[i], OUTPUT);
    }
 }
 /********************************************************/void Display_2_Write(int number)
 {
   byte numberBit = anodeDisplay[number];
   for (int i = 0; i < 7; i++)
    {
      int bit = bitRead(numberBit, i);
      digitalWrite(display_2_Pinout[i], bit);
    }
 }
 /********************************************************/void Display_1_Write(int number)
 {
   byte numberBit = anodeDisplay[number];
   for (int i = 0; i < 7; i++)
    {
       int bit = bitRead(numberBit, i);
       digitalWrite(display_1_Pinout[i], bit);
    }
 }
 /*****************************************************/void Display_Show(int number)
 {
   int units = number % 10;
   int tens = number / 10;
   Display_1_Write(units);
   Display_2_Write(tens);
 }
 /********************************************************/void loop()
 {
    if(digitalRead(incDecPinin) == HIGH)
     {
      for(int cnt=0; cnt<100; cnt++)
       {
         Display_Show(cnt);
         delay(1000);
       }
     }
    else
     {
       for(int cnt=99; cnt >= 0; cnt--)
         {
           Display_Show(cnt);
           delay(1000);
         }
     }
    delay(10000);
 }

 

 

CONTADOR INCREMENTAL POR PULSO.

Neste esboço, implementamos um contador incremental por pulso. O circuito para testar este exemplo pode ser observado na Figura 8.

 

Figura 1
Figura 8

Para gerar os pulsos do contador, usamos um interruptor ou pulsador. A maioria dos pinos da placa Arduino Uno tem uma resistência interna conectada ao positivo e pode ser ativada usando o parâmetro INPUT_PULLUP, quando o pino está configurado como entrada. Com relação ao programa do medidor, a Figura 9 mostra uma máquina de estados usada para este exemplo e que explicaremos mais adiante.

 

Figura 9
Figura 9

O código-exemplo é o seguinte:

 

enum States
 {
   High,
   Low
 };
 enum Events
 {
   EV_HIGH,
   EV_LOW,
 };
 int buttonPinin = A3;int buttonValue = 0;int counter = 0;int state = High;
 const int display_1_Pinout[7] = { 2, 3, 4, 5, 6, 7, 8 };const int display_2_Pinout[7] = { 9, 10, 11, 12, A0, A1, A2 };const byte anodeDisplay[10] =
 {
   0b1000000, //0
   0b1111001, //1
   0b0100100, //2
   0b0110000, //3
   0b0011001, //4
   0b0010010, //5
   0b0000010, //6
   0b1111000, //7
   0b0000000, //8
   0b0010000, //9
 };
 /*************************************************************/void setup()
 {
   pinMode(buttonPinin, INPUT_PULLUP);
   for(int i = 0; i < 7; i++)
    {
      pinMode(display_1_Pinout[i], OUTPUT);
      pinMode(display_2_Pinout[i], OUTPUT);
    }
  Display_Show(counter);
 }
 /*************************************************************/void Display_2_Write(int number)
 {
   byte numberBit = anodeDisplay[number];
   for (int i = 0; i < 7; i++)
    {
      int bit = bitRead(numberBit, i);
      digitalWrite(display_2_Pinout[i], bit);
    }
 }/*************************************************************/void Display_1_Write(int number)
 {
   byte numberBit = anodeDisplay[number];
   for (int i = 0; i < 7; i++)
    {
      int bit = bitRead(numberBit, i);
      digitalWrite(display_1_Pinout[i], bit);
    }
 }
 /*************************************************************/void Display_Show(int number)
 {
   int units = number % 10;
   int tens = number / 10;
   Display_1_Write(units);
   Display_2_Write(tens);
 }
 /*************************************************************/void StateMachine(Events e)
 {
   switch(state)
    {
      case High:
      switch(e)
       {
         case EV_LOW:
         counter++;
         if(counter>=100)
         counter=0;
         Display_Show(counter);
         state = Low;
       }
      break;
      case Low:
      switch(e)
       {
         case EV_HIGH:
         state = High;
       }
      break;
      }
    }/**********************************************************/void loop()
 {
   buttonValue = digitalRead(buttonPinin);
   if (buttonValue == HIGH)
     {
        StateMachine(EV_HIGH);
     }
   else
     {
        StateMachine(EV_LOW);
     }
 }

 

As máquinas de estado são códigos baseados em instruções de decisão (comutador), que determinam em que estado um programa está e, portanto, executam algum código respectivo. Neste exemplo, temos os estados Alto e Baixo, que determinam o estado do botão. Se o programa estiver no estado Alto e o botão for pressionado, o programa envia o evento EV_LOW para esse estado e um código é chamado para incrementar o contador e exibi-lo.

Observe que o contador é verificado para ver se já atingiu 100 e, portanto, redefina-o para zero (0). Então chamamos a função: Display_Show(counter); para mostrar o valor do contador nos displays. Além disso, o status do botão para Baixa é alterado. Essa técnica é usada para incrementar o contador, somente quando o botão passa de alto para baixo, ou seja, quando pressionado pelo usuário. Observe que um capacitor de 220 nF é colocado, para evitar o ruído produzido pelos botões ou interruptores, uma vez que estes são mecânicos, enviam muitos pulsos ao circuito, quando pressionados.

A função loop() é responsável por ler o botão e chamar a função: StateMachine(Events e), enviando o evento apropriado como parâmetro.

 

 

CONTADOR INCREMENTAL COM SETPOINT.

Neste sketch, implementamos um contador de pulsos incremental com ponto de ajuste. Quando o valor programado no ponto de ajuste é atingido, um LED acende. O circuito para testar este programa pode ser visto na Figura 10. A seguir está o código de exemplo:

 

Figura 10
Figura 10

 

enum States
 {
   High,
   Low
 };enum Events
 {
   EV_HIGH,
   EV_LOW,
 };
 const int SETPOINT = 37;const int buttonPinin = A3;const int ledPinout = A4;int buttonValue = 0;int counter = 0;int state = High;const int display_1_Pinout[7] = { 2, 3, 4, 5, 6, 7, 8 };const int display_2_Pinout[7] = { 9, 10, 11, 12, A0, A1, A2 };const byte anodeDisplay[10] =
 {
   0b1000000, //0
   0b1111001, //1
   0b0100100, //2
   0b0110000, //3
   0b0011001, //4
   0b0010010, //5
   0b0000010, //6
   0b1111000, //7
   0b0000000, //8
   0b0010000, //9
 };
 /*************************************************************/void setup()
 {
   pinMode(ledPinout, OUTPUT);
   Led_Off();
   pinMode(buttonPinin, INPUT_PULLUP);
   for(int i = 0; i < 7; i++)
    {
      pinMode(display_1_Pinout[i], OUTPUT);
      pinMode(display_2_Pinout[i], OUTPUT);
    }
  Display_Show(counter);
 }/*************************************************************/void Led_On()
 {
   digitalWrite(ledPinout, LOW);
 }/*************************************************************/void Led_Off()
 {
   digitalWrite(ledPinout, HIGH);
 }
 /*************************************************************/void Display_2_Write(int number)
 {
  byte numberBit = anodeDisplay[number];
  for (int i = 0; i < 7; i++)
   {
    int bit = bitRead(numberBit, i);
    digitalWrite(display_2_Pinout[i], bit);
   }
 }
 /************************************************************/void Display_1_Write(int number)
 {
  byte numberBit = anodeDisplay[number];
  for(int i = 0; i < 7; i++)
   {
     int bit = bitRead(numberBit, i);
     digitalWrite(display_1_Pinout[i], bit);
   }
 }
 /*************************************************************/void Display_Show(int number)
 {
   int units = number % 10;
   int tens = number / 10;
   Display_1_Write(units);
   Display_2_Write(tens);
 }
 /*************************************************************/void StateMachine(Events e)
 {
   switch(state)
    {
      case High:
      switch (e)
        {
        case EV_LOW:
        counter++;
        if(counter == SETPOINT)
         {
           Led_On();
         }
         else if(counter > SETPOINT)
         {
           counter=1;
           Led_Off();
         }
         else
         {
           Led_Off();
         }
  
      Display_Show(counter);
      state = Low;
    }
    break;
  
    case Low:
    switch (e)
       {
         case EV_HIGH:
         state = High;
       }
       break;
    }
 }
 /*************************************************************/void loop()
 {
   buttonValue = digitalRead(buttonPinin);
   if (buttonValue == HIGH)
    {
      StateMachine(EV_HIGH);
    }
   else
    {
      StateMachine(EV_LOW);
    }
 }

 

Neste programa, usamos a mesma técnica de programa de contador vista anteriormente neste artigo. Mas uma constante inteira definida na seguinte linha de código foi adicionada:

const int SETPOINT = 37;

Este valor define o ponto de ajuste do contador. O valor pode ser alterado para atender à necessidade, mas deve estar no intervalo de 1 a 99, para ser exibido. Além disso, um pino de saída foi definido para conectar um LED. A seguinte linha de código faz isso:

const int ledPinout = A4;

 

CONCLUSÃO

O manuseio do display de 7 segmentos é relativamente fácil e suas aplicações são quase ilimitadas. Este código é endereçado a dois dígitos. Os contadores são a base da construção, temporizadores digitais, medidores de frequência digital, velocímetros, tacômetros, etc.

 

Nota: Não esqueça de conectar o capacitor de 0,22 uF ao pino de entrada A3, pois isso evitará o ruído produzido pelas quedas mecânicas dos botões de pressão.