简介:Wiegand(韦根)协议是由摩托罗拉公司制定的一种通讯协议,门禁系统的读卡器、IC卡常用到这种协议。此协议没有规定数据传输的波特率和长度。目前市场上常用的数据长度是26bit,34bit,36bit,44bit等。由于34bit与26bit原理相同的,代码仅仅是一点点区别,在这里主要讲述的是26bit
Wiegand 26格式:
校验位1 | HID | PID | 校验位2 |
---|---|---|---|
1bit | 2~9bit | 10~25bit | 26bit |
第2~9位:ID卡HID码的低8位
第10~25位:ID卡的PID号码
第1位:2~13位的偶校验位
第26位:14~25位的奇校验位
校验位1: 2~13位中,如果有偶数个1,则校验位1 = 0,反之为1
校验位2:14~25位中,如果有奇数个个1,则校验位2 = 0,反之为1
通信:
韦根的发送主要是依赖于两根数据线,一根是DATA0,另外一根是DATA1。由名字不难看出出,DATA0主要是发数据“0”的,而DATA1主要是发送数据“1”的。
发送:
在空闲的时候,两根数据线的电平都是为高的。当想发送“0”的时候,DATA0数据线由高电平被拉低并保持100us-300us的持续时间,就会将数据“0”发送出去。而发送数据“1”的方法也是类似的,但要注意的是在发送完一位数据后,要有1ms~3ms的时间间隔才去发送下一位数据。
上图是我用逻辑分析以抓取出来的数据,由图可知低电平持续的时间大概是200us,而下个信号再发出的时间是2ms左右。
接收:
韦根的接收由于是不用判断脉冲宽度的,速度很快,仅仅是一个电平就可以了的。所以通常采用的是中断的方式去进行接收。两张卡的电平最小时间间隔是250ms,所以当要接收多张卡片时,可以用这个时间去判断这一张卡片的数据是否完全接收完成。
整体介绍完了,下面看看代码实现。
韦根26的发送:
int WG_Send26(unsigned char *str)
{
unsigned char i, j, one_num = 0;
unsigned char even = 0;
unsigned char odd = 0;
unsigned short check_temp;
unsigned short wgdata = 0;
if(NULL == str)
return -1;
//偶校验
check_temp = str[0];
for(i = 0;i < 8;i++)
{
if(check_temp<<i & 0x80)
one_num+=1;
}
check_temp = str[1];
for(i = 0;i < 4;i++)
{
if(check_temp<<i & 0x80)
one_num+=1;
}
if(one_num % 2 )
even = 1;
else
even = 0;
//奇校验
one_num = 0;
check_temp = str[1];
for(i = 0;i < 4;i++)
{
if(check_temp>>i & 0x01)
one_num+=1;
}
check_temp = str[2];
for(i = 0;i < 8;i++)
{
if(check_temp<<i & 0x80)
one_num+=1;
}
if(one_num % 2 )
odd = 0;
else
odd = 1;
DATA0 = 1;
DATA1 = 1;
delay_ms(1);
if(even)
{
WG_send_bit_1();
}
else
{
WG_send_bit_0();
}
//发送24位
for(i=0;i<3;i++) {
wgdata = str[i];
for(j=0;j<8;j++)
{
if((wgdata<<j) & 0x80)
{
WG_send_bit_1();
}
else
{
WG_send_bit_0();
}
}
}
if(odd)
{
WG_send_bit_1();
}
else
{
WG_send_bit_0();
}
DATA0 = 1;
DATA1 = 1;
return 0;
}
韦根26的接收:
int WG_Recv26(unsigned char *str)
{
if(WG_State){
if(WG_Count == 26){
str[0] = WG_Data>>17 & 0xFF;
str[1] = WG_Data>>9 & 0xFF;
str[2] = WG_Data>>1 & 0xFF;
check_even_odd(str);
if(EVEN == (WG_Data>>25 & 0x01) && ODD == (WG_Data & 0x01)){
WG_State = 0;
WG_Data = 0;
WG_Count = 0;
return 1;
}
else {
WG_State = 0;
WG_Data = 0;
WG_Count = 0;
return 0;
}
}
WG_State = 0;
WG_Data = 0;
WG_Count = 0;
return -1;
}
return -2;
}
中断:
//外部中断3服务程序
void EXTI0_IRQHandler(void)
{
if( EXTI_GetITStatus(EXTI_Line0) != RESET )
{
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE);
if(DATA_IN0 == 0){
WG_Data <<= 1;
WG_Count++;
}
EXTI_ClearITPendingBit(EXTI_Line0); //清除LINE2上的中断标志位
}
}
//外部中断4服务程序
void EXTI1_IRQHandler(void)
{
if( EXTI_GetITStatus(EXTI_Line1) != RESET )
{
TIM_SetCounter(TIM3,0);
TIM_Cmd(TIM3, ENABLE);
if(DATA_IN1 == 0){
WG_Data = (WG_Data<<1) | 0x01;
WG_Count++;
}
EXTI_ClearITPendingBit(EXTI_Line1); //清除LINE3上的中断标志位
}
}
//定时器3中断服务程序
void TIM3_IRQHandler(void) //TIM3中断
{
if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查TIM3更新中断发生与否
{
TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除TIMx更新中断标志
WG_State = 1;
TIM_Cmd(TIM3, DISABLE);
}
}
韦根26收发的步骤跟程序也都记录下来了,可能有些地方描述的不清晰或者有错误,希望找到错误的朋友能在下面提醒我一下,我好做更改。
整体测试工程是下面链接可下载,要是没积分的话可留邮箱,我见到就会发。单片机用的是STM32f103系列的(好像是…)
工程下载