地鐵刷卡、上下班門禁打卡、高鐵進站刷身份證、Apple Pay 購物……這些日常使用場景,都使用了 NFC 非接觸式識別和互聯技術,極大地方便了人們的生活。
不過,目前市面上常見的NFC無線讀卡器都使用 WIFI或藍牙進行數據傳輸,功耗較高、且傳輸距離有限。而如果采用 LoRaWAN?傳輸,則可以解決上述問題。事實上,基于 LoRaWAN?的 NFC 讀卡器優點突出:
1、LoRaWAN?的傳輸距離遠、接收靈敏度高、且功耗低
2、采用LoRaWAN?無線傳輸的讀卡器安裝部署方便
3、能使用電池供電、可持續使用半年以上。
本文將通過瑞科慧聯的模塊化開發套件 WisBlock 教大家快速搭建一個支持LoRaWAN?的無線讀卡器,讓這個讀卡器讀到電子標簽數據時,可以自動將數據上傳到 LoRaWAN?服務器上。WisBlock 其實是一個物聯網解決方案設計生態系統,由可拼接的模塊和易于使用的軟件工具組成,可加快物聯網產品生產周期、縮短上市時間。
搭建 LoRaWAN?NFC 讀卡器概述
本次搭建使用的硬件是瑞科慧聯(RAK)的 WisBlock 套件,MCU 選擇的是RAK4631WisBlock Core 模塊,該模塊采用強大的 Nordic nRF52840 MCU,可以支持藍牙 5.0(藍牙低能耗),以及 Semtech最新的 LoRa?收發器 SX1262,支持 LoRa?和藍牙兩種通信模式。
該 NFC 還選擇了 WisBlock 套件的 RAK13600 NFC 讀卡器模組,它使用的是 PN532芯片,可以支持 ISO/ICE 14443A/B 卡類型的讀寫,而且還搭配了一個蜂鳴器模組 RAK18001,當 NFC 刷卡有效時,蜂鳴器會發出響聲提醒。
對了,該 NFC 讀卡器的搭建還會使用到瑞科慧聯(RAK)的低代碼開發平臺 RUI3,它為 WisBlock 提供包含傳感器驅動接口、無線發送接口等豐富的 API接口函數,這樣我們只需要寫少量的應用代碼就可以完成此產品搭建了。
硬件電路搭建
硬件準備
首先我們需要準備 RAK4631 模塊、RAK5005-O 底板、RAK13600 NFC 讀卡器、RAK18001 蜂鳴器、兩張 ISO 14443B 卡、一根 LoRa?天線、一根 NFC天線、一個 Unify 外殼、一根藍牙天線(安裝在外殼內)。
RAK4631 模塊、RAK19007 底板、RAK13600 NFC 讀卡器等硬件準備硬件組裝
把 RAK4631 模塊扣在 CPU SLOT 的位置,RAK13600 扣在 IO SLOT 的位置,RAK18001 扣在 SLOT A(或者SLOT B),并且使用螺絲把模組固定。
連接NFC天線、LoRa?天線、藍牙天線,并安裝至外殼中。硬件組裝完成之后就可以進行軟件設置。
軟件環境搭建
在Arduino IDE中添加 RAK4631-R 開發板
打開 Arduino IDE,進入“文件 > 首選項”
打開 Arduino IDE單擊圖中圖標,修改“附加開發板管理器網址”選項,將 RAK4631-R WisBlock Core 添加中 Arduino 開發板管理器中。
在 Arduino IDE上修改“附加開發板管理器網址”現在復制這個 URL https://raw.githubusercontent.com/RAKWireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless.com_rui_index.json 并粘貼至下圖所示區域。如果已存在其他鏈接,將上述鏈接粘貼至新的一行。完成后,單擊“好”。
在Arduino IDE上粘貼復制好的URL重啟 Arduino IDE。 進入“工具 > 開發板:“RAK4631” > 開發板管理器”。
重啟Arduino IDE并執行操作在搜索框中輸入“RAK”,窗口會自動出現可用的RAKwireless WisBlock Core Boards,選擇“RAKwireless RUI nRF Boards”并安裝。
選擇并安裝 RAKwireless RUI nRF BoardsBSP 安裝完成后,根據圖中路徑選擇 RAKwireless WisBlock Core模塊。
選擇 RAKwireless WisBlock Core 模塊安裝使用到的庫
現在安裝 RAK13600-PN532 庫和 Adafruit bus 庫:
安裝 RAK13600-PN532 庫安裝 Adafruit bus 庫代碼開發
LoRaWAN?部分的初始化,此函數可以初始化協議棧的所有參數,入網方式是OTAA,用戶需要根據自己的頻段,入網參數修改此宏定義,代碼中使用的頻段是 AS923。
/************************************* LoRaWAN band setting: RAK_REGION_EU433 RAK_REGION_CN470 RAK_REGION_RU864 RAK_REGION_IN865 RAK_REGION_EU868 RAK_REGION_US915 RAK_REGION_AU915 RAK_REGION_KR920 RAK_REGION_AS923 *************************************/ #define OTAA_BAND (RAK_REGION_AS923) #define OTAA_DEVEUI {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} #define OTAA_APPEUI {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} #define OTAA_APPKEY {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} void lora_init()
蜂鳴器采用的是 PWM 控制,所以要記住在未使用蜂鳴器時,記得關閉輸出。
pinMode(BUZZER_CONTROL,OUTPUT); noTone(BUZZER_CONTROL);
NFC 芯片初始化代碼,采用 IIC 通信協議,初始化結束后,就可以使用 NFC的刷卡功能了。
nfc.begin(); uint32_t versiondata = nfc.getFirmwareVersion(); if (! versiondata) { Serial.print("Didn't find PN53x board"); while (1); // halt } // Got ok data, print it out! Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX); Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC); Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC); // Set the max number of retry attempts to read from a card // This prevents us from waiting forever for a card, which is // the default behaviour of the PN532. nfc.setPassiveActivationRetries(0xFF); //configure board to read RFID tags nfc.SAMConfig(); Serial.println("Waiting for an ISO14443A card");
每間隔 1 秒循環讀取是否有 NFC 卡存在,如果讀取 ID 成功,蜂鳴器會響 150 毫秒左右,然后發送卡 ID 到 LoRaWAN?服務器上。
void loop(void) { boolean success; uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID uint8_t uidLength; // Length of the UID (4 or 7 bytes dep ending on ISO14443A card type) // Wait for an ISO14443B type cards (Mifare, etc.). When one is found // 'uid' will be populated with the UID, and uidLength will indicate // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength); if (success) { tone(BUZZER_CONTROL,4000); delay(150); noTone(BUZZER_CONTROL); Serial.println("Found a card!"); Serial.print("UID Length: "); Serial.print(uidLength, DEC); Serial.println(" byte s"); Serial.print("UID Value: "); for (uint8_t i = 0; i < uidLength; i++) { Serial.print(" 0x"); Serial.print(uid[i], HEX); } Serial.println(""); digitalWrite(ledPin1, HIGH); // LED turn on when input pin value is HIGH delay(150); digitalWrite(ledPin1, LOW); // /** Send the data package */ if (api.lorawan.send(uidLength, (uint8_t *) & uid, 2, true, 1)) { Serial.println("Sending is requested"); } else { Serial.println("Sending failed"); } // Wait 1 second before continuing delay(1000); } else { // PN532 probably timed out waiting for a card Serial.println("Timed out waiting for a card"); } }
數據日志
本地串口日志的信息如下所示:
RAK7268內置LoRaWAN?服務器日志:
備注:全部源代碼如下所示
/** @file iso14443a_uid.ino @author rakwireless.com @brief This example will attempt to connect to an ISO14443A card and read card UID @version 0.1 @date 2021-10-14 @copyright Copyright (c) 2021 **/ /**************************************************************************/ #include #include #include // Click here to get the library: http://librarymanager/All#RAK13600-PN532 /************************************* LoRaWAN band setting: RAK_REGION_EU433 RAK_REGION_CN470 RAK_REGION_RU864 RAK_REGION_IN865 RAK_REGION_EU868 RAK_REGION_US915 RAK_REGION_AU915 RAK_REGION_KR920 RAK_REGION_AS923 *************************************/ #define OTAA_BAND (RAK_REGION_AS923) #define OTAA_DEVEUI {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} #define OTAA_APPEUI {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} #define OTAA_APPKEY {0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88} // If using the breakout or shield with I2C, define just the pins connected #define PN532_IRQ (WB_IO6) #define PN532_RESET (WB_IO5) // Not connected by default on the NFC Shield #define BUZZER_CONTROL WB_IO1 uint8_t ledPin1 = LED_GREEN; uint8_t ledPin2 = LED_BLUE; // Or use this line for a breakout or shield with an I2C connection: NFC_PN532 nfc(PN532_IRQ, PN532_RESET); void lora_init(); void setup(void) { Serial.begin(115200); pinMode(WB_IO2, OUTPUT); digitalWrite(WB_IO2, HIGH); pinMode(BUZZER_CONTROL,OUTPUT); noTone(BUZZER_CONTROL); // initialize the LED pin as an output pinMode(ledPin1, OUTPUT); pinMode(ledPin2, OUTPUT); lora_init(); delay(300); while (!Serial) delay(10); Serial.println("Hello!"); nfc.begin(); uint32_t versiondata = nfc.getFirmwareVersion(); if (! versiondata) { Serial.print("Didn't find PN53x board"); while (1); // halt } // Got ok data, print it out! Serial.print("Found chip PN5"); Serial.println((versiondata >> 24) & 0xFF, HEX); Serial.print("Firmware ver. "); Serial.print((versiondata >> 16) & 0xFF, DEC); Serial.print('.'); Serial.println((versiondata >> 8) & 0xFF, DEC); // Set the max number of retry attempts to read from a card // This prevents us from waiting forever for a card, which is // the default behaviour of the PN532. nfc.setPassiveActivationRetries(0xFF); //configure board to read RFID tags nfc.SAMConfig(); Serial.println("Waiting for an ISO14443A card"); } void loop(void) { boolean success; uint8_t uid[] = { 0, 0, 0, 0, 0, 0, 0 }; // Buffer to store the returned UID uint8_t uidLength; // Length of the UID (4 or 7 bytes depending on ISO14443A card type) // Wait for an ISO14443B type cards (Mifare, etc.). When one is found // 'uid' will be populated with the UID, and uidLength will indicate // if the uid is 4 bytes (Mifare Classic) or 7 bytes (Mifare Ultralight) success = nfc.readPassiveTargetID(PN532_MIFARE_ISO14443A, &uid[0], &uidLength); if (success) { tone(BUZZER_CONTROL,4000); delay(150); noTone(BUZZER_CONTROL); Serial.println("Found a card!"); Serial.print("UID Length: "); Serial.print(uidLength, DEC); Serial.println(" bytes"); Serial.print("UID Value: "); for (uint8_t i = 0; i < uidLength; i++) { Serial.print(" 0x"); Serial.print(uid[i], HEX); } Serial.println(""); digitalWrite(ledPin1, HIGH); // LED turn on when input pin value is HIGH delay(150); digitalWrite(ledPin1, LOW); // /** Send the data package */ if (api.lorawan.send(uidLength, (uint8_t *) & uid, 2, true, 1)) { Serial.println("Sending is requested"); } else { Serial.println("Sending failed"); } // Wait 1 second before continuing delay(1000); } else { // PN532 probably timed out waiting for a card Serial.println("Timed out waiting for a card"); } } void lora_init() { // OTAA Device EUI MSB first uint8_t node_device_eui[8] = OTAA_DEVEUI; // OTAA Application EUI MSB first uint8_t node_app_eui[8] = OTAA_APPEUI; // OTAA Application Key MSB first uint8_t node_app_key[16] = OTAA_APPKEY; if (!api.lorawan.appeui.set(node_app_eui, 8)) { Serial.printf("LoRaWan OTAA - set application EUI is incorrect! \r\n"); return; } if (!api.lorawan.appkey.set(node_app_key, 16)) { Serial.printf("LoRaWan OTAA - set application key is incorrect! \r\n"); return; } if (!api.lorawan.deui.set(node_device_eui, 8)) { Serial.printf("LoRaWan OTAA - set device EUI is incorrect! \r\n"); return; } if (!api.lorawan.band.set(OTAA_BAND)) { Serial.printf("LoRaWan OTAA - set band is incorrect! \r\n"); return; } if (!api.lorawan.deviceClass.set(RAK_LORA_CLASS_A)) { Serial.printf("LoRaWan OTAA - set device class is incorrect! \r\n"); return; } if (!api.lorawan.njm.set(RAK_LORA_OTAA)) // Set the network join mode to OTAA { Serial. printf("LoRaWan OTAA - set network join mode is incorrect! \r\n"); return; } if (!api.lorawan.join()) // Join to Gateway { Serial.printf("LoRaWan OTAA - join fail! \r\n"); return; } /** Wait for Join success */ while (api.lorawan.njs.get() == 0) { Serial.print("Wait for LoRaWAN join..."); api.lorawan.join(); delay(10000); } if (!api.lorawan.adr.set(true)) { Serial.printf ("LoRaWan OTAA - set adaptive data rate is incorrect! \r\n"); return; } if (!api.lorawan.rety.set(1)) { Serial.printf("LoRaWan OTAA - set retry times is incorrect! \r\n"); return; } if (!api.lorawan.cfm.set(1)) { Serial.printf("LoRaWan OTAA - set confirm mode is incorrect! \r\n"); return; } /** Check LoRaWan Status*/ Serial.printf("Duty cycle is %s\r\n", api.lorawan.dcs.get()? "ON" : "OFF"); // Check Duty Cycle status Serial.printf("Packet is %s\r\n", api.lorawan.cfm.get()? "CONFIRMED" : "UNCONFIRMED"); // Check Confirm status uint8_t assigned_dev_addr[4] = { 0 }; api.lorawan.daddr.get(assigned_dev_addr, 4); Serial.printf("Device Address is %02X%02X%02X%02X\r\n", assigned_dev_addr[0], assigned_dev_addr[1], assigned_dev_addr[2], assigned_dev_addr[3]); // Check Device Address Serial.println(""); }
-
nfc
+關注
關注
59文章
1629瀏覽量
180794 -
RAK
+關注
關注
0文章
48瀏覽量
2104
發布評論請先 登錄
相關推薦
評論