1

用搭积木的方式自制一个NFC读卡器

 1 year ago
source link: https://www.eefocus.com/communication/525783
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

用搭积木的方式自制一个NFC读卡器-通信/网络-与非网

ai.php?filename=970_90@4x-100-1_2.jpg&contenttype=jpeg
54ab566de7f0e7ddc2a49f185221b8c6.jpg
d548328fbc2aa79503857619c12b9842.gif

地铁刷卡、上下班门禁打卡、高铁进站刷身份证、Apple Pay 购物……这些日常使用场景,都使用了 NFC 非接触式识别和互联技术,极大地方便了人们的生活。

不过,目前市面上常见的NFC无线读卡器都使用 WIFI 或蓝牙进行数据传输,功耗较高、且传输距离有限。而如果采用 LoRaWAN® 传输,则可以解决上述问题。事实上,基于 LoRaWAN® 的 NFC 读卡器优点突出:

1、LoRaWAN®的传输距离远、接收灵敏度高、且功耗低

2、采用LoRaWAN® 无线传输的读卡器安装部署方便

3、能使用电池供电、可持续使用半年以上。

本文将通过瑞科慧联的模块化开发套件 WisBlock 教大家快速搭建一个支持LoRaWAN® 的无线读卡器,让这个读卡器读到电子标签数据时,可以自动将数据上传到 LoRaWAN® 服务器上。WisBlock 其实是一个物联网解决方案设计生态系统,由可拼接的模块和易于使用的软件工具组成,可加快物联网产品生产周期、缩短上市时间。

搭建 LoRaWAN® NFC 读卡器概述

本次搭建使用的硬件是瑞科慧联(RAK)的 WisBlock 套件,MCU 选择的是RAK4631 WisBlock 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 外壳、一根蓝牙天线(安装在外壳内)。

6319839dcfb34.jpg


RAK4631 模块、RAK19007 底板、RAK13600 NFC 读卡器等硬件准备

硬件组装

把 RAK4631 模块扣在 CPU SLOT 的位置,RAK13600 扣在 IO SLOT 的位置,RAK18001 扣在 SLOT A(或者SLOT B),并且使用螺丝把模组固定。

连接 NFC 天线、LoRa® 天线、蓝牙天线,并安装至外壳中。硬件组装完成之后就可以进行软件设置。

6319839ef0731.png



软件环境搭建

Arduino IDE中添加 RAK4631-R 开发板

打开 Arduino IDE,进入“文件 > 首选项”

6319839e2a4c1.png


打开 Arduino IDE

单击图中图标,修改“附加开发板管理器网址”选项,将 RAK4631-R WisBlock Core 添加中 Arduino 开发板管理器中。

6319839dcf8ba.jpg


在 Arduino IDE上修改“附加开发板管理器网址”

现在复制这个 URL https://raw.githubusercontent.com/RAKWireless/RAKwireless-Arduino-BSP-Index/main/package_rakwireless.com_rui_index.json 并粘贴至下图所示区域。如果已存在其他链接,将上述链接粘贴至新的一行。完成后,单击“好”。

6319839e5f75b.png


在Arduino IDE上粘贴复制好的URL

重启 Arduino IDE。 进入“工具 > 开发板:“RAK4631” > 开发板管理器”。

6319839e477f6.png


重启Arduino IDE并执行操作

在搜索框中输入“RAK”,窗口会自动出现可用的RAKwireless WisBlock Core Boards,选择“RAKwireless RUI nRF Boards”并安装。

6319839e35595.png


选择并安装 RAKwireless RUI nRF Boards

BSP 安装完成后,根据图中路径选择 RAKwireless WisBlock Core模块。

6319839e48d48.png


选择 RAKwireless WisBlock Core 模块

安装使用到的库

现在安装 RAK13600-PN532 库和 Adafruit bus 库:

6319839e69296.png


安装 RAK13600-PN532 库

6319839e66ea1.png


安装 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"); } }

本地串口日志的信息如下所示:

6319841f78b64.png

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(""); }

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK