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

     在刚开始接触到韦根接口时,知道这是一种门禁相关的传输协议。其中有两种比较常用的韦根数据格式,韦根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                     |

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

 

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

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

stm32收发 wiegand 韦根协议开发详解_第1张图片

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

wiegand.h文件

#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 

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的位数
		
	}	 
}

定时器计时代码timer.c

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

 

你可能感兴趣的:(linux学习笔记,linux学习)