quinta-feira, 13 de junho de 2013

CONTADOR DE PEÇAS COM ARDUINO UNO R3. + LCD Keypad Shield

Meu novo projeto agora é trazer o contador com a PIC 16F877a para o arduino uno R3 e o LCD keypad Shield.
-Eu optei pelo arduino pelo simples fato de ter o hardware já pronto. Não havendo necessidade desenvolver e confeccionar placas de circuito impresso. 

Hardware necessário:

Placa principal do ARDUÍNO UNO R3.  Veja AQUI


LCD Keypad Shield Veja AQUI


Aqui tem a WIKI do LCD, com pinagem, programas de exemplo, etc.

- Este LCD Keypad Shield possui 4 chaves ligadas em uma unica porta analógica do arduino. No meu projeto não vou utiliza-las, já que vou precisar de teclas maiores que ficarão em um painel maior.

- Ligação do LCD com o arduino.
- Os pinos utilizados pelo LCD são os seguintes: 
4,5,6,7,8,9 (São os pinos no arduino, não no LCD). É assim que ele vem ligado ao Arduino. O importante é o programa saber disso. Que neste caso será a seguinte instrução no começo do programa:


// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);  significa que estes pinos são do Arduino e estão reservados para o LCD. 

- Uma mudança importante neste projeto em relação ao antigo, é a inclusão do item PEÇAS GRAVADAS. Ou seja, além do valor TOTAL digitado e o valor da contagem, aparecerá no display o número de peças já gravadas.

Exemplo do display:

T.: 1000     X1
F.: 999    G:1


Onde T.: é TOTAL de peças, X1, contará de uma-em-uma. F.: Peças que Faltam gravar e G: peças Gravadas.

Pinos utilizados no arduino:

1 -> SAÍDA  - RELÊ 1 - faz a mudança do botão de PULSO para o arduino controlar. Quando o arduino estiver desligado ou ligado mas sem estar programado, o botão PULSO estará ligado diretamente na máquina laser. Como se o Arduíno não existisse. Eu fiz isso para o caso de você querer gravar sem contar peças. Assim que o botão Enter é pressionado pela primeira vez, este relê ativa e transfere o botão PULSO direto para o Arduíno. Ou seja, ao pressionar o botão PULSO, o comando vai para o pino 12 do Arduíno, e o Arduíno vai acionar o RELÊ 2, que fará o papel do botão PULSO para a máquina Laser.
2 <- ENTRADA - Botão SOBE, ligado a chave e da chave ao GND. Aciona com nivel 0.
3 <- ENTRADA - Botão ENTER, ligado a chave e da chave ao GND. Aciona com nivel 0.
4,5,6,7,8,9 Reservado ao LCD.
10 - Back Light do LCD.
11 -> SAÍDA - BUZZ, aciona a busina do alarme.
12 <- ENTRADA - Sinal de PULSO, ativa em nivel 0.
13 -> SAÍDA - RELÊ 2 - ativa a gravação.



Esquema elétrico no Proteus.

O arquivo fonte de programação do Arduino. AQUI

Um pouco sobre o programa.
- Meu forte não é programação, porém vou explicar um pouco sobre o funcionamento deste aqui.
- Como todo mundo já deve saber, uma das primeiras coisas e, as mais importantes na programação é a definição de variáveis. É por onde tudo começa.
- Eu defini as seguintes variaveis:
- q1, q2, q3 e q4, serão utilizadas para armazenar o número que se deseja contar, cada uma representa uma casa decimal. Q1 é milhar, Q2 é centena, Q3 é dezenas e Q4 unidade.
No programa fica assim:
int long q1=0;
int long q2=0;
int long q3=0;
int long q4=0;

As outras são: conta, total e m.
O principio de funcionamento é começar utilizando a variável CONTA para escolher a casa do milhar (q1), assim que o valor é escolhido o valor de CONTA vai para q1. O próximo passo é escolher a centena (q2), novamente utilizando CONTA e passando para q2, e assim sucessivamente até chegar em q4.

Exemplo: Você escolheu a quantidade de 1000 peças a serem gravadas. Então as variáveis ficariam assim:
- Primeiramente CONTA=0, utilizando a tecla SOBE o valor de CONTA foi para 1, apertando ENTER, o valor  CONTA foi para q1, q1=conta;
- Segundo passo, CONTA=0, aperando ENTER, q2=conta;
No final teremos: 
-q1=1
-q2=0
-q3=0
-q4=0

Valor total 1000.
Agora precisamos colocar esse valor de 1000 na variável CONTA.
Usamos a seguinte expressão:
conta=(q4*1000)+(q3*100)+(q2*10)+q1;

Agora a variável CONTA tem o valor de 1000, e assim podemos começar a contagem.
A formula é bem simples, conta=conta-1; toda vez que temos o sinal de PULSO diminuímos 1 do valor de CONTA.

