在Modbus RTU中同时进行读取和写入操作

简介: 在Modbus RTU中同时进行读取和写入操作
#include "ModbusRTU.h"
#include <iostream>
#include <cstring> // For memcpy

ModbusRTU::ModbusRTU(boost::asio::io_service& io_service, const std::string& port_name)
    : serial(io_service, port_name) {
    serial.set_option(boost::asio::serial_port_base::baud_rate(9600));
    serial.set_option(boost::asio::serial_port_base::character_size(8));
    serial.set_option(boost::asio::serial_port_base::parity(boost::asio::serial_port_base::parity::none));
    serial.set_option(boost::asio::serial_port_base::stop_bits(boost::asio::serial_port_base::stop_bits::one));
}

template<typename T>
void ModbusRTU::writeData(uint8_t slave_id, uint8_t function_code, uint16_t start_address, T value) {
    uint8_t frame[8 + sizeof(T)];
    frame[0] = slave_id;
    frame[1] = function_code;
    frame[2] = (start_address >> 8) & 0xFF;
    frame[3] = start_address & 0xFF;

    std::memcpy(&frame[4], &value, sizeof(T));

    uint16_t crc = calculateCRC(frame, 4 + sizeof(T));
    frame[4 + sizeof(T)] = crc & 0xFF;
    frame[5 + sizeof(T)] = (crc >> 8) & 0xFF;

    boost::asio::write(serial, boost::asio::buffer(frame, 6 + sizeof(T)));
}

template<typename T>
T ModbusRTU::readData(uint8_t slave_id, uint8_t function_code, uint16_t start_address, uint16_t num_registers) {
    uint8_t frame[8];
    frame[0] = slave_id;
    frame[1] = function_code;
    frame[2] = (start_address >> 8) & 0xFF;
    frame[3] = start_address & 0xFF;
    frame[4] = (num_registers >> 8) & 0xFF;
    frame[5] = num_registers & 0xFF;
    uint16_t crc = calculateCRC(frame, 6);
    frame[6] = crc & 0xFF;
    frame[7] = (crc >> 8) & 0xFF;

    boost::asio::write(serial, boost::asio::buffer(frame, 8));

    uint8_t response[256];
    size_t length = serial.read_some(boost::asio::buffer(response, 256));
    if (length > 0 && response[1] == function_code) {
        T result = 0;
        for (size_t i = 0; i < sizeof(T); ++i) {
            reinterpret_cast<uint8_t*>(&result)[i] = response[3 + i];
        }
        return result;
    }
    else {
        std::cerr << "错误:无效的响应或没有收到响应。" << std::endl;
    }
    return T(); // 返回类型 T 的默认值
}

uint16_t ModbusRTU::calculateCRC(const uint8_t* data, size_t length) {
    uint16_t crc = 0xFFFF;
    for (size_t i = 0; i < length; ++i) {
        crc ^= data[i];
        for (int j = 0; j < 8; ++j) {
            if (crc & 1) crc = (crc >> 1) ^ 0xA001;
            else crc >>= 1;
        }
    }
    return crc;
}



