quarta-feira, 8 de julho de 2015

Teclado Touch Digital Capacitivo 16 Teclas Ttp229

Hoje falaremos um pouco sobre o Teclado Touch Digital Capacitivo 16 Teclas Ttp229.

O uso de teclados touch capacitivos é uma tendência nos dias atuais, já que a vida útil de uma tecla desse tipo é muito superior a de uma tecla mecânica. Outro fator interessante para o uso desse tipo de teclado é a possibilidade de um design mais moderno. Cada vez mais estão surgindo interfaces desse tipo, seja em eletrodomésticos, aparelhos eletrônicos ou até mesmo em interfaces industriais.

Nesta postagem iremos mostrar como configurar o Teclado Touch Digital Capacitivo 16 Teclas Ttp229 para trabalhar em conjunto com o seu Arduino.
O Teclado Touch Digital Capacitivo 16 Teclas Ttp229 pode ser configurado de duas maneiras: para trabalhar como um teclado  de 8 ou 16 teclas.
Para que ele funcione com 16 teclas, precisamos utilizar um jumper entre os pinos 3 e 4 do barramento P1 (destacado em vermelho na imagem abaixo). Esse jumper pode ser feito de duas formas: conectando os terminais diretamente com solda ou soldando terminais do tipo Barra de Pinos e utilizando Jumpers convencionais.

1. Conecte os terminais VCC e GND do teclado aos pinos correspondentes no Arduino.
2. Conectar o pino SCL do teclado ao pino 7 do Arduino. (Se necessário, é possivel alterar esse pino. Basta alterar para o pino desejado no código. Para isto, precisamos encontrar no código a linha que contem a declaração "TTP16Button.Configure(7, 2)" e substituir o numero 7 pelo número do pino desejado)
3. Conectar o pino SDO do teclado ao pino 2 do Arduino (Conectar a outros pinos é possível, desde que se altere o número 2 pelo número desejado na declaração "TTP16Button.Configure(7, 2)").

Pronto! Agora é só enviar o código para o Arduino e abrir o Monitor Serial para conferir os resultados.
"Pressionando" sequencialmente as teclas, partindo do número 1 e chegando ao 16, a tela do Monitor Serial deverá ficar como mostrado na imagem abaixo:

