0%

韦根信号详解

1、什么是韦根信号

​ 韦根信号是两根数据线传输二进制数据,在空闲时端,两线的对0V的电源都为TTL电平的水平,也就是5V,一般通过5K电阻上拉,当有数据传输时,两根线交替地发送400uS低脉冲,当Data0线发脉冲时,数据是0;当Data1发脉冲时,发送的数据是1,不能两根线同时发脉冲。脉冲的间隔时间是1mS。

韦根的数据格式一般是由三部分组成:校验位、出厂码和数据位。不同的韦根格式有不同的组成。如26Bit格式,其第一位和第二十六位是校验位,2-9位是厂家码,10-25位是卡号位。

2、什么是韦根协议

Wiegand协议是国际上统一的标准,是由摩托罗拉公司制定的一种通讯协议,适用于门禁控制系统的读卡器和卡片的许多特性。

Wiegand协议很多格式,最常用的格式是26bit,即韦根26,此外还有34bit、32bit、36bit、37bit、42bit、44bit等格式。标准26-bit 格式是一个开放式的格式,他是广泛使用的工业标准,几乎所有的门禁控制系统都接受标准的26-Bit格式。

Wiegand协议并没有定义通讯的波特率、也没有定义数据长度,韦根格式主要定义数据传输方式:Data0和Data1两根数据线分别传输二进制数据0和二进制数据1。

3、标准Wiegand协议

Wiegand 26格式:
20191022111812599.png

各数据位的含义:
第 1 位:  为输出数据2—13位的偶校验位
第 2 - 9 位:  ID卡的HID码的低8位
第10 - 25位: ID卡的PID号码
第 26 位:  为输出数据14-25位的奇校验位

检验位1为偶校验位:对于WG26来说,如果前2-13位有偶数个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

输出如下:

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 PID 奇校验
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

Wiegand 34格式:

20191022113152698.png

各数据位的含义:

第 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 PID 奇校验
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

4、韦根数据接收

​ 韦根的接收对时间的实时性要求比较高,如果用查询的方法接收会出现丢帧的现象:假设查询到 DATA0为 0 时主程序正在指向其他任务,等主程序执行完该任务时 DATA0 已经变为 1 了,那么这样就导致了一个 0 bit 丢了,这样读出的卡号肯定奇偶校验通不过,所以表现出 CPU 接收不到 ID 模块发送的卡号了。

唯一的办法是在外部中断里接收每个 bit。 (仅仅在中断里获得开始接收 wiegand 数据还不行,因为这是尽管给开始接收 wiegand数据标志位置位了,但是主程序还在执行其他代码而没有到达查询开始接收 wiegand 数据标志位这条指令)。

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

20190215134104563.png

5、韦根接口定义

Wiegand接口由三条导线组成:

​ DATA0——简称D0,韦根信号0,通常使用线的颜色为:绿色/兰色。
​ DATA1——简称D1,韦根信号1,通常使用线的颜色:白色。
​ Data return(GND)——韦根信号地,通常为黑色。

D0,D1在没有数据输出时都保持+5V高电平;若输出为0,则D0拉低一段时间(负脉冲);若输出为1,则D1拉低一段时间(负脉冲)。
D0,D1不能两根线同时发脉冲,脉冲的间隔时间是1ms。

输出‘0’时:DATA0 线上出现负脉冲;
输出‘1’时:DATA1 线上出现负脉冲;

负脉冲宽度 TP=100~200 微秒;周期 TW=1000~3000 微秒

6、韦根信号线建议使用线缆

韦根信号线除了必须使用的三条导线:D0、D1、GND外,通常还需考虑韦根设备供电:Vcc(一般为红色线)。

此外可能还需要传输 LED、蜂鸣器等信号。

所以韦根信号线至少需要使用4芯电缆,最多需使用6芯电缆,一般情况下建议使用5芯电缆就可以了。

建议使用线缆型号:

最低4芯:RVVP4*0.5成束全屏蔽电缆(平行非双绞)

扩展4+1芯:RVVP5*0.5成束全屏蔽电缆(平行非双绞)

扩展4+2芯:RVVP6*0.5成束全屏蔽电缆(平行非双绞)

RVV6_0

7、韦根信号线传输距离

为保障韦根传输距离,建议使用标准线缆,韦根信号线传输距离一般在150 米左右,考虑到设备、线缆、现场环境等因素,建议敷设线缆长度控制在80米以下。

8、参考程序

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
//功能:把数组封包成韦根26的格式,并发送出去
// 原理是把每个字节的低4位取出,来计算这个字节的值
//入口:str=要封包的数组,
//出口:DATA0P3.0;DATA1=P3.1

