韦根协议及IO模拟韦根34接口


1、写在前面

韦根(Wiegand)协议是国际上统一的标准,是由摩托罗拉公司制定的一种通讯协议。它适用于涉及门禁控制系统的读卡器和卡片的许多特性。 它有很多格式,标准的26-bit 应该是最常用的格式。此外,还有34-bit 、37-bit 等格式。 而标准26-bit 格式是一个开放式的格式,这就意味着任何人都可以购买某一特定格式的HID卡,并且这些特定格式的种类是公开可选的。26-Bit格式就是一个广泛使用的工业标准,并且对所有HID的用户开放。几乎所有的门禁控制系统都接受标准的26-Bit格式。

 

2、韦根接口

 

Wiegand接口通常由3根线组成,它们分别是:数据0(Data0),数据1(Data1)和 Data return。这3条线负责传输Wiegand信号。D0,D1在没有数据输出时都保持+5V高电平。若输出为0,则D0拉低一段时间,若输出为1,则D1拉低一段时间。两个电子卡韦根输出之间的最小间隔为0.25秒。
 
3、韦根34协议

Wiegand 34各数据位的含义如下:

第 1 位: 为输出第2—17位的偶校验位

第 2-17 位: ID卡的HID码

第18-33位: ID卡的PID号码

第 34 位: 为输出第18-33位的奇校验位

数据输出顺序:HID码和PID码均为高位在前,低位在后。

 

例:一张ID卡内容为:

HID:32769   PID:34953  (假设卡面印字为:2147584137   001   34953 )

相应的二进制为:

HID:1000 0000 0000 0001

PID:1000 1000 1000 1001

输出如下:

12                     1718                     33  34

0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 10 0 0 1 0 0 0 1 0 0 1   0

|       HID_L            |          PID            |

4、韦根34接收程序(stm32,测试过可用!)
  1. #ifndef _WIEGAND_H_  
  2. #define _WIEGAND_H_  
  3.   
  4. // Wiegand 数据格式  
  5. #define     WG_DATA_BITS            34  //韦根34格式  
  6.   
  7. // Wiegand 数据线接口  
  8. #define     WIEGAND_PORT            GPIOB  
  9. #define     WIEGAND_DATA1_GPIO      GPIO_Pin_13  
  10. #define     WIEGAND_DATA0_GPIO      GPIO_Pin_12  
  11. #define     WIEGAND_RCC_PORT        RCC_APB2Periph_GPIOB  
  12. #define     WIEGAND_DATA1           PBin(13)  
  13. #define     WIEGAND_DATA0           PBin(12)  
  14.   
  15. // 外部函数  
  16. extern void WiegandInit(void);  
  17. extern void IDDataPrintf(void);  
  18.   
  19. #endif  
#ifndef _WIEGAND_H_
#define	_WIEGAND_H_

// Wiegand 数据格式
#define		WG_DATA_BITS			34	//韦根34格式

// Wiegand 数据线接口
#define 	WIEGAND_PORT   			GPIOB
#define 	WIEGAND_DATA1_GPIO		GPIO_Pin_13
#define 	WIEGAND_DATA0_GPIO		GPIO_Pin_12
#define 	WIEGAND_RCC_PORT  		RCC_APB2Periph_GPIOB
#define		WIEGAND_DATA1			PBin(13)
#define		WIEGAND_DATA0			PBin(12)

// 外部函数
extern void WiegandInit(void);
extern void IDDataPrintf(void);

