近几年来,由于茶叶质量安全危机频繁发生,引起了广大消费者的关注,如何对茶叶质量安全进行有效追踪与追溯,已成为一个急需解决的课题。利用RFID技术建立一个茶叶质量安全追踪与追溯体系,一旦发现茶叶存在质量安全的问题,通过RFID读写器读写贴合在茶叶产品上带有唯一标识的RFID标签,结合茶叶产品数据库就可以对茶叶质量进行跟踪与追溯,查清哪个环节出了问题。本文主要针对茶叶质量安全进行追踪与追溯研究。
关键词: RFID,防伪系统,茶叶溯源,数据库
IN recent years, due to the frequent occurrence of tea quality and safety crisis, causing the concerns of consumers, how to tea quality and safety for effective tracking and tracing, has become an urgent problem to be solved. The use of RFID technology to establish a tea quality and safety tracking and tracing system, once found in tea quality and safety issues, through the RFID reader to read and write RFID tags with lamination uniquely identified on tea products, tea products combine the database can tea quality tracking and tracing, to identify which aspects of a problem. Tracking and tracing paper mainly research on tea quality and safety.
Key Words: RFID,Security systems,Origin of tea,database
论文+代码下载地址:下载地址
第1章 绪论 1
1.1 研究背景 1
1.2 研究意义 1
1.3 研究内容 2
第2章 茶叶物流追溯系统支撑技术 3
2.1 RFID技术 3
2.1.1 RFID系统工作原理 3
2.1.2 RFID标签 3
2.1.3 读写器 4
2.1.4 RFID技术特点与优势 5
2.2 Visual Studio技术 5
2.3 My Sql 5
2.4 c#语言 6
第3章 茶叶防伪的数据库的设计 7
3.1 数据库 7
第4章 基于茶叶防伪的系统设计 9
4.1 功能设计 9
4.2 概要设计 9
4.3 详细设计 10
4.3.1 茶叶种植 10
4.3.2 茶叶采摘 10
4.3.3 茶叶加工 11
4.3.4 茶叶销售 11
4.4 用户界面逻辑设计 12
4.4.1 茶叶采摘录入界面 12
4.4.2 用户查询防伪界面 13
第5章 系统测试 14
5.1 完成采摘环节 14
5.2 完成所有环节 15
5.3 假冒伪劣产品 16
结论 17
参考文献 18
致谢 19
附录1 部分关键源码及解释 20
附录2 翻译 31
RFID技术
什么是RFID,RFID就是一种利用空间耦合来自动实现捕获目标对象并且获得相关数据的技术,如果你的标签发出的频率在读卡器的接收频率范围内,就能成功读取信息。比如我们日常出入的小区大门中就有使用到。RFID与读卡器的结合不需要硬件上的连接,也就是说不需要焊在一起等,也不需要像二维码,需要摄像头扫描清楚二维码的图像才能成功扫描,RFID发出的无线电就像无孔不入的信息流,只要有配对的读卡器,像淘宝上买的手持式读卡器,读写距离可以延伸到几百米,实用性很强操作方便。
2.1.1 RFID系统工作原理
RFID系统主要是由电子标签、读写器还有PC终端三大部分组成。工作原理就是我们物理中学习到的:rfid标签与读卡器主要通过磁场来互相传递能量和相关信息,当RFID标签进入磁场,读写器发出的操作需求,RFID可以自行接收,此时感应线圈将被激活,同时RFID将信息传到读卡器再通过读卡器翻译后发到电脑端,便于操作人员使用
2.1.2 RFID标签
RFID标签就是向读卡器发射信号的,电子标签由天线、线圈、存储器和集成电路组成,电子标签最大的特点莫过于他的唯一性,这也是他能够成功防伪的特点之一。下面我们将从三个部分来说说这个RFID标签
(1)主动式标签。何为主动式标签,就是自己能提供能量发送信号。并且由于这个特点,他的读写距离远,但是呢,没有十全十美的东西,这种标签也是如此,因为本身带有电源,一旦电源耗尽电量,他的所有优点就会变成缺点,这样一来,随着使用次数越来越多,传输距离也有可能从几百米缩短到几米甚至几厘米。这样就太不稳定了。
(2)被动式标签。被动式标签相对于上面那种最大的区别就是没有电源,所以在使用的时候,就需要外界给予刺激,读卡器就承担了这份工作。被动式标签的最大特点就是耐用,可以说这是一个永久牌的标签,只要没有特殊原因导致标签损坏,他就还能用。人无完人,他也是有缺点的,相较于前者,他并没有那么长的读写距离。信号强点,可以读的远一点,信号弱的话,距离就会更近。
(3)半主动式标签。第三种标签叫做半主动式标签,他是比较中肯的一款产品,集聚了上面两款的优点,既有电源,使得读写距离比被动式远,又耐用,这样比较中肯的产品也深受企业家的喜爱,像我们图书馆,宿舍门禁实用的门禁卡,多数使用的就是这一种标签。
2.1.3 读写器
读写器就是与标签配套使用的读取标签信息的工具。读取到信息后,再将翻译后的信息发送到电脑端,读写器既能读,也可以写。读写器一般是由天线、射频模块和读写模块组成。除此之外,读写器还分为固定式读写器和手持式读写器两种,一般来说,手持式使用更加方便,但是制作成本更大,也是的价格略高,在某宝上,固定式读写器只需一两百,而手持式至少上千。本文所使用的是固定式读写器ER302NFC读写器。ER302和电脑是通过USB数据线连接的。也就是说,电脑端发送指令给读卡器,读卡器再发送指令给RFID标签,最后再返回结果给电脑端。如果电脑端没有给读卡器发送指令。读卡器便不会工作,比如读卡,写卡等等。
2.1.4 RFID技术特点与优势
RFID技术是近几年比较盛行的,用读卡器读取标签很方便,三岁儿童也可以完成,只要与读卡器在一定的距离范围内即可识别,不需要像条形码或者二维码一样对准取景入框。并且,相比较条形码来说,标签不仅是可以读取信息还可以写。对比之前的那些防伪方法,有点真是有过之而无不及。下面我们将从四个方面来分析RFID技术到底有哪些优点,也对我们为什么要选取它来进行防伪来进行解释。
(1)易读:RFID标签不需要与读卡器进行实物上的连接,只需在读卡范围内,或者这样说,读卡器在读取信息的时候,也可以将标签遮盖,这样也能有效读取。以上我们讨论的三种标签的第一种,他自己具有电源,所以距离远。即使是后面两种标签也比条形码和二维码来得远。在茶叶加工后入库时,操作员工也可以一次性读取比较多的标签,这样既能缩短时间,提高效率,还能便于管理。
(2)唯一性:我们通常买东西后会刷刷二维码,接着打开一个网页或者一行字,其实二维码很容易复制,如果黑心商家将假冒的产品每个都贴上相同的二维码,在制作一个网页。消费者在扫瞄二维码后成功打开网页,网页上文字显示下产品的真实性,就很容易欺骗到消费者。而RFID标签,在设计的时候就已保证他自身的唯一性,且具有唯一的卡号。正品商家在自家网站上建立好完整的产品信息库,消费者购买后通过扫描标签,即可知道产品的真伪并得到想要的信息。
(3)范围广:买过有二维码标签的人都知道,一旦不小心将物品弄脏,再要扫描二维码就不容易了,而RFID标签。及时在有水,烟的情况下,仍旧能有效读取。这就决定了RFID标签的使用防伪更加广。不仅是安静洁净的房间里,在脏兮兮的地方也能使用,真是能屈能伸啊。
(4)实时:操作人员在录入信息的时候可以实时动态读取和录入。操作效率高,节约时间和人力。
本系统是基于RFID的茶叶防伪的从茶园到茶杯的一系列溯源追踪。主要调查内容包括茶叶种植、采摘、加工、包装、物流运输、经销商、零售价等。通过不同阶段扫描标签,不同种类的数据都被整合到后台数据库,通过用户界面呈现出来。管理员可以根据现实情况对茶叶制作等相关数据的修改和更新。用户在pc端可通过读卡器读取rfid标签读取每个阶段的信息。
系统展示
部分代码
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
using MySql.Data.MySqlClient;
namespace Mifare1K
{
public partial class Mifare_1K : Form
{
[DllImport("kernel32.dll")]
static extern void Sleep(int dwMilliseconds);
[DllImport("MasterRD.dll")]
static extern int lib_ver(ref uint pVer);
[DllImport("MasterRD.dll")]
static extern int rf_init_com(int port, int baud);
[DllImport("MasterRD.dll")]
static extern int rf_ClosePort();
[DllImport("MasterRD.dll")]
static extern int rf_antenna_sta(short icdev, byte mode);
[DllImport("MasterRD.dll")]
static extern int rf_init_type(short icdev, byte type);
[DllImport("MasterRD.dll")]
static extern int rf_request(short icdev, byte mode, ref ushort pTagType);
[DllImport("MasterRD.dll")]
static extern int rf_anticoll(short icdev, byte bcnt, IntPtr pSnr, ref byte pRLength);
[DllImport("MasterRD.dll")]
static extern int rf_select(short icdev, IntPtr pSnr, byte srcLen, ref sbyte Size);
[DllImport("MasterRD.dll")]
static extern int rf_halt(short icdev);
[DllImport("MasterRD.dll")]
static extern int rf_M1_authentication2(short icdev, byte mode, byte secnr, IntPtr key);
[DllImport("MasterRD.dll")]
static extern int rf_M1_initval(short icdev, byte adr, Int32 value);
[DllImport("MasterRD.dll")]
static extern int rf_M1_increment(short icdev, byte adr, Int32 value);
[DllImport("MasterRD.dll")]
static extern int rf_M1_decrement(short icdev, byte adr, Int32 value);
[DllImport("MasterRD.dll")]
static extern int rf_M1_readval(short icdev, byte adr, ref Int32 pValue);
[DllImport("MasterRD.dll")]
static extern int rf_M1_read(short icdev, byte adr, IntPtr pData, ref byte pLen);
[DllImport("MasterRD.dll")]
static extern int rf_M1_write(short icdev, byte adr, IntPtr pData);
[DllImport("MasterRD.dll")]
static extern int rf_ul_select(short icdev, IntPtr pSnr, ref byte pRLength);
[DllImport("MasterRD.dll")]
static extern int rf_ul_write(short icdev, byte page, IntPtr pData);
[DllImport("MasterRD.dll")]
static extern int rf_beep(short icdev, char msec);
//
bool bConnectedDevice;/*是否连接上设备*/
static char[] hexDigits = {
'0','1','2','3','4','5','6','7',
'8','9','A','B','C','D','E','F'};
public static byte GetHexBitsValue(byte ch)
{
byte sz = 0;
if (ch <= '9' && ch >= '0')
sz = (byte)(ch - 0x30);
if (ch <= 'F' && ch >= 'A')
sz = (byte)(ch - 0x37);
if (ch <= 'f' && ch >= 'a')
sz = (byte)(ch - 0x57);
return sz;
}
//
#region byteHEX
///
/// 单个字节转字字符.
///
/// 字节.
/// 转换好的字符.
public static String byteHEX(Byte ib)
{
String _str = String.Empty;
try
{
char[] Digit = {
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A',
'B', 'C', 'D', 'E', 'F' };
char[] ob = new char[2];
ob[0] = Digit[(ib >> 4) & 0X0F];
ob[1] = Digit[ib & 0X0F];
_str = new String(ob);
}
catch (Exception)
{
new Exception("对不起有错。");
}
return _str;
}
#endregion
public static string ToHexString(byte[] bytes)
{
String hexString = String.Empty;
for (int i = 0; i < bytes.Length; i++)
hexString += byteHEX(bytes[i]);
return hexString;
}
public static byte[] ToDigitsBytes(string theHex)
{
byte[] bytes = new byte[theHex.Length / 2 + (((theHex.Length % 2) > 0) ? 1 : 0)];
for (int i = 0; i < bytes.Length; i++)
{
char lowbits = theHex[i * 2];
char highbits;
if ((i * 2 + 1) < theHex.Length)
highbits = theHex[i * 2 + 1];
else
highbits = '0';
int a = (int)GetHexBitsValue((byte)lowbits);
int b = (int)GetHexBitsValue((byte)highbits);
bytes[i] = (byte)((a << 4) + b);
}
return bytes;
}
/**/
public Mifare_1K()
{
InitializeComponent();
}
private void Mifare_1K_Load(object sender, EventArgs e)
{
bConnectedDevice = false;
tscbxPort.SelectedIndex = 2; // default port 3
tscbxBaud.SelectedIndex = 6; // default 115200
}
private void tsbtnConnect_Click(object sender, EventArgs e)
{
/*toolbar button[connect] clicked*/
if (!bConnectedDevice)
{
int port = 0;
int baud = 0;
int status;
port = Convert.ToInt32(tscbxPort.Text);
baud = Convert.ToInt32(tscbxBaud.Text);
status = rf_init_com(port, baud);
if (0 == status)
{
tsbtnConnect.Text = "Disconnect";
bConnectedDevice = true;
MessageBox.Show("Connect device success!");
}
else
{
string strError;
strError = "Connect device failed";
bConnectedDevice = false;
MessageBox.Show(strError, "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
}
else {
rf_ClosePort();
bConnectedDevice = false;
tsbtnConnect.Text = "Connect";
}
}
//查找并读取标签的7个字节UID号
// This command include 2 commands: request and UL_Select,finally get the 7 bytes UID of Ultralight tag.
private void btnUID7_Click(object sender, EventArgs e)
{
short icdev = 0x0000;
int status;
// byte type = (byte)'A';//mifare one type is A 卡询卡方式为A
byte mode = 0x26; // Request the card which is not halted.
ushort TagType = 0;
// byte bcnt = 0x04;//mifare 卡都用4, hold on 4
IntPtr pSnr;
byte len = 255;
// sbyte size = 0;
if (!bConnectedDevice)
{
MessageBox.Show("Not connect to device!!", "error", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
txtUID7.Text = "";
pSnr = Marshal.AllocHGlobal(1024);
for (int i = 0; i < 2; i++)
{
// Sleep(50); // After open the antenna, it needs about 50ms delay before request.
status = rf_request(icdev, mode, ref TagType);//搜寻没有休眠的卡,request card
if (status != 0)
continue;
status = rf_ul_select(icdev, pSnr, ref len);//防冲突得到返回卡的序列号,--get the card UID
if (status != 0)
continue;
byte[] szBytes = new byte[len];
for (int j = 0; j < len; j++)
{
szBytes[j] = Marshal.ReadByte(pSnr, j);
}
String m_cardNo = "";
for (int q = 0; q < len; q++)
{
m_cardNo += byteHEX(szBytes[q]);
}
txtUID7.Text = m_cardNo;
//连接数据库信息
string constr = "server=localhost;User Id=root;password=root;Database=tea_info";
using (MySqlConnection mycon = new MySqlConnection(constr))
{
mycon.Open();
MySqlCommand mycmd = new MySqlCommand("select* from tea_table where UID = '" + txtUID7.Text + "'", mycon);
using (MySqlDataReader reader = mycmd.ExecuteReader())
{
if (reader.Read())
{
/*从数据库里查询出和用户相对应的teaName的值
*reader.GetOrdinal("teaName")的作用是得到teaName的为这行数据中的第几列,返回回值是int
*reader.GetString()的作用是得到第几列的值,返回类型为String.
*/
string teaName = reader.GetString(reader.GetOrdinal("teaName"));
string teaGrade = reader.GetString(reader.GetOrdinal("teaGrade"));
string plantLoc = reader.GetString(reader.GetOrdinal("plantLoc"));
string locWorker = reader.GetString(reader.GetOrdinal("locWorker"));
string pickTime = reader.GetString(reader.GetOrdinal("pickTime"));
string pickWorker = reader.GetString(reader.GetOrdinal("pickWorker"));
string processNum = reader.GetString(reader.GetOrdinal("processNum"));
string wdWorker = reader.GetString(reader.GetOrdinal("wdWorker"));
string zqWorker = reader.GetString(reader.GetOrdinal("zqWorker"));
string sqWorker = reader.GetString(reader.GetOrdinal("sqWorker"));
string rhWorker = reader.GetString(reader.GetOrdinal("rhWorker"));
string rkWorker = reader.GetString(reader.GetOrdinal("rkWorker"));
string wareTime = reader.GetString(reader.GetOrdinal("wareTime"));
string sellers = reader.GetString(reader.GetOrdinal("sellers"));
string price = reader.GetString(reader.GetOrdinal("price"));
String str = "该" + teaName + "是真货\r\n\r\n";
textBox1.AppendText(str);
str = "茶叶等级:" + teaGrade + "\r\n\r\n";
textBox1.AppendText(str);
str = "种植地:" + plantLoc + "\t种植员工:" + locWorker + "\r\n\r\n";
textBox1.AppendText(str);
str = "采摘时间:" + pickTime + "\t采摘员工:" + pickWorker + "\r\n\r\n";
textBox1.AppendText(str);
str = "加工批号:" + processNum + "\r\n\r\n";
textBox1.AppendText(str);
str = "加工工序:\r\n\r\n";
textBox1.AppendText(str);
str = "\t萎凋\t负责员工:" + wdWorker + "\r\n\r\n";
textBox1.AppendText(str);
str = "\t做青\t负责员工:" + zqWorker + "\r\n\r\n";
textBox1.AppendText(str);
str = "\t杀青\t负责员工:" + sqWorker + "\r\n\r\n";
textBox1.AppendText(str);
str = "\t揉捻\t负责员工:" + rhWorker + "\r\n\r\n";
textBox1.AppendText(str);
str = "入库时间:" + wareTime + "\t负责员工:" + rkWorker + "\r\n\r\n";
textBox1.AppendText(str);
str = "销售商:" + sellers + "\r\n\r\n";
textBox1.AppendText(str);
str = "全国统一售价:" + price;
textBox1.AppendText(str);
}
else
{
char msec = (char)80;//蜂鸣器响的时间,1个单位10ms
rf_beep(icdev, msec);
textBox1.Text = "该产品是假货";
}
}
}
break;
}
Marshal.FreeHGlobal(pSnr);
}
}
}
**参考文献:**
```bash
[1] C程序设计 谭浩强 清华大学出版社
[2] C++程序设计 谭浩强 清华大学出版社
[3] ARM体系结构与编程 杜春雷 清华大学出版社
[4] Windows程序设计 王艳平 人民邮电出版社
[5] 射频识别系统设计、仿真与应用 周晓光 人民邮电出版社
[6] 智能卡技术-----ic卡、rfid标签与物联网 王爱英 清华大学出版社
[7] 超高频识别技术与应用 Dominique paret|安建平译 电子工业出版社