void delay_100us(void)
{
//-------------------------延时100us
TR0 = 0;
TH0 = (65536 - 78)/256; //定时100us
TL0 = (65536 - 78)%256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) { ;}
}
void delay_1500us(void)
{
TR0 = 0;
TH0 = (65536 - 1382)/256; //定时1500us
TL0 = (65536 - 1382)%256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) { ;}
}
void WG_send_bit_1(void)
{
WG_DATA1 = 0;
//----------------------延时100us
delay_100us();
WG_DATA1 = 1;
//-------------------------------延时一个发送周期
delay_1500us();
}
void WG_send_bit_0(void)
{
WG_DATA0 = 0;
//----------------------延时100us
delay_100us();
WG_DATA0 = 1;
//-------------------------------延时一个发送周期
delay_1500us();
}

void send_wiegand26(uchar *str)
{
//| wiegand[0] | wiegand[1] | wiegand[2] |
//| *str *(str + 1) | *(str + 2) *(str + 3)| *(str + 4) *(str + 5)|
uchar data i;
uchar data check_temp; //韦根包奇偶效验中间暂存
bit data even; //韦根包前12位偶效验
bit data odd; //韦根包后12位齐效验
uchar data wiegand[3]; //韦根包数据24位

//--------------------------------端口方向定义
P3M0 = 0x00; //普通I/O口
P3M1 = 0x00;
//================================数组到韦根包的转化
wiegand[0] = wiegand[0]|((*str)<<4);//原理是把每个字节的低4位取出,来计算这个字节的值
wiegand[0] = wiegand[0]|(*(str+1)&0x0f);
wiegand[1] = wiegand[1]|(*(str+2)<<4);
wiegand[1] = wiegand[1]|(*(str+3)&0x0f)
wiegand[2] = wiegand[2]|(*(str+4)<<4);
wiegand[2] = wiegand[2]|(*(str+5)&0x0f);

//--------------------------------计算前12位1的个数是否为偶数,为偶效验用
check_temp = wiegand[1]&0xf0;
check_temp ^= wiegand[0];
check_temp ^= check_temp>>4;
check_temp ^= check_temp>>2;
check_temp ^= check_temp>>1;
even=!(check_temp&1);

//--------------------------------计算后12位1的个数是否为偶数,为奇效验用
check_temp = wiegand[1]&0x0f;
check_temp ^= wiegand[2];
check_temp ^= check_temp>>4;
check_temp ^= check_temp>>2;
check_temp ^= check_temp>>1;
odd=check_temp&1;

//================================启动发送,用定时器做时间延时
//--------------------------------韦根 输出端初始化
WG_DATA0 = 1;
WG_DATA1 = 1;
//--------------------------------发送偶效验
if(even)
{
WG_send_bit_1();
}
else
{
WG_send_bit_0();
}
//-------------------------------发送24位数据
for(i = 0;i<24;i++)
{
//---------------------------韦根 输出端初始化
if((wiegand[0])&0x80)
{
WG_send_bit_1();
}
else
{
WG_send_bit_0();
}
(*(long*)&wiegand[0]) <<= 1;
}
//==============================发送奇效验位
if(odd)
{
WG_send_bit_1();
}
else
{
WG_send_bit_0();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
//------------------------------------------------------
//功能:把数组封包成韦根 26 的格式,并发送出去
// 原理是把每个字节的低 4 位取出,来计算这个字节的值
//入口:str=要封包的数组,
//出口:DATA0P3.0;DATA1=P3.1
//------------------------------------------------------
void send_wiegand26(uchar * str) {
//| wiegand[0] | wiegand[1] | wiegand[2] |
//| *str *(str + 1) | *(str + 2) *(str + 3)| *(str + 4) *(str + 5)|
uchar data i;
static uchar data one_num; //计算 1 的个数
uchar data check_temp; //韦根包奇偶效验中间暂存
bit data even; //韦根包前 12 位偶效验
bit data odd; //韦根包后 12 位齐效验
static uchar data wiegand[3]; //韦根包数据 24 位
//--------------------------------端口方向定义
P3M0 = 0x00; //普通 I/O 口
P3M1 = 0x00;
//================================数组到韦根包的转化
wiegand[0] = wiegand[0] | (( * str) << 4); //原理是把每个字节的低 4 位取出,来计算这个字节的值
wiegand[0] = wiegand[0] | ( * (str + 1) & 0x0f);
//--------------------------------计算前 8 位 1 的个数,为偶效验用
check_temp = wiegand[0];
for (i = 0; i < 8; i++) {
if (check_temp & 0x01) //(check_temp&0x01)
{
one_num++;
}
check_temp >>= 1;
}
wiegand[1] = wiegand[1] | ( * (str + 2) << 4);
//--------------------------------计算接下来的 4 位 1 的个数,为偶效验用
check_temp = wiegand[1];
for (i = 0; i < 4; i++) {
if (check_temp & 0x80) {
one_num++;
}
check_temp <<= 1;
}
//--------------------------------判断 1 的个数
one_num % 2 == 0 ? (even = 0) : (even = 1);
one_num = 0;

wiegand[1] = wiegand[1] | ( * (str + 3) & 0x0f);
//--------------------------------计算接下来的 4 位 1 的个数,为奇效验用
check_temp = wiegand[1];
for (i = 0; i < 4; i++) {
if (check_temp & 0x01) {
one_num++;
}
check_temp >>= 1;
}
wiegand[2] = wiegand[2] | ( * (str + 4) << 4);
wiegand[2] = wiegand[2] | ( * (str + 5) & 0x0f);
//--------------------------------计算接下来的 8 位 1 的个数,为奇效验用
check_temp = wiegand[2];
for (i = 0; i < 8; i++) {
if (check_temp & 0x01) {
one_num++;
}
check_temp >>= 1;
}
//--------------------------------判断 1 的个数
one_num % 2 == 0 ? (odd = 1) : (odd = 0);
one_num = 0;

//================================启动发送,用定时器做时间延时
//--------------------------------韦根 输出端初始化
WG_DATA0 = 1;
WG_DATA1 = 1;
//--------------------------------发送偶效验
if (even) {
WG_DATA1 = 0;

//-------------------------延时 100us
TR0 = 0;
TH0 = (65536 - 78) / 256; //定时 100us
TL0 = (65536 - 78) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) {;
}

TF0 = 0;
WG_DATA1 = 1;
} else {
WG_DATA0 = 0;
//------------------------延时 100us
TR0 = 0;
TH0 = (65536 - 78) / 256; //定时 100us
TL0 = (65536 - 78) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) {;
}

TF0 = 0;
WG_DATA0 = 1;
}
//----------------------------延时一个发送周期
TR0 = 0;
TH0 = (65536 - 1382) / 256; //定时 1500us
TL0 = (65536 - 1382) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) {;
}

TF0 = 0;
//-------------------------------发送 24 位数据
for (i = 0; i < 24; i++) {
//---------------------------韦根 输出端初始化
WG_DATA0 = 1;
WG_DATA1 = 1;
if ((wiegand[0]) & 0x80) {
WG_DATA1 = 0;
//----------------------延时 100us

TR0 = 0;
TH0 = (65536 - 78) / 256; //定时 100us
TL0 = (65536 - 78) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;

while (!TF0) {;
}
TF0 = 0;
WG_DATA1 = 1;
} else {
WG_DATA0 = 0;
//---------------------延时 100us
TR0 = 0;
TH0 = (65536 - 78) / 256; //定时 100us
TL0 = (65536 - 78) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) {;
}
TF0 = 0;
WG_DATA0 = 1;
}
( * (long * ) & wiegand[0]) <<= 1;
//-------------------------------延时一个发送周期
TR0 = 0;
TH0 = (65536 - 1382) / 256; //定时 1500us
TL0 = (65536 - 1382) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) {;
}
TF0 = 0;
}
//==============================发送奇效验位
//------------------------------韦根 输出端初始化
WG_DATA0 = 1;
WG_DATA1 = 1;

if (odd) {
WG_DATA1 = 0;

//-------------------------延时 100us
TR0 = 0;
TH0 = (65536 - 78) / 256; //定时 100us
TL0 = (65536 - 78) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) {;
}
TF0 = 0;
WG_DATA1 = 1;
} else {
WG_DATA0 = 0;
//-------------------------延时 100us
TR0 = 0;
TH0 = (65536 - 78) / 256; //定时 100us
TL0 = (65536 - 78) % 256;
TF0 = 0;
ET0 = 0;
TR0 = 1;
while (!TF0) {;
}
TF0 = 0;
WG_DATA0 = 1;
}
}

以下为韦根26和韦根34发送代码:
wiegand.h文件

1
2
3
4
5
6
7
8
9
10
11
#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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
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 )==0)
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 )==1)
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 )==0)
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 )==1)
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还没有接收到脉冲,如果超过,则认为一帧接收完成了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
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

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
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
}
}
}
}