#endif
 
  1. #include "stm32f10x.h"  
  2. #include "wiegand.h"  
  3. #define USEING_INTERR               //中断方式  
  4.   
  5. static u8 u_EvenCheck = 2;          //偶检验  
  6. static u8 u_OddCheck  = 2;          //奇校验  
  7. static u8 u_EvenNums  = 0;          //偶校验软件比较  
  8. static u8 u_OddNums   = 0;          //奇校验软件比较  
  9. static u8 u_DataBits  = 0;          //当前接收数据位数  
  10. u8 IDData[4];                   //4字节ID号  
  11.   
  12. #ifdef USEING_INTERR                //中断方式读取韦根数据  
  13. /*********************************************************** 
  14.  * 函数名:WiegandInit 
  15.  * 功能  :外部中断引脚初始化  
  16.  * 输入  : 无 
  17.  * 输出  :无 
  18. **********************************************************/  
  19. void WiegandInit(void)  
  20. {  
  21.     GPIO_InitTypeDef GPIO_InitStructure;  
  22.     EXTI_InitTypeDef EXTI_InitStructure;  
  23.     NVIC_InitTypeDef NVIC_InitStructure;  
  24.   
  25.     RCC_APB2PeriphClockCmd(WIEGAND_RCC_PORT | RCC_APB2Periph_AFIO,ENABLE);  
  26.   
  27.     GPIO_InitStructure.GPIO_Pin  = WIEGAND_DATA0_GPIO | WIEGAND_DATA1_GPIO;  
  28.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;               //下拉输入  
  29.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;  
  30.     GPIO_Init(WIEGAND_PORT, &GPIO_InitStructure);  
  31.   
  32.     //Data0 中断线 PB12  
  33.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12);   
  34.     EXTI_InitStructure.EXTI_Line    = EXTI_Line12;  
  35.     EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;    
  36.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;     //下降沿触发  
  37.     EXTI_InitStructure.EXTI_LineCmd = ENABLE;  
  38.     EXTI_Init(&EXTI_InitStructure);    
  39.       
  40.     //Data1 中断线  PB13  
  41.     GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource13);  
  42.     EXTI_InitStructure.EXTI_Line    = EXTI_Line13;  
  43.     EXTI_InitStructure.EXTI_Mode    = EXTI_Mode_Interrupt;    
  44.     EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;     //下降沿触发  
  45.     EXTI_InitStructure.EXTI_LineCmd = ENABLE;  
  46.     EXTI_Init(&EXTI_InitStructure);       
  47.   
  48.     //中断优先级,尽可能设为最高优先级  
  49.     NVIC_InitStructure.NVIC_IRQChannel          = EXTI15_10_IRQn;   //使能按键所在的外部中断通道  
  50.     NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;            //抢占优先级   
  51.     NVIC_InitStructure.NVIC_IRQChannelSubPriority   = 0x00;             //子优先级  
  52.     NVIC_InitStructure.NVIC_IRQChannelCmd           = ENABLE;       //使能外部中断通道  
  53.     NVIC_Init(&NVIC_InitStructure);   
  54. }  
  55.   
  56. /*********************************************************** 
  57.  * 函数名:EXTI15_10_IRQHandler 
  58.  * 功能  :两数据线中断函数 
  59.  * 输入  : 无 
  60.  * 输出  :无 
  61. **********************************************************/  
  62. void EXTI15_10_IRQHandler(void)  
  63. {          
  64.     <span style="white-space: pre;">    </span>if(EXTI_GetITStatus(EXTI_Line12) != RESET)  
  65. <span style="white-space: pre;">    </span>{//Data0-> 低电平表示1位0  
  66.     <span style="white-space: pre;">    </span>if (u_DataBits == 0)  
  67.         {//偶校验  
  68.             u_EvenCheck = 0;  
  69.         }  
  70.         else if (u_DataBits == (WG_DATA_BITS -1))  
  71.         {//奇校验  
  72.             u_OddCheck = 0;  
  73.         }  
  74.         else  
  75.         {//数据,4字节、高位在前  
  76.         <span style="white-space: pre;">    </span>IDData[(WG_DATA_BITS - 2 - u_DataBits) / 8] &= ~(0x1 << ((WG_DATA_BITS - 2 - u_DataBits) % 8));      
  77.         }  
  78.             u_DataBits++;   
  79.             EXTI_ClearITPendingBit(EXTI_Line12);   
  80.     }  
  81.     else if(EXTI_GetITStatus(EXTI_Line13) != RESET)  
  82.     {//Data1 -> 低电平表示1位1  
  83.         if (u_DataBits == 0)  
  84.         {   //偶校验   
  85.             u_EvenCheck = 1;  
  86.         }  
  87.         else if (u_DataBits == (WG_DATA_BITS -1))  
  88.         {  //奇校验  
  89.             u_OddCheck = 1;  
  90.         }  
  91.         else   
  92.         {//数据,4字节、高位在前  
  93.             IDData[(WG_DATA_BITS - 2 - u_DataBits) / 8] |= (0x1 << ((WG_DATA_BITS - 2 - u_DataBits) % 8));  
  94.             if(u_DataBits < WG_DATA_BITS / 2)  
  95.                 u_EvenNums++;                           //计算1的个数来作偶校验  
  96.             else if(u_DataBits < WG_DATA_BITS - 1)                                     
  97.                 u_OddNums++;                            //计算1的个数来作奇校验  
  98.         }  
  99.         u_DataBits++;   
  100.         EXTI_ClearITPendingBit(EXTI_Line13);      
  101.     }      
  102. }  
  103.   
  104. /*********************************************************** 
  105.  * 函数名:Check 
  106.  * 功能  :奇偶校验,确定读出数据书否正确  
  107.  * 输入  : 无 
  108.  * 输出  :0->校验成功,数据有效    1->校验失败,数据无效 
  109. **********************************************************/  
  110. u8 DataCheck(void)  
  111. {  
  112.     u8 oddcheck,evencheck;  
  113.   
  114.     if(u_DataBits >= WG_DATA_BITS)  
  115.     {//数据接收完才校验  
  116.         //u_DataBits = 0;         
  117.         if(u_EvenNums % 2 == 0)  
  118.         <span style="white-space: pre;">    </span>evencheck = 0;                   //偶数个1  
  119.         else                                  
  120.         <span style="white-space: pre;">    </span>evencheck = 1;                   //奇数个1  
  121.         if(u_OddNums % 2 == 0)  
  122.             oddcheck = 1;                   //偶数个1  
  123.         else   
  124.             oddcheck = 0;                   //奇数个1   
  125.         u_EvenNums = 0;  
  126.         u_OddNums  = 0;                     <span style="white-space: pre;">    </span>//清零  
  127.         if((u_EvenCheck == evencheck) && (u_OddCheck == oddcheck))    
  128.         {//校验成功  
  129.             u_EvenCheck = 2;  
  130.             u_OddCheck  = 2;  
  131.             return 0;                   //和实际的校验码一起返回成功  
  132.         }  
  133.         else  
  134.         {   //校验失败  
  135.             u_EvenCheck = 2;  
  136.             u_OddCheck  = 2;  
  137.             return 1;  
  138.         }     
  139.     }  
  140.     else  
  141.         return 2;     
  142. }  
  143. #else  //查询方式初始化  
  144. /*********************************************************** 
  145.  * 函数名:WiegandInit 
  146.  * 功能  :Wiegan数据线引脚初始化,  
  147.  * 输入  : 无 
  148.  * 输出  :无 
  149. **********************************************************/  
  150. void WiegandInit(void)  
  151. {  
  152.     GPIO_InitTypeDef GPIO_InitStructure;  
  153.   
  154.     RCC_APB2PeriphClockCmd(WIEGAND_RCC_PORT | RCC_APB2Periph_AFIO,ENABLE);  
  155.     GPIO_InitStructure.GPIO_Pin  = WIEGAND_DATA0_GPIO | WIEGAND_DATA1_GPIO;  
  156.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;  
  157.     GPIO_Init(WIEGAND_PORT, &GPIO_InitStructure);  
  158. }  
  159. /*********************************************************** 
  160.  * 函数名:GetWiegandData 
  161.  * 功能  :查询方式获取Wiegand数据 
  162.  * 输入  : 无 
  163.  * 输出  :无 
  164. **********************************************************/  
  165. u8 GetWiegandData(void)  
  166. {     
  167.   
  168.   
  169. }  
  170. #endif  
  171.   
  172. //串口打印  
  173. void IDDataPrintf(void)  
  174. {  
  175.     u8 CheckFlag = 0;  
  176.     u8 Buff[6],i;  
  177.   
  178.     if(u_DataBits >= WG_DATA_BITS)  
  179.     {  
  180.         CheckFlag = DataCheck();  
  181.         if(CheckFlag == 0)  
  182.         {     
  183.         #if 0  
  184.             USART_printf(USART1,"%s " "%d " "%d " "%d " "%d ","ID:", IDData[0],IDData[1],IDData[2],IDData[3]);  
  185.             USART_send_string("\n");  
  186.             USART_send_string("DataBits/Check: ");  
  187.             USART_printf(USART1, "%d " "%d\n ",u_DataBits,CheckFlag);  
  188.         #else  
  189.             for (i = 0;i < 4;i++)  
  190.                 Buff[i] = IDData[i];  
  191.             Buff[i++] = u_DataBits;  
  192.             Buff[i]   = CheckFlag;  
  193.             g_Driver.OnSendCanData(Buff,6,0);  
  194.         #endif        
  195.         }      
  196.         else if(CheckFlag == 1)  
  197.         {  
  198.         #if 0  
  199.             USART_send_string("Read Data Failed\n");  
  200.         #else   
  201.             for (i = 0;i < 4;i++)  
  202.                 Buff[i] = IDData[i];  
  203.             Buff[i++] = u_DataBits;  
  204.             Buff[i]   = CheckFlag;  
  205.             g_Driver.OnSendCanData(Buff,6,0);  
  206.         #endif    
  207.         }  
  208.         u_DataBits = 0;  
  209.     }         
  210. }  
