环境:ubuntu18.04 python3.6
1. 绑定串口号与串口设备
背景:一台主机与多个串口模块连接,每次开机会使得设备的串口号发生变化,需要对串口号与串口设备进行绑定。
(1)查看串口设备号
拔插串口设备,终端lsusb
找出需要命名的设备号,形式如下:
Bus 003 Device 006: ID 067b:2303 Prolific Technology, Inc. PL2303 Serial Port
记录设备号 067b:2303
,自定义绑定规则:
(2) cd /etc/udev/rules.d
(3) 创建自定义规则文件 sudo gedit usb.rules
(4)输入如下命令绑定串口号,其中idVendor和idProduct为(1)记录的设备号,SYMLINK”为自定义的设备名字。
KERNEL=="ttyUSB*", ATTRS{idVendor}=="067b", ATTRS{idProduct}=="2303", MODE:="0777", SYMLINK+="imu"
(5)使规则生效:
sudo udevadm control –reload-rules
sudo service udev restart
sudo udevadm trigger
(6)使用 /dev/imu
读取设备即可。
2. modbus_tk 读取设备
2.1 安装modbus_tk
pip install pymodbus_tk
2.2 读取串口demo
# -*- coding: utf_8 -*-
# 2021-08-11 添加自动扫描COM口的程序 @1
import serial.tools.list_ports #@1 获取COM口列表库
import serial
import modbus_tk
import modbus_tk.defines as cst
from modbus_tk import modbus_rtu
import time #添加定时器
from time import *
import numpy as np
Baudrate = [9600,115200,19200,38400,57600]
# @1 start 获取现有COM口程序
ports = serial.tools.list_ports.comports()
for p in ports:
print(p.device)
print(len(ports), 'ports found')
#time.sleep(1) #延时1s(可以不延时,方便看输出)
# @1 end
def mod(BAUDRATE,SlaveID):
red = []
alarm = ""
try:
# 设定串口为从站
# p.device 为读取的串口设备名,默认为ttyUSB*,可以替换为自定义设备名,如/dev/imu
# baudarate 为波特率
master = modbus_rtu.RtuMaster(serial.Serial(port=p.device,
baudrate=BAUDRATE, bytesize=8, parity='N', stopbits=1))
master.set_timeout(0.05) #50ms
master.set_verbose(True)
# 读保持寄存器
# SlaveID为站台号,0为地址,2为读取长度,可查看设备文档获取地址信息与含义
# cst.READ_HOLDING_REGISTERS 为读取保持寄存器,2.3有其他的功能码说明
red = master.execute(SlaveID, cst.READ_HOLDING_REGISTERS, 0, 2) # 这里可以修改需要读取的功能码
print(red)
alarm = "正常"
# return list(red), alarm
return alarm
except Exception as exc:
#print(str(exc))
alarm = (str(exc))
return red, alarm ##如果异常就返回[],故障信息
if __name__ == "__main__":
print("开始扫描当前设备站号和波特率,全部扫描结束时间为90S左右")
print("雷达站号范围:1-100,波特率:9600、19200、38400、57600、115200")
print("----------------------------------------")
begin_time = time()
for x in range(5):
for y in range(1,100):
z = mod(Baudrate[x],y)
if z == '正常':
print("当前波特率:",Baudrate[x],"当前站号:",y)
end_time = time()
run_time = end_time - begin_time
print("查询运行时间:",run_time)
2.3 功能码
参考链接
READ_COILS H01 读线圈
READ_DISCRETE_INPUTS H02 读离散输入
READ_HOLDING_REGISTERS H03 读寄存器
READ_INPUT_REGISTERS H04 读输入寄存器
WRITE_SINGLE_COIL H05 写单一线圈
WRITE_SINGLE_REGISTER H06 写单一寄存器
WRITE_MULTIPLE_COILS H15 写多个线圈
WRITE_MULTIPLE_REGISTERS H16 写多寄存器
#读保持寄存器 03H 1站号 0地址 长度2
logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 2))
#01 03 00 00 00 02 C4 0B
# 读输入寄存器 04H
logger.info(master.execute(1, cst.READ_INPUT_REGISTERS, 0, 8))
#反馈:01 04 00 00 00 08 F1 CC
# 读线圈寄存器 01H
logger.info(master.execute(1, cst.READ_COILS, 0, 6))
#反馈:01 01 00 00 00 06 BC 08
#读离散输入寄存器 02H
logger.info(master.execute(1, cst.READ_DISCRETE_INPUTS, 0, 16))
#反馈:01 02 00 00 00 10 79 C6
# 单个读写寄存器操作 06H
# 写寄存器地址为0的保持寄存器 06H
logger.info(master.execute(1, cst.WRITE_SINGLE_REGISTER, 0, output_value=6))
#反馈:01 06 00 00 00 06 09 C8
logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 1))
#反馈:01 03 00 00 00 01 84 0A
# 写寄存器地址为0的线圈寄存器,写入内容为0(位操作) 05H
logger.info(master.execute(1, cst.WRITE_SINGLE_COIL, 0, output_value=0))
#反馈:01 05 00 00 00 00 CD CA
logger.info(master.execute(1, cst.READ_COILS, 0, 1))
#反馈:01 01 00 00 00 01 FD CA
# 多个寄存器读写操作 10H
# 写寄存器起始地址为0的保持寄存器,操作寄存器个数为4
logger.info(master.execute(1, cst.WRITE_MULTIPLE_REGISTERS, 11, output_value=[20,21,22,23]))
#反馈:01 10 00 0B 00 04 08 00 14 00 15 00 16 00 17 AB A9
logger.info(master.execute(1, cst.READ_HOLDING_REGISTERS, 0, 4))
#反馈:01 03 00 00 00 04 44 09