Arduino: como ler tags iButton
O leitor de iButton é barato, fácil de operar, e permite implementar um sistema de registro ou controle de acesso usando os práticos e resistentes iButtons como chaves.
O identificador/tag no padrão iButton é um cilindro com o mesmo tamanho e formato das pequenas baterias de relógio. Ele não é uma bateria, entretanto, e nem tem uma bateria dentro de si: é um chip dentro de um pequeno cilindro de aço inoxidável feito para operar por até 10 anos, mesmo se exposto a condições adversas.
O iButton é feito pela Dallas/Maxim e implementa o protocolo 1-Wire. Sua função básica é: ao ser encostado em um leitor de iButton, informar o seu código de identificação (cada iButton recebe um código único ao sair da fábrica). Com isso, ele pode ser usado na automação de aplicações que tradicionalmente usam chaves, tickets ou crachás.
Para um futuro experimento envolvendo implementar os elementos centrais de um sistema de registro de acesso, eu recebi da Usinainfo (da qual sou cliente e recomendo), como parte de nosso acordo de patrocínio, um par de tags iButton em formato de chaveiro, um leitor de iButton para controle de acesso e um módulo para cartão Micro SD. Agradeço à Usinainfo pelo patrocínio do futuro experimento, e ainda mais por ter me dado plena liberdade na condução do mesmo.
Hoje, entretanto, não vou implementar o sistema do experimento, mas apenas documentar o que aprendi sobre o funcionamento do iButton e o procedimento de leitura do código identificador de cada um deles.
Entendendo o iButton
Os iButtons que recebi são para controle de acesso, mas nem todo iButton serve apenas como identificação: existem também aqueles que podem receber e armazenar um saldo de tickets, reduzindo-o a cada transação - o Akbil, sistema de transporte urbano de Istambul usa esses iButtons como passe, por exemplo.
Há ainda iButtons com sensores embutidos, tirando proveito do seu tamanho reduzido para caber dentro das embalagens, fazendo um registro das variações de temperatura e/ou umidade durante o transporte de mercadorias valiosas e perecíveis.
Mesmo os iButtons feitos para controle de acesso têm várias possibilidades de utilização: controle de entrada e saída de mercadorias ou veículos, chave para garagens ou quartos de hotel, registro de presença ou frequência, acesso a catracas de clubes, academias, eventos, etc.
O modelo que eu recebi é para aplicações de identificação: é uma tag iButton F5 já integrada a um chaveiro. Essa chave digital tem um identificador único de 64 bits, e as suas aplicações são aquelas que concedem permissões a um portador, fazendo o papel de uma chave ou cartão de acesso.
Um iButton é feito para durar 10 anos mesmo em ambientes adversos: alta temperatura, umidade, acidez, poluição eletromagnética, etc.
Em relação a outras tecnologias empregadas para essas mesmas finalidades, o iButton tem vantagens como a portabilidade, o custo baixo dos sensores (pois eles fazem apenas o contato elétrico entre a tag e o controlador), e a resistência a ambientes adversos (temperatura elevada, água, poluição eletromagnética, etc.). Os padrões concorrentes, como cartões (magnéticos ou com chip) e RFID, também têm suas vantagens específicas, e para cada aplicação convém escolher a tecnologia mais adequada.
O iButton usa o protocolo de comunicação 1-Wire, que recebe este nome porque foi projetado para permitir que os dispositivos conectados possam enviar seus dados pelo mesmo cabo que os alimenta. Com este protocolo, vários dispositivos podem ser encadeados em sequência (compartilhando um mesmo pino do Arduino, por exemplo).
O suporte ao 1-Wire no Arduino envolve instalar a biblioteca OneWire.
Arduino e leitor de iButton: como conectar
A pinagem típica de um dispositivo 1-Wire como os leitores de iButton é bem simples: envolve um cabo ligado ao terra e outro cabo ligado a um pino do controlador – no meu caso, escolhi ligar ao pino 2 do Arduino.
Essa conexão ao Arduino deve ter também um resistor (R1) de 2,4KΩ atuando como pull-up, ou seja, com um de seus terminais conectado ao pino de dados (o pino 2, no meu caso) e o outro conectado ao pino 5V.
No caso do leitor de iButton que eu recebi da Usinainfo, o cabo verde é o que foi ligado ao pino 2 do Arduino (e ao pull-up), e o cabo vermelho é o que foi ligado ao terra.
O leitor de iButton que eu recebi tem um led vermelho embutido, e este também tem 2 cabos: no caso, o cabo preto é o positivo(!) do led, e o cabo branco é o seu negativo. Para deixar o led permanentemente aceso, usei um resistor (R2) de 300Ω para conectar o seu cabo preto ao 5V, e conectei seu cabo branco ao terra.
Vale observar que o estado ou conexão do led em nada interfere com o funcionamento do leitor. O led está lá para facilitar a identificação do local em que devemos posicionar a tag iButton, ou para comunicar informações de status, se o desenvolvedor assim preferir.
Arduino e leitor de iButton: como programar
Toda tag iButton tem um identificador único, de 12 dígitos hexadecimais, gravado a laser na sua superfície visível. É esse identificador que ela informa ao leitor sempre que encosta nele.
Para aplicações práticas é necessário considerar todos os 12 dígitos do identificador. Como estou operando apenas com fins didáticos relacionados à operação de leitura, vou considerar apenas os 8 dígitos da direita, já que os outros 4 (à esquerda) estão zerados em todas as tags a que tive acesso. Note que em aplicações reais essa opção tem riscos, pois cria a possibilidade que outra tag com os mesmos 8 dígitos à direita (e algum dígito diferente de zero à esquerda) seja lida como se fosse a minha.
O programa a seguir é o que eu criei para, usando a biblioteca OneWire, monitorar continuamente um leitor de iButton, exibindo no monitor serial os 8 dígitos da direita do identificar da tag e o número decimal correspondente, sempre que detecta um contato:
#include <OneWire.h>
OneWire leitortag(2); // 2 e' o pino do Arduino ligado ao leitor
void setup(void) {
Serial.begin(9600);
}
byte addr[8]; // buffer global para armazenar enderecos de tags
void loop(void) {
if(consultaTag()){
Serial.print("iButton em hexadecimal: ");
for(byte i=4;i>0;i--) {
String digitos=String(addr[i], HEX);
if (digitos.length()==1) digitos="0" + digitos;
Serial.print(digitos);
}
Serial.println();
unsigned long tagdecimal=(unsigned long)addr[1];
tagdecimal=tagdecimal|((unsigned long)addr[2]) << 8;
tagdecimal=tagdecimal|((unsigned long)addr[3]) << 16;
tagdecimal=tagdecimal|((unsigned long)addr[4]) << 24;
Serial.print("iButton em decimal....: ");
Serial.println(tagdecimal);
Serial.println();
}
}
boolean consultaTag() {
boolean leituraok=false;
if (leitortag.search(addr)) {
if (OneWire::crc8(addr, 7) == addr[7]) { // testa a verificacao CRC
if (addr[0]==1) { // para tags iButton o primeiro byte sempre e' 1
leituraok=true;
}
}
}
leitortag.reset();
return leituraok;
}
Embora o que o programa faz seja bem simples (obter uma sequência de bytes e exibi-la), essa operação exige alguns elementos de programação em C que fogem ao básico, e peço desculpas por não conseguir reduzi-la a elementos mais simples de compreender.
Comecemos pelos 2 trechos em lilás, com definições. O primeiro deles inclui a biblioteca OneWire e instancia, no objeto leitortag
, o leitor conectado ao pino 2 do Arduino. O segundo trecho, de uma linha só, define uma estrutura de 8 bytes, chamada addr
, na qual o programa armazenará cada endereço de iButtons que for lido.
Pulemos agora para o trecho final: a função consultaTag()
. Note que ela é do tipo boolean, ou seja, vai retornar um resultado falso ou verdadeiro, indicando se conseguiu ler um endereço de tag. As linhas relacionadas a esse retorno foram marcadas em verde.
Ainda dentro da função, marquei em marrom as linhas em que há contato com o sensor propriamente dito. A mais especial é a primeira, que usa a função ds.search()
para verificar se há um iButton conectado ao leitor. Se sim, ela retornará um valor verdadeiro, e armazenará na estrutura addr
o endereço do iButton e algumas informações associadas a ele.
Em seguida, caso um endereço tenha sido lido, a função crc8()
é usada para calcular o CRC (que funciona de forma similar a um dígito verificador) do endereço, e compará-lo com o byte 7 da estrutura addr
, no qual o leitor também deve ter informado o mesmo CRC. Ambos precisam ser iguais, caso contrário terá ocorrido algum erro de leitura.
A seguir, o programa verifica se o byte 0 da estrutura addr
contém o valor 1, que é o que o leitor armazenará lá se o objeto identificado por ele for uma tag iButton (e não, por exemplo, um sensor one-wire de temperatura).
Caso todos esses testes dêem certo, a função consultaTag()
retornará um valor verdadeiro, indicando que um endereço de tag iButton estará disponível na estrutura addr
.
Ao final, seja qual for o resultado, o leitor recebe um reset()
para que a próxima leitura não seja afetada pelo resultado da atual. Se eu tivesse vários leitores encadeados em um mesmo barramento 1-Wire, teria que pensar melhor em como e quando resetar, mas não é o caso ;-)
O que os trechos em laranja e vermelho do meio do programa acima fazem é usar funções de manipulação de estruturas e números para mandar para o monitor serial, em formato hexadecimal e decimal, o endereço de cada tag que for encostada no leitor. Algo assim:
iButton em hexadecimal: 016f2e1d
iButton em decimal....: 24063517
iButton em hexadecimal: 01ff0621
iButton em decimal....: 33490465
Para ter certeza de que funcionou, basta verificar se os 8 dígitos em hexadecimal correspondem aos 8 dígitos da direita do identificador impresso a laser na ponta metálica da sua tag.
Patrocínio: UsinaInfo
Quero agradecer à UsinaInfo, que vem patrocinando alguns experimentos do BR-Arduino, inclusive este com tags iButton e o seu leitor, que também farão parte de um experimento maior (elementos de um sistema de registro de acesso) patrocinado por ela.
Além de receber material da empresa para os experimentos como parte do acordo de patrocínio, eu já fiz compras de componentes lá, aproveitando a variedade, o estoque bem suprido, as descrições detalhadas e a qualidade do seu sistema de comércio eletrônico. Recomendo sem ressalvas.
Agradeço também pela confiança que ficou expressa nos termos do patrocínio: a empresa me enviou os componentes necessários ao experimento combinado (um sistema de registro de acesso), mas não fez qualquer exigência sobre a forma e nem buscou exercer controle sobre o que eu fosse escrever. Nem sempre os termos são tão amplos, ainda mais para um blog recém-iniciado. Obrigado, UsinaInfo!
Comentar