韋根協議及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