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

stm32收发 wiegand 韦根协议开发详解在刚开始接触到韦根接口时,知道这是一种门禁相关的传输协议。其中有两种比较常用的韦根数据格式,韦根26和韦根34,其中韦根26是开放的,韦根34开不开放我不知道(看样子不开放),但是在网上还是能看到韦根34的代码协议,下面介绍一下韦根26以及韦根34的相关内容。Wiegand26格式:各数据位的含义:第1位: 为输出数据2—13位的偶校验位第2-9位:…

大家好,又见面了,我是你们的朋友全栈君。如果您正在找激活码,请点击查看最新教程,关注关注公众号 “全栈程序员社区” 获取激活教程,可能之前旧版本教程已经失效.最新Idea2022.1教程亲测有效,一键激活。

Jetbrains全家桶1年46,售后保障稳定

     在刚开始接触到韦根接口时,知道这是一种门禁相关的传输协议。其中有两种比较常用的韦根数据格式,韦根26和韦根34,其中韦根26是开放的,韦根34开不开放我不知道(看样子不开放),但是在网上还是能看到韦根34的代码协议,下面介绍一下韦根26以及韦根34的相关内容。

Wiegand 26格式:

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

各数据位的含义:

第 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格式:

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

各数据位的含义:

第 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,以此判断前一张卡片数据是否已经接收完成,韦根的接收程序一般是用中断方式完成,然后使用定时器进行计数以判断是否接受完一帧数据。

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

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

以下为韦根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;						//韦根数据接收结构

Jetbrains全家桶1年46,售后保障稳定

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 = 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;
}
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还没有接收到脉冲,如果超过,则认为一帧接收完成了。

 

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

 

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

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

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • 图书销售管理系统需求分析,各种功能图部分

    图书销售管理系统需求分析,各种功能图部分负责人:大佬(20160402122)DEDRAGON(20160401094)完成部分:3.2有关功能图3.2.1层次图:3.2.2ipo图3.2.3e-r图3.2.4主数据流图3.2.5子功能图进货管理图库存管理图:销售管…

  • 阅读书源最新2020在线导入_书源篇五「建议收藏」

    阅读书源最新2020在线导入_书源篇五「建议收藏」书源篇五爱阅书香语昨晚半夜发的书源,竟然把另一位同学的书源仓库给忘了,我的失误啊,已经自罚酒一杯,喝完再干三杯。新的书源仓库分别是『Liquor030』及『Mxy』同学,写法很厉害,虽然我设计了这一套规则,但怎么用,用得好,全靠各位同学自己创建的。被各位同学不断鞭策,才能不断的完善。让我们一起努力吧。书源及工作原理书源:一个网站的规则描述文件,可能包括有多个来源;…

  • cubieboard mysql_Cubieboard开发笔记[通俗易懂]

    cubieboard mysql_Cubieboard开发笔记[通俗易懂]原创作品,转载请注明出处,谢谢!写在前面:亲测可用的搭建流程,但是此流程是针对32位系统的,如果您是64位系统,请勿采用本博文的方式。我搭这个环境居然折腾了一周时间,本来用32位系统好好的,但是官网非要推荐我用64位系统。因为最终打包必须在64位环境下实现。于是乎我一直在不断换系统版本,希望能按照对方工程师所描述的状况来实现,但是我将Error发给他时,他也无计可施。因而还是回到最熟悉的方式进行编…

  • python json转字符串_在python中将json转换为字符串

    python json转字符串_在python中将json转换为字符串在python中将json转换为字符串

  • idea最新激活码2022【2022最新】2022.02.07「建议收藏」

    (idea最新激活码2022)好多小伙伴总是说激活码老是失效,太麻烦,关注/收藏全栈君太难教程,2021永久激活的方法等着你。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.html4KDDGND3CI-eyJsaWNlbnNlSW…

  • RenderControl获取控件输出的HTML

    RenderControl获取控件输出的HTML之前写过一篇文章,通过实现ICallbackEventHandler接口,实现其两个方法。RaiseCallbackEvent实现回调处理,GetCallbackResult实现将处理产生的结果输出到客户端。为了实现页面不刷新,我们在GetCallbackResult方法中可以将前台的控件html通过RenderControl方法获取,并Return到客户端…

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号