无网不进  
软硬件开发

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
posted on 2018-02-28 10:46  无网不进  阅读(8147)  评论(0)    收藏  举报