行空板如何获取RS485设备数据 - RS485风速变送器
1-介绍:RS-485协议
RS-485协议,是一种串行通信协议,用于在多个设备之间进行数据传输。它是一种差分信号通信协议,可以实现长距离、高速、可靠的数据传输。
RS-485协议使用两根传输线(A线和B线)进行数据传输,其中一个设备充当主设备,其他设备充当从设备。主设备负责控制通信的开始和结束,以及数据的传输速率。从设备只有在主设备允许的情况下才能发送数据。
RS-485协议具有以下特点:
-
高速传输:RS-485协议支持较高的数据传输速率,可以达到几十兆比特每秒的速度。
-
远距离传输:由于差分信号的使用,RS-485协议可以在较长的距离上进行数据传输,通常可覆盖数千米的距离。
-
抗干扰能力强:RS-485协议采用差分信号传输,可以有效地抵抗电磁干扰和噪声,提供可靠的数据传输。
-
多设备通信:RS-485协议支持多个设备之间的通信,主设备可以与多个从设备进行双向通信。
详细wiki介绍:SEN0483 RS485风速变送器 (dfrobot.com.cn)
从wiki中可以得到这个传感器的一些关键信息:
2.1-线色说明
颜色 |
功能 |
红色 |
电源正 |
黑色 |
电源负 |
黄色 |
RS485+/A/T+ |
绿色 |
RS485-/B/T- |
2.2-通讯协议:
- 主机(在这里是行空板)通过串口(使用串口转rs485模块)与从机(这里是风速传感器)通信,波特率为 9600 bps。
通讯方式很简单:主机按照协议发一串查询数据给从机,从机接受到查询指令后将风速数据返回给主机,然后主机接受到数据解析就可以得到风速值了。
读寄存器0x0000,即风速的测量值
- 主机查询帧(16进制):02 03 00 00 00 01 84 39(8byt)
从机地址 |
功能码 |
寄存器起始地址 |
寄存器长度 |
校验码高位 |
校验码低位 |
1byt |
1byt |
2byt |
2byt |
1byt |
1byt |
0x02 |
0x03 |
0x00 0x00 |
0x00 0x01 |
0x84 |
0x39 |
- 从机应答帧(16进制):02 03 02 00 25 3D 9F(7byt)
从机地址 |
功能码 |
有效字节数 |
数据区 |
校验码高位 |
校验码低位 |
1byt |
1byt |
1byt |
2byt |
1byt |
1byt |
0x02 |
0x03 |
0x02 |
0x00 0x25 |
0x3D |
0x9F |
风速值为(16进制,原码)00 25 = 0x0025 = 37,那么风速测量值为37 / 10 = 3.7m/s
因此,要获取风速测量值,主机需要通过串口发送查询帧,并解析从机应答帧中的数据。
3-行空板串口通讯:
在行空板上有两种方法可以引出串口:
前面介绍了RS485风速变送器的通讯协议,接下来将两种方法的使用步骤进行介绍。
3.1-使用USB串口通讯
3.1.1-USB转485模块和行空板接线图
3.1.2-接线说明
根据接线说明,把RS485风速变送器其中的黄色和绿色分别接到USB转485模块A/B,需要注意电压问题:
- RS485风速变送器供电电压:7-24V
- USB转485模块供电电压:5V
因此需要额外外接电源,测试中我使用的使用12V电源。
3.1.3-编程
全部接好以后,就直接插上行空板USB,进行编程.
示例代码:
import serial
import time
#使用的是USB转串口,因此不需要使用pinpong库
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.5) #USB转RS485模块的串口编号
while True:
query_frame = [0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x39] # 查询帧
ser.write(query_frame)
time.sleep(1)
try:
response_frame = ser.read(7) # 读取从机应答帧,根据应答帧格式修改字节数
byte4 = response_frame[3] # 获取第4位数据
byte5 = response_frame[4] # 获取第5位数据
value = ((byte4 << 8) + byte5) / 10 #根据风速传感器说明计算风速值
print("风速值:", value)
time.sleep(0.1)
except:
print("无数据")
测试结果:
3.1.4-数据校验
上面的案例中,我们直接读取了第4和5位获取风速值,实际上在通讯中可能会存在数据丢失一部分的情况,因此从机返回的数据里面还有校验码,通过将接收到的数据做计算与校验码比对,可以确保接收到的数据是正确的。
import serial
import time
ser = serial.Serial('/dev/ttyUSB0', 9600, timeout=0.5)
def calculate_checksum(data):
checksum = 0xFFFF # 初始校验码值
for byte in data:
checksum ^= byte # 异或操作
for _ in range(8):
if checksum & 0x0001: # 最低位为1
checksum >>= 1 # 右移一位
checksum ^= 0xA001 # 异或操作
else:
checksum >>= 1 # 右移一位
return checksum.to_bytes(2, byteorder='little') # 返回校验码的字节表示,小端序
def validate_response_frame(frame):
if len(frame) < 5:
return False
received_checksum = frame[-2:] # 从应答帧中提取接收到的校验码
expected_checksum = calculate_checksum(frame[:-2]) # 计算期望的校验码
return received_checksum == expected_checksum
while True:
query_frame = [0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x39] # 查询帧
ser.write(query_frame) # 发送查询帧
time.sleep(0.1)
try:
response_frame = ser.read(7) # 读取从机应答帧
if validate_response_frame(response_frame):
byte4 = response_frame[3] # 获取第4位数据
byte5 = response_frame[4] # 获取第5位数据
value = (( byte4<< 8) + byte5) / 10
print("风速值:", value)
else:
print("应答帧校验失败")
time.sleep(0.1)
except:
print("无数据")
测试结果:
3.2-使用金手指上的UART引脚通讯
3.2.1-RS485转UART和行空板接线图
3.2.2-接线说明
3.2.3-编程
示例代码:
# -*- coding: utf-8 -*-
import time
from pinpong.board import Board, UART
#使用的是行空板金手指上的UART口,因此使用pinpong库
Board().begin() #初始化,选择板型,不输入板型则进行自动识别
#硬串口1 P0-RX P3-TX
uart1 = UART(0)
uart1.init() #默认波特率为9600
while True:
query_frame = [0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x39] # 查询帧
uart1.write(query_frame)
time.sleep(1)
try:
response_frame = uart1.read(7) # 读取从机应答帧,根据应答帧格式修改字节数
byte4 = response_frame[3] # 获取第4位数据
byte5 = response_frame[4] # 获取第5位数据
value = ((byte4 << 8) + byte5) / 10
print("风速值:", value)
time.sleep(0.1)
except:
print("无数据")
测试结果:
3.2.4-数据校验
通过校验码,来确定数据的准确性,示例代码:
import time
from pinpong.board import Board, UART
Board().begin() # 初始化,选择板型,不输入板型则进行自动识别
# 硬串口1 P0-RX P3-TX
uart1 = UART(0)
uart1.init() # 默认波特率为9600
def calculate_checksum(data):
checksum = 0xFFFF # 初始校验码值
for byte in data:
checksum ^= byte # 异或操作
for _ in range(8):
if checksum & 0x0001: # 最低位为1
checksum >>= 1 # 右移一位
checksum ^= 0xA001 # 异或操作
else:
checksum >>= 1 # 右移一位
return checksum.to_bytes(2, byteorder='little') # 返回校验码的字节表示,小端序
def validate_response_frame(frame):
if len(frame) < 5:
return False
received_checksum = frame[-2:] # 从应答帧中提取接收到的校验码
expected_checksum = calculate_checksum(frame[:-2]) # 计算期望的校验码
return received_checksum == expected_checksum
while True:
query_frame = [0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x39] # 查询帧
uart1.write(query_frame) # 发送查询帧
time.sleep(0.1)
try:
response_frame = uart1.read(7) # 读取从机应答帧
if validate_response_frame(bytes(response_frame)): # 与USB通讯不一样的,需要转化成字节串
byte4 = response_frame[3] # 获取第4位数据
byte5 = response_frame[4] # 获取第5位数据
value = (( byte4<< 8) + byte5) / 10
print("风速值:", value)
else:
print("应答帧校验失败")
time.sleep(0.1)
except:
print("无数据")
测试结果:
4-常见问题:
如何查看usb转rs485模块的串口号
在行空板终端使用如何命令可以查看所有的串口编号,通过把USB转485插上查询一次,拔掉查询一次,多出来的串口就是这个模块的串口号。
ls /dev/tty*
有的USB转rs485模块使用的驱动在行空板上没有,例如PL2303驱动,则通过上述方法无法查询到串口,这里提供一下PL2303驱动的安装方法,如果找到串口了可忽略下文:
把附件PL2303G_Unihiker_Driver.zip放进行空板根目录后,输入下面命令:
unzip PL2303G_Unihiker_Driver.zip
cd PL2303G_Unihiker_Driver
chmod 777 install.sh
bash install.sh
输入最后一条指令会出现以下:
再次查询
ls /dev/tty*
出现下图,说明安装成功