Baixe aqui o arquivo do Skech para essa montagem.
Segue abaixo o código fonte utilizado para esse teste.

 //############### ELETRODEX ELETRÔNICA ###############  
 // Programa de interface entre o Arduino  
 // e o Teclado Touch Digital Capacitivo 16 Teclas Ttp229  
 //   
 // As Conexões devem ser feitas da seguinte forma:  
 // Teclado TTP229 |  Arduino  
 //   GND    |   GND  
 //   VCC    |   5v  
 //   SCL    |   D7  
 //   SDO    |   D2  
 #include <SPI.h>  
 #if 0  
  #define DEBUG_BUTTON16(a) (a)  
 #else  
  #define DEBUG_BUTTON16(a)  
 #endif  
 #if 1  
  #define DEBUG_STATUS(a) (a)  
 #else  
  #define DEBUG_STATUS(a)  
 #endif  
 #pragma pack(push, 0)  
 // TBD: Replace with proper interrupt pin macros. It does not seem to be defined for atmega328p or I am incapable of finding it  
 #ifndef INT0_PIN  
 #ifdef __AVR_ATmega328P__  
 #define INT0_PIN 2  
 #else  
  #warning Define INT0_PIN for this microcontroller to use interrupt  
 #endif  
 #endif  
 #ifndef INT1_PIN   
 #ifdef __AVR_ATmega328P__  
 #define INT1_PIN 3  
 #else  
  #warning Define INT1_PIN for this microcontroller to use interrupt  
 #endif  
 #endif  
 uint32_t g_intCount = 0;  
 struct CTtp229ButtonEvent  
 {  
  uint8_t ButtonNumber : 5;     // ButtonNumber != 0 : Event is present. if equals 0, no event is received  
  uint8_t IsButtonReleased : 1;   // True = Button is pressed. False = Button is released  
 };  
 class CTtP229TouchButton  
 {  
  struct CTtp229Prop  
  {  
   uint16_t SclPin : 6;  
   uint16_t SdoPin : 6;  
   uint16_t Is16Button : 1;  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
   uint16_t HasPendingInterrupt : 1;  
   uint16_t IgnoreNextEvent : 1;      // When reading 16th key and if it is pressed, SDO stays low for 2ms.  
                        // If we enable interrupt before that, then it will trigger after 2ms, only to find the same condition.  
                        // To make things worse, at the end of reading the pin will stay low and generate another interrupt.  
                        // TBD: One possible fix is to send more pulses to make it roll over to HIGH. Have to find out if all 16 keys can be pressed in multi-key scenario (NOT supported yet).    
   uint16_t UnhandledButtonPresses;  
 #endif  
   uint16_t PreviousButtonValue;  
  };  
  static CTtp229Prop g_prop;  
  //  
  //  Internal function that captures the data from TTP229 on which key is pressed.  
  // Currently, this function only supports one key being pressed. Multi-key press needs to be added later.  
  //   
  // Return Value : Bit field of buttons pressed  
  //  
  static uint16_t GetPressedButton()  
  {  
   DEBUG_BUTTON16(Serial.println("GetPressedButton : Enter "));  
   uint16_t buttonsPressed = 0;  
   // Need to generate the LOW and then HIGH on the clock and read the value from data when clock is back high.  
   // As per the specification, the TTP229 chip can support 512Khz. This translates to approximately 2us for a cycle. So introducing clock with fall and raise each of 1us.  
   uint8_t maxCnt = g_prop.Is16Button ? 16 : 8;  
   for(uint8_t ndx = 0; ndx < maxCnt; ndx++ )  
   {  
    digitalWrite(g_prop.SclPin, LOW);  
    delayMicroseconds(1);  
    digitalWrite(g_prop.SclPin, HIGH);  
    int val = digitalRead(g_prop.SdoPin);  
    delayMicroseconds(1); // Technically this can be moved after the if for most atmel microcontrollers. But if there is a really fast one (now/future) and the next call to GetPressedButton made immediately, we might overclock TTP229. Being safe here  
    if( LOW == val )  
    {  
     buttonsPressed |= (1 << ndx);  
    }     
   }  
   DEBUG_BUTTON16(Serial.print("GetPressedButton : Exit. Return Value : ")); DEBUG_BUTTON16(Serial.println(buttonsPressed));  
   return buttonsPressed;  
  }  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
  // Detaching the interrupt after receiving the data can cause problem in sleeping. If the interrupt is not properly dispatched, it can lead to permanent sleep and can't wake up from button  
  static void HandleButtonEvent()  
  {  
   if( g_prop.IgnoreNextEvent )  
   {  
    // We ignored an event. Now we will accept the event  
    g_prop.IgnoreNextEvent = false;  
   }  
   else  
   {  
    g_prop.HasPendingInterrupt = true;  
    g_intCount++;  
   }  
  }  
  static void SetInterruptHandler()  
  {  
 #ifdef INT0_PIN    
   if( INT0_PIN == g_prop.SdoPin )   
   {  
    DEBUG_BUTTON16(Serial.println("Configure : With interrupt 0"));  
    EIFR = 0x01; // Clear INTF0 flag  
    attachInterrupt(0, HandleButtonEvent, RISING); // The pin goes down for 93us and then raises that is when the device is ready (technically after 10us)     
   }  
 #endif   
 #ifdef INT1_PIN    
   if( INT1_PIN == g_prop.SdoPin )   
   {  
    DEBUG_BUTTON16(Serial.println("Configure : With interrupt 1"));  
    EIFR = 0x02; // Clear INTF1 flag  
    attachInterrupt(1, HandleButtonEvent, RISING); // The pin goes down for 93us and then raises that is when the device is ready (technically after 10us)     
   }  
 #endif   
  }  
  static void RemoveInterruptHandler()  
  {  
 #ifdef INT0_PIN  
   if( INT0_PIN == g_prop.SdoPin )   
   {  
    detachInterrupt(0);  
   }  
 #endif  
 #ifdef INT1_PIN   
   if( INT1_PIN == g_prop.SdoPin )   
   {  
    detachInterrupt(1);  
   }  
 #endif  
  }  
 #endif  
  //  
  //  Returns button number being pressed. High bit indicates more changes present  
  //  
  static uint8_t GetButtonNumberFromFlag(uint16_t buttonsChanged)  
  {  
   uint16_t flag = 1;  
   for(uint8_t ndx = 1; ndx <=16; ndx++, flag <<= 1)  
   {  
    if( (buttonsChanged & flag) != 0 )  
    {  
     if( (buttonsChanged & ~flag) != 0 )  
     {  
      // Some other bit is present  
      ndx |= 0x80;  
     }  
     return ndx;  
    }  
   }  
   return 0;  
  }  
  public:  
  //  
  //  Setup the TTP229 Touch button on this input.  
  //  
  // Inputs:  
  //   sclPin - Clock Pin of the button (3rd from left on button, connected to arduino's digital pin number)  
  //   sdoPin - Data pin to read from the button (4th pin from left on button, connected to arduino's digital pin number)  
  //   is16Button - true = 16 buttons board. false = 8 button board  
  //  
  static void Configure(int sclPin, int sdoPin, bool is16Button = true)  
  {  
   DEBUG_BUTTON16(Serial.println("Configure : Enter"));   
   g_prop.SclPin = sclPin;  
   g_prop.SdoPin = sdoPin;  
   g_prop.Is16Button = is16Button;  
   g_prop.PreviousButtonValue = 0;  
   // Configure clock as output and hold it high  
   pinMode( sclPin, OUTPUT );   
   digitalWrite(sclPin, HIGH);    
   // Configure data pin as input  
   pinMode( sdoPin, INPUT);  
   DEBUG_BUTTON16(Serial.print("Button Configuration\n\rSCL Pin : "));  
   DEBUG_BUTTON16(Serial.println(sclPin));  
   DEBUG_BUTTON16(Serial.print("SDO Pin : "));  
   DEBUG_BUTTON16(Serial.println(sdoPin));  
   DEBUG_BUTTON16(Serial.print("Number of Keys : "));  
   DEBUG_BUTTON16(Serial.println(is16Button ? 16 : 8));  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
   g_prop.UnhandledButtonPresses = 0;  
   g_prop.HasPendingInterrupt = false;  
   g_prop.IgnoreNextEvent = false;  
   SetInterruptHandler();  
 #endif  
   DEBUG_BUTTON16(Serial.println("Configure : Exit"));  
  }  
  //  
  //  Get the current status from the 16 button touch device  
  //  
  //  Return Value : Returns the bitflag of the keys pressed. returns 0, if no key is pressed.  
  //  
  static uint16_t GetButtonStatus()  
  {  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
   g_prop.HasPendingInterrupt = 0;  
 #endif  
   uint16_t returnValue = GetPressedButton();  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
   returnValue |= g_prop.UnhandledButtonPresses;  // and also include any data that was received that we have not sent yet.  
   g_prop.UnhandledButtonPresses = 0;  
 #endif  
   g_prop.PreviousButtonValue = returnValue;  
   return returnValue;   
  }  
  //  
  //  Gets the event from the button. This is useful for monitoring press and release only.   
  // Each button press will generate max 2 events, one for press and another for release. When the button is press and held, this method will return no event.  
  // If the calls were not made often enough, the events could be missed. For instance, you might get 2 pressed, followed by 4 pressed, which automatically means 2 released in single key mode.  
  //  
  // Return Value : if ButtonNumber is 0, then no event  
  //  
  static CTtp229ButtonEvent GetButtonEvent()  
  {  
   CTtp229ButtonEvent returnValue = {0, 0};  
   uint8_t buttonNumber;  
   DEBUG_BUTTON16(Serial.print("Old Value : "));  
   DEBUG_BUTTON16(Serial.println(g_prop.PreviousButtonValue));  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
   if(  
 #if defined(INT0_PIN)  
   INT0_PIN == g_prop.SdoPin   
 #endif  
 #if defined(INT0_PIN) && defined(INT1_PIN)  
   ||  
 #endif  
 #if defined(INT1_PIN)  
   INT1_PIN == g_prop.SdoPin   
 #endif  
   )   
   {  
    // Interrupts are used. Check if we have interrupt  
    if( g_prop.HasPendingInterrupt )  
    {  
     RemoveInterruptHandler();         // From this point upto SetInterruptHandler is called, ensure there is no return path that will leave without SetInterruptHandler  
    }  
    else  
    {  
     DEBUG_BUTTON16(Serial.println("GetButtonEvent: No interrupt pending"));  
     return returnValue;  
    }  
   }  
 #endif  
   uint16_t currValue = GetPressedButton();  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
   currValue |= g_prop.UnhandledButtonPresses; // Get any previously returned but not returned now values also into the mix  
 #endif  
   uint16_t changes = g_prop.PreviousButtonValue ^ currValue;  
   uint16_t pressed = (changes & currValue);  
   uint16_t released = (changes & g_prop.PreviousButtonValue);  
   // First check if any key is that is pressed and generate press event  
   if( 0 != pressed )  
   {  
    buttonNumber = GetButtonNumberFromFlag(pressed);  
    returnValue.ButtonNumber = (buttonNumber & 0x7F);  
    uint16_t mask = (1 << (returnValue.ButtonNumber -1));  
    // set the new notified button into prev  
    g_prop.PreviousButtonValue |= mask;  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
    g_prop.UnhandledButtonPresses = currValue;  
    g_prop.UnhandledButtonPresses = currValue & ~g_prop.PreviousButtonValue;  // clear unhandled for this bit, just in case  
 #endif  
   }  
   else if(0 != released)  
   {  
    buttonNumber = GetButtonNumberFromFlag(released);  
    returnValue.ButtonNumber = (buttonNumber & 0x7F);  
    // The unmatching bit whose previous value of 1 means, it is released  
    returnValue.IsButtonReleased = true;  
    // clear the notified release button  
    g_prop.PreviousButtonValue &= ~(1 << (returnValue.ButtonNumber -1));  
   }  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
   if(((!returnValue.IsButtonReleased || (0 == pressed))  // We handle release but no pending press  
      && ((buttonNumber & 0x80) == 0 )) // or more button changes are detected  
     || (returnValue.ButtonNumber == 0) )  // safety in case interrupt and data mismatch or code bug  
   {  
    // No more button notification pending  
    g_prop.HasPendingInterrupt = false;  
   }  
   else  
   {  
    DEBUG_BUTTON16(Serial.println("not Clearing interrupt"));  
   }  
   g_prop.IgnoreNextEvent = digitalRead(g_prop.SdoPin) == LOW; // If the pin is still low at the end of reading, ignore next event which is for data finished raise  
   DEBUG_BUTTON16(Serial.print(g_prop.IgnoreNextEvent ? "Ignoring next event\n\r" : "Not ignoring\n\r"));  
   // All the data has been read. Now reactivate the interrupt  
   SetInterruptHandler();  
 #endif  
   DEBUG_BUTTON16(Serial.print("currValue : "));  
   DEBUG_BUTTON16(Serial.println(currValue));  
   DEBUG_BUTTON16(Serial.print("Changes  : "));  
   DEBUG_BUTTON16(Serial.println(changes));  
   DEBUG_BUTTON16(Serial.print("Button N  : "));  
   DEBUG_BUTTON16(Serial.println(buttonNumber));  
   DEBUG_BUTTON16(Serial.print("Unhandled : "));  
   DEBUG_BUTTON16(Serial.println(g_prop.UnhandledButtonPresses));  
   DEBUG_BUTTON16(Serial.print("ButtonRelease : "));  
   DEBUG_BUTTON16(Serial.println(returnValue.IsButtonReleased));  
   DEBUG_BUTTON16(Serial.print("buttonNumber : "));  
   DEBUG_BUTTON16(Serial.println(buttonNumber));  
   DEBUG_BUTTON16(Serial.print("Pending interrupts :"));  
   DEBUG_BUTTON16(Serial.println(g_prop.HasPendingInterrupt));  
   return returnValue;  
  }  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
  static bool HasEvent()  
  {  
 #if defined(INT0_PIN)  
   if( INT0_PIN == g_prop.SdoPin )  
   {  
    return g_prop.HasPendingInterrupt;  
   }  
 #endif  
 #if defined(INT1_PIN)  
   if( INT1_PIN == g_prop.SdoPin )  
   {  
    return g_prop.HasPendingInterrupt;  
   }  
 #endif  
   return true;  
  }  
 #endif  
 };  
 CTtP229TouchButton::CTtp229Prop CTtP229TouchButton::g_prop;  
 CTtP229TouchButton g_ttp229Button;  
 #define TTP16Button g_ttp229Button  
 #pragma pack(pop)  
 void setup()  
 {  
  Serial.begin(115200);  
  DEBUG_STATUS(Serial.println("===================================="));  
  DEBUG_STATUS(Serial.println("Teste do Teclado Capacitivo Iniciado"));   
  DEBUG_STATUS(Serial.println("===================================="));  
  TTP16Button.Configure(7, 2);  
 }  
 void TestStatus()  
 {  
  uint8_t buttonNumber = TTP16Button.GetButtonStatus();  
  if( 0 != buttonNumber )  
  {  
   DEBUG_STATUS(Serial.print("Tecla Acionada : "));  
   DEBUG_STATUS(Serial.println(buttonNumber));  
  }  
  delayMicroseconds(2500); // TTP229 document says it will reset the output if 2ms idle + little bit safety  
 }  
 void TestEvent()  
 {  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
  if( TTP16Button.HasEvent())  
 #endif  
  {  
   CTtp229ButtonEvent buttonEvent = TTP16Button.GetButtonEvent();  
   if( 0 != buttonEvent.ButtonNumber )  
   {  
    if( buttonEvent.IsButtonReleased )  
    {  
     DEBUG_STATUS(Serial.print("Tecla Liberada : "));  
    }  
    else  
    {  
     DEBUG_STATUS(Serial.print("Tecla Acionada : "));  
    }  
    DEBUG_STATUS(Serial.println(buttonEvent.ButtonNumber));  
   }  
   else  
   {  
 #if defined(INT0_PIN) || defined(INT1_PIN)  
 //    DEBUG_STATUS(Serial.println("Are you not using interrupt? Should never come here for interrupt based system."));  
 #endif  
   }  
   //Serial.print("CurrentTime : "); Serial.println(millis());  
   delayMicroseconds(2500); // TTP229 document says it will reset the output if 2ms idle + little bit safety. Not required if using interrupts  
  }  
 }  
 void loop()  
 {  
  //TestStatus();  
  TestEvent();  
 }  

