Vous avez certainement déjà remarqué que les vendeurs ou serveurs utilisent ce type de clé sur leurs caisses enregistreuses. Il suffit de poser la clé Dallas sur son lecteur pour identifier automatiquement le porteur de la clé.
Les clés Dallas sont simplement constituées d’un iButton qui contient un numéro de série unique permettant d’identifier automatiquement son utilisateur. Le iButton communique avec le lecteur de clé Dallas via le bus 1-Wire.
Le bus 1-Wire
1-Wire est un bus de communication conçu par Dallas Semiconductor qui permet de véhiculer des données et une alimentation sur un seul conducteur. Le second conducteur est tout simplement le fil de masse.
L’alimentation du iButton est fournie via le bus 1-Wire par le lecteur de clé Dallas, il n’a donc pas besoin d’intégrer de pile ou de batterie.
Le bus 1-Wire nécessite d’utiliser une résistance de rappel “pull-up” (voir mon article à ce sujet) de 4,7 kΩ.
Le schéma est très simple, il suffit de relier la sortie du lecteur de clé Dallas à la broche 2 de l’Arduino Uno en s’assurant que la résistance de rappel soit reliée au 5V de l’Arduino.
iButton
Un iButton (e.g. DS1990A) contient un composant électronique qui stocke dans sa ROM un numéro de série unique et qui communique avec le lecteur de clé Dallas via le bus 1-Wire. Le numéro de série est également gravé sur le iButton.
Les iButton existent en deux dimensions (F3 et F5) et nous voyons sur l’image suivante l’emplacement des broches IO (alimentation et échange de données) et GND (masse).
La ROM du iButton a une taille de 64 bits (8 octets), elle contient :
- Un “Family Code” de 1 octet (0x01 pour un iButton)
- Le numéro de série unique sur 6 octets
- Le CRC des 7 premiers octets (Family Code + Serial Number) codé sur 1 octet.
Programme Arduino pour lire la ROM d’un iButton
Voici le code Arduino qui permet de lire la ROM du iButton et afficher son numéro de série unique.
/*
iButton Reader
Created March 2022
by Tutoduino
*/
// For Dallas iButton reader
#include <OneWire.h>
#define PIN 2 // iButton is connected to PIN 2
OneWire iButton(PIN);
/* Print iButton ROM buffer */
void printBuffer(byte* buf) {
char serialNumber[16 + 1]; // Printable 8 hex bytes buffer (+1 for '\0')
sprintf(serialNumber,
"%02X%02X%02X%02X%02X%02X",
buf[6],
buf[5],
buf[4],
buf[3],
buf[2],
buf[1]);
Serial.print("Family code: ");
Serial.print(buf[0], HEX);
Serial.print(", Serial number: ");
Serial.print(serialNumber);
Serial.print(", CRC: ");
Serial.println(buf[7],HEX);
}
bool checkCrc8(byte* buf) {
// Compare the received CRC (8-BIT CRC CODE is byte 7 of the buffer)
// against the computed CRC on the first 7 bytes of the buffer
byte crc8 = iButton.crc8(buf, 7);
if (buf[7] != crc8) {
Serial.print("Invalid CRC: Received=");
Serial.print(buf[7],HEX);
Serial.print(" Expected=");
Serial.println(crc8, HEX);
printBuffer(buf);
return false;
}
return true;
}
void readButton(byte* buf) {
// Send Read ROM [0x33] Function Command to iButton
iButton.write(0x33);
// Read the 8 bytes of the ROM
iButton.read_bytes(buf,8);
printBuffer(buf);
// Check of CRC is ok
if (checkCrc8(buf) == true) {
// Check if the family code is iButton [0x01]
if (buf[0] != 0x01) {
Serial.println("Not iButton family code");
}
}
}
void setup() {
Serial.begin(115200);
Serial.println("Put iButton on reader");
iButton.reset();
}
void loop() {
byte oneWireBuffer[8]; // 64-Bit Unique ROM buffer
// Send a reset pulse and check presence pulse
if ( iButton.reset() != 0) {
readButton(oneWireBuffer);
}
delay(200);
}
Voici ci-dessous l’affichage dans le moniteur série de l’IDE Arduino des numéros de série de 2 iButton différents.
Changer le numéro de série d’une clé Dallas réinscriptible
Il est possible de modifier le numéro de série des clés Dallas réinscriptibles (RW1990). Le montage est identique au précédent mais le programme est un peu plus compliqué. En effet la séquence d’écriture des boutons RW1990 ne permet pas d’utiliser la librairie OneWire telle quelle. Je me suis inspiré du code de swiftgeek pour réaliser mon programme.
/*
iButton Writer
Created March 2022
by Tutoduino
Based on https://gist.github.com/swiftgeek/0ccfb7f87918b56b2259
*/
#include <OneWire.h>
#define PIN 2
OneWire iButton (PIN); // I button connected on PIN 2.
void sendLogical0() {
// Send logical 0
digitalWrite(PIN, LOW); pinMode(PIN, OUTPUT); delayMicroseconds(60);
pinMode(PIN, INPUT); digitalWrite(PIN, HIGH); delay(10);
}
void sendLogical1() {
digitalWrite(PIN, LOW); pinMode(PIN, OUTPUT); delayMicroseconds(10);
pinMode(PIN, INPUT); digitalWrite(PIN, HIGH); delay(10);
}
/* Write a byte to iButton ROM */
int writeByte(byte data){
for(byte data_bit=0; data_bit<8; data_bit++){
if (data & 1){
sendLogical0();
} else {
sendLogical1();
}
data = data >> 1;
}
return 0;
}
/* Print iButton ROM buffer */
void printBuffer(byte* buf) {
char serialNumber[16 + 1]; // Printable 8 hex bytes buffer (+1 for '\0')
sprintf(serialNumber,
"%02X%02X%02X%02X%02X%02X",
buf[6],
buf[5],
buf[4],
buf[3],
buf[2],
buf[1]);
Serial.print("Family code: ");
Serial.print(buf[0], HEX);
Serial.print(", Serial number: ");
Serial.print(serialNumber);
Serial.print(", CRC: ");
Serial.println(buf[7],HEX);
}
bool checkCrc8(byte* buf) {
// Compare the received CRC (8-BIT CRC CODE is byte 7 of the buffer)
// against the computed CRC on the first 7 bytes of the buffer
byte crc8 = iButton.crc8(buf, 7);
if (buf[7] != crc8) {
Serial.print("Invalid CRC: Received=");
Serial.print(buf[7],HEX);
Serial.print(" Expected=");
Serial.println(crc8, HEX);
printBuffer(buf);
return false;
} else {
return true;
}
}
void setNewBuffer(byte* newBuffer, byte* serialNumber) {
// Family Code = 0x01 (iButton)
newBuffer[0] = 0x01;
// SerialNumber
memcpy(newBuffer+1, serialNumber, 6);
// CRC
newBuffer[7] = iButton.crc8(newBuffer, 7);
}
void readButton(byte *buf) {
// Send Read ROM [0x33] Function Command to iButton
iButton.write(0x33);
// Read the 8 bytes of the ROM
iButton.read_bytes(buf,8);
printBuffer(buf);
// Check of CRC is ok
if (checkCrc8(buf) == true) {
// Check if the family code is iButton [0x01]
if (buf[0] != 0x01) {
Serial.println("Not iButton family code");
}
}
}
void setup(){
Serial.begin(115200);
Serial.println("Put iButton on reader");
}
void loop(){
byte oneWireBuffer[8]; //array to store the Ibutton ID.
byte newOneWireBuffer[8]; //array to store the new Ibutton ID.
byte newSerialNumber[6] = {0xBB, 0xAA, 0xCC, 0x01, 0x00, 0x00};
// Send a reset pulse and check presence pulse
if ( iButton.reset() != 0) {
// Read serial number
readButton(oneWireBuffer);
delay(500);
// Set new serial number in new buffer
setNewBuffer(newOneWireBuffer, newSerialNumber);
// Check if new serial number if already set
if (memcmp(oneWireBuffer, newOneWireBuffer, 8) == 0) {
return;
}
// Write new serial number
// Prepare to write
iButton.skip();
iButton.reset();
iButton.write(0xD1);
sendLogical0();
// Write
Serial.print(" Writing iButton ID:\n ");
iButton.skip();
iButton.reset();
iButton.write(0xD5);
for (byte x = 0; x<8; x++){
delay(10);
writeByte(newOneWireBuffer[x]);
Serial.print('*');
}
Serial.print('\n');
iButton.reset();
iButton.write(0xD1);
sendLogical1();
}
}
Voici ci-dessous l’affichage dans le moniteur série de l’IDE Arduino du changement de numéro de série d’un iButton.
Il faut donc noter qu’il est extrêmement facile de dupliquer une clé Dallas, et que ce type de clé n’est pas du tout sécurisé contrairement à ce que certains peuvent affirmer dans leurs arguments de vente. Une clé Dallas permet simplement d’identifier facilement et rapidement un utilisateur…
Avertissement : ce tutoriel est uniquement à but pédagogique et son contenu ne doit pas être utilisé pour des activités illicites !
Merci à GoTronic pour la fourniture du iButton Dallas DS1990A nécessaire à la rédaction de ce tutoriel.
Bonjour je suis sous pico en micropython (avec thonny comme idée). Est ce que quelqu’un aurait ces progs pour lire ET écrire en micropython avec ce ibutton ds1990?
Merci de vos retours. Bonne journée.