1、寫在前面
韋根(Wiegand)協議是國際上統一的標准,是由摩托羅拉公司制定的一種通訊協議。它適用於涉及門禁控制系統的讀卡器和卡片的許多特性。 它有很多格式,標准的26-bit 應該是最常用的格式。此外,還有34-bit 、37-bit 等格式。 而標准26-bit 格式是一個開放式的格式,這就意味着任何人都可以購買某一特定格式的HID卡,並且這些特定格式的種類是公開可選的。26-Bit格式就是一個廣泛使用的工業標准,並且對所有HID的用戶開放。幾乎所有的門禁控制系統都接受標准的26-Bit格式。
2、韋根接口

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 |
- #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
#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
- #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)
- {
- <span style="white-space: pre;"> </span>if(EXTI_GetITStatus(EXTI_Line12) != RESET)
- <span style="white-space: pre;"> </span>{//Data0-> 低電平表示1位0
- <span style="white-space: pre;"> </span>if (u_DataBits == 0)
- {//偶校驗
- u_EvenCheck = 0;
- }
- else if (u_DataBits == (WG_DATA_BITS -1))
- {//奇校驗
- u_OddCheck = 0;
- }
- else
- {//數據,4字節、高位在前
- <span style="white-space: pre;"> </span>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)
- <span style="white-space: pre;"> </span>evencheck = 0; //偶數個1
- else
- <span style="white-space: pre;"> </span>evencheck = 1; //奇數個1
- if(u_OddNums % 2 == 0)
- oddcheck = 1; //偶數個1
- else
- oddcheck = 0; //奇數個1
- u_EvenNums = 0;
- u_OddNums = 0; <span style="white-space: pre;"> </span>//清零
- 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;
- }
- }
#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; } }