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

#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 = 0;elseeven = 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;elseodd = 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;elseeven = 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;elseodd = 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位0if(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位1else 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}}}
}

stm32收发 wiegand 韦根协议开发详解相关推荐

  1. 物联网数据传输协议MQTT介绍与应用开发详解

    本文首发微信公众号:码上观世界 Part 1 物联网概述 1. 物联网概念 物联网是指通过各种信息传感器.射频识别技术.全球定位系统.红外感应器.激光扫描器等各种装置与技术,实时采集任何需要监控. 连 ...

  2. STM32开发 -- 蓝牙开发详解(2)

    如需转载请注明出处:https://juyou.blog.csdn.net/article/details/100708695 接着 STM32开发 – 蓝牙开发详解(1) 这一篇接着讲. 看了好久好 ...

  3. STM32开发 -- L3GD20H陀螺仪开发详解

    如需转载请注明出处:https://blog.csdn.net/qq_29350001/article/details/93894852 之前讲过: MPU6050开发系列 STM32开发 – LIS ...

  4. STM32开发 -- 惯导模块开发详解

    如需转载请注明出处:https://juyou.blog.csdn.net/article/details/93476976 STM32开发 – GPS模块开发详解 这篇文章已经对于GPS模块开发讲得 ...

  5. 芯片常用协议种类详解,含多协议转换器

    题目:芯片常用协议种类详解,含多协议转换器 目录 1. 引言 1.1常用通信样式 1.2 FPGA芯片上的UART也是一样的 1.3 FPGA用verilog实现UART 1.4基于FPGA的SPI协 ...

  6. 《Linux设备驱动开发详解 A》一一2.3 接口与总线

    本节书摘来华章计算机出版社<Linux设备驱动开发详解 A>一书中的第2章,第2.3节,作者:宋宝华 更多章节内容可以访问云栖社区"华章计算机"公众号查看.1 2.3 ...

  7. C#socket之TCP开发详解(一)

    文章目录 C#socket开发详解(一) 简介: 预备知识: 相关概念梳理: 1.什么是socket? 2.什么是TCP/IP.UDP? 3.socket与TCP/IP.UDP的关系? 4.TCP与U ...

  8. linux 设备驱动 ppt,linux设备驱动开发详解讲座ppt

    PPT内容 这是linux设备驱动开发详解讲座ppt下载,主要介绍了设备驱动简介:建立和运行模块:字符驱动:调试技术:并发和竞争:分配内存:硬件通讯:中断处理:块设备驱动,欢迎点击下载. 嵌入式Lin ...

  9. STM32应用IAP进行程序更新详解及实例

      这是以前就想写的一个小专题关于IAP,以及IAP在STM32编程的应用,专题分三小节,主要介绍常见的单片机烧录方式,IAP的实际应用,以及Ymodem协议在IAP编程中应用,在笔记吃灰很久了,终于 ...

  10. Apache Thrift - java开发详解

    2019独角兽企业重金招聘Python工程师标准>>> Apache Thrift - java开发详解 博客分类: java 架构 中间件 1.添加依赖 jar <depen ...

最新文章

  1. JAVA springboot微服务b2b2c电子商务系统(十三)断路器聚合监控(Hystrix Turbine)
  2. solidworks模板_SolidWorks文件属性分类和创建方法,图纸自动属性的基础
  3. Linux tree命令
  4. rabbitmq 同步策略_RabbitMQ(三):消息持久化策略
  5. 使用ENTER模拟触发表单提交或者click事件
  6. 外架小横杆外露长度规范要求_脚手架各部位构造要求解读!
  7. linux系统脚本安装失败,ubuntu16.04下vim安装失败的原因分析及解决方案
  8. Windows2003屏蔽IP
  9. python-opencv实现简单的车牌定位
  10. linux重要的目录之etc
  11. 编译Windows版本ffmpeg:MingW方式失败
  12. anylogic和java,基于Anylogic的Java代码入门教程
  13. python round函数
  14. 第五届山东ACM大赛汇总
  15. 文件搜索工具(简单版)
  16. 五、interfaces 和 daos
  17. 微信小程序 php解密,微信小程序des加密、PHP des解密
  18. educoder 数据库原理与应用 实验六 约束与索引
  19. 英语思维导图大全 定语从句(十四)
  20. 后网盘时代:百度问鼎、阿里紧追、360们跟进

热门文章

  1. 【AR开发】ARCore简介
  2. 维纳滤波(Wiener Filter)
  3. 怎么卸载apowerrec_如何卸载win10自带的游戏中心
  4. mybatisplus自动生成id_【mybatis-plus】主键id生成、字段自动填充
  5. jq-ui的Sortable插件 两列布局 左右拖拽
  6. 微信小程序笔记——滚动计数器
  7. 手机触摸屏有电阻屏和电容屏,有什么区别?
  8. 三个精致的钢琴音源 Native Instruments Definitive Piano Collection
  9. 控制系统matlab计算及仿真,控制系统MATLAB计算及仿真实训
  10. VBS可扩展类库--语音库