Agora que você já sabe como configurar seu Teclado Touch Digital Capacitivo 16 Teclas Ttp229 como um dispositivo de entrada para seus projetos, conte-nos sobre suas experiências com os produtos da nossa loja.

Dados Técnicos:
  • Tamanho PCB: 49,3 x 64,5 mm.
  • Quantidade de teclas: 16.
  • Comunicação: I2C.
  • Voltagem de operação: 2,5V a 5V DC
  • Pode configurar a velocidade de resposta, e formato de saída
  • Indicador LED 
Até a próxima postagem!

sexta-feira, 3 de julho de 2015

Utilizando o Modulo Sensor de Reconhecimento de Impressão Digital

Nesta postagem iremos mostrar como utilizar o Modulo Sensor de Reconhecimento de Impressão Digital.

Com esse módulo, a adição de detecção e verificação de impressões digitais ao seu projeto fica super simples! Esse módulo faz a captura de imagem, os cálculos, a varredura por detalhes na imagem e a busca no banco de dados (que é capaz de armazenar 1000 entradas) por conta própria, sendo necessária somente a conexão com um sistema com comunicação serial TTL para a tomada de decisão a partir da informação de aprovação ou rejeição da impressão digital lida.

Além de ser um dispositivo de fácil utilização, existe um software bastante intuitivo (que pode ser baixado aqui) para simplificar os testes e o uso do Modulo Sensor de Reconhecimento de Impressão Digital e até mesmo efetuar diretamente o registro de digitais na memória dele.

