单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  • 发送0Gap1

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  • 发送1Gap0

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  • 发送1Gap1

单片机编码BPSK信号

前言:
  一些终端短距无限通讯的设备,依然选择使用电信号作为信号的载体,比如主动笔和触控屏之间。算然短距但是信号幅度不强又易受到干扰,通常传输中伴随着信号源的运动,比如笔在书写的过程中向屏发送信号等。这就要求我们选择的通讯方式要具有较强的抗干扰能力,从笔端到屏端发送的数据可以以BPSK码作为载波,增强信号传输过程中的抗干扰能力。本文介绍了如何通过单片机将数据转化为BPSK码发送。

1 什么是BPSK信号?

  BPSK(Binary phase Shift Keying)即二进制相移键控。在通讯领域通常将基带信号对应上要发送的码元,比如码元为101100时,基带信号为持续1个单位长度的高电平,持续1一个单位长度的低电平,持续2个单位长度的高电平,持续两个单位长度的低电平。将该码元信号作为基带信号,假设载波信号是一个正弦函数,则调相规则为基带信号为高电平时载波信号不变,基带信号为低电平时载波信号进行相位移动,通常移动半个周期即反向。

BPSK sin.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 6, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 1:
y1.append(1)
elif v < 2:
y1.append(0)
elif v < 4:
y1.append(1)
elif v < 6:
y1.append(0)

