上下位机通信
上下位机使用使用Modbus协议进行通信。在Qt开发中,可以采用第三方库libmodbus完成
目录
modbus协议介绍
简介
- modbus是一种免费的应用层协议,采用请求响应模式进行设备间的通信,由主机请求从机。
- 应用Modbus协议进行通信的程序调试可以使用几个重要工具:
- Modbus Poll
- Modbus Slave
- VSPD:虚拟串口工具
- 串口调试助手
- 网络调试助手
Modbus中的存储区
- 线圈状态(输出线圈)(coil status):存储开关量,值为0或者1。值可读可写
- 输入状态(输入线圈)(input status):存储开关量,值为0或者1。值只读不可写
- 保持寄存器(输出寄存器)(Holding Register):存储一个字,值可读可写。
- 输入寄存器(Input Registers):存储一个字,值可读不可写
地址模型
- 长地址模型:六位地址模型。这种地址模型中,每个存储区能存储65536个线圈或者寄存器
- 输出线圈:地址从000001~065536
- 输入线圈:地址从100001~165536
- 输入寄存器:地址从300001~365536
- 输出寄存器:地址从400001~465536
- 短地址模型:五位地址模型
- 输出线圈:地址范围从00001~09999
- 输入线圈:地址从10001~19999
- 输入寄存器:地址从30001~39999
- 输出寄存器:地址从40001~49999
Modbus协议分类
- ModbusRTU通信协议
- ModbusRTUOverTCP通信协议
- ModbusRTUOverUDP通信协议
- ModbusASCII通信协议
- ModbusASCIIOverTCP通信协议
- ModbusASCIIOverUDP通信协议
- ModbusTCP通信协议
- ModbusUDP通信协议
功能码及异常码
- 功能码:告知从机设备需要执行的动作。这些功能码表征了Modbus协议具有的功能
- 读操作:
- 0x01:读线圈状态(输出线圈)。
- 0x02:读输入状态(输入线圈)。
- 0x03:读保持寄存器的值(输出寄存器)。
- 0x04:读输入寄存器的值(输入寄存器)。
- 写操作:
- 0x05:写单个线圈状态(输出线圈)。
- 0x06:写单个保持寄存器的值。
- 0x0F:写多个线圈状态。
- 0x10:写多个保持寄存器的值。
- 读操作:
- 异常码:将对应功能码的最高位置为1,比如说0x01的异常码为0x81
Modbus通信协议
Modbus RTU通信协议
对于Modbus RTU通信协议,通用的发送报文格式为:从站地址(1个字节) + 功能码(1个字节) + 数据部分 + 校验码(两个字节)。数据部分,如果是读取,则数据部分为要读取的起始地址(2字节)和读取的长度(2字节);如果是写入,则数据部分为写入的地址(2字节)和数据(N个字节)
- 功能码01读取输出线圈:
- 发送报文为
从站地址+功能码01+起始线圈地址+线圈数量+CRC校验码 - 接收报文为
从站地址+功能码01+字节计数+具体数据+CRC校验码
- 发送报文为
- 功能码02读取输入线圈:
- 发送报文格式为
从站地址+功能码02+起始线圈地址+线圈数量+CRC校验码 - 接受报文格式为
从站地址+功能码02+字节计数+具体数据+CRC校验码
- 发送报文格式为
- 功能码03读取输出寄存器:
- 发送报文格式为:
从站地址+功能码03+起始寄存器地址+寄存器数量+CRC校验码 - 接受报文格式为:
从站地址+功能码03+字节计数+具体数据+CRC校验码
- 发送报文格式为:
- 功能码04读取输入寄存器:
- 发送报文格式为:
从站地址+功能码04+起始寄存器地址+寄存器数量+CRC校验码 - 接受报文格式为:
从站地址+功能码04+字节计数+具体数据+CRC校验码
- 发送报文格式为:
- 功能码05写入单个输出线圈:成功时,发送报文和接收报文一致
- 发送报文格式为:
从站地址+功能码05+线圈地址+写入的值+CRC校验码,对于写入1时写入的值为FF00,对于写入0时写入的值为0000 - 接受报文格式为:
从站地址+功能码05+线圈地址+写入的值+CRC校验码
- 发送报文格式为:
- 功能码06写入单个输出寄存器:
- 发送报文格式为:
从站地址+功能码06+寄存器地址+写入的值+CRC校验码 - 接受报文格式为:
从站地址+功能码06+寄存器地址+写入的值+CRC校验码
- 发送报文格式为:
- 功能码0F写入多个输出线圈:
- 发送报文格式为:
从站地址+功能码0F+起始线圈地址+线圈数量+字节计数+ 具体写入的值+CRC校验码 - 接受报文格式为:
从站地址+功能码0F+起始线圈地址+线圈数量+CRC校验码
- 发送报文格式为:
- 功能码10写入多个输出寄存器:
- 发送报文格式为:
从站地址+功能码10+起始寄存器地址+寄存器数量+字节计数+ 具体写入的值+CRC校验码 - 接受报文格式为:
从站地址+功能码10+起始寄存器地址+寄存器数量+CRC校验码
- 发送报文格式为:
Modbus ASCII
Modbus TCP协议报文格式
上下位机Modbus通信
1.第三方库libmodbus的基本使用
环境 Windows,visual studio 2019,Qt5.15.2,libmodbus3.1.11
- 双击运行源码src\win32目录下的configure.js的文件,用于生成相应操作系统的配置。如果报错
输入错误: 没有文件扩展“.js”的脚本引擎。则进行注册表的修改- win + r =》regedit,进入注册表
- 查找
HKEY_CLASSES_ROOT\.js,将默认值修改为JSFile
- 将八个头文件放置 include目录下。删除项目目录下的modbus-version.h文件,然后重新添加src/modbus-version.h头文件
- 使用 VS 打开解决方案文件modbus-9.sln,根据需要编译x64还是x86平台的。如果选择x64位的,需要在项目属性页中选择链接器=》输入=》附加依赖项,输入ws2_32.lib
- 将 配置类型更改为动态库
- 重新生成解决方案,编译生成modbus.dll和modbus.lib
- 将lib和dll也分别放置项目目录下
- CMAKE配置如下所示:
cmake_minimum_required(VERSION 3.20)
project(TEST VERSION 1.0 LANGUAGES CXX)
find_package(QT NAMES Qt5 REQUIRED COMPONENTS Core Gui Widgets PrintSupport )
find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core Gui Widgets PrintSupport)
# 设置源文件编码为UTF-8
if(MSVC)
add_compile_options(/utf-8)
endif()
# 自动处理Qt的moc、uic、rcc
set(CMAKE_AUTOMOC ON)
set(CMAKE_AUTORCC ON)
set(CMAKE_AUTOUIC ON)
message(STATUS "CMAKE_CURRENT_BINARY_DIR: ${CMAKE_CURRENT_BINARY_DIR}")
# 设置C++标准
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
file(GLOB copyResources
"${CMAKE_SOURCE_DIR}/LICENSE"
"${CMAKE_SOURCE_DIR}/assets/x64/release/modbus.dll"
)
file(COPY ${copyResources} DESTINATION ${CMAKE_BINARY_DIR})
# 源文件列表
file(GLOB PROJECT_SOURCES
"${CMAKE_SOURCE_DIR}/src/*.cpp"
)
message("PROJECT_SOURCES:${PROJECT_SOURCES}")
# 设置 UI 文件搜索路径
set(CMAKE_AUTOUIC_SEARCH_PATHS
"${CMAKE_SOURCE_DIR}/ui"
)
# UI文件
file(GLOB UI_FILES
"${CMAKE_SOURCE_DIR}/ui/*.ui"
)
# 资源文件
file(GLOB RESOURCE_FILES
"${CMAKE_SOURCE_DIR}/res/*.qrc"
)
# 创建可执行文件
file(GLOB HEADERS
"${CMAKE_SOURCE_DIR}/include/*.h"
)
IF(CMAKE_BUILD_TYPE STREQUAL "Debug")
# Debug模式显示用于调试的控制台
ADD_EXECUTABLE(${PROJECT_NAME}
${HEADERS} #MOC处理使用了Qt元系统的头文件
${PROJECT_SOURCES}
${UI_FILES}
${RESOURCE_FILES})
ELSE()
# Release模式不显示控制台
ADD_EXECUTABLE(${PROJECT_NAME} WIN32
${HEADERS} #MOC处理使用了Qt元系统的头文件
${PROJECT_SOURCES}
${UI_FILES}
${RESOURCE_FILES})
ENDIF()
# 设置 MOC选项和生成路径
set_target_properties(${PROJECT_NAME} PROPERTIES
AUTOMOC_MOC_OPTIONS "-I${CMAKE_CURRENT_SOURCE_DIR}/include"
AUTOGEN_BUILD_DIR "${CMAKE_CURRENT_BINARY_DIR}/autogen"
)
# 包含目录
target_include_directories(${PROJECT_NAME} PRIVATE
"${CMAKE_SOURCE_DIR}/include"
"${CMAKE_SOURCE_DIR}/third_party/libmodbus/include"
${CMAKE_CURRENT_BINARY_DIR}/autogen/include #生成的ui_xxx文件的头文件目录
)
# 链接Qt库
target_link_libraries(${PROJECT_NAME} PRIVATE
Qt${QT_VERSION_MAJOR}::Core
Qt${QT_VERSION_MAJOR}::Gui
Qt${QT_VERSION_MAJOR}::Widgets
Qt${QT_VERSION_MAJOR}::PrintSupport
"${CMAKE_SOURCE_DIR}/third_party/libmodbus/lib/x64/release/modbus.lib"
)
# 开启 MOC 调试输出
set(CMAKE_AUTOMOC_VERBOSE ON)
- 简单测试如下:
void modbus_rtu_test() {
char* pcom = "COM5"; //COM口
int serverAddress = 1; //站号
modbus_t * mb = modbus_new_rtu(pcom, 115200, 'N', 8, 1);
modbus_set_slave(mb, serverAddress);
if (modbus_connect(mb) != 0) {
qDebug() << "connect error!";
}
}
void modbus_tcp_test() {
int serverAddress = 1; //站号
modbus_t* mb = modbus_new_tcp("127.0.0.1", 502);
modbus_set_slave(mb, serverAddress);
if (modbus_connect(mb) != 0) {
qDebug() << "connect error!";
}
}
2.使用Qt中的SerialBus模块
这是Qt官方提供的模块。参考
浙公网安备 33010602011771号