Porém eu utilizo um parâmetro a mais que é possibilidade de contar até de 4 em 4.
Você vai notar que ao iniciar o programa (ligar o Arduino), o primeiro parâmetro a ser definido é o MULTIPLO, por padrão ele já vem com o valor de 1, e vai até 4. Isso significa que eu posso querer gravar até quatro peças ao mesmo tempo, ou seja, toda vez que eu apertar o botão PULSO uma vez, ele vai descontar esse valor do total.
Usando como base o valor acima que é 1000, e com múltiplo setado em 4 a conta fica assim: conta=conta-4;
Neste caso eu utilizo a variável m para armazenar este valor.
conta=conta-m;

.....

Eu gostaria de comentar um pouco sobre uma rotina interessante, que na qual custei para desenvolver, porém é bem simples, mas como eu disse no começo, programação não é meu forte.
A questão é a seguinte: O programa dentro do chip do arduino roda muito rápido, milhões de ciclos por segundo, e como o programa fica lendo cada porta de entrada do chip em cada ciclo, temos um problema de repetição da tecla repetida.
Exemplo: Temos o botão SOBE ligado ao pino 2, cada vez que apertamos o botão o nivel do sinal deste pino vai para ZERO. O programa percebe isso e aceita como a tecla pressionada, no próximo ciclo de clock e vai ler novamente este pino e se estiver em ZERO, vai entender que a tecla foi pressionada novamente, mas na verdade não foi, pois o processo é tão rápido que nem deu tempo de soltar a tecla. Mesmo que você pressione rapidamente a tecla, a contagem no display será muito rápida. 
Para resolver isso eu fiz uma rotina que após a tecla ser pressionada, ele não passa adiante enquanto ela não for solta.

    if (digitalRead(Btnsobe)==LOW)
          {
            conta=conta+1;
            sobe3:
            ;
            if (digitalRead(Btnsobe)==LOW)
            {
               goto sobe3;
             }
     

Funciona assim, na primeira (1ª) linha diz o seguinte: SE a entrada digital(digitalRead), pino 2 (Btnsobe) for igual a ZERO (que é o botão SOBE pressionado), então execute o que está dentro da chave { , que é somar 1 no valor da variavel CONTA (3ª) e vá adiante.
Na linha tem um ponto de GOTO, ele vai passar direto a primeira vez.
Na linha está o segredo, ele vai verificar novamente se o botão continua pressionado, e como está pressionado e vai executar a linha que é desviar para a rotina sobe3; na linha, e vai ficar neste loop até a o botão for solto, só então ele vai continuar o programa.


MONTAGEM

- Imagem da finalização da caixa e botões.
- A chave preta rotativa do lado direito e os dois botões pequenos, não fazem parte do projeto Arduino.





Video de funcionamento.



Só quero lembrar que a chave preta do lado direito e os dois botões pequenos (verde e vermelho) não fazem parte do esquema elétrico do projeto Arduíno.




Código arduino. 


#include <LiquidCrystal.h>
// Ultima alteração em 22/08/2014
// Foi alterado o valor do delay do botão pulso de 300 para 180 ms.
// select the pins used on the LCD panel
LiquidCrystal lcd(8, 9, 4, 5, 6, 7);

// define some values used by the panel and buttons
int lcd_key     = 0;
int adc_key_in  = 0;
long int q1=0 ; // Armazena o primeiro digito da contagem
long int q2=0 ;
long int q3=0 ;
long int q4=0 ;
long int total=0; // valor total de gravação
long int conta=0; //usado para contagem
int m=1; // multiplos
int t=1;
int Btnsobe=2; //botão sobe usará o pino 2
int BtnEnter=3; //Botão Enter usará o pino3
int BtnPulso=12; //Botão Pulso usará o pino 12
int buzz=13; // buzzer no pino 11
int relay1=1; //rele1
int relay2=11; //rele2 pulso
int sobe=0;
int enter=0;
int pulso=0;
int caso=0;
int pronto=0;
int gravados=0;
#define btnRIGHT  0
#define btnUP     1
#define btnDOWN   2
#define btnLEFT   3
#define btnSELECT 4
#define btnNONE   5

// read the buttons
int read_LCD_buttons()
{
 adc_key_in = analogRead(0);      // read the value from the sensor
 // my buttons when read are centered at these valies: 0, 144, 329, 504, 741
 // we add approx 50 to those values and check to see if we are close
 if (adc_key_in > 1000) return btnNONE; // We make this the 1st option for speed reasons since it will be the most likely result
 // For V1.1 us this threshold
 if (adc_key_in < 50)   return btnRIGHT;
 if (adc_key_in < 250)  return btnUP;
 if (adc_key_in < 450)  return btnDOWN;
 if (adc_key_in < 650)  return btnLEFT;
 if (adc_key_in < 850)  return btnSELECT;

 // For V1.0 comment the other threshold and use the one below:
/*
 if (adc_key_in < 50)   return btnRIGHT;
 if (adc_key_in < 195)  return btnUP;
 if (adc_key_in < 380)  return btnDOWN;
 if (adc_key_in < 555)  return btnLEFT;
 if (adc_key_in < 790)  return btnSELECT;
*/


 return btnNONE;  // when all others fail, return this...
}

void setup()
{
 pinMode(Btnsobe,INPUT_PULLUP); // Habilita o pullup do pino 2, significa que está em nivel alto sempre, mudara para 0 quando o botão SOBE ligar este pino ao terra(GND).
 pinMode(BtnEnter,INPUT_PULLUP); // Enter
 pinMode(BtnPulso,INPUT_PULLUP); // Pulso, origem do sinal que vai ativar a máquina. É este sinal que ele vai ler para diminuir o valor da contagem.
 pinMode(buzz,OUTPUT); // Saida do buzzer
 pinMode(relay1,OUTPUT); // saida rele 1
 pinMode(relay2,OUTPUT); // Saida rele 2  - pulso
 digitalWrite(buzz,LOW);
 digitalWrite(relay1,LOW);
 digitalWrite(relay2,LOW);
 lcd.begin(16, 2);              // Inicia a biblioteca do LCD
 lcd.setCursor(0,0);            // Coloca o cursor na primeira linha e primeira coluna.
 lcd.print("Contador Arduino"); // Imprime a mensagem CONTADOR ARDUINO
 lcd.setCursor(0,1);            // Coloca o cursos na SEGUNDA linha e coluna 0
 //lcd.print(millis()/1000);      // display seconds elapsed since power-up
 lcd.print("Multiplos:");
}

void loop()
{
   delay (100);
   lcd.setCursor(12,1); // move to the begining of the second line
   lcd_key = read_LCD_buttons();  // read the buttons
   sobe=digitalRead(Btnsobe); //faz a leitura da porta digital 2 (Botão Sobe)
   enter=digitalRead(BtnEnter);
   pulso=digitalRead(BtnPulso);
   lcd.print(m);
   if (sobe==0) // Verifica se o botão SOBE foi ativado, ativa em ZERO(LOW) - obs.: Aqui tb poderia se usado if (digitalRead(Btnsobe)==LOW)
    {
      m=m+1; // Soma mais um à variavel M que é a contagem dos MULTIPLOS
      m1: // Ponto de retorno do GOTO, usado para verificar se a tecla permanece acionada
      ;
      if (m>5)
       {
        m=1; // se o valor de M for maior que 5, volta a ser 1
        lcd.setCursor(12,1);
        lcd.print(m);
       }
      if (digitalRead(Btnsobe)==LOW) // verifica se o botao continua apertado, se continuar, vai para o loop M1 logo acima.
       {
        goto m1;
       }
    }
   if (digitalRead(BtnEnter)==LOW) // Defini o valor do MULTIPLO e entra na rotina para definir a quantidade de peças.
    {
       digitalWrite(relay1,HIGH);
       lcd.clear(); //Limpa o LCD
       lcd.setCursor(10,0);
       lcd.print("X");
       lcd.print(m);
       lcd.setCursor(0,1);
       lcd.print("Qtda: ");
       Enter:
       ;
       if (digitalRead(BtnEnter)==LOW) //Verifica se a tecla Enter continua acionada.
         {
           goto Enter;
         }
       conta=0;
       do  //rotina para definir a quantidade
       {
          delay (100);
          if (digitalRead(Btnsobe)==LOW)
           {
             conta=conta+1;
             sobe4:
             ;
             if (digitalRead(Btnsobe)==LOW)
              {
               goto sobe4;
              }
           }
          if (conta >9)
           {
             conta=0;
           }
          lcd.setCursor(12,1);
          lcd.print(conta);      
          if (digitalRead(BtnEnter)==LOW)
           {
             q4=conta; // armazena o valor escolhido para casa de milhar na variavel Q4
             enter4:
             ;
             if (digitalRead(BtnEnter)==LOW)
              {
               goto enter4;
              }
              pronto=1;
           }
     
       } while (pronto==0);
     
       conta=0;
       pronto=0;
       do  //rotina para definir a quantidade
       {
          delay (100);
          if (digitalRead(Btnsobe)==LOW)
           {
             conta=conta+1;
             sobe3:
             ;
             if (digitalRead(Btnsobe)==LOW)
              {
               goto sobe3;
              }
           }
          if (conta >9)
           {
             conta=0;
           }
          lcd.setCursor(13,1);
          lcd.print(conta);      
          if (digitalRead(BtnEnter)==LOW)
           {
             q3=conta; // armazena o valor escolhido para casa de milhar na variavel Q4
             enter3:
             ;
             if (digitalRead(BtnEnter)==LOW)
              {
               goto enter3;
              }
              pronto=1;
         }
     
       } while (pronto==0);
       conta=0;
       pronto=0;
       do  //rotina para definir a quantidade
       {
          delay (100);
          if (digitalRead(Btnsobe)==LOW)
           {
             conta=conta+1;
             sobe2:
             ;
             if (digitalRead(Btnsobe)==LOW)
              {
               goto sobe2;
              }
           }
          if (conta >9)
           {
             conta=0;
           }
          lcd.setCursor(14,1);
          lcd.print(conta);      
          if (digitalRead(BtnEnter)==LOW)
           {
             q2=conta; // armazena o valor escolhido para casa de milhar na variavel Q4
             enter2:
             ;
             if (digitalRead(BtnEnter)==LOW)
              {
               goto enter2;
              }
              pronto=1;
         }
     
       } while (pronto==0);
       conta=0;
       pronto=0;
       do  //rotina para definir a quantidade
       {
          delay (100);
          if (digitalRead(Btnsobe)==LOW)
           {
             conta=conta+1;
             sobe1:
             ;
             if (digitalRead(Btnsobe)==LOW)
              {
               goto sobe1;
              }
           }
          if (conta >9)
           {
             conta=0;
           }
          lcd.setCursor(15,1);
          lcd.print(conta);      
          if (digitalRead(BtnEnter)==LOW)
           {
             q1=conta; // armazena o valor escolhido para casa de milhar na variavel Q4
             enter1:
             ;
             if (digitalRead(BtnEnter)==LOW)
              {
               goto enter1;
              }
              pronto=1;
         }
     
       } while (pronto==0);
       conta=(q4*1000)+(q3*100)+(q2*10)+q1; //formula da contagem
       total=conta;
       delay(50);
       lcd.clear();
       lcd.setCursor(0,0);
       lcd.print("T.: ");
       lcd.print(conta);
       lcd.setCursor(14,0);
       lcd.print("    ");
       lcd.setCursor(14,0);
       lcd.print("X");
       lcd.print(m);
       lcd.setCursor(0,1);
       lcd.print("F.: ");
     
       do // Rotina para a contagem das peças
       {
         if(digitalRead(BtnPulso)==LOW) // verifica se chegou o pulso para gravação
           {
             delay(120); // tempo que o botão deve ficar pressionado
             if(digitalRead(BtnPulso)==LOW) // O botão precisa ficar pressionado por mais tempo para ir adiante, evita ruido.
                    {
                   digitalWrite(relay2,HIGH);
                   delay(300);
                   digitalWrite(relay2,LOW);
                   digitalWrite(buzz,HIGH);
                   delay(100);
                   digitalWrite(buzz,LOW);
                   conta=conta-m; // diminui do total a ser gravado o valor do Multiplo
                   if ((conta-m<=0)||(conta-m>65500)) // Vai acionar o alarme quando estiver na penúltima gravação
                      {
                     digitalWrite(buzz,HIGH);
                     delay(250);
                     digitalWrite(buzz,LOW);                      
                      }
                    }
           if ((conta<=0)||(conta>65500)) //qdo chegar a ZERO ou passar dele, encerra a contagem, FIM
            {
            conta=0; // deixa a contagem em ZERO
            lcd.setCursor(13,0);
            lcd.print("FIM");
            //lcd.setCursor(4,1);
            //lcd.print("0   ");
            //lcd.setCursor(10,1);
            //lcd.print(total);
            digitalWrite(buzz,HIGH);
            delay(3000);
            digitalWrite(buzz,LOW);
            digitalWrite(relay1,HIGH);
            }
           delay(250);
           lcd.setCursor(4,1);
           lcd.print("    ");
           lcd.setCursor(4,1);
           lcd.print(conta);
           lcd.setCursor(10,1);
           lcd.print("G:"); // G de peças já gravadas
           gravados=total-conta; // coloca na variavel GRAVADOS a diferença do TOTAL, ou seja, as peças já gravadas
           lcd.print(gravados); // imprime quantas peças já foram gravadas
           p:
           ;
           if(digitalRead(BtnPulso)==LOW) // verifica se o botão continua pressionado
             {
               goto p;
             }
         
         }
       }while (conta!=0);
       fim:
       ;
       goto fim;
     }
}

   







3 comentários:

  1. posta o arquivo(código) novamente amigo

    ResponderExcluir
  2. valeu o contador esta 80% Otimo, Obrigado

    ResponderExcluir
  3. Muito bom amigo. Parabéns.
    pra que serve essa linha
    lcd_key = read_LCD_buttons(); // read the buttons
    se você não usa os botões da placa?
    e aquele problema do bounce que você fez os go to. Daria pra colocar um delay após essa leitura? ex: delay(300);

    ResponderExcluir