#载波信号
y2 = np.sin(2 * math.pi * (x - 1 / 2))

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
y3.append(y2[n])
elif y1[n] == 0:
y3.append(-y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

2 运用于单片机短距通讯的数字信号BPSK编码规则

  以上是在通讯领域BPSK一般运用,在单片机短距数字通讯时,为了更好的发送数字信号我们用周期是基带信号一个码元电平持续时间偶数倍分之一的方波信号作为载波信号,这个方波信号它初始电平为高或低,本文讨论高电平起始,低电平起始情况类似。

BPSK PWM.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 12, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

  我们假设要发送的码元数据为0x5A,对应二进制为01011010b。基带信号中一个码元1为持续一个单位时间的高电平,一个码元0则为持续一个单位时间的低电平。而载波信号为是占空比为50%的方波信号,它的周期是基带信号单位时间的偶数倍分之一,其初始电平为高。按BPSK的调相规则信号调制后如图:

BPSK PWM 0x5A.png

  python3测试代码:

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
import numpy as np
import math
import matplotlib.pyplot as plt

x = np.arange(0, 32, 0.0001)

#基带信号
y1 = []
for v in x:
if v < 4:
y1.append(0)
elif v < 8:
y1.append(1)
elif v < 12:
y1.append(0)
elif v < 16:
y1.append(1)
elif v < 20:
y1.append(1)
elif v < 24:
y1.append(0)
elif v < 28:
y1.append(1)
elif v < 32:
y1.append(0)

#载波信号
y2 = []
m = 1 #PWM起始电平高
u = 1
for v in x:
if v < u:
pass
else:
u += 1
if m == 1:
m = 0
else:
m = 1

y2.append(m)

#BPSK调相信号
y3 = []
for v in x:
n = int(v * 10000)
if y1[n] == 1:
if y2[n] == 1:
y3.append(0)
elif y2[n] == 0:
y3.append(1)
elif y1[n] == 0:
y3.append(y2[n])

#设置窗格大小
Window = plt.figure(num = 3)
#添加子图
Line1 = Window.add_subplot(3, 1, 1)
Line2 = Window.add_subplot(3, 1, 2)
Line3 = Window.add_subplot(3, 1, 3)

Line1.plot(x, y1)
Line2.plot(x, y2)
Line3.plot(x, y3)

plt.show()

3 如何通过单片机外设资源输出BPSK信号

  弄清楚了数据编码规则后,就需要考虑如何调用单片机的外设资源从IO口输出BPSK信号了。
  以下我们以基带信号每个码元的单位时间对应载波信号方波的两个周期举例。码元0对应载波信号方波以高电平起始,码元1为低电平起始,也就相当于移相半个周期。
  对单片机外设资源的要求:单片机需要具备带PWM输出的定时器,该定时器除了能设置PWM输出的频率和占空比外,还需要控制PWM的起始电平、停止电平、匹配值电平、溢出值电平(周期值电平),方便在灵活的控制PWM的高低电平变化。同时需要能产生比较值和溢出值中断。为了方便控制,定时器可以设置为锯齿波模式,向上计数。

3.1 发送单个码元

  码元0是高电平起始,对应载波信号两个周期方波输出。为了保证起始值输出高电平,定时器需要将起始电平设为高,停止电平设为低。为了保证输出50%的占空比,将比较值电平配置为低,溢出值电平配置为高。码元1是低电平起始,定时器需要配置为起始电平低,停止电平低,比较值电平高,溢出值电平低。

锯齿波码元0_.png

锯齿波码元1_.png

  为了能数出方波的个数,需要开启比较中断,在中断里进行累加。一个码元对应两个方波周期,则累加到2时表示完成一个码元输出,可以开始下一个码元输出。
  单个码元发送结束后需要关闭定时器停止输出。关闭的时机很重要,如果关闭过早或过晚会导致输出的BPSK信号残缺或有多余部分,最终导致接收设备处理出错。如果输出的最后一个码元是0,其高电平起始意味着低电平结束,我们可以在最后一个匹配值中断中停止输出。而如果最后一个码元是1,其低电平起始意味着高电平结束,为了保证信号输出完整,我们需要在最后一个匹配值中断中将溢出值中断打开,然后在触发的溢出值中断里停止输出。

Single bit 0_.png

Single bit 1_.png

  为了便于后文描述,我们将以下定时器配置称为码元0配置:
起始电平:高
停止电平:低
匹配值电平:低
溢出值电平:高
  将以下定时器配置称为码元1配置:
起始电平:低
停止电平:低
匹配值电平:高
溢出值电平:低

3.2 发送多个码元

  发送多个码元,如果码元值不变,比如全0或全1,这种情况只是发送单个码元后控制好关闭信号输出的时间而已,这里主要讨论码元变化的情况。拆分细了说可以分为两种情况:

  • 发送码元01

Bits 01_.png

  在开始发送码元0之前我们会先进行码元0配置,发送码元1当然也需要切换定时器配置,为了保证信号不在切换配置时出现差错,切换配置的时机选择非常重要。我们应当选择码元0的最后一个匹配值中断里切换为码元1配置,保证在下一个边沿信号出现之前完成配置,同时又保证码元0和码元1的信号输出完整。码元1切换码元0配置同理。

  • 发送码元10

Bits 10_.png
  方法同发送01。先设置码元1配置,然后在码元1的最后一个匹配值中断里切码元0配置。

3.3 码元中插入间隔发送

  在通讯中为了使接收设备能更好的同步上发送设备的信号,以及让接收设备更容易解析出发送设备的数据,我们常常在持续发送一段码元后空出载波信号一个周期的低电平作为信标。比如每3Bit的码元就空出一个周期间隔。
  这里为了便于描述问题,我们只看gap的前后1个码元,总共有四种情况:

  • 发送0Gap0

0Gap0_.png

  • 发送0Gap1

0Gap1_.png

  • 发送1Gap0

1Gap0_.png

  • 发送1Gap1

1Gap1_.png

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。

  虽然有四种情况,但是处理方式其实都是一样的,即从码元0/1配置切换到Gap配置,再从Gap配置切换回码元0/1配置。关键问题在于Gap0的配置,以及切换配置的时机。
  如下配置我们称为Gap配置:
匹配值电平:低
溢出值电平:低
  有了上面的基础这里我们很容易明白从码元切到Gap配置的时机依然是码元最后一个匹配值中断里,从Gap切换回码元的时机为Gap中的匹配值中断。只有在这样的时机切换配置才能保证输出信号每个周期的电平都是完整,不多不少的。