第四阶段:通过物联网智能对象 - RFID 编程





5.00/5 (16投票s)
关于如何读取 RFID 标签和 DIY 安全系统项目的教程。
目录
1.背景
2.教程概述
3.入门 RFID 读卡器套件
4.用于读取标签的 C# 串行客户端
5.将 RFID 集成到物联网 (IoT)
5.1 RFID 客户端:将 RFID 连接到物联网
5.2 远程获取 RFID 标签
6. 结论
1.背景
RFID 或射频识别是 物联网 中最受欢迎的智能对象之一。带有唯一编号的智能标签有各种形式,如卡片或钥匙链。它可用于考勤系统中的个人识别、银行保险箱开启以及取代家庭和汽车锁钥匙等小型应用。RFID 标签价格便宜、效率高且耐用,使其成为多种应用的理想选择。RFID 读卡器是一种电子设备,可以读取 RFID 标签并通过串行端口发送读取的数据。因此,串行客户端应用程序可以消耗这些数据并用于进一步的逻辑或分析目的。尽管有许多串行通信软件可供选择,并且可以使用几乎所有编程语言进行编码,但您在互联网上搜索 RFID 的资源时,找不到太多真正可用的。这是因为使用 RFID 进行编程和使用它不仅仅是简单的串行通信。许多问题可能甚至不允许您开始使用这些设备。在本教程中,我们将构建一个非常高效的 RFID 客户端。不仅如此,我们还将将其集成到物联网基础设施中,以便远程 Arduino 硬件可以读取标签,并根据标签做出适当的决策。概念将在下一节中详细阐述。
2.教程概述
图 2:教程的整体概念
图 2 详细解释了本教程的目标。我们希望通过 C# RFIDClient 将 RFID 读卡器模块连接到物联网。客户端应用程序将通过串行通信从 RFID 读卡器读取标签,并通过我们的自定义 Web 服务将其推送到云存储。远程客户端将轮询此标签,该客户端将连接到 Arduino 设备。Arduino 必须借助 C# RemoteClientForRFID 从云端读取标签,将其与存储的标签进行匹配,并根据身份验证结果触发硬件事件。
3.入门 RFID 读卡器套件
RFID 读卡器套件配有 RS232 9 针端口。您很可能想将其连接到笔记本电脑。因此,您需要一根 RS232 转 USB 转换线,如图 3.1 所示。
图 3.1:RS232 转 USB 线(图片来源:snapdeal.com)
一旦您获得这个,您可能认为您的工作已经完成。但事实并非如此。电缆需要驱动程序。是的,您会收到随电缆附带的驱动程序,但该驱动程序不起作用。无论您怎么尝试,都无法使用该电缆。但仍有一线希望。
我们有一个来自 http://www.tri-plc.com/ 的 Windows Vista 32 位驱动程序。是的,无论您运行的是 Windows 7/8 64/32 位,唯一能与此电缆正常工作的驱动程序是 Vista 32 位 RS232/USB 转换器驱动程序。
因此,请安装驱动程序。
您需要一个 +9V 适配器为您的 RFID 设备供电。为设备供电,连接 USB 线。为了检查您的设备是否正常工作,您需要确保您的电缆和读卡器已被您的系统检测到。打开设备管理器,查看 COM 和 LPT 端口。您会看到 USB 转串行转换器在特定端口处被检测到,如图 3.2 所示。
图 3.2:通过 USB 转串行 COM 端口检查 RFID 设备连接
现在,准备好几张 RFID 卡。以下是我使用 RFID 卡、读卡器、9V 适配器和 RS232/USB 转换线进行设置的图示。
图 3.3 RFID 的主要设置
您也可以将 RFID 读卡器连接到 9V 电池组。一旦通电,读卡器蜂鸣器将鸣响大约两分钟。我不知道为什么蜂鸣器要响这么长时间,尤其是在一段时间后开启时。当蜂鸣器和绿色 LED 熄灭后,您可以将卡片靠近设备进行读取,如图 3.4 所示。当读卡器读取卡片的标签时,会发出蜂鸣声,LED 会亮起一段时间(约半秒)。
图 3.4:读取 RFID 标签
在上图中,当您将标签靠近读卡器时,您可以看到 LED 亮起。RFID 是一种短距离无线技术。因此,您无需将卡片与读卡器接触。
读卡器检测到标签后,会立即将值发送到串行端口。端口有一个内置延迟,用于等待一段时间,然后才能检测到另一张卡片。因此,在短时间内检测到同一张卡片的机会很低。
成功设置设备及其驱动程序后,终于可以开始编码了。我向您保证,使用 RFID 比某些博客所说的简单读取串行数据要复杂得多!
4.用于读取标签的 C# 串行客户端
您需要查看我关于 将 Arduino 配置为 IoT 节点 的教程,特别是 C# 串行客户端部分,以了解 C# 串行通信与外部设备的基本知识。
对于 Arduino,我们可以设置串行通信的波特率,因此在客户端中我们可以相应地选择速率。但对于 RFID 读卡器,虽然我们可以识别串行端口号,但问题是如何识别波特率。串行设备的经验法则是,如果没有另行说明,它们以 9600 波特率通信。因此,在设计时,我们可以简单地选择带有 9600 波特率的适当串行端口。现在我们觉得完成了!
然而,故事中还有一些曲折!
让我们首先通过使用 Arduino 串行监视器测试读卡器来测试标签的发送方式。
图 4.1:通过 Arduino 串行监视器读取 RFID 标签
您可以看到正在读取 12 字节的标签,但没有**换行符**。**这是非常重要的一点。现在让我们看看我们迄今为止使用的 C# 中的 serialPort DataReceived 事件处理程序。
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string s = serialPort1.ReadLine();
this.BeginInvoke(MyDlg, s);
}
上述代码的问题在于,由于没有行尾符,它永远无法完成串行端口数据的读取。
因此,让我们使用 `ReadExisting()` 而不是 `ReadLine()`。因此,我们更新的代码现在是
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
string s = serialPort1.ReadExisting();
this.BeginInvoke(MyDlg, s);
}
同样,在我们的 Display 方法中,我们将简单地处理字符串并将其放入列表框。
void Display(string s)
{
listBox1.Items.Add(s);
textBox1.Text = s;
}
现在让我们测试应用程序!
图 4.2:在 C# 串行客户端中读取 RFID 标签
这就是设计变得棘手的地方。这也是您在网上找不到太多 RFID 工作示例的确切原因。
现在我们看到,第一次标签被正确读取。之后,情况变得不可预测。这是因为读卡器模块会不断地将读取的字节发送到端口。
那么,如果我们存储一个变量来记录标签长度,并始终读取该长度的串行端口数据会怎样?下面是“读取到标签大小”逻辑的实现。
int tagSize = -1;
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
//// 1. If tag size was not known, store it/////////////
if (tagSize == -1)
{tagSize=serialPort1.BytesToRead;
}
//////////////////////////////////////////////////////
///////////////2. Read As many Bytes in a buffer as available
char[]buff=new char[serialPort1.BytesToRead];
serialPort1.Read(buff,0,serialPort1.BytesToRead);
///////////////////////////////////////////////////////
//////////////////// 3. store the characters in a temp string
String tmpS = new String(buff);
////////////////////////////////////////////////
/////////////////// 4. If tag length numbers of characters are read, call delegate//
if (tmpS.Length == tagSize)
{
s = "";
this.BeginInvoke(MyDlg, tmpS);
return;
}
////////////////////////////////////////////////////////////
////////////////// 5. If not all tag size amounts of bytes are read, store them temporarily//////////////
if (s.Length < tagSize)
{
s = s + tmpS;
}
/////////////////////// 6. When all tag size no of bytes read, call delegate////////////
else
{
tmpS = s;
s = "";
this.BeginInvoke(MyDlg, tmpS);
}
///////////////////////////////////////////////////////////////////////
}
从程序开始,看起来它应该能正常工作,对吧?
嗯,它比第一次尝试要好,但仍不足以让人信任,如图 4.3 所示。
图 4.3:通过修改后的逻辑读取标签
这个问题简直让我抓狂,也是我选择写这篇教程的原因之一。作为一名嵌入式程序员,您总是追求健壮性和效率。那么,像 C# 这样优秀的语言不能为这类问题提供真正的解决方案吗?
经过数小时的反复试验和大量的咖啡因摄入,我终于找到了解决方案。
仔细观察模式会发现,标签数据会按顺序串行出现。因此,如果我们把所有数据合并成一个字符串,并且知道第一个字符,我们就可以从那个字符开始扫描。不幸的是,我们不知道第一个或最后一个字符,甚至任何一个字符。但我们知道标签的确切长度,因为第一次它是作为一个整体被读取的(非常感谢为此付出的人)!
所以我将字符逐个放入一个文本框。在文本框的 `TextChanged` 属性中,我不断检查长度。如果长度与标签大小相同,我们就获取文本框的内容并放入列表框,然后清空文本框。
所以,以下是我们 `SerialPort DataReceived` 事件处理程序、`textBox1` 的 `TextChanged` 事件处理程序以及由委托调用的 `Display` 方法的形状。
string s = "";
string mydata = "";
int tagSize = -1;
private void serialPort1_DataReceived(object sender, System.IO.Ports.SerialDataReceivedEventArgs e)
{
if (tagSize == -1)
{
tagSize = serialPort1.BytesToRead;
}
char[] buff = new char[serialPort1.BytesToRead];
serialPort1.Read(buff, 0, serialPort1.BytesToRead);
String tmpS = new String(buff);
this.BeginInvoke(MyDlg, tmpS);
}
void Display(string s)
{
textBox1.Text = textBox1.Text+s;
}
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text.Length >= tagSize)
{
listBox1.Items.Add(textBox1.Text);
textBox1.Text = "";
}
}
就这样!当您进行测试时,您会很高兴看到一致的结果。图 4.4 演示了测试过程,图 4.5 显示了 RFID 标签数据一致读取的屏幕截图。
图 4.4 测试 RFID
图 4.5:使用我们的方法完美读取 RFID 标签
我们还将更改 `projId`,以便独立处理标签。
5.将 RFID 集成到物联网 (IoT)
在我们关于 将 Arduino 集成到 IoT 节点 的教程中,我们已经构建了自己的物联网基础设施中间件。我们已经在以下位置开发并托管了实时 Web 服务:
http://grasshoppernetwork.com/IoTService.asmx
我们将使用这个自定义服务来绑定我们的 RFID 模块和物联网,然后演示一个与之相关的操作。
string projId = "RFIDIoT";
现在我们需要处理两个不同的模块:第一个是 RFIDClient,它将连接到 RFID 设备;第二个是远程客户端,它将连接到 Arduino 板。
5.1 RFID 客户端:将 RFID 连接到物联网
图 5.1:RFIDClient 模块设计
图 5.1 展示了 RFIDClient 的设计。由于我在同一系统上运行两个模块,因此它们都具有相同的 IP 地址。用户需要在 `txtRemoteIp` 文本框中输入远程计算机的 IP 地址。当数据(RFID 标签)从 RFID 读卡器模块读取时,将触发 `textBox1` 的 `TextChanged` 事件。我们在这里需要做的就是检查用户是否希望通过服务发送数据,如果是,数据将使用名为 `iotClient` 的 Web 服务的 `ServiceReference` 发送。
BackgroundWorker bw = null;
string remoteIP = "";
string tag = "";
private void textBox1_TextChanged(object sender, EventArgs e)
{
if (textBox1.Text.Length >= tagSize)
{
tag = textBox1.Text;
listBox1.Items.Add(textBox1.Text);
textBox1.Text = "";
if (checkBox1.Checked)
{
remoteIP = txtRemoteIP.Text;
bw = new BackgroundWorker();
bw.DoWork += new DoWorkEventHandler(bw_DoWork);
bw.RunWorkerAsync();
}
}
}
void bw_DoWork(object sender, DoWorkEventArgs e)
{
//throw new NotImplementedException();
try
{
iotClient.InsertCommand(projId, remoteIP, "LED ON", "TAG:" + tag, DateTime.Now, "EXECUTE");
//iotClient.co
}
catch
{
}
}
我们将使用 `BackgroundWorker`,这样远程调用就不会阻塞 UI 线程。
5.2 远程获取 RFID 标签
在远程发送 RFID 标签后,我们的下一个任务是构建一个 RFID 读卡器的远程客户端,它将消耗标签数据。我将此模块命名为 `RemoteClientForRFID`。
这是其 IP 地址在 RFIDClient 中提供的机器。该模块应连接到 Arduino。Arduino 应通过串行端口读取标签。如果标签与预存储的标签匹配,它将发送一个名为“Matched”的串行命令,否则发送一个名为“Failed”的串行命令。
如果标签匹配,Arduino 设备还会将 PIN 13 LED 点亮 5 秒钟。此概念可用于开发安全扩展,您可以驱动与引脚 13 关联的继电器,以打开某些门或银行保险箱等。
该设备还在 LCD 上显示传入标签,根据标签是否匹配,显示“OK”或“BAD”信息。如果您想将数据库集成到应用程序中,您当然也可以在 C# 代码中使用匹配逻辑。我想在 Arduino 中展示比较,所以我决定在硬件层面进行匹配。
在此期间,要了解 LED 如何控制以及如何将 LCD 与 Arduino 连接,请参阅我关于 将硬件与 Arduino 连接的初学者教程。
这是 Arduino 草图,它从串行端口读取数据,比较标签并在匹配时点亮 LED。
#include <LiquidCrystal.h>
LiquidCrystal lcd(9,8,7,6,5,4); //create the lcd variable
void setup()
{
pinMode(13,OUTPUT);
digitalWrite(13,LOW);
lcd.clear(); //clear the LCD during setup
lcd.begin(16,2); //define the columns (16) and rows (2)
Serial.begin(9600);
}
void loop() {
lcd.print("RFID Tag:");
String content = "";
char character;
char data [13];
int number_of_bytes_received;
if(Serial.available() )
{
number_of_bytes_received = Serial.readBytesUntil (13,data,12);
data[number_of_bytes_received] = 0;
lcd.setCursor(0,1);
lcd.print(data);
//Serial.println(strcmp (data, "123456789"));
if(strcmp (data, "510074C3AC4A")==0)
{
Serial.println("Matched");
lcd.setCursor(13,1);
lcd.print("OK");
digitalWrite(13,HIGH);
delay(5000);
digitalWrite(13,LOW);
}
else
{
Serial.println("Failed");
Serial.println(strcmp (data, "510074C3AC4A"));
lcd.setCursor(13,1);
lcd.print("BAD");
}
}
delay(2000);
//clear LCD, since we are still on 2nd line...
lcd.home(); //set the cursor the top left
}
最后,我们需要一个 C# 客户端,我们称之为 `RemoteClientForRFID`,它从 IoT 中间件轮询命令并将其推送到 Arduino 设备。
图 5.2 展示了这个客户端的截图。
图 5.2 RemoteClientForRFID
此客户端的核心是一个计时器,它不断轮询发送给此客户端的命令。它还会读取串行数据并将其记录在列表框中作为本地数据。
private void timerPoll_Tick(object sender, EventArgs e)
{
timerPoll.Enabled = false;
try
{
string s = iotClient.CommandToExecute(projId, labIp.Text);
if (s.Length > 0)
{
string tag=s.Split(new char[]{'#',':'})[2];
listBox1.Items.Add(tag);
serialPort1.WriteLine(tag);
iotClient.DeleteCommand(projId, labIp.Text);
}
//iotClient.co
}
catch
{
}
timerPoll.Enabled = true;
}
回想一下我们关于 Arduino 作为 IoT 节点教程中的 `CommandToExecute()` 函数,它返回一个包含命令(标签)、发送者 IP、命令生成时间和命令状态的字符串。在这里,我们会在处理完命令后将其删除,以减少数据库存储。
因此,您需要先运行此客户端。连接到 Arduino,它会通过远程 Web 服务不断检查标签。此客户端的 IP 地址需要输入到 RFIDClient 的远程 IP 地址文本框中,并且必须勾选“发送到远程”复选框。一旦您提供了标签,它将读取标签并远程发送信息,该信息将被连接到 Arduino 的远程客户端获取并处理。
图 5.3 展示了成功的标签身份验证。
图 5.3:成功的 RFID 标签身份验证
图 5.4 显示了 LCD 中的错误身份验证结果,图 5.5 显示了正确身份验证的结果。
图 5.4:错误身份验证
图 5.5:正确身份验证
6. 结论
RFID 是物联网上的智能对象之一。这不是一个新设备,嵌入式程序员已经使用它很长时间了。但是,当您寻找一个展示 RFID 与 C# 配合工作的教程时,您找不到太多。此外,我找不到一个详细的教程来阐述如何使用物联网上的智能标签以及如何远程访问它们。本教程旨在指导您使用物联网上的 RFID。您可以根据本教程提供的基础开发自己的服务和应用程序扩展,以构建真正酷炫的东西。我希望您喜欢这篇教程,这是我关于物联网与 Arduino 的初学者系列教程中的最后一篇。