Primeiramente, iremos falar sobre o software baixado no link acima:
Para realizar a ligação do Modulo Sensor de Reconhecimento de Impressão Digital com o computador, é necessário que ele seja ligado a uma interface Serial do tipo TTL.
Nos notebooks, essa interface deve ser feita através de um hardware específico, como o Cabo USB Serial TTL PL2303HX, conectado em uma porta USB.
Porém, também é possível (e muito mais fácil), utilizar um Arduino para realizar tal interface. Basta programar o mesmo com um código vazio, como o mostrado abaixo:

 //############### ELETRODEX ELETRÔNICA ###############  
 //  
 // Sketch para ignorar o ATmega do Arduino  
 // e conectar diretamente o Sensor de Impressão Digital  
 // ao chip conversor USB-Serial  
 // As Conexões devem ser feitas da seguinte forma:  
 // Módulo Sensor | Arduino  
 //  Preto        |   GND  
 //  Vermelho     |   5v  
 //  Branco       |   D0  
 //  Verde        |   D1  
 void setup() {}  
 void loop() {}  

Confira uma imagem da interface do programa, com destaque em suas principais funções:

Agora teremos uma breve descrição das principais funções do programa:

Em Initialization (destacado em Roxo):
  • Open Device(O): Inicialização do dispositivo. É a primeira coisa que se deve fazer, para estabelecer a comunicação entre o computador e o sensor. Após clicar em Open Device, irá aparecer uma janela solicitando que seja informada a porta COM utilizada pelo sensor.
Em  Image Manage (destacado em Amarelo):  
  • Capture: Captura de impressões digitais, sem gravação. Serve para verificar se o dispositivo está funcionando corretamente e se comunicando com o computador (a janela do sensor pisca em vermelho quando o mesmo está ativo).
  • Con Capture: É a realização dessa ação de maneira repetitiva.
Em Enroll (destacado em Verde):
  • Enroll: Captura de impressões digitais, com a gravação das mesmas na memória do dispositivo. Cada impressão é associada a um número. 
  • Con Enroll: É a realização dessa ação de maneira repetitiva. 
 Note que a imagem da impressão digital cadastrada somente irá ser mostrada se a caixa "Preview" estiver devidamente marcada. 

Em Match (destacado em Azul): 
  • Match: Confere se a próxima impressão digital é compatível com o registro selecionado (deve-se selecionar um, no campo Address)
  • Search: Confere se a próxima impressão digital é compatível com qualquer um dos registros armazenados.
  • Con Search: Realiza a ação acima de maneira repetitiva
  • Quick Search: Tem a mesma função do botão Con Search
Em Template Database (destacado em Vermelho):
  • Empty: Apaga TODAS as impressões digitais registradas.
  • Delete: Apaga somente a impressão digital selecionada.
Agora vamos falar sobre a utilização do Modulo Sensor de Reconhecimento de Impressão Digital em conjunto com o Arduino.

Primeiramente, é necessário baixar a biblioteca para interfacear o Arduino com o sensor.
(A biblioteca pode ser baixada aqui, mas também está disponível no site da Adafruit.)

Uma vez baixada e instalada, a biblioteca possui seis Sketches de exemplo, que serão discutidos a seguir: (em todos os exemplos constam quais as ligações a serem efetuadas entre o Arduino e o Modulo Sensor de Reconhecimento de Impressão Digital)

  1.  blank, que já foi mostrado acima e serve para realizar a ligação direta entre o Modulo Sensor de Reconhecimento de Impressão Digital e o conversor USB-Serial do Arduino, possibilitando a interface com o programa mostrado anteriormente. 
  2. delete, que serve unicamente para apagar a impressão digital do endereço informado pelo usuário. Assim que o programa inicia, é solicitado que o usuário informe o número da digital que deseja apagar. 
  3. enroll, que é o Sketch utilizado para armazenar as impressões digitais na memória do dispositivo. Quando executado, o programa solicita ao usuário que informe o endereço para a alocação dos dados da impressão digital analisada. 
  4. fingerprint, que verifica se alguma das impressões digitais armazenadas coincide com a que está sendo analizada no momento. Quando executado, o programa aguarda até que o usuário coloque o dedo no sensor e analisa se a impressão digital está armazenada no banco de dados. Se a impressão digital constar no sistema, ele retorna uma mensagem, informando qual posição no banco de dados ela ocupa e qual o grau de confiabilidade da leitura (quanto maior o número informado, melhor). Caso a impressão digital não conste no banco de dados, o programa simplesmente irá ignorá-la, não retornando nenhuma informação. 
  5. leo_passthru, que possui a mesma finalidade do blank, porém para o Arduino Leonardo 
  6. show_fingerprint_templates que mostra no Monitor Serial o padrão utilizado para o armazenamento das impressões digitais no sensor.


IMPORTANTE!!
  •  Sempre que for utilizado o monitor serial em conjunto com um dos Sketches acima, a caixa de seleção destacada em vermelho na imagem abaixo deverá sempre estar mostrando a opção "Nova-linha".

