一、韦根协议原理
韦根接口在门禁行业广泛使用,是一个门禁行业的通信标准,通过两条数据线 DATA0(D0)和 DATA1 (D1)发送数据。目前用的最多的是韦根 34 和韦根 26,二者数据格式相同,只是发送的位数的不同。
DATA0 和DATA1 在无信号时同时保持高电平
若发送数据为0,则DATA0 数据线上出现一个 200us(可定义)的低电平,DATA1 数据线上信号保持不变
若发送数据为 1,则DATA1 数据线上出现一个 200us(可定义)的低电平,DATA0 数据线上信号保持不变
在 200us 低电平之外,DATA0 和DATA1 始终保持高电平。
标准韦根26 格式如图所示,由 24 位卡号和 1 位偶校验位、1 位奇校验位组成。卡号中的高 12 位进 行偶校验,低 12 位进行奇校验。发送顺序从高位(每字节的 bit7)开始,如箭头所示。
标准韦根34格式与韦根26相同,由 32 位卡号和 1 位偶校验位、1 位奇校验位组成。卡号中的高 16 位进 行偶校验,低 16 位进行奇校验。发送顺序从高位(每字节的 bit7)开始。
韦根 66 与韦根 26 的结构相同,但发送的字节长度有所不同,刷 Mifare1 S50 卡时发送 4 字节卡号;刷 UltraLight 卡时发送 7 字节卡号;刷身份证时发送 8 字节物理卡号
二、代码实现
本代码使用引脚电平变化中断实现韦根协议刷卡
1、韦根引脚初始化
/*****************************************************************
** 名称:void WGInit(void)
** 功能:韦根协议引脚设置为输入,并开启对应的引脚电平变化中断
** 入口参数:无
** 出口参数:无
** 使用说明:
*****************************************************************/
void WGInit(void)
{
WG0_IN; //设置DATA0引脚为输入
WG1_IN; //设置DATA1引脚为输入
PCIFR|=1<<PCIF2; //清除PCINT23-16的引脚电平变化中断标志位
PCICR|=1<<PCIE2; //开启PCINT23-16上的的引脚电平变化中断
PCMSK2|=1<<PCINT22; //选择PCINT22-PD6的引脚电平变化中断
PCMSK2|=1<<PCINT23; //选择PCINT23-PD7的引脚电平变化中断
PCMSK2&=~(1<<PCINT16); //取消PCINT22-PD6的引脚电平变化中断
}
//引脚电平变化中断
ISR(PCINT2_vect)
{
global *gv = &global_struct; //全局结构体
T4_INIT(); //定时器4初始化,这里设置如果引脚电平变化中断触发后连续200ms无触发/数据,则认为接受完成 。
if((PIND&(1<<PIND7))==0x00)
{
gv->WG_Data[gv->WG_Count] = 0;
gv->WG_Count++;
}
if ((PIND&(1<<PIND6))==0x00)
{
gv->WG_Data[gv->WG_Count] = 1;
gv->WG_Count++;
}
if (gv->WG_Count>34)
{
gv->WG_Count=0;
}
}
2、定时器4初始化代码
/*****************************************************************
** 名称:void T4_INIT(void)
** 功能:定时器T4初始化 16位定时器
** 入口参数:无
** 出口参数:无
** 使用说明:
*****************************************************************/
void T4_INIT(void)
{
PRR1 &= ~((1<<PRTIM4)); //启用USART2模块
//关闭T1 选择无时钟源,关闭系统时钟 T1-CS10 T2-CS20 T0-CS00
TCCR4B = (TMR_CLK_STOP<<CS40);
//36864/3686400 = 10ms
TCNT4 = 65535-36864; //16位 65535
//sei();
//T1定时器普通模式、无分频,并开启定时器
TCCR4A = 0X00;
TCCR4B |= (TMR_CLK_NO_PRESCALE << CS40);
//开定时器T2溢出中断
TIMSK4 |= (1 << TOIE4);
}
/*****************************************************************
** 名称:ISR(TIMER4_OVF_vect)
** 功能:定时器T4 10ms溢出中断
** 入口参数:无
** 出口参数:无
** 使用说明:
*****************************************************************/
extern u8 wgdate[34];
ISR(TIMER4_OVF_vect)
{
global *gv = &global_struct;
TCNT4 = 65535-36864;
TIME_BASE.time3++;
if (TIME_BASE.time3>=20) //定时时间到200ms
{
TIME_BASE.time3=0;
if (gv->WG_Count==34)
{
gv->WG_Count=0;
memcpy(wgdate,gv->WG_Data,34);
gv->WG_State=1; //连续200ms无数据接收,韦根接收完成标志位置位
}
else
{
gv->WG_Count=0;
}
TCCR4B &= ~(TMR_CLK_STOP<<CS40); //无时钟源,关闭系统时钟
TIMSK4 &= ~(1 << TOIE4); //关闭时器T1溢出中断
}
}
3、韦根协议奇偶检验代码
/*****************************************************************
** 名称:void check_even_odd(u8 *str)
** 功能:计算接受到的韦根数据的奇偶校验
** 入口参数:接受到的韦根数据
** 出口参数:无
** 使用说明:
*****************************************************************/
void check_even_odd(u8 *str)
{
u8 i=0;
u8 one_num=0;
//偶校验计算:有偶数个1,那么检验位1=0,反之为1
for(i = 1;i < 17;i++)
{
if(str[i] & 0x01)
one_num++;
}
if((one_num % 2)==0)
odd = 0;
else
odd = 1;
one_num=0;
//奇校验计算:有奇数个1,那么检验位2=0,反之为1
for(i = 17;i < 33;i++)
{
if(str[i] & 0x01)
one_num++;
}
if((one_num % 2)==1)
even = 0;
else
even = 1;
}
4、韦根协议最终卡号获取代码
int WG_Recv34(unsigned char *str)
{
global *gv = &global_struct;
if(gv->WG_State)
{
check_even_odd(wgdate); //韦根数据奇偶校验
if((even == wgdate[33]) && (odd == wgdate[0])) //判断韦根数据奇偶校验是否正确
{
gv->WG_State = 0;
for(char m=0; m<(34/8); m++) //获取通过校验的韦根卡号对应的16进制数据gv->WG_ID
{
for(char n=0; n<8; n++)
{
gv->WG_ID[m] += wgdate[8*m+1+n]<<(7-n);
wgdate[8*m+1+n]=0;
}
}
memset(wgdate,0,34);
even=0;
odd=0;
return 1;
}
else //韦根数据奇偶校验错误舍去该次数据
{
even=0;
odd=0;
gv->WG_State = 0;
memset(wgdate,0,34);
memset(gv->WG_ID,0,4);
return 0;
}
}
return -2;
}