1.实验目的
- 熟悉Keil4开发环境的使用
- 了解学习LoRa通信原理
- 熟练掌握STM32芯片控制LoRa通信过程
2.实验内容
本次实验共使用2个LoRa 节点,一个作为 Master(主机),一个作为 Slave(从机),自主设计的实验流程如下:
第一步:上位机发送数据“你好 666”给 Master,Master 串口 2 接收到数
据“你好 666”以后通过 LoRa 无线发送给 Slave;
第二步:Slave 通过无线方式接收到数据“你好 666”以后,再通过 LoRa 无线把数据“你好 666”原封发送给Master;
第三步:Master 通过 LoRa 无线接收到数据“你好 666”以后,通过串口 2
把数据“你好 666”发送给上位机;
以此实现 Master 与 Slave 之间的通信(数据收发)。
3.实验设备
硬件:LoRa节点2个、电脑、J-LINK、串口线等;
软件:Keil4 开发环境、串口通信小工具;
芯片手册:配套光盘\附件\芯片资料\LoRa 芯片资料;
源码路径:配套光盘\源代码\LoRa 通讯课程实验\实验 1 LoRa 通讯实验-V20180604;
4.实验原理
LoRa是美国Semtech(升特)公司开发及推广的一种基于扩频技术超远距离无线传输方案,它主要为用户提供一种简单的能实现远距离、长电池寿命、大容量系统、可扩展的传感网络,目前LoRa主要在全球免费频道运行,如433、868、915MHz频道运行。
为了更好推广LoRa技术,由 Semtech公司组织成立的LoRa联盟在2015 年3月成立,成员主要有法国Acility、中国AUGTEK、荷兰皇家电信kpn、IBM、思科、法国Orange等厂家。本实验用到的LoRa芯片是SX1278射频芯片,用于超长距离扩频通讯,抗干扰强,能够最大限度降低电流消耗,具有-148dBm的高灵敏度,+20dBm的功率输出。传输距离在板载天线情况下,室内约50米,空旷室外约200米;在外置IPEX棒状天线情况下,室内约100米,有建筑物室外约2000米,如果是空旷室外情况下,传输距离甚至可到5000米。
5.实验步骤
5.1主从机间LoRa通信
预先配置:打开串口通信小工具确定连接的是哪个COM端口,不确定可以打开设备管理器进行查看;本次实验需要使用2个LoRa节点,一个作为 Master(主机),一个作Slave(从机)。
第一步:打开源代码\LoRa通讯课程实验\实验1 LoRa通讯实验 -V20180604\LoRa_STM32_Master\RVMDK目录下的LoRa_STM32_Master.uvproj工程。
第二步:对工程代码进行编译,使用J-LINK连接电脑与Master节点(任一 LoRa节点),点击把工程代码下载到Master节点。
第三步:打开源代码\LoRa 通讯课程实验\实验 1 LoRa 通讯实验-V20180604\LoRa_STM32_Slave\RVMDK 目录下的 LoRa_STM32_Slave.uvproj 工程。与此同时,点击对工程代码进行编译,把 J-LINK 连接好电脑与 Slave 节点(任一 LoRa 节点),点击把工程代码下载到 Slave 节点。
第四步:用串口线连接电脑与Master节点,并把 Master 节点的三档开关拨到最左边(STM32 的串口2与RS232接口连接)。
第五步:打开串口助手,串口号为COM5,串口参数:9600-8-N-1,不选16 进制收发。
第六步:在串口通信助手上,发送“你好 666”后观察返回的相关信息内容,如下:、
问题分析:观察发现发送“你好666”后,接收的信息并不是我们想要的?这是为什么呢?
思考后,我们知道LoRa是无线射频芯片,我们在实验室中有很多同学同时在做该实验,因此就会导致同频率的信息参杂在一起,我们会接收到其他同学发出的信号。
解决方法:修改配置代码中的发射频率,保证不受其他无线信号的干扰。
修改后发现接收信号变得稳定了很多。
5.2 Python 代码实现通信过程监控
具体代码如下:
1. import serial#导入串口通讯库
2. import binascii#导入 16 进制数据操作库
3. import chardet#导入字符编码检测库
4. from tkinter import *#从 tkinter 库中导入全部模块
5. import time#导入时间操作库
6. try:#尝试连接串口
7. portx = "COM5"#选择串口
8. bps=9600#选择波特率
9. timex=None#无超时时间
10. ser = serial.Serial(portx, bps, timeout=timex)#创建串口对象
11.except Exception as e:#如果没有这个串口或选错了串口弹出异常
12. print(e)
13.def main():#主函数
14. def refresh():#刷新函数
15. print("!!!!")
16. count = ser.inWaiting()#获取串口输入缓冲区字节数
17. data = ser.read(count)#从串口读取数据
18. if data != b'':#如果数据不为空
19. chartype = chardet.detect(data)['encoding']#探测字符编
码
20. if chartype:
21. msg = data.decode(chartype)#解码串口接收到的数
据
22. strMsg = time.strftime("%Y-%m-%d%H:%M:%S",time.loc
altime())+ '\n'#显示时间
23. txtMsgList.insert(END, strMsg, 'greencolor')#在
text 控件插入时间和数据
24. txtMsgList.insert(END, msg+"\n")
25. txtMsgList.update()
26. app.after(500, refresh)#每 500 毫秒调用刷新函数
27. def sendMsg():#发送数据函数
28. print(txtMsg.get('0.0', END))#打印要发送的数据
29. strMsg = time.strftime("%Y-%m-%d %H:%M:%S",time.localtime(
))+ '\n'#显示时间
30. txtMsgList.insert(END, strMsg, 'greencolor')#在 text 控件插
入时间和数据
31. txtMsgList.insert(END, txtMsg.get('0.0', END))
32. txtMsgList.update()
33. txtMsg.delete('0.0', END)#清空 text 控件
34. txtMsg.update()
35. def cancelMsg():#取消发送函数
36. txtMsg.delete('0.0', END)#清空 text 控件
37. def sendMsgEvent(event):#通过回车键发送数据
38. if event.keysym =='Up':
39. sendMsg()
40. app = Tk()#创建窗口
41. app.title('Lora 收发')#设置窗口标题
42. frmLT = Frame(width = 500, height = 320, bg = 'white')#定义绘制
区域
43. frmLC = Frame(width = 500, height = 150, bg = 'white')
44. frmLB = Frame(width = 500, height = 30)
45. frmRT = Frame(width = 200, height = 500)
46. txtMsgList = Text(frmLT)#在 frmLT 区域创建一个文本框
47. txtMsgList.tag_config('greencolor',foreground = '#008C00')#设
置文本框中 greencolor 这个 tag 的前景色为绿色
48. txtMsg = Text(frmLC)#在 frmLC 区域创建一个文本框
49. txtMsg.bind("<KeyPress-Up>", sendMsgEvent)#绑定 Up 这个按键的按下
事件为 sendMsgEvent 函数
50. btnSend = Button(frmLB, text = 'SEND', width = 8, command = se
ndMsg)#创建发送按钮
51. btnCancel =Button(frmLB, text = 'CANCEL', width = 8, command =
cancelMsg)#创建取消按钮
52. lblImage = Label(frmRT)#在 frmRT 区域创建一个 Label 用于显示图片
53. frmLT.grid(row = 0, column = 0, columnspan = 2, padx = 1, pady
= 3)#放置 frmLT 区域
54. frmLC.grid(row = 1, column = 0, columnspan = 2, padx = 1, pady
= 3)#放置 frmLC 区域
55. frmLB.grid(row = 2, column = 0, columnspan = 2)#放置 frmLB 区域
56. frmRT.grid(row = 0, column = 2, rowspan = 3, padx =2, pady = 3
)#放置 frmRT 区域
57. frmLT.grid_propagate(0)#锁定 frmLT 区域大小
58. frmLC.grid_propagate(0)#锁定 frmLC 区域大小
59. frmLB.grid_propagate(0)#锁定 frmLB 区域大小
60. frmRT.grid_propagate(0)#锁定 frmRT 区域大小
61. btnSend.grid(row = 2, column = 0)#放置发送按钮
62. btnCancel.grid(row = 2, column = 1)#放置取消按钮
63. lblImage.grid()#放置图片 label
64. txtMsgList.grid()#放置 txtMsgList 文本框
65. txtMsg.grid()#放置 txtMsg 文本框
66. app.after(500, refresh)#500 毫秒后调用 refresh 函数
67. app.mainloop()#进入消息循环
68.if __name__ == "__main__":
69. main()#如果是主程序运行 main 函数
6.实验心得
略