Confira abaixo abaixo algumas informações sobre ele:
Material: Plástico + componentes eletrônicos
Frequência de operação: 433Mhz/868Mhz/915Mhz
Sensibilidade: -100dBm 
Tensão de operação: 1.9~3.6V,
Taxa de operação: 50Kbps,
Tensão de Alimentação: DC 3.6~6.0V 
Tamanho do arquivo de caractere: 256 bytes
Tamanho do template: 512 bytes
Capacidade de armazenamento: 1000 impressões digitais
Tempo de busca: < 1 second
Grau de Reconhecimento em Falso-Positivo (False Acceptance Rate - FAR) < 0.001% 
Grau de Reconhecimento em Falso-Negativo (False Rejection Rate - FRR) < 1.0% (security level: 3)
Tensão: 3.6-6.0V DC via USB
Corrente de operação: < 120mA
Tensão de Pico: < 140mA
Dimensões da janela do sensor: 14 x 18mm
Taxa de transmissão de dados: UART: (9600×N)bps (N=1~12, N padrão 6, =57600bps)
Temperatura ambiente para operação: -20 a 50°C
Umidade Relativa: 40%RH to 85%RH (sem condensação)

Conte-nos suas experiências utilizando os produtos adquiridos em  nossa loja!
Até o próximo artigo!

quinta-feira, 2 de julho de 2015

Utilizando o Motor Micro Servo TowerPro SG-5010 360º Rotação Contínua



Nessa postagem iremos mostrar como utilizar o Motor Micro Servo TowerPro SG-5010 360º Rotação Contínua em conjunto com o Arduino.

Motor Micro Servo TowerPro SG-5010 360º Rotação Contínua
A característica de maior destaque em um servo motor é a capacidade de movimentar o seu eixo até uma posição e, mesmo que este seja forçado em outra direção, manter o eixo imóvel.
A maioria dos servo motores são construidos de maneira a ter uma rotação de no máximo 180°, sendo que essa rotação é dividida entre 90° no sentido horário e 90° no sentido anti-horário.

Esse tipo de motor é acionado quando recebe um sinal no formato PWM (Pulse Width Modulation). Este sinal pode ter nível lógico alto (5V) ou baixo (0V). Os servos possuem um circuito de controle que monitora o sinal de entrada a cada 20ms, e se dentro deste intervalo ele percebe uma alteração do sinal de 0v para 5v com uma duração entre 1ms e 2ms ele envia um comando para o motor, de maneira a obedecer a ordem do sinal.
Sinal PWM com período de 20ms
 
Um sinal de 1ms corresponde a uma posição do braço do servo todo a esquerda ou 0º.
Um sinal de 1,5ms é o que chamamos de posição central do servo ou 90º.
Um sinal de 2ms corresponde a uma posição do braço do servo todo a direita ou 180º.

 Sinais PWM para controle de um servo motor
Uma vez que o servo recebe um sinal de 1,5ms ( por exemplo ), ele verifica se o potenciômetro encontra-se na posição correspondente(no caso, 90°). Caso se encontre na posição desejada, não acontecerá nada. Se o potenciômetro não estiver na posição correspondente ao sinal recebido, o circuito de controle aciona o motor até o potenciômetro estar na posição certa.
A direção de rotação do motor do servo vai depender também da posição do potenciômetro, sendo que se ele estiver em uma posição entre 0° e 90° o motor vai girar em uma direção, e se ele estiver entre 90° e 180°,ele irá girar na direção contrária.
Um outro detalhe interessante é em relação à velocidade: quando um sinal PWM é enviado ao servo, quanto mais "afastado" ele estiver da posição de referência (90°), maior será a sua velocidade de rotação. Por exemplo: se for enviado o sinal PWM correspondente a 80°, a velocidade de rotação em direção à posição referente à posição 0° será muito menor que a velocidade de rotação quando o sinal enviado corresponde a 10°. Da mesma maneira, o sinal referente a 100° resulta em uma velocidade muito menor que a velocidade resultante de um sinal de 170°, em direção à posição referente a 180°.


O Motor Micro Servo TowerPro SG-5010 360º Rotação Contínua é um servo de rotação contínua, ou seja, ele não possui a limitação de giro em 180°, como os servo motores comuns. Isso nos possibilita uma variedade imensa de aplicações, uma vez que é um motor com rotação contínua, velocidade controlada, baixa rotação e altíssimo torque.
Uma dessas aplicações, que será mostrada a seguir, é uma montagem simples, com o objetivo de içar uma carga.
A carga utilizada é composta por dois rolos de Solda Alpha Telecore 1 mm P3 Lead-Free 500g, totalizando 1kg de carga.
Para facilitar a visualização e a interação com o Arduino, será utilizado também um Shield LCD com teclado para Arduino.
O código funciona da seguinte forma:
As teclas "Up" e "Down" incrementam e decrementam a variável "grau" em uma unidade, respectivamente;
As teclas "Left" e "Right" incrementam e decrementam a variável "grau" em dez  unidades, respectivamente;
A tecla "Select" envia o comando para o Servo.

Confira um vídeo mostrando o andamento do teste:
[VIDEO]

Baixe aqui o sketch com a programação do Arduino para esse projeto.
Segue abaixo o código fonte utilizado nesse projeto.

 //############### ELETRODEX ELETRÔNICA ###############  
 // Programa de Teste de carga do Servo TowerPro SG-5010  
 //  
 // As Conexões devem ser feitas da seguinte forma:  
 //  SG-5010  |  Arduino  
 //  MARROM   |   GND  
 //  VERMELHO |   5v  
 //  AMARELO  |   D3  
 #include <LiquidCrystal.h>  
 #include <Servo.h>  
 Servo motor;  
 LiquidCrystal lcd(8, 9, 4, 5, 6, 7);  
 int grau = 90;  
 void setup()  
 {  
  motor.attach(3);  
  lcd.begin(16, 2);  
  lcd.setCursor(0, 0);  
  lcd.print("  Eletrodex  ");  
  lcd.setCursor(0, 1);  
  lcd.print("Graus:");  
 }  
 void loop()  
 {  
  int botao;  
  botao = analogRead (0); //Leitura do valor da porta analógica A0  
  lcd.setCursor(8, 1);  
  if (botao < 90)  
  {  
   grau = grau + 10;  
   lcd.print (grau);  
   delay(100);  
  }  
  else if (botao < 250)  
  {  
   grau++;  
   lcd.print (grau);  
   delay(100);  
  }  
  else if (botao < 400)  
  {  
   grau--;  
   lcd.print (grau);  
   delay(100);  
  }  
  else if (botao < 630)  
  {  
   grau = grau - 10;  
   lcd.print (grau);  
   delay(100);  
  }  
  else if (botao < 800) {  
   motor.write(grau);  
   lcd.print (grau);  
   delay(100);  
  }  
 }  


Conte-nos suas experiências utilizando os produtos adquiridos em  nossa loja!
Até o próximo artigo!

sábado, 27 de junho de 2015

Como programar com Programador KIT 3.5 para PIC

Nesta postagem iremos falar sobre o Programador KIT 3.5



O Programador KIT 3.5 é um programador para microcontroladores PIC bastante completo, até o momento compatível com  mais de 600 dispositivos da linha de microcontroladores da Microchip, incluindo a nova linha dsPIC.
(Confira aqui a lista com os microcontroladores compatíveis com o Kit 3.5)

Permite a programação diretamente na placa (ICSP) ou então através de conectores ZIF (não inclusos).
Detalhe para a interface ICSP

Com ele é possível gravar (programar), ler, verificar e copiar os códigos dos microcontroladores, através do software gratuito PicKit 3 Programmer (instruções de uso), uma vez que ele é totalmente compatível com o PICkit3.
Lembrando que este software é apenas para a gravação do arquivo HEX no seu microcontrolador, sendo que é necessário gerar esse arquivo em um compilador de sua escolha.
Além disso, é possível utilizá-lo como ferramenta de depuração (debug) através do software MPLAB.

Características:
  • Conexão USB (Full speed 12 Mbits/s)
  • Execução em tempo real
  • Compatível com MPLAB IDE (Download grátis pelo site da Microchip)
  • Monitor de curto-circuito/sobretensão embutido
  • Firmware upgradeable from PC/web download
  • Totalmente fechado, com conexões somente para o cabo USB e para o cabo ICSP
  • LEDs para indicação de funcionamento (POWER, ACTIVE, STATUS)
  • Permite a escrita/leitura tanto da memória de programa quanto da memória de dados do microcontrolador
  • Limpeza da memória de programa com verificação automática
  • Cabo ICSP incluso

Interface do software 
Abaixo podemos ver uma imagem com a interface do software, onde explicaremos as principais funções.


Em vermelho: é onde será feita a seleção do microcontrolador a ser programado
Em amarelo: clicando aqui será aberta uma janela onde serão configurados os FUSES do PIC
Em verde: é a janela de status, onde serão mostradas as informações sobre o processo
Em azul: são os botões com as funções principais, que serão descritas abaixo:
Utilizando o Programador KIT 3.5


Iremos demonstrar agora, o esquema de ligação para a utilização do Programador KIT 3.5 para programar um PIC16F88
Basta realizar as ligações, da forma indicada na figura abaixo:
Conexões para o PIC16F88

Confira as conexões ICSP para alguns microcontroladores PIC:
Conexões ICSP para alguns microcontroladores da linha PIC

Conte-nos suas experiências utilizando os produtos adquiridos em  nossa loja!
Até o próximo artigo!

quinta-feira, 25 de junho de 2015

Testando o Módulo Sensor Hall M44


Nesta postagem iremos demonstrar a utilização do Módulo Sensor Hall M44.



Módulo Sensor Hall M44

É um sensor que detecta se existe algum campo magnético próximo a ele, fazendo a comutação do nível lógico em sua saída de "Alto"(5V) para "Baixo"(0V). Basicamente, esse sensor funciona atuando como uma chave que realiza a comutação caso seja detectada a presença do campo magnético, de maneira similar ao funcionamento de uma Ampola Reed, porém sem a fragilidade de um componente feito em vidro.



O Módulo Sensor Hall M44 possui um furo na placa, com finalidade de ser fixado através de um parafuso, podendo ser utilizado em diversas aplicações, sendo particularmente útil em situações em que se faça necessária uma detecção simples de movimento, como por exemplo indicar em um sistema de segurança se uma porta ou janela foram abertas, ou como equipamento de segurança em ferramentas pesadas, somente permitindo o acionamento se um determinado procedimento de segurança for atendido.


Especificações:
  • Módulo Sensor de Efeito Hall usando o Sensor M44 
  • Sinal do sensor regulado por um comparador embutido
  • Pino AO: Saída em nível Alto do Sensor de Efeito Hall em tempo real (não é uma saída analógica)
  • Pino DO: Saída em nível baixo do Sensor de Efeito Hall mais estável, através do comparador
  • Corrente de saída do Comparador : 16mA
  • Tensão de entrada: 0-15 V DC
  • Diametro interno do furo de fixação: Aproximadamente 3mm
  • Tamanho (Comprimento x Largura): Aproximadamente. 36 x 16mm
Nota: A face de detecção do sensor é a face OPOSTA à dos componentes.

Para demonstrar o funcionamento do sensor, iremos realizar uma montagem simples, utilizando o Módulo Sensor Hall M44 diretamente em conjunto com o Módulo Relé 5V 1 canal, de maneira a acionar o relé quando o sensor detectar um campo magnético, simulando um dispositivo de segurança qualquer para um equipamento.
A ligação será feita da seguinte forma:

A alimentação do  Módulo Sensor Hall M44 e do Módulo Relé 5V 1 canal será feita conectando normalmente os pinos VCC e GND na fonte de energia, nos terminais 5V e GND, respectivamente.
Após isso, será conectado um Cabo Jumper Fêmea-Fêmea ao pino IN do Módulo Relé 5V 1 canal, que será conectado ao Módulo Sensor Hall M44 como segue:

Situação 1: ao pino A0 (de nível alto), para demonstrar um circuito que ativa o relé;




Situação 2: ao pino D0 (de nível baixo), para demonstrar um circuito que desativa o relé.

Obs.:
Da mesma forma que na postagem do Módulo Display 7 Segmentos para Relogio, o relé estará conectado a uma lâmpada do tipo olho de boi, apenas para demonstração de funcionamento.

Conte-nos suas experiências utilizando os produtos adquiridos em  nossa loja!
Até o próximo artigo!

sexta-feira, 19 de junho de 2015

Utilizando o Programador USB para PIC K150

Nessa postagem iremos demonstrar a utilização do Programador USB para PIC K150

