Bogusław Kempny

Czytnik kart zbliżeniowych RFID RDM630

×
Autor English
Początek HC-SR04 LCD Kamera fork() sms strfry() GPIO impulsy Klawiatura Brama GPIO PWM SG90 RFID Grafolog RCP Shutdown Temperatura ....











Czytnik RFID za 15 złotych.
Nie licząc anteny, (kliknij obrazek żeby ją zobaczyć) 2cmx4cm:

Z czułości anteny niestety nie byłem zadowolony, zrobiłem własną, 50 zwojów drutu nawojowego (to ten czarny krążek średnicy około 50 mm widoczny na powiększeniu). Średnica drutu nawojowego nie bardzo istotna, użyłem 0,40 mm, bo taki akurat się pod łapę "nawinął".

Jak to działa?

Czytnik RDM630 za pomocą cewki generuje pole elektromagnetyczne o częstotliwości 125 kHz (są też inne standardy, nie będę ich tu opisywał).
Jeśli umieścimy w tym polu tzw. transponder, korzystając z energii tego pola zawarty w nim mikroukład scalony zacznie działać i wyśle swój pięciobajtowy identyfikator.
Identyfikator ten jest unikalny, nie ma dwu transponderów o takim samym identyfikatorze (no, przynajmniej nie powinno być, miałem już kiedyś pudełko transponderów jakiegoś taniego producenta, na 200 kart trafiły się dwa identyfikatory użyte dwukrotnie).
Czytnik, jak to czytnik, odczyta ten identyfikator i przekaże nam do wykorzystania.
Transponder może być plastikową kartą, breloczkiem, hermetycznym modułem do zastosowań przemysłowych itp.

To mały przykład:

No to zabieramy się za robotę.

Potrzebujemy czytnik, jakiś transponder do testów, dwa rezystory, np, 1k i 1,9k, no i oczywiście Rapberry.

Po co te rezystory? Ano, GPIO Raspberry pracuje z napięciem 3,3V, a nasz czytnik transmituje w standardzie 5V. Raspberry zasilany jest napięciem 5V, ale na pinach łączówki GPIO sygnały są w standardzie CMOS, 3,3V. Podanie napięcia wyższego niż 3,3V na pin GPIO może skończyć się jego uszkodzeniem.

Sygnał z czytnika musimy podpiąć do GPIO przez zwykły dzielnik z dwu rezystorów:

Podpinamy więc do naszego czytnika zasilanie 5V, wyjście TX (pin1 pięciopinowej łączówki) przez dzielnik do pinu 10 (RX) łączówki GPIO:

Dokumentację RDM630 bez problemu znajdziemy w internecie, dla wygody skopiowałem ją też tutaj.

I tu pierwsza przeszkoda. Potrzebujemy na wyłączność portu szeregowego UART Raspberry. Może on być jednak używany jako port konsoli, albo przez bluetooth. Jeśli po wydaniu komendy

gpio readall

zobaczymy, ze piny TX i RX są w trybie ALT5, jak w poniższej tabeli, to czeka nas trochę przygotowawczej pracy.
 +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 |     |     |    3.3v |      |   |  1 || 2  |   |      | 5v      |     |     |
 |   2 |   8 |   SDA.1 |   IN | 1 |  3 || 4  |   |      | 5v      |     |     |
 |   3 |   9 |   SCL.1 |   IN | 1 |  5 || 6  |   |      | 0v      |     |     |
 |   4 |   7 | GPIO. 7 |   IN | 1 |  7 || 8  | 1 | ALT5 | TxD     | 15  | 14  |
 |     |     |      0v |      |   |  9 || 10 | 1 | ALT5 | RxD     | 16  | 15  |
 |  17 |   0 | GPIO. 0 |  OUT | 0 | 11 || 12 | 0 | OUT  | GPIO. 1 | 1   | 18  |
 |  27 |   2 | GPIO. 2 |  OUT | 1 | 13 || 14 |   |      | 0v      |     |     |
 |  22 |   3 | GPIO. 3 |  OUT | 0 | 15 || 16 | 0 | IN   | GPIO. 4 | 4   | 23  |
 |     |     |    3.3v |      |   | 17 || 18 | 0 | IN   | GPIO. 5 | 5   | 24  |
 |  10 |  12 |    MOSI |   IN | 0 | 19 || 20 |   |      | 0v      |     |     |
 |   9 |  13 |    MISO |   IN | 0 | 21 || 22 | 0 | IN   | GPIO. 6 | 6   | 25  |
 |  11 |  14 |    SCLK |   IN | 0 | 23 || 24 | 0 | OUT  | CE0     | 10  | 8   |
 |     |     |      0v |      |   | 25 || 26 | 0 | OUT  | CE1     | 11  | 7   |
 |   0 |  30 |   SDA.0 |   IN | 1 | 27 || 28 | 1 | IN   | SCL.0   | 31  | 1   |
 |   5 |  21 | GPIO.21 |   IN | 1 | 29 || 30 |   |      | 0v      |     |     |
 |   6 |  22 | GPIO.22 |   IN | 1 | 31 || 32 | 0 | IN   | GPIO.26 | 26  | 12  |
 |  13 |  23 | GPIO.23 |   IN | 0 | 33 || 34 |   |      | 0v      |     |     |
 |  19 |  24 | GPIO.24 |   IN | 0 | 35 || 36 | 0 | IN   | GPIO.27 | 27  | 16  |
 |  26 |  25 | GPIO.25 |   IN | 0 | 37 || 38 | 0 | IN   | GPIO.28 | 28  | 20  |
 |     |     |      0v |      |   | 39 || 40 | 0 | IN   | GPIO.29 | 29  | 21  |
 +-----+-----+---------+------+---+----++----+---+------+---------+-----+-----+
 | BCM | wPi |   Name  | Mode | V | Physical | V | Mode | Name    | wPi | BCM |
 +-----+-----+---------+------+---+---Pi 3---+---+------+---------+-----+-----+