#include "stm32f10x.h"
#include "wiegand.h"
#define USEING_INTERR				//中断方式

static u8 u_EvenCheck = 2;			//偶检验
static u8 u_OddCheck  = 2;			//奇校验
static u8 u_EvenNums  = 0;			//偶校验软件比较
static u8 u_OddNums   = 0;			//奇校验软件比较
static u8 u_DataBits  = 0;			//当前接收数据位数
u8 IDData[4];					//4字节ID号

#ifdef USEING_INTERR				//中断方式读取韦根数据
/***********************************************************
 * 函数名:WiegandInit
 * 功能  :外部中断引脚初始化 
 * 输入  : 无
 * 输出  :无
**********************************************************/
void WiegandInit(void)
{
  	GPIO_InitTypeDef GPIO_InitStructure;
	EXTI_InitTypeDef EXTI_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;

  	RCC_APB2PeriphClockCmd(WIEGAND_RCC_PORT | RCC_APB2Periph_AFIO,ENABLE);

  	GPIO_InitStructure.GPIO_Pin  = WIEGAND_DATA0_GPIO | WIEGAND_DATA1_GPIO;
  	GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;		  		//下拉输入
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  	GPIO_Init(WIEGAND_PORT, &GPIO_InitStructure);

	//Data0 中断线	PB12
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource12); 
  	EXTI_InitStructure.EXTI_Line	= EXTI_Line12;
  	EXTI_InitStructure.EXTI_Mode 	= EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;		//下降沿触发
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);	 
	
	//Data1 中断线  PB13
	GPIO_EXTILineConfig(GPIO_PortSourceGPIOB,GPIO_PinSource13);
	EXTI_InitStructure.EXTI_Line	= EXTI_Line13;
  	EXTI_InitStructure.EXTI_Mode 	= EXTI_Mode_Interrupt;	
  	EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;	  	//下降沿触发
  	EXTI_InitStructure.EXTI_LineCmd = ENABLE;
  	EXTI_Init(&EXTI_InitStructure);		

   	//中断优先级,尽可能设为最高优先级
  	NVIC_InitStructure.NVIC_IRQChannel 			= EXTI15_10_IRQn;	//使能按键所在的外部中断通道
  	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0x01;			//抢占优先级 
  	NVIC_InitStructure.NVIC_IRQChannelSubPriority 	= 0x00;				//子优先级
  	NVIC_InitStructure.NVIC_IRQChannelCmd 			= ENABLE;		//使能外部中断通道
  	NVIC_Init(&NVIC_InitStructure); 
}

