wtorek, 29 kwietnia 2025

[14] ESP32 - Arduino - Klawiatura Bluetooth PN532

W tym poście chciałbym opisać sposób wykonania klawiatury bluetooth, wysyłającej numer seryjny karty Mifare.


Na samym początku należy pobrać bibliotekę z serwisu GitHub [link]. Najlepiej pobrać ją w najnowszej dostępnej wersji. Wcześniejsze wersje nie działają poprawnie podczas ponownego nawiązywania połączenia, bez wcześniejszego odłączenia urządzenia od zasilania. 

Po zainstalowaniu biblioteki należy wprowadzić korektę w bibliotece. Ponieważ pojawiają się następujące błędy:


Zmiany należy dokonać w funkcji begin:

  1. void BleKeyboard::begin(void)
  2. {
  3.   //BLEDevice::init(deviceName);
  4.   BLEDevice::init(String(deviceName.c_str()));
  5.   BLEServer* pServer = BLEDevice::createServer();
  6.   pServer->setCallbacks(this);
  7.  
  8.   hid = new BLEHIDDevice(pServer);
  9.   inputKeyboard = hid->inputReport(KEYBOARD_ID);  // <-- input REPORTID from report map
  10.   outputKeyboard = hid->outputReport(KEYBOARD_ID);
  11.   inputMediaKeys = hid->inputReport(MEDIA_KEYS_ID);
  12.  
  13.   outputKeyboard->setCallbacks(this);
  14.  
  15.   //hid->manufacturer()->setValue(deviceManufacturer);
  16.   hid->manufacturer()->setValue(String(deviceManufacturer.c_str()));

Błąd wynika z niekompatybilności przekazywanych typów do funkcji. 

Drugą biblioteką jest PN532. Tutaj z menadżera bibliotek należy zainstalować bibliotekę Adafruit PN532.


Po zainstalowaniu bibliotek można przejść do programu. Komunikacja z modułem PN532 jest nawiązywana przez UART (Serial2 TX pin 17, RX pin 16). Do funkcji nfc() należy też przekazać definicje pinu reset. Natomiast mój moduł nie ma go bezpośrednio wyprowadzonego (DFRobot NFC Module for Arduino V1.0) więc przekazuje jakiś wolny pin do programu. 

  1. #include <BleKeyboard.h>
  2. #include <Wire.h>
  3. #include <Adafruit_PN532.h>
  4. #include <BLEDevice.h>
  5. #include <BLEServer.h>
  6. #include <BLEUtils.h>
  7. #include <BLESecurity.h>
  8.  
  9. #define PN532_TX 17
  10. #define PN532_RX 16
  11. #define PN532_RESET 4
  12.  
  13. HardwareSerial SerialPort2(2);
  14. Adafruit_PN532 nfc(PN532_RESET, &SerialPort2);
  15.  
  16. //100 battery state value, simulate in this program
  17. BleKeyboard bleKeyboard("NFC Keyboard", "Test NFC", 100);
  18.  
  19. void sendUidAsKeypresses(uint8_t* uid, uint8_t uidLength) {
  20.     uint32_t serial = uidToUint32(uid, uidLength);
  21.  
  22.     String serialStr = String(serial);
  23.  
  24.     for (uint8_t i = 0; i < serialStr.length(); i++) {
  25.         char c = serialStr.charAt(i);
  26.         bleKeyboard.press(c);
  27.         delay(10);
  28.         bleKeyboard.releaseAll();
  29.         delay(10);
  30.     }
  31.  
  32.     bleKeyboard.press(KEY_RETURN);
  33.     delay(10);
  34.     bleKeyboard.releaseAll();
  35. }
  36.  
  37. uint32_t uidToUint32(uint8_t *uid, uint8_t uidLength) {
  38.     if (uidLength < 4) {
  39.         return 0;
  40.     }
  41.  
  42.     uint32_t serial = 0;
  43.     for (uint8_t i = 0; i < 4; i++) {
  44.         serial = (serial << 8) | uid[i];
  45.     }
  46.     return serial;
  47. }
  48.  
  49. void setup() {
  50.   Serial.begin(115200);
  51.   Serial.println("Initializing PN532 with UART...");
  52.   Serial2.begin(9600, SERIAL_8N1, PN532_TX, PN532_RX);
  53.   nfc.begin();
  54.   uint32_t version = nfc.getFirmwareVersion();
  55.   if (!version) {
  56.       Serial.println("Didn't find PN532 board");
  57.       while (1);
  58.   }
  59.  
  60.   nfc.SAMConfig();
  61.   Serial.println("PN532 initialized over UART!");
  62.  
  63.   Serial.println("Bluetooth keyboard");
  64.  
  65.   BLEDevice::init("NFC Keyboard");
  66.   bleKeyboard.begin();
  67. }
  68.  
  69. void loop() {
  70.     uint8_t success;
  71.     uint8_t uid[7];
  72.     uint8_t uidLength;
  73.  
  74.     success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, uid, &uidLength);
  75.     if (success) {
  76.         Serial.print("Found NFC tag with UID: ");
  77.         for (uint8_t i = 0; i < uidLength; i++) {
  78.             Serial.print(uid[i], DEC);
  79.             Serial.print(" ");
  80.         }
  81.         Serial.println();
  82.  
  83.         if (bleKeyboard.isConnected()) {
  84.             sendUidAsKeypresses(uid, uidLength);
  85.         }
  86.     }
  87. }

Biblioteka BleKeybord posiada też funkcje print, gdzie bezpośrednio można przekazać znaki do wysłania., jak przez UART. Natomiast w moim przypadku działała ona bardzo niestabilnie i często nie przesyłała wszystkich znaków. Z tego powodu przesyłanie znaków przez pojedyncze kliknięcie przycisku zostało zastosowane.