,

Usando dois LEDs como IHM HMI

Posted by

Vamos aprender a usar dois LEDs como interface homem-máquina. Quando se trata de eletrônica, sou minimalista, gosto de circuitos o menor possível. Então, criei uma IHM (interface homem-máquina) que é bem minimalista, capaz de mostrar números com dois dígitos (de 0 a 99) usando apenas dois LEDs.

Pode-se argumentar que apenas o código Morse (em um LED) pode ser menor que isso. A ideia aqui é simples, um LED piscará para as dezenas e outro para as unidades. Então, por exemplo, para o número 28, o LED das dezenas piscará duas vezes e o LED das unidades piscará oito vezes. O mesmo para o número 89, onde o LED das dezenas piscará oito vezes e o LED das unidades piscará nove vezes.

Circuito para teste

Para este experimento, você precisará de um Arduino (na verdade, qualquer um serve), um potenciômetro, dois LEDs e dois resistores (estou usando valor de 1k Ohm). Procure o diagrama esquemático abaixo.

Diagrama esquemático da IHM de dois LEDs
Diagrama esquemático da IHM de dois LEDs
Montagem em protoboard da IHM de dois LEDs
Montagem em protoboard da IHM de dois LEDs

Observe que este potenciômetro é apenas uma das muitas coisas que você pode usar como dados de entrada para esta interface homem-máquina. Você pode, por exemplo, ler dados de um sensor i2c (BMP280, SHT21, etc.), obter dados da internet usando um internet shield ou um ESP32, e muito mais. O importante é que os dados sejam limitados entre inteiros de um e dois dígitos (0-99).

Código para testes

Há algumas etapas necessárias para converter um valor analógico em dois LEDs piscando no padrão correto. Vou explicar isso passo a passo e o código completo final estará no final. Primeiro, você precisa transformar seus dados analógicos em um valor inteiro de 1 a 99; estou usando a função map() para isso:

analoginput= map(analogRead(A1), 0, 1023, 0, 99);

Eu leio a entrada analógica A1 e converto seu valor de 0-1023 para 0-99, então coloco o resultado em “analoginput”. Novamente, alguém poderia ler qualquer valor de qualquer sensor usando qualquer protocolo, sendo suficiente convertê-lo para um valor inteiro de 0-99.

O segundo passo é separar dezenas de unidades, eu faço isso comparando o valor inteiro a pedaços ou partes de inteiros:

if(analoginput < 10){
      tens= 0;
      unit= analoginput;
    }else if(analoginput >= 10 && analoginput < 20){
       tens= 1;
       unit= analoginput - 10;
    }else if(analoginput >= 20 && analoginput < 30){
      tens= 2;
      unit= analoginput - 20;
    }else if(analoginput >= 30 && analoginput < 40){
      tens= 3;
      unit= analoginput - 30;
    }else if(analoginput >= 40 && analoginput < 50){
      tens= 4;
      unit= analoginput - 40;
    }else if(analoginput >= 50 && analoginput < 60){
      tens= 5;
      unit= analoginput - 50;
    }else if(analoginput >= 60 && analoginput < 70){
      tens= 6;
      unit= analoginput - 60;
    }else if(analoginput >= 70 && analoginput < 80){
      tens= 7;
      unit= analoginput - 70;
    }else if(analoginput >= 80 && analoginput < 90){
      tens= 8;
      unit= analoginput - 80;
    }else if(analoginput >= 90 && analoginput < 100){
      tens= 9;
      unit= analoginput - 90;
    }else{
      tens= 0;
      unit= 0;
    }

Poderíamos fazer isso para 0-999 também, aninhando IFs da maneira correta. Observe que isso é muito “trabalhoso”, um monte de IFs um após o outro. Essa é a maneira como eu descobri como resolver o problema, mas não a única maneira que poderia ser feito. Ambos os pedaços de código acima estão dentro de um loop que é executado a cada 50 ms (milissegundos):