void main() {
    try {
        boost::asio::io_service io_service;
        ModbusRTU modbus(io_service, "/dev/ttyS0"); // 根据你的实际串口设备调整

        uint8_t slave_id = 1;  // 从站地址
        uint16_t start_address = 0x0001; // 起始寄存器地址
        uint16_t value_to_write = 12345;  // 要写入的值

        // 写入数据
        modbus.writeData<uint16_t>(slave_id, 0x06, start_address, value_to_write); // 0x06 是写单寄存器的功能码

        std::cout << "数据已写入。" << std::endl;

        // 读取数据
        uint16_t read_value = modbus.readData<uint16_t>(slave_id, 0x03, start_address, 1); // 0x03 是读保持寄存器的功能码

        std::cout << "读取的数据: " << read_value << std::endl;

    }
    catch (const std::exception& e) {
        std::cerr << "异常: " << e.what() << std::endl;
        return 1;
    }

    return 0;
}
目录
相关文章
|
存储 开发框架 算法
【串口通信】使用C++和Qt设计和实现串口协议解析器(一)
【串口通信】使用C++和Qt设计和实现串口协议解析器
4488 0
|
传感器 算法 数据格式
QT Modbus RTU调试助手(包含算法实现CRC MODBUS16校验)
QT Modbus RTU调试助手(包含算法实现CRC MODBUS16校验)
1835 0
|
5月前
|
人工智能 Cloud Native 前端开发
2026 研发效能测评:Coding Agent 究竟哪个最成熟?(附深度纵评)
2026年,AI 编程已全面从单行补全跨入自主规划的 Coding Agent 时代。面对错综复杂的企业级微服务与重构诉求,究竟哪个产品最成熟?本文打破公有云“盲盒生成”的迷思,深度横评当前主流 Agent 矩阵,为你揭秘真正能工业级落地的效能中台。
987 0
|
安全 Windows
Win10弹出WerFault.exe应用程序错误是什么原因,(0xc0000142)问题?
Win10弹出WerFault.exe应用程序错误是什么原因,(0xc0000142)问题?
2740 0
|
Linux
CentOS U盘挂载指南
在 CentOS 中挂载 U 盘的步骤如下:1. 使用 `sudo fdisk -l` 或 `lsblk` 检测 U 盘设备(如 `/dev/sdb1`)。2. 创建挂载点 `sudo mkdir /mnt/usb`。3. 根据格式挂载 U 盘,如 FAT32 使用 `sudo mount -t vfat /dev/sdb1 /mnt/usb -o rw,uid=1000,gid=1000`。4. 访问数据 `cd /mnt/usb && ls -l`。5. 卸载 `sudo umount /mnt/usb`。常见问题包括权限和中文乱码,可添加相应参数解决。
1480 2
(5)Qt中的日期和时间
本文介绍了Qt中处理日期和时间的类QDate、QTime和QDateTime,包括它们的格式化选项、构造函数、公共成员函数以及如何进行日期和时间的增减、比较,同时提到了QElapsedTimer作为QTime的替代品用于计时。
1600 0
|
存储 关系型数据库 MySQL
深入解析MySQL数据存储机制:从表结构到物理存储
深入解析MySQL数据存储机制:从表结构到物理存储
1986 1
|
机器学习/深度学习 算法 TensorFlow
深度学习笔记(五):学习率过大过小对于网络训练有何影响以及如何解决
学习率是深度学习中的关键超参数,它影响模型的训练进度和收敛性,过大或过小的学习率都会对网络训练产生负面影响,需要通过适当的设置和调整策略来优化。
3215 0
深度学习笔记(五):学习率过大过小对于网络训练有何影响以及如何解决
|
存储 关系型数据库 MySQL
数据管理的艺术:PolarDB开源版详评与实战部署策略(一)
PolarDB-X是阿里巴巴自研的高性能云原生分布式数据库,基于共享存储的Shared-nothing架构,支持MySQL生态,具备金融级高可用、分布式水平扩展、HTAP混合负载等能力。它通过CN(计算节点)和DN(存储节点)实现计算与存储分离,保证数据强一致性,并支持全局二级索引和多主多写。PolarDB-X开源版提供更高程度的定制化和控制权,适合追求技术自主性和成本优化的开发者。部署方式包括RPM包、PXD工具和Kubernetes,其中PXD工具提供了一键部署的便利性。
237877 22
|
网络安全
出现“Host key verification failed”错误--解决
遇到“Host key verification failed”错误,通常是因为远程主机密钥发生变化,与本地保存的信息不符。这种情况可能是远程主机系统更改或重装等原因导致的。解决方法是根据提示使用`ssh-keygen -f "/root/.ssh/known_hosts" -R "[10.61.0.152]:29022"`命令移除旧的密钥信息,然后重新尝试连接。
3567 5