标准韦根26通讯格式
1、前言:
Wiegand(韦根)协议是由摩托罗拉公司制定的一种通讯协议,它适用于涉及门禁控制系统的读卡器和卡片的许多特性;其协议并没有定义通讯的波特率、也没有定义数据长度韦根格式主要定义是数据传输方式:Data0和Data1两根数据线分别传输0和1。现在应用最多的是26bit,34bit,36bit,44bit等等。
2、维根数据输出的基本概念:
维根数据输出由二根线组成,分别是DATA0和 DATA1;二根线分别将0或1输出。
输出0时:DATA0线上出现负脉冲;
输出1时:DATA1线上出现负脉冲;
负脉冲宽度TP=100微妙;周期TW=1600微妙
3、维根26位输出格式:
标准韦根输出是由26位二进制数组成,每一位的含义如下:
1 2 9 10 13 25 26
E X X X X X X X X X X X X X X X X X X X X X X X X O 二进制
第1位为2-13位的偶校验位
第2-9位对应与电子卡HID码的低8位
第10-25位对应电子卡的PID号码
第26位为14-25位的奇校验位
以上数据从左至右顺序发送。高位在前。
例如:一只HID:16385,PID:00004的电子卡其26位韦根输出为:
1 0 0 0 0 0 0 0 1 00 0 0 0 0 0 0 0 0 0 0 0 1 0 0 0
检验位 HID =16385(二进制的低8位) PID = 4( 二进制) 检验位
这26位数据在读出器的韦根输出线DATA0,DATA1上输出。
DATA0,DATA1在没有数据输出时都保持+5V高电平。若输出为0,则DATA0拉低一段时间,若输出为1,则DATA1拉低一段时间。
两个电子卡韦根输出之间的最小间隔为0.25秒。
4、维根26接收:
韦根的接收对时间的实时性要求比较高,如果用查询的方法接收会出现丢帧的现象:假设查询到DATA0为0时主程序正在指向其他任务,等主程序执行完该任务时DATA0已经变为1了,那么这样就导致了一个0?bit丢了,这样读出的卡号肯定奇偶校验通不过,所以表现出CPU接收不到ID模块发送的卡号了。唯一的办法是在外部中断里接收每个bit。(仅仅在中断里获得开始接收wiegand数据还不行,因为这是尽管给开始接收wiegand数据标志位置位了,但是主程序还在执行其他代码而没有到达查询开始接收wiegand数据标志位这条指令)。
5、韦根接口定义:
Wiegand接口界面由三条导线组成:
DATA0:暂定,兰色,P2.5(通常为绿色)。
DATA1:暂定,白色,P2.6(通常为白色)。
GND:(通常为黑色),暂定信号地。
当安装商拿到读卡器时,他们希望在读卡器和门禁控制面板的连接点(终端)上都能够看到这三个名称。目前所有的标准型读卡器都提供可选择的Wiegand接口。这三条线负责传送Wiegand数据,也被称为Wiegand信号。
6、特别说明:
在上述标准26位韦根格式中,只包含了电子卡HID码的低8位,即对应于韦根输出的第2位到第9位,实际上电子卡的HID码为16位。
除非特别说明,所售Census产品的韦根通讯协议均为上述标准协议。
奇/偶校验(ECC)是数据传送时采用的一种校正数据错误的一种方式,分为奇校验和偶校验两种,其原理如下:如果是采用奇校验,在传送每一个字节的时候另外附加一位作为校验位,当实际数据中“1”的个数为偶数的时候,这个校验位就是“1”,否则,这个校验位就是“0”,这样就可以保证传送的数据满足奇校验的要求。在接收方收到数据时,将按照奇校验的要求检测数据中“1”的个数,如果为奇数,表示传送正确,反之,表示传送错误。偶校验的过程和奇校验一样,只不过是检测数据中的“1”的个数为偶数。
#include <reg52.h>
#include <intrins.h>
#include <absacc.h>
/*类型声明*/
typedef unsigned char uchar;
typedef unsigned int uint;
typedef unsigned long ulong;
void delay(void);
sbit DATA1_INT0=P3^2;
sbit DATA0=P1^6;
uchar ReadIDflag=0;
bit RcvEven;
bit RcvOdd;
bit CheckEven=0;
bit CheckOdd=1;
bit RCVOK=0;
uchar RcvWG[3]={0,0,0};
uchar Rcnt=0;
sbit bell_cl=P1^7; //蜂鸣器
sbit WD=P3^5; //看门狗
sbit OE2_138=P1^5; //低有效
sbit INT_1=P3^3;
uchar COUNT_T0=0;
ulong flashbell=0;
#define T0H 0Xf9
#define T0L 0X85 //1.8ms
#define NOP5() _nop_();_nop_();_nop_();_nop_();_nop_()
#define selDW_CS_18ADD XBYTE[0X5fff]
#define selDW_CS_90ADD XBYTE[0X7fff]
#define selDM_ADD XBYTE[0X3fff]
#define EN138 OE2_138=1
#define DISEN138 OE2_138=0
uchar code DM[10]={0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
uchar codeIDindex[10]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09};
uchar ID[10]={0xE9,0xa0,0xa0,0x4f,0x00,0x00,0x00,0x00,0x00,0x00};
uchar codeDW_CS[10]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f,0xfE,0xfD};
bit b_ClrDog=0;
uchar ClrDogcount=0;
void initial(void)
{
EA=0;
EN138;
bell_cl=1;
COUNT_T0=0;
//INT0=0;
IT0=0;//低电平触发中断
EX0=1;//外部中断允许
//T0
TMOD= 0x11;
TH0 = T0H;
TL0 = T0L;
//T1
TH1 = T1H;
TL1 = T1L;
ET0=1;
TR0=1;
ET1=1;
TR1=0;
EA=1;
}
void delay(void)
{
uinti;
for(i=125;i>0;i--)
{}
}
voidv_ClrDog(void)
{
if(b_ClrDog)
{
b_ClrDog=0;
WD=0;NOP5();
WD=1;NOP5();
WD=0;
}
}
void main (void)
{
uchari=0;
initial();
while(1)
{
v_ClrDog();
if(ReadIDflag==1)
{ EA=0;
if(Rcnt<=1))//读偶校验位1
{
if(DATA0==0)RcvEven=0;
else RcvEven=1;
}
else if(Rcnt>=26)//读奇校验位26
{
if(DATA0==0)RcvOdd=0;
else RcvOdd=1;
}
else//读24位卡号数据
{
if(DATA0==0)
{if(Rcnt<=9)
RcvWG[0]=RcvWG[0]|0x00;
else if(Rcnt<=17)
RcvWG[1]=RcvWG[1]|0x00;
else RcvWG[2]=RcvWG[2]|0x00;
}
else
{
if(Rcnt<=9) //2~9位 用RcvWG[0]存
RcvWG[0]=RcvWG[0]|0x01;
else if(Rcnt<=17) //10~17位 用RcvWG[1]存
RcvWG[1]=RcvWG[1]|0x01;
elseRcvWG[2]=RcvWG[2]|0x01; //18~25位 用RcvWG[2]存
if(Rcnt<=13)CheckEven=~CheckEven;//偶校验
else CheckOdd=~CheckOdd; //奇校验
}
if(Rcnt<=9)
RcvWG[0]=RcvWG[0]<<1;
else if(Rcnt<=17)
RcvWG[1]=RcvWG[1]<<1;
else RcvWG[2]=RcvWG[2]<<1;
}
ReadIDflag=0;
EA=1;
}
if(Rcnt>26)//26韦根数据读完
{
if((CheckEven==RcvEven)&&(CheckOdd==RcvOdd))//检验数据是否接受正确
{
for(i=0;i<10;i++)//显示卡号
{
if(RcvWG[0]/16==IDindex[i])ID[0]= DM[i];
if(RcvWG[0]%16==IDindex[i])ID[1]= DM[i];
if(RcvWG[1]/16==IDindex[i])ID[2]= DM[i];
if(RcvWG[1]%16==IDindex[i])ID[3]= DM[i];
if(RcvWG[2]/16==IDindex[i])ID[4]= DM[i];
if(RcvWG[2]%16==IDindex[i])ID[5]= DM[i];
}
RcvWG[0]=0;
RcvWG[1]=0;
RcvWG[2]=0;
RcvEven=0;
RcvOdd=0;
CheckEven=0;
CheckOdd=1;
temp=0;
Rcnt=0;
RWGcnt=0;
RCVOK=1;
}
}
if (RCVOK)//读卡成功后,延时,再开始读下一次
{
EX0=0;
for(i=200;i>0;i--)
delay();
EX0=1;
}
if(ClrDogcount>=20){b_ClrDog=1;ClrDogcount=0;}
}
}
void T0_interrupt (void) interrupt 1 using1 //动态显示3字节卡号数据
{
EA =0;
TR0 =0;
v_ClrDog();
if(COUNT_T0>=10)COUNT_T0=0;
selDW_CS_18ADD=0xff;
selDW_CS_90ADD=0xff;
selDM_ADD=0x00;
if(RCVOK)
{
switch (COUNT_T0)
{
v_ClrDog();
case 0:{ selDW_CS_18ADD= DW_CS[0] ; selDM_ADD=ID[0];break;}
case 1:{ selDW_CS_18ADD= DW_CS[1] ; selDM_ADD=ID[1];break;}
case 2:{ selDW_CS_18ADD= DW_CS[2] ; selDM_ADD=ID[2];break;}
case 3:{ selDW_CS_18ADD= DW_CS[3] ; selDM_ADD=ID[3];break;}
case 4:{ selDW_CS_18ADD= DW_CS[4] ; selDM_ADD=ID[4];break;}
case 5:{ selDW_CS_18ADD= DW_CS[5] ; selDM_ADD=ID[5];break;}
case 6:{ selDW_CS_18ADD= DW_CS[6] ; selDM_ADD=ID[6];break;}
case 7:{ selDW_CS_18ADD= DW_CS[7] ; selDM_ADD=ID[7];break;}
case 8:{ selDW_CS_90ADD= DW_CS[8] ; selDM_ADD=ID[8];break;}
case 9:{ selDW_CS_90ADD= DW_CS[9] ; selDM_ADD=ID[9];break;}
}
}
else
{ switch (COUNT_T0)
{
v_ClrDog();
case 0:{ selDW_CS_18ADD= DW_CS[0] ; selDM_ADD=DM[0];break;}
case 1:{ selDW_CS_18ADD= DW_CS[1] ; selDM_ADD=DM[1];break;}
case 2:{ selDW_CS_18ADD= DW_CS[2] ; selDM_ADD=DM[2];break;}
case 3:{ selDW_CS_18ADD= DW_CS[3] ; selDM_ADD=DM[3];break;}
case 4:{ selDW_CS_18ADD= DW_CS[4] ; selDM_ADD=DM[4];break;}
case 5:{ selDW_CS_18ADD= DW_CS[5] ; selDM_ADD=DM[5];break;}
case 6:{ selDW_CS_18ADD= DW_CS[6] ; selDM_ADD=DM[6];break;}
case 7:{ selDW_CS_18ADD= DW_CS[7] ; selDM_ADD=DM[7];break;}
case 8:{ selDW_CS_90ADD= DW_CS[8] ; selDM_ADD=DM[8];break;}
case 9:{ selDW_CS_90ADD= DW_CS[9] ; selDM_ADD=DM[9];break;}
}
}
v_ClrDog();
ClrDogcount++;
COUNT_T0++;
TH0 =T0H;
TL0 =T0L;
TR0 =1;
EA =1;
}
void INT0_interrupt (void) interrupt 0 using2
{
EA =0;
ReadIDflag=1;
Rcnt++;
EA =1;
}