/***********************************************************
 * 函数名:EXTI15_10_IRQHandler
 * 功能  :两数据线中断函数
 * 输入  : 无
 * 输出  :无
**********************************************************/
void EXTI15_10_IRQHandler(void)
{		 
    	if(EXTI_GetITStatus(EXTI_Line12) != RESET)
 {//Data0-> 低电平表示1位0  if (u_DataBits == 0) {//偶校验 u_EvenCheck = 0; } else if (u_DataBits == (WG_DATA_BITS -1)) {//奇校验 u_OddCheck = 0; } else {//数据,4字节、高位在前  IDData[(WG_DATA_BITS - 2 - u_DataBits) / 8] &= ~(0x1 << ((WG_DATA_BITS - 2 - u_DataBits) % 8)); } u_DataBits++; EXTI_ClearITPendingBit(EXTI_Line12); } else if(EXTI_GetITStatus(EXTI_Line13) != RESET) {//Data1 -> 低电平表示1位1 if (u_DataBits == 0) { //偶校验 u_EvenCheck = 1; } else if (u_DataBits == (WG_DATA_BITS -1)) { //奇校验 u_OddCheck = 1; } else {//数据,4字节、高位在前 IDData[(WG_DATA_BITS - 2 - u_DataBits) / 8] |= (0x1 << ((WG_DATA_BITS - 2 - u_DataBits) % 8)); if(u_DataBits < WG_DATA_BITS / 2) u_EvenNums++; //计算1的个数来作偶校验 else if(u_DataBits < WG_DATA_BITS - 1) u_OddNums++; //计算1的个数来作奇校验 } u_DataBits++; EXTI_ClearITPendingBit(EXTI_Line13); } } /*********************************************************** * 函数名:Check * 功能 :奇偶校验,确定读出数据书否正确 * 输入 : 无 * 输出 :0->校验成功,数据有效 1->校验失败,数据无效 **********************************************************/ u8 DataCheck(void) { u8 oddcheck,evencheck; if(u_DataBits >= WG_DATA_BITS) {//数据接收完才校验 //u_DataBits = 0; if(u_EvenNums % 2 == 0)  evencheck = 0; //偶数个1 else  evencheck = 1; //奇数个1 if(u_OddNums % 2 == 0) oddcheck = 1; //偶数个1 else oddcheck = 0; //奇数个1 u_EvenNums = 0; u_OddNums = 0;  //清零 if((u_EvenCheck == evencheck) && (u_OddCheck == oddcheck)) {//校验成功 u_EvenCheck = 2; u_OddCheck = 2; return 0; //和实际的校验码一起返回成功 } else { //校验失败 u_EvenCheck = 2; u_OddCheck = 2; return 1; } } else return 2; } #else //查询方式初始化 /*********************************************************** * 函数名:WiegandInit * 功能 :Wiegan数据线引脚初始化, * 输入 : 无 * 输出 :无 **********************************************************/ void WiegandInit(void) { GPIO_InitTypeDef GPIO_InitStructure; RCC_APB2PeriphClockCmd(WIEGAND_RCC_PORT | RCC_APB2Periph_AFIO,ENABLE); GPIO_InitStructure.GPIO_Pin = WIEGAND_DATA0_GPIO | WIEGAND_DATA1_GPIO; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; GPIO_Init(WIEGAND_PORT, &GPIO_InitStructure); } /*********************************************************** * 函数名:GetWiegandData * 功能 :查询方式获取Wiegand数据 * 输入 : 无 * 输出 :无 **********************************************************/ u8 GetWiegandData(void) { } #endif //串口打印 void IDDataPrintf(void) { u8 CheckFlag = 0; u8 Buff[6],i; if(u_DataBits >= WG_DATA_BITS) { CheckFlag = DataCheck(); if(CheckFlag == 0) { #if 0 USART_printf(USART1,"%s " "%d " "%d " "%d " "%d ","ID:", IDData[0],IDData[1],IDData[2],IDData[3]); USART_send_string("\n"); USART_send_string("DataBits/Check: "); USART_printf(USART1, "%d " "%d\n ",u_DataBits,CheckFlag); #else for (i = 0;i < 4;i++) Buff[i] = IDData[i]; Buff[i++] = u_DataBits; Buff[i] = CheckFlag; g_Driver.OnSendCanData(Buff,6,0); #endif } else if(CheckFlag == 1) { #if 0 USART_send_string("Read Data Failed\n"); #else for (i = 0;i < 4;i++) Buff[i] = IDData[i]; Buff[i++] = u_DataBits; Buff[i] = CheckFlag; g_Driver.OnSendCanData(Buff,6,0); #endif } u_DataBits = 0; } } 
 
5、注意事项
1)采用IO中断的方式接收,查询方式可能响应不过来;
2)IO中断方式尽可能设为最高,防止被其他中断打断,导致数据错误;
3)IO中断中处理事务尽可能少,减少耗时;
4)IO输入口必须加RC滤波,从硬件上增加抗干扰能力。
 
6、参考
https://baike.baidu.com/item/韦根协议/9914978?fr=aladdin


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM