韦根协议(26位)及其读取算法
PPeach 于 2013-1-23 10:46 编辑
Wiegand协议是国际上统一的标准,是由摩托罗拉公司制定的一种通讯协议。它适用于涉及门禁控制系统的读卡器和卡片的许多特性。 它有很多格式,标准的26-bit 应该是最常用的格式。此外,还有34-bit 、37-bit 等格式。 而标准26-bit 格式是一个开放式的格式,这就意味着任何人都可以购买某一特定格式的HID卡,并且这些特定格式的种类是公开可选的。26-Bit格式就是一个广泛使用的工业标准,并且对所有HID的用户开放。几乎所有的门禁控制系统都接受标准的26-Bit格式。(摘自百度百科)
Wiegand接口通常由3根线组成,它们是:数据0(Data0),数据1(Data1)和 Data return(这次教程没有这根线)。这3条线负责传输Wiegand信号。D0,D1在没有数据输出时都保持+5V高电平。若输出为0,则D0拉低一段时间,若输出为1,则D1拉低一段时间。两个电子卡韦根输出之间的最小间隔为0.25秒。(摘自百度百科)
两根线,DATE0接Mega的20口,DATE1接21口
UNO的话自己改一下DATE0是绿线,DATE1是白线,通常情况下
在放出程序前,我们先来进行思路的一个整理:
因为是26-Bit,所以应该有26位二进制数,现在来假设一个
0 0110 0011 1001 0101 1000 1100 0
这么一段二进制,首先我们要分析这段数据的组成
第1位为2—13位的偶校验位
第2—9位对应与电子卡HID码的低8位
第10-25位对应电子卡的PID号码
第26位为14-25位的奇校验位
对于我们来说首尾奇的偶校验位是没有用的,尽管我们读取到了。去掉首尾的奇偶校验位后,我们会发现现在就是3个八位二进制即
0110 0011 1001 0101 1000 1100
每个ID卡(还不知道是IC卡,反正就是那种类似于挂件的,不是类似银行卡的)背面都有一个属于自己的数,我接下来要介绍的算法就是如何得出其背后的数据。
我先口述一下,前8位二进制即:0110 0011 把他换算成十进制后去乘以256的平方;中八位二进制即:1001 0101 换算成十进制后乘以256,后八位二进制即:1000 1100 换算成十进制,随后把三次得到的数据相加就是其背后的卡号(我们老师告诉我的,牛啊!)
好的,现在算法也知道了,我们就要开始取数据了,首先我们对原始的数据进行处理。
0 0110 0011 1001 0101 1000 1100 0
0 1111 1111 1111 1111 1111 1111 0
当我们将这两组数据相与并将数据向右移1位的时候,就会得到
0110 0011 1001 0101 1000 1100
这个时候估计会有朋友想为什么不直接右移一位,我是担心首尾万一有数据是1的话那岂不是会被移到左边去(VB中貌似是这样的,我忘了,如果不会被移到左边去的话,还请朋友跟帖告诉我)
好了,现在我们得到了3组八位二进制,接下来就是取数据了,前八位也用位与的方法。
0110 0011 1001 0101 1000 1100
1111 1111 0000 0000 0000 0000
用他来与原来的得到的数据对与,之后再把得到的数据向右移16位,换算成十进制再乘以256的平方
特别注意:
0110 0011 0000 0000 0000 0000
和
0000 0000 0000 0000 0110 0011
这两组数据的十进制是不一样的!不相信的用WP7自带的计算器算!
接下来的中八位和后八位也用与的方法,我就给大家看一下我的草稿吧!
原始
0 0110 0011 1001 0101 1000 1100 0
Hid
0110 0011 1001 0101 1000 1100原始数据去首尾
1111 1111 0000 0000 0000 0000与的数据
0110 0011 0000 0000 0000 0000 得到的数据(下同)
Pid1
0110 0011 1001 0101 1000 1100
0000 0000 1111 1111 0000 0000
0000 0000 1001 0101 0000 0000
Pid2
0110 0011 1001 0101 1000 1100
0000 0000 0000 0000 1111 1111
0000 0000 0000 0000 1000 1100
除去第一次原始数据的处理,每次与的数据都是向右移8位。
所有与完了都不要忘记向右移,我来分别说一下,右移的位数。
处理原始数据向右移1位;HID向右移16位;Pid1右移8位;
Pid2不用移了。
接下来放程序
[C] 纯文本查看 复制代码
volatile long reader = 0;
volatile int readerCount = 0;
long sign = 0xff0000;void readerOne(void)
{
readerCount++;
reader = reader << 1;
reader |= 1;
}void readerZero(void)
{
readerCount++;
reader = reader << 1;
}void setup()
{
Serial.begin(9600);
attachInterrupt(3, readerZero, RISING);
attachInterrupt(2, readerOne, RISING);
delay(10);
reader = 0;
readerCount = 0;
}void loop()
{
if(readerCount >=26)
{
Serial.print(" Reader:");
Serial.print(reader);
Serial.println("");
reader = reader & 0x1fffffe;
reader = reader >> 1;long hid = reader & sign; hid = hid >> 16; hid = hid * 256 * 256; sign = sign >> 8; long pid1 = reader & sign; pid1 = pid1 >> 8; pid1 = pid1 * 256; sign = sign >> 8; long pid2 = reader & sign; sign = 0xff0000; long value = hid + pid1 + pid2; Serial.println( value); reader = 0, readerCount = 0; hid = 0, pid1 = 0, pid2 = 0, value = 0;
}
}
代码中的0x啥啥啥都是位与数据的换算成16进制得到的,若仔细看此贴,就知道为什么sign>>8的原因了。
via - arduino中文社区