Trzeba przeedytować zbiory konfiguracyjne /boot/cmdline.txt (usunąć uruchamianie konsoli) i /boot/config.txt (usunąć uruchamianie bluetooth i włączyć UART, jeśli był wyłączony.).

Trudno podać jednoznaczną instrukcję jak to zrobić, w różnych wersjach Raspbiana różnie to wygląda, polecam poklikać w internecie.
W moim Raspbianie (10.4) w pliku /boot/cmdline.txt trzeba było usunąć console=tty1, a w pliku /boot/config.txt dopisać (i usunąć, poprzedzić znakiem komentarza):

enable_uart=1
dtoverlay=pi3-disable-bt-overlay
dtoverlay=disable-bt
dtoverlay=miniuart
#dtparam=audio=on
W Raspbian 9.8 poprawki wyglądały tak:
#dtparam=audio=off
enable_uart=1
dtoverlay=miniuart
dtoverlay=pi3-disable-bt
dtoverlay=disable-bt
Potem jeszcze trzeba było zatrzymać:
systemctl disable hciuart.service
systemctl disable bluealsa.service
systemctl disable bluetooth.service

Po przeładowaniu systemu port szeregowy powinien być do naszej wyłącznej dyspozycji.

No to kawałek programu.

Jak zwykle gotowy, działający, przykładowy program znajdziesz tutaj, wystarczy skompilować:

cc rdm.c -o rdm

i uruchomić:

./rdm

Po pierwszej kompilacji pewnie trzeba będzie zmienić prawa do zbioru:

chmod 754 rdm

Ale jak on działa?

Na początku programujemy port szeregowy, opisałem to już przy okazji programu do wysyłania SMS , nie będę więc pisał drugi raz tego samego (choć myszką łatwo skopiować i wkleić).

Problem może się pojawić przy otwieraniu portu szeregowego:

if((pd = open("/dev/ttyAMA0",O_RDWR  | O_NDELAY |O_NONBLOCK)) != -1)
Układ BCM2835 w Raspberry (w starszych modelach trochę inny) ma dwa porty szeregowe, jeśli interesują Cię szczegóły techniczne, polecam dokumentację

Nie wchodząc w szczegóły, jeśli na ttyAMA0 nie zadziała, podmień w tej linii kodu ttyAMA0 na ttyS0

Po każdym odczycie karty czytnik wysyła na port szeregowy:

Bajty ID wysyłane sa w postaci kodów ASCII, więc na przykład bajt 7A wysłany zostanie jako dwa znaki, 37H (szesnastkowo) i 41H, stąd 10 znaków zamiast 5.

No to zaczynamy: Właściwy fragment programu do odczytu kart zaczyna się tu:

W niekończącej się pętli czytamy dane z portu szeregowego.

 for(;;)
  {
Dwie poniższe linijki kodu wymagają wyjaśnienia. Kiedy transponder znajdzie się w polu elektromagnetycznym anteny, czytnik wysyła kilka jej odczytów.

Nie wiem dlaczego, czasami 3, czasami 7, kolejne odczyty transpondera wysyłane są dopiero jak transponder usuniemy i zbliżymy ponownie.

Dlatego po każdym odczycie odczekujemy sekundę , po czym czytamy wszystkie bajty które są w buforze UART. W ten sposób pozbywamy się wielokrotnych odczytów karty.

// remove multiple card readings
    sleep(1);
     while(  read(pd, &znak, 99) > 0) ;
Teraz czekamy na bajt 02H, start transmisji:
     znak[0]=0x00;
     while (znak[0] != 0x02) // start of card ID
      {
       read(pd, &znak[0], 1);
      }
    n=0;
Czytamy 11 kolejnych bajtów, czyli kody ASCII ID karty i CRC. Bajt końca transmisji, 03H ignorujemy, zostanie usunięty mechanizmem opisanym wyżej.
    for(;;)
     {
       if ((a=read (pd, &znak, 1)) != -1)
        {
         karta[n] = znak[0];
         n++;
         if (n>11) break;
        }
     }
Nie sprawdzamy CRC, praktyka uczy, że przekłamania są bardzo rzadkie, a w praktyce nasz program i tak będzie sprawdzał ID karty w bazie danych, żeby ustalić na przykład uprawnienia właściciela.

W miejsce bajtu CRC wpisujemy bajt 00H, znacznik końca łańcucha w języku C:

//  remove CRC
       karta[10]=0x00;
No i coś teraz z odczytanym ID musimy zrobić, sprawdzić w bazie danych, zapisać do pliku... W naszym przykładowym programie po prostu go wyświetlimy:
       printf("karta: %s\n", karta); fflush(0);
  }