stm32收发 wiegand 韦根协议开发详解

2022-11-16 18:01:26 浏览数 (1)

大家好,又见面了,我是你们的朋友全栈君。

在刚开始接触到韦根接口时,知道这是一种门禁相关的传输协议。其中有两种比较常用的韦根数据格式,韦根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来说,如果前1-8位有偶数个1,那么检验位1=0,反之为1

检验位2为奇校验位:对于WG26来说,如果后14-25位有奇数个1,那么检验位2=0,反之为1

数据输出顺序:

HID码和PID码均为高位在前,低位在后

例:一张ID卡内容为:

HID:32769 PID:34953 ( 卡面印:2147584137 001, 34953 )

相应的二进制为:

HID:1000 0000 0000 0001 ( 只输出低8位 )

PID:1000 1000 1000 1001

输出如下:

1 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 |

Wiegand 34格式:

各数据位的含义:

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

第 2-17 位:  ID卡的HID码

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

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

检验位1为偶校验位:对于WG34来说,如果前16位有数个1,那么检验位1=0,反之为1

检验位2为奇校验位:对于WG34来说,如果前16位有数个1,那么检验位2=0,反之为1

数据输出顺序:

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 |

在空闲时间,两个线保持的是高电平 5V,两根线分别为DATA0和DATA1。其中,DATA0用来传输‘0’,DATA1用来传输‘1’,原本处于高电平状态的DATA0拉低一个脉冲宽度W,便发出了‘0’,DATA1原本处于高电平状态拉低一个脉冲宽度W,便发出了一个‘1’。上述脉冲宽度W=100us-200us较为合适,两输出之间间隔T=1ms-3ms较为合适。

韦根连续发送两张卡的电平最小时间间隔T为0.25s,因此如果要连续接收多张电子卡数据时,可判断脉冲间隔T是否大于240ms,以此判断前一张卡片数据是否已经接收完成,韦根的接收程序一般是用中断方式完成,然后使用定时器进行计数以判断是否接受完一帧数据。

下图所示为,韦根时序图。

以下为韦根26和韦根34发送代码:

wiegand.h文件

代码语言:javascript复制
#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;						//韦根数据接收结构

wiegand.c

代码语言:javascript复制
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 = 0;
	else
		even = 1;

	
	/*然后计算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 = 1;
	else
		odd = 0;

	/*保持高电平准备发送数据*/
	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;
}
代码语言:javascript复制
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 = 0;
	else
		even = 1;
	
	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 = 1;
	else
		odd = 0;
	
	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还没有接收到脉冲,如果超过,则认为一帧接收完成了。

代码语言:javascript复制
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的位数
}	 
}

定时器计时代码timer.c

代码语言:javascript复制
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
}
}
}
}

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员栈长,转载请注明出处:https://javaforall.cn/215875.html原文链接:https://javaforall.cn

0 人点赞