O gravador possui um soquete do tipo ZIF (ZIF - Zero Insertion Force - é um soquete com uma alavanca, que permite a colocação e a retirada dos microcontroladores sem risco de danificar seus terminais) para a programação dos microcontroladores. Conta também com um conector para a programação ICSP (In Circuit Serial Programming, que será abordada futuramente em outra postagem, pois é necessário que se faça algumas adaptações no circuito a ser programado).
O programador é controlado pelo PIC16F628A, e no site do fabricante do gravador é possível encontrar informações sobre como atualizar o firmware do gravador, para possibilitar a gravação de mais dispositivos.

Instalação do Programador USB para PIC K150

Se você estiver utilizando o Windows 7/Vista/XP, o driver deve ser instalado normalmente, sem que seja necessária a interferência do usuário. Caso esteja utilizando o Windows 8/8.1, o processo é um pouco mais difícil, pois os drivers mais atuais não são suportados. Nesse caso, é preciso restaurar os drivers para uma versão antiga, que ainda é suportada.
Para realizar a instalação do gravador no computador, são necessários alguns arquivos, que disponibilizamos aqui. É só selecionar a pasta referente ao seu sistema operacional e proceder com a instalação.

Além disso, você deverá ir ao Gerenciador de dispositivos do Windows e anotar o número da porta serial (COM) à qual o Programador USB para PIC K150 está relacionado. Isto será necessário para configurar o programa Microbrn.exe.

Configurando o Microbrn:

O programa Microbrn.exe encontra-se disponível no arquivo disponibilizado acima. Ao executá-lo pela primeira vez, ele apresentará um erro, pois ainda não está configurado para interagir com a porta COM relacionada ao Programador.
Para realizar essa configuração, basta clicar na opção PORT (destacado em verde), no menu File do Microbrn.
 
Após isso, irá surgir uma janela para digitar o número da porta COM que foi anotado anteriormente. No nosso caso, foi a COM 2.

Se o modelo do programador não for detectado automaticamente, basta ir na opção Programmer, também no menu File, e selecionar o modelo K150 (destacado em amarelo).

Obs.: Deve-se conectar a placa sem nenhum microcontrolador inserido. Caso contrário, o programa apresentará um erro, dizendo que foi impossível reinicializar a placa (reset).

O programa apresenta uma interface simples, com uma imagem do soquete ZIF, onde a parte superior indica o lado onde fica a alavanca. Esta imagem indicará a posição em que se deve colocar o microcontrolador em relação aos pinos do ZIF.
Abaixo dessa imagem é possível selecionar qual o microcontrolador a ser utilizado (destacado em vermelho).


Segue abaixo uma breve descrição sobre os principais botões da interface do programa, utilizados para gravar um código HEX no PIC:

Load: Carrega o seu arquivo HEX para o programa.
Save: Caso o código HEX seja editado, é possível salvá-lo através do Microbrn.

Program: Escreve o código HEX carregado no microcontrolador
Verify: Confere se o código HEX foi gravado corretamente.
Read: Lê um código gravado em seu microcontrolador.
Blank: Apaga tudo que está escrito no microcontrolador. Essa opção abre uma pequena janela com duas opções: Erase Check (que verifica se existe algum código gravado no microcontrolador) e Erase Chip (que apaga qualquer programa que estiver salvo no chip).

Fuses: Configura os FUSES do seu microcontrolador (note que essa opção só pode ser acessada após carregar um código HEX).


Muitas vezes, o arquivo HEX gerado pelo seu compilador pode ser incompatível com o Microbrn, apresentando erros na gravação. Caso isso aconteça, utilize o aplicativo Fixhex2.exe, presente no arquivo que você baixou do link acima. Ele corrige os possíveis problemas no arquivo HEX gerado pelo seu compilador, gerando um arquivo HEX compatível com o Microbr.
Basta clicar em Load File (destacado em azul) e logo após em Convert (destacado em laranja).
O arquivo compatível com o Microbrn estará no caminho indicado no campo Saved File (destacado em verde)



Segue abaixo a listagem das Linhas Suportadas:
10 Series:
PIC10F200 * PIC10F202 * PIC10F204 * PIC10F206 *
PIC10F220 * PIC10F222 *

12C series:
PIC12C508 PIC12C508A PIC12C509 PIC12C509A
PIC12C671 PIC12C672 PIC12CE518 PIC12CE519
PIC12CE673 PIC12CE674

12F series:
PIC12F509 PIC12F629 PIC12F635
PIC12F675 PIC12F683

16C series:
PIC16C505 PIC16C554 PIC16C558 PIC16C61
PIC16C62 PIC16C62A PIC16C62B PIC16C63
PIC16C63A PIC 16C64 PIC16C64A PIC16C65
PIC16C65A PIC16C65B PIC16C66 PIC16C66A
PIC16C67 PIC16C620 PIC16C620A PIC16C621
PIC16C621A PIC16C622 PIC16C622A PIC16C71
PIC16C71A PIC16C72 PIC16C72A PIC16C73
PIC16C73A PIC16C73B PIC16C74 PIC16C74A
PIC16C74B PIC16C76 PIC16C77 PIC16C710
PIC16C711 PIC16C712 PIC16C716 PIC16C745
PIC16C765 PIC16C773 PIC16C774 PIC16C83
PIC16C84

16F series:
PIC16F505 PIC16F506 PIC16F54 PIC16F57 *
PIC16F59 * PIC16F627 PIC16LF627A PIC16F627A
PIC16F628 PIC16LF628A PIC16F628A PIC16F630
PIC16F631 PIC16F631-1 PIC16F636 PIC16F636-1
PIC16F639 * PIC16F639-1 * PIC16F648A PIC16F676
PIC16F677 PIC16F677-1 PIC16F684 PIC16F685 *
PIC16F685-1 * PIC16F687 * PIC16F687 * -1 PIC16F688
PIC16F689 * PIC16F689-1 * PIC16F690 * PIC16F690-1 *

PIC16F72 PIC16F73 PIC16F74
PIC16F76 PIC16F77 PIC16F737 PIC16F747
PIC16F767 PIC16F777 PIC16F83 PIC16F84
PIC16F84A PIC16F87 PIC16F88 PIC16F818
PIC16F819 PIC16F870 PIC16F871 PIC16F872
PIC16F873 PIC16F873A PIC16LF873A PIC16F874
PIC16F874A PIC16F876 PIC16F876A PIC16F877
PIC16F877A

