在刚开始接触到韦根接口时,知道这是一种门禁相关的传输协议。其中有两种比较常用的韦根数据格式,韦根26和韦根34,其中韦根26是开放的,韦根34开不开放我不知道(看样子不开放),但是在网上还是能看到韦根34的代码协议,下面介绍一下韦根26以及韦根34的相关内容。
Wiegand 26格式:
各数据位的含义:
第 1 位: 为输出数据2—13位的偶校验位
第 2—9 位: ID卡的HID码的低8位
第10-25位: ID卡的PID号码
第 26 位: 为输出数据14-25位的奇校验位
检验位1为偶校验位:对于WG26来说,如果前8位有偶数个1,那么检验位1=1,反之为0
检验位2为偶校验位:对于WG26来说,如果前8位有奇数个1,那么检验位1=1,反之为0
数据输出顺序:
HID码和PID码均为高位在前,低位在后
例:一张ID卡内容为:
HID:32769 PID:34953 ( 卡面印:2147584137 001, 34953 )
相应的二进制为:
HID:1000 0000 0000 0001 ( 只输出低8位 )
PID:1000 1000 1000 1001
输出如下:
0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 1
| HID_L | | PID |
Wiegand 34格式:
各数据位的含义:
第 1 位: 为输出第2—17位的偶校验位
第 2-17 位: ID卡的HID码
第18-33位: ID卡的PID号码
第 34 位: 为输出第18-33位的奇校验位
检验位1为偶校验位:对于WG34来说,如果前16位有偶数个1,那么检验位1=1,反之为0
检验位2为偶校验位:对于WG34来说,如果前16位有奇数个1,那么检验位1=1,反之为0
数据输出顺序:
HID码和PID码均为高位在前,低位在后
例:一张ID卡内容为:
HID:32769 PID:34953 ( 卡面印:2147584137 001, 34953 )
相应的二进制为:
HID:1000 0000 0000 0001
PID:1000 1000 1000 1001
输出如下:
0 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 0 1 0
| HID_L | | PID |
下图所示为,韦根时序图。
#define WG_DATA0(x) {if(0==(x)) HAL_GPIO_WritePin(WGD0_GPIO_Port, WGD0_Pin,GPIO_PIN_RESET); else HAL_GPIO_WritePin(WGD0_GPIO_Port, WGD0_Pin,GPIO_PIN_SET);}
#define WG_DATA1(x) {if(0==(x)) HAL_GPIO_WritePin(WGD1_GPIO_Port, WGD1_Pin,GPIO_PIN_RESET); else HAL_GPIO_WritePin(WGD1_GPIO_Port, WGD1_Pin,GPIO_PIN_SET);}
typedef struct
{
INT8U ucRxRingBuffer[WG_RX_BUFFERSIZE];//接收环形缓冲区
INT16U usReadPos; //环形接收缓冲区读位置
INT16U usWritePos; //环形接收缓冲区写位置
INT8S usFrameCount; //帧数
}WieGand_MSG_ST; //韦根数据接收结构
int WG_Send26(unsigned char *str)
{
unsigned char one_num = 0;
unsigned char even = 0;
unsigned char odd = 0;
unsigned char check_temp,i;
if(NULL == str)
return -1;
/*首先计算2-13位共12位的奇偶*/
check_temp = *str;
for(i = 0;i < 8;i++)
{
if(check_temp & 0x01)
one_num++;
check_temp >>= 1;
}
check_temp = *(str + 1);
for(i = 0;i < 4;i++)
{
if(check_temp & 0x80)
one_num++;
check_temp <<= 1;
}
if(one_num % 2 )
even = 1;
else
even = 0;
/*然后计算14-25位共12位的奇偶*/
one_num = 0;
check_temp = *(str + 1);
for(i = 0;i < 4;i++)
{
if(check_temp & 0x01)
one_num++;
check_temp >>= 1;
}
check_temp = *(str + 2);
for(i = 0;i < 8;i++)
{
if(check_temp & 0x01)
one_num++;
check_temp >>= 1;
}
if(one_num % 2 )
odd = 0;
else
odd = 1;
/*保持高电平准备发送数据*/
WG_DATA0(1);
WG_DATA1(1);
HAL_Delay(5);
/*发送第一位校验位*/
if(even)
{
WG_DATA1(0);
myDelay_us(300);
WG_DATA1(1);
}
else
{
WG_DATA0(0);
myDelay_us(300);
WG_DATA0(1);
}
HAL_Delay(2);
/*发送24位数据*/
for(i = 0;i < 24;i++)
{
WG_DATA0(1);
WG_DATA1(1);
if(str[0] & 0x80)
{
WG_DATA1(0);
myDelay_us(300);
WG_DATA1(1);
}
else
{
WG_DATA0(0);
myDelay_us(300);
WG_DATA0(1);
}
(*(long*)&str[0]) <<= 1;
HAL_Delay(2);
}
WG_DATA0(1); //拉高两条数据线电平
WG_DATA1(1);
/*发送最后一位校验位*/
if(odd)
{
WG_DATA1(0);
myDelay_us(300);
WG_DATA1(1);
}
else
{
WG_DATA0(0);
myDelay_us(300);
WG_DATA0(1);
}
WG_DATA0(1); //拉高两条数据线电平
WG_DATA1(1);
return 0;
}
int WG_Send34(unsigned char *str)
{
unsigned char one_num = 0;
unsigned char even = 0;
unsigned char odd = 0;
unsigned char check_temp,i;
if(NULL == str)
return -1;
check_temp = *str; //第一个字节
for(i = 0;i < 8;i++)
{
if(check_temp & 0x01)
one_num++;
check_temp >>= 1;
}
check_temp = *(str + 1);//第二个字节
for(i = 0;i < 8;i++)
{
if(check_temp & 0x01)
one_num++;
check_temp >>= 1;
}
if(one_num % 2 )
even = 1;
else
even = 0;
one_num = 0;
check_temp = *(str + 2);//第三个字节
for(i = 0;i < 8;i++)
{
if(check_temp & 0x01)
one_num++;
check_temp >>= 1;
}
check_temp = *(str + 3);//第三个字节
for(i = 0;i < 8;i++)
{
if(check_temp & 0x01)
one_num++;
check_temp >>= 1;
}
if(one_num % 2 )
odd = 0;
else
odd = 1;
WG_DATA0(1); //拉高两条数据线电平
WG_DATA1(1);
HAL_Delay(5);
/*发送第一位*/
if(even)
{
WG_DATA1(0);
myDelay_us(300);
WG_DATA1(1);
}
else
{
WG_DATA0(0);
myDelay_us(300);
WG_DATA0(1);
}
HAL_Delay(2);
/*发送32字节数据*/
for(i = 0;i < 32;i++)
{
WG_DATA0(1);
WG_DATA1(1);
if(str[0] & 0x80)
{
WG_DATA1(0);
myDelay_us(300);
WG_DATA1(1);
}
else
{
WG_DATA0(0);
myDelay_us(300);
WG_DATA0(1);
}
(*(long*)&str[0]) <<= 1;
HAL_Delay(2);
}
WG_DATA0(1); //拉高两条数据线电平
WG_DATA1(1);
/*发送最后一位校验位*/
if(odd)
{
WG_DATA1(0);
myDelay_us(300);
WG_DATA1(1);
}
else
{
WG_DATA0(0);
myDelay_us(300);
WG_DATA0(1);
}
WG_DATA0(1); //拉高两条数据线电平
WG_DATA1(1);
return 0;
}
在韦根信号接收方面,我使用了一个循环缓冲数组进行接收,在接收代码编写过程中,之前有一个疑问是,似乎采用中断接收时,是不用判断脉冲宽度的,然后只增加了对于一帧数据是否接收完的超时判断,这个超时计数是通过定时器做的,判断是否大于240ms还没有接收到脉冲,如果超过,则认为一帧接收完成了。
WieGand_MSG_ST stWG_Receive; //韦根数据接收结构
INT8U u_DataBits = 0; //当前接收数据位数
INT16S us_FirstBitPos = 0; //记录存放帧格式的位置
extern TIMER_WG_ST st_Timer_WG; //韦根接收定时结构
void WG_Receive(unsigned char dataLineType)
{
//Data0-> 低电平表示1位0
if(WG_DATA0_LINE == dataLineType)
{
/*接收的第一位*/
if (st_Timer_WG.usTIM_WgRxTimeCount == 0xffff)
{
/*接收位数清零*/
u_DataBits = 0;
st_Timer_WG.usTIM_WgRxTimeCount = 0;/*开始计时*/
/*记录存放本次接收位数的位置*/
us_FirstBitPos = stWG_Receive.usWritePos;
/*更新保存的位置*/
stWG_Receive.usWritePos++;
if(stWG_Receive.usWritePos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usWritePos = 0;
}
/*增加--若写指针赶上了读指针,需要处理*/
if(stWG_Receive.usWritePos == stWG_Receive.usReadPos)
{
/*读指针往后偏移一位*/
if(stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE26 || stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE34)
{
stWG_Receive.usReadPos++;
if(stWG_Receive.usReadPos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usReadPos = 0;
}
}
else /*读指针往后偏移一帧*/
{
if((WG_RX_BUFFERSIZE - stWG_Receive.usReadPos)> (stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos]+1))
{
stWG_Receive.usReadPos +=stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] +1;
}
else
{
stWG_Receive.usReadPos = (stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos]+1) - (WG_RX_BUFFERSIZE - stWG_Receive.usReadPos);
}
if(stWG_Receive.usFrameCount > 0)
stWG_Receive.usFrameCount--;
}
}
/*保存接收到的0*/
stWG_Receive.ucRxRingBuffer[stWG_Receive.usWritePos] = 0;
stWG_Receive.usWritePos++;
if(stWG_Receive.usWritePos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usWritePos = 0;
}
}
else/*不是接收第一位*/
{
/*增加--若写指针赶上了读指针,需要处理*/
if(stWG_Receive.usWritePos == stWG_Receive.usReadPos)
{
/*读指针往后偏移一位*/
if(stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE26 || stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE34)
{
stWG_Receive.usReadPos++;
}
else /*读指针往后偏移一帧*/
{
if((WG_RX_BUFFERSIZE - stWG_Receive.usReadPos)> stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos]+1)
stWG_Receive.usReadPos +=stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] +1;
else
{
stWG_Receive.usReadPos = (WG_RX_BUFFERSIZE - stWG_Receive.usReadPos) +1;
}
if(stWG_Receive.usFrameCount > 0)
stWG_Receive.usFrameCount--;
}
}
/*保存接收到的0*/
stWG_Receive.ucRxRingBuffer[stWG_Receive.usWritePos] = 0;
stWG_Receive.usWritePos++;
if(stWG_Receive.usWritePos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usWritePos = 0;
}
}
/*累计接收到的位数*/
u_DataBits++;
st_Timer_WG.usTIM_WgRxTimeCount = 0;
stWG_Receive.ucRxRingBuffer[us_FirstBitPos] = u_DataBits; //存放接收到WG的位数
}
//Data1 -> 低电平表示1位1
else if(WG_DATA1_LINE == dataLineType)
{
/*接收的第一位*/
if (st_Timer_WG.usTIM_WgRxTimeCount == 0xffff)
{
/*接收位数清零*/
u_DataBits = 0;
/*开始计时*/
st_Timer_WG.usTIM_WgRxTimeCount = 0;
/*记录存放本次接收位数的位置*/
us_FirstBitPos = stWG_Receive.usWritePos;
/*更新保存的位置*/
stWG_Receive.usWritePos++;
if(stWG_Receive.usWritePos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usWritePos = 0;
}
/*增加--若写指针赶上了读指针,需要处理*/
if(stWG_Receive.usWritePos == stWG_Receive.usReadPos)
{
/*读指针往后偏移一位*/
if(stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE26 || stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE34)
{
stWG_Receive.usReadPos++;
if(stWG_Receive.usReadPos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usReadPos = 0;
}
}
else /*读指针往后偏移一帧*/
{
if((WG_RX_BUFFERSIZE - stWG_Receive.usReadPos)> (stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos]+1))
{
stWG_Receive.usReadPos +=stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] +1;
}
else
{
stWG_Receive.usReadPos = (stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos]+1) - (WG_RX_BUFFERSIZE - stWG_Receive.usReadPos);
}
if(stWG_Receive.usFrameCount > 0)
stWG_Receive.usFrameCount--;
}
}
/*保存接收到的值*/
stWG_Receive.ucRxRingBuffer[stWG_Receive.usWritePos] = 1;
stWG_Receive.usWritePos++;
if(stWG_Receive.usWritePos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usWritePos = 0;
}
}
else/*不是接收第一位*/
{
/*增加--若写指针赶上了读指针,需要处理*/
if(stWG_Receive.usWritePos == stWG_Receive.usReadPos)
{
/*读指针往后偏移一位*/
if(stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE26|| stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] != WG_TYPE34)
{
stWG_Receive.usReadPos++;
}
else /*读指针往后偏移一帧*/
{
if((WG_RX_BUFFERSIZE - stWG_Receive.usReadPos)> stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos]+1)
stWG_Receive.usReadPos +=stWG_Receive.ucRxRingBuffer[stWG_Receive.usReadPos] +1;
else
{
stWG_Receive.usReadPos = (WG_RX_BUFFERSIZE - stWG_Receive.usReadPos) +1;
}
if(stWG_Receive.usFrameCount > 0)
stWG_Receive.usFrameCount--;
}
}
/*保存接收到的值*/
stWG_Receive.ucRxRingBuffer[stWG_Receive.usWritePos] = 1;
stWG_Receive.usWritePos++;
if(stWG_Receive.usWritePos == WG_RX_BUFFERSIZE)
{
stWG_Receive.usWritePos = 0;
}
}
/*累计接收到的位数*/
u_DataBits++;
st_Timer_WG.usTIM_WgRxTimeCount = 0;
stWG_Receive.ucRxRingBuffer[us_FirstBitPos] = u_DataBits; //存放接收到WG的位数
}
}
typedef struct
{
INT16U usTIM_WgRxTimeCount; //接收韦根超时的信息结构体
}TIMER_WG_ST;
TIMER_WG_ST st_Timer_WG;
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
/*韦根接收计时*/
if (htim->Instance == htim3.Instance)
{
if(st_Timer_WG.usTIM_WgRxTimeCount != 0xffff)
{
st_Timer_WG.usTIM_WgRxTimeCount++;
if(st_Timer_WG.usTIM_WgRxTimeCount == WG_RXTIMEOUT)
{
//到达20ms延时,读取按键状态
st_Timer_WG.usTIM_WgRxTimeCount = 0xffff;
stWG_Receive.usFrameCount++; //接收到帧数+1
}
}
}
}