if (enterFunction2 == true && waittime == true) { //Enter this function every xx milisseconds and IF LEDs are not blinking
    previousTime2 = time2;

Ele também é executado somente quando “waittime” é verdadeiro, o que significa que esses cálculos só acontecem quando os dados não estão sendo mostrados. Agora, para a parte de exibição de dados, a saída digital 6 (dezenas) é alternada (ligada e desligada alternadamente) toda vez que essa função é inserida, se “blinkingtens” for verdadeiro:

if(blinkingtens == true && blinkingunits == false){
      digitalWrite(7, LOW);
      if(enteredtens == false){
        enteredtens = true;
        doubletens = 2 * tens;
        if(doubletens == 0){
          doubletens= 1;
        }
      }
      doubletens --;
      if(doubletens != 0){
        digitalWrite(6, !digitalRead(6));
      }else{
        blinkingunits = true;
        blinkingtens = false;
      }

    }

Devido ao uso de alternância, tenho que executar a função duas vezes mais “lentamente”, fazendo:

doubletens = 2 * tens;

Em seguida, faço o mesmo para as unidades (saída digital 7), também dobrando o número de vezes que ele executa, devido à função de alternância:

else if(blinkingunits == true && blinkingtens == false){
      digitalWrite(6, LOW);
      blinkingtens= false;
      if(enteredunit == false){
        enteredunit = true;
        doubleunit = 2 * unit;
        if(doubleunit == 0){
          doubleunit= 1;
        }
      }
      doubleunit --;
      if(doubleunit != 0){
        digitalWrite(7, !digitalRead(7));
      }else{
        waittime = true;
        blinkingunits = false;
        startedwait = true;
      }

    }

Quando mostro dezenas e unidades, faço um atraso de (aproximadamente) 700 ms com tudo desligado, antes de passar para a próxima rodada:

else if(waittime == true){
      if(startedwait == true){
        digitalWrite(6, LOW);
        digitalWrite(7, LOW);
        startedwait = false;
        elapsedtime = millis();
      }
      if(millis() - elapsedtime > 698){
        waittime = false;
      }

    }

Então o processo é repetido novamente, apenas com um novo valor analógico que foi lido recentemente da entrada analógica. O código completo pode ser visto abaixo. É NÃO BLOQUEANTE, o que significa que você pode executar outros pedaços de código no meio tempo. Usa apenas 10% do espaço do programa e 10% da memória, programa muito leve.

unsigned long time1;
unsigned long previousTime;
bool enterFunction = true;
unsigned long time2;
unsigned long previousTime2;
bool enterFunction2 = true;
bool blinkingtens= false;
bool enteredtens= false;
int doubletens= 0;
bool blinkingunits = false;
bool enteredunit = false;
int doubleunit = 0;
int unit = 0;
int tens = 0;
bool waittime = true;
bool startedwait = false;
long elapsedtime;
int analoginput;

int digituponentering = 1;


void setup() {
  
  Serial.begin(9600);
  pinMode(6, OUTPUT);
  pinMode(7, OUTPUT);
}

void loop() {

  time1 = micros();
  time2 = micros();
  if (enterFunction == true) {
    previousTime = time1;
    
    // Start your code below
    //-----------------------

    if(blinkingtens == true && blinkingunits == false){
      digitalWrite(7, LOW);
      if(enteredtens == false){
        enteredtens = true;
        doubletens = 2 * tens;
        if(doubletens == 0){
          doubletens= 1;
        }
      }
      doubletens --;
      if(doubletens != 0){
        digitalWrite(6, !digitalRead(6));
      }else{
        blinkingunits = true;
        blinkingtens = false;
      }

    }else if(blinkingunits == true && blinkingtens == false){
      digitalWrite(6, LOW);
      blinkingtens= false;
      if(enteredunit == false){
        enteredunit = true;
        doubleunit = 2 * unit;
        if(doubleunit == 0){
          doubleunit= 1;
        }
      }
      doubleunit --;
      if(doubleunit != 0){
        digitalWrite(7, !digitalRead(7));
      }else{
        waittime = true;
        blinkingunits = false;
        startedwait = true;
      }

    }else if(waittime == true){
      if(startedwait == true){
        digitalWrite(6, LOW);
        digitalWrite(7, LOW);
        startedwait = false;
        elapsedtime = millis();
      }
      if(millis() - elapsedtime > 698){
        waittime = false;
      }

    }else{
      blinkingtens= true;
      enteredtens = false;
      enteredunit = false;
    }  
    
    //-----------------------
    // End of your code
  }

  if (enterFunction2 == true && waittime == true) { //Enter this function every xx milisseconds and IF LEDs are not blinking
    previousTime2 = time2;

    // Le o sensor algumas vezes
    analoginput= map(analogRead(A1), 0, 1023, 0, 99);
    Serial.println(analoginput);
    
    if(analoginput < 10){
      tens= 0;
      unit= analoginput;
    }else if(analoginput >= 10 && analoginput < 20){
       tens= 1;
       unit= analoginput - 10;
    }else if(analoginput >= 20 && analoginput < 30){
      tens= 2;
      unit= analoginput - 20;
    }else if(analoginput >= 30 && analoginput < 40){
      tens= 3;
      unit= analoginput - 30;
    }else if(analoginput >= 40 && analoginput < 50){
      tens= 4;
      unit= analoginput - 40;
    }else if(analoginput >= 50 && analoginput < 60){
      tens= 5;
      unit= analoginput - 50;
    }else if(analoginput >= 60 && analoginput < 70){
      tens= 6;
      unit= analoginput - 60;
    }else if(analoginput >= 70 && analoginput < 80){
      tens= 7;
      unit= analoginput - 70;
    }else if(analoginput >= 80 && analoginput < 90){
      tens= 8;
      unit= analoginput - 80;
    }else if(analoginput >= 90 && analoginput < 100){
      tens= 9;
      unit= analoginput - 90;
    }else{
      tens= 0;
      unit= 0;
    }
  }


  // The DELAY time is adjusted in the constant below >>
  if (time1 - previousTime < 299990) { // 1 million microsencods= 1 second delay
    /* I have actually used 0.999990 seconds, in a trial to compensate the time that
       this IF function takes to be executed. this is really a point that
       need improvement in my code */
    enterFunction = false;
  }
  else {
    enterFunction = true;
  }
  if (time2 - previousTime2 < 49990) { // 1 million microsencods= 1 second delay
    /* I have actually used 0.999990 seconds, in a trial to compensate the time that
       this IF function takes to be executed. this is really a point that
       need improvement in my code */
    enterFunction2 = false;
  }
  else {
    enterFunction2 = true;
  }

}

Resultado final

Fiz um vídeo mostrando como esse código e protótipo funcionam, confira abaixo. Quer ver como usar outro display com Arduino? veja este artigo.

Deixe um comentário

O seu endereço de email não será publicado. Campos obrigatórios marcados com *