18 Series:
PIC18F242 PIC18F248 PIC18F252 PIC18F258 PIC18F442 PIC18F448
PIC18F452 PIC18F458 PIC18F1220 PIC18F1320 PIC18F2220 PIC18F2320
PIC18F2321 PIC18F4210 PIC18F2331 PIC18F2450 PIC18F2455 PIC18F2480
PIC18F2510 PIC18F2515 PIC18F2520 PIC18F2550 PIC18F2580
PIC18F2585 PIC18F2610 PIC18F2620 PIC18F2680 PIC18F4220 PIC18F4320
PIC18F6525 PIC18F6621 PIC18F8525 PIC18F8621 PIC18F2331 PIC18F2431
PIC18F4331 PIC18F4431 PIC18F2455 PIC18F2550 PIC18F4455 PIC18F4580 PIC18F2580 PIC18F2420 PIC18F2520 PIC18F2620 PIC18F6520 PIC18F6620 PIC18F6720 PIC18F6585 PIC18F6680 PIC18F8585 PIC18F8680


Conte-nos suas experiências utilizando os produtos adquiridos em  nossa loja!
Até o próximo artigo!

terça-feira, 16 de junho de 2015

Teste do Encoder Rotativo KY-040

Neste artigo vamos mostrar um pequeno teste do uso do Encoder Rotativo KY-040.
Encoder Rotativo KY-040

Novamente, a Placa Base utilizada como controladora é a Arduino Uno, que foi utilizada em conjunto com o Protoshield compatível com a mesma. Todos os itens utilizados podem ser adquiridos em nossa loja.

Este encoder trabalha com um disco óptico. Ele tem dois sinais de saída chamados de Clock (CLK) e Data (DT). Além de um sinal que vem do botão (SW) embutido no encoder.

O objetivo deste teste é ler estas saídas e fazer o programa identificar se o encoder está girando no sentido horário ou anti-horário, e quantos degraus ele se deslocou.

Este é um encoder que identifica 20 passos/360°. Ou seja, a cada 18° temos a identificação de um passo.

As duas saídas (CLK e DT) estão defasadas entre si em 90° o que permite a detecção do sentido de rotação. E estão ativas quando em nível baixo.

Para os testes utilizamos:

Arduino Uno
Shield Placa Expansora para Arduino UNO
Módulo Encoder Rotativo KY-040
Capacitor de poliéster 100nF
Resistor 10kΩ
Fios para ligação (Sugestão: Cabo Jumper MACHO/FÊMEA 20cm 40 vias);


Os capacitores de 100nF são usados para efeitos de "debounce" (um artifício para que o Arduino identifique corretamente cada passo do encoder, de maneira que seja contabilizado um único pulso a cada passo) para os três pinos de saída do módulo (DT, CLK e SW).

No módulo já está incluso 2 resistores (SMD) de pull-up que garantem sinal alto (+5V) nas saídas, que vão abaixo (0V) quando estão ativas. Exceto na saída do push button (SW) que tem o espaço mas não tem o resistor instalado (porém, esse resistor pode ser adquirido na nossa loja). Confira na imagem abaixo.



Após realizada as conexões dos capacitores e resistor, podemos ligar o módulo ao Arduino. Lembrando que o Arduino utilizado foi o modelo Arduino Uno.

As Conexões devem ser feitas da seguinte forma:

Encoder KY-040 Arduino
GND GND
+ 5v
SW D4
DT D3
CLK D2








Além disso, foram conectados dois LED's (com os resistores apropriados) aos pinos D5 e D6 do Arduino, para facilitar a indicação da direção do giro.

Segue abaixo uma imagem com o circuito montado.


Confira abaixo um vídeo com o funcionamento do projeto.


Baixe aqui o sketch com a programação do Arduino para esse projeto.
Segue abaixo o código fonte utilizado nesse projeto.
 //############### ELETRODEX ELETRÔNICA ###############  
 // Programa de teste do Módulo Encoder KY-040  
 //   
 // As Conexões devem ser feitas da seguinte forma:  
 // Módulo Encoder |  Arduino  
 //    GND   |   GND  
 //     +    |   5v  
 //    SW    |   D4  
 //    DT    |   D3  
 //    CLK   |   D2  
 //    LED 1  |   D5  
 //    LED 2  |   D6  
 //  
 // Lembrando que devem ser inseridos os capacitores de 100nF entre   
 // os pinos SW, DT e CLK do Encoder e o pino GND do Arduino, e um resistor de 10K Ohms   
 // entre o pino SW do Encoder e o pino 5v do Arduino  
 const int interruptA = 0; // Interrupt 0 (pin 2)  
 const int interruptB = 1; // Interrupt 1 (pin 3)  
 int CLK = 2; // PIN2  
 int DAT = 3; // PIN3  
 int BUTTON = 4; // PIN4  
 int LED1 = 5; // PIN5  
 int LED2 = 6; // PIN6  
 int COUNT = 0;  
 void setup ()  
 {  
 attachInterrupt (interruptA, RoteStateChanged, FALLING);  
 //attachInterrupt (interruptB, buttonState, FALLING);  
 pinMode (CLK, INPUT);  
 digitalWrite (2, HIGH); // Pull High Restance  
 pinMode (DAT, INPUT);  
 digitalWrite (3, HIGH); // Pull High Restance  
 pinMode (BUTTON, INPUT);  
 digitalWrite (4, HIGH); // Pull High Restance  
 pinMode (LED1, OUTPUT);  
 pinMode (LED2, OUTPUT);  
 Serial.begin (9600);  
 }  
 void loop ()  
 {  
 if (! (digitalRead (BUTTON)))  
 {  
 COUNT = 0;  
 Serial.println ("STOP COUNT = 0");  
 digitalWrite (LED1, LOW);  
 digitalWrite (LED2, LOW);  
 delay (2000);  
 }  
 Serial.println (COUNT);  
 }  
 // -------------------------------------------  
 void RoteStateChanged () // When CLK FALLING READ DAT  
 {  
 if (digitalRead (DAT)) // When DAT = HIGH IS FORWARD  
 {  
 COUNT++;  
 digitalWrite (LED1, HIGH);  
 digitalWrite (LED2, LOW);  
 delay (200);  
 }  
 else // When DAT = LOW IS BackRote  
 {  
 COUNT --;  
 digitalWrite (LED2, HIGH);  
 digitalWrite (LED1, LOW);  
 delay (200);  
 }  
 }  

Conte-nos suas experiências utilizando os produtos adquiridos em  nossa loja!
Até o próximo artigo!