硬汉嵌入式论坛

 找回密码
 立即注册
12
返回列表 发新帖
楼主: yono
收起左侧

modbus 开源库完成辣

  [复制链接]

1

主题

17

回帖

20

积分

新手上路

积分
20
发表于 2025-6-24 16:39:38 | 显示全部楼层
跟freemodbus相比,有什么优点吗?
回复

使用道具 举报

25

主题

232

回帖

307

积分

高级会员

积分
307
QQ
 楼主| 发表于 2025-6-26 15:58:46 | 显示全部楼层
Rundstedt 发表于 2025-6-24 16:39
跟freemodbus相比,有什么优点吗?

嵌入式使用的话,吊打吧
回复

使用道具 举报

25

主题

232

回帖

307

积分

高级会员

积分
307
QQ
 楼主| 发表于 2025-6-26 16:35:05 | 显示全部楼层
Rundstedt 发表于 2025-6-24 16:39
跟freemodbus相比,有什么优点吗?

大概这样吧,嵌入式使用的话全方位吊打

New Board.png
回复

使用道具 举报

24

主题

365

回帖

437

积分

高级会员

积分
437
发表于 2025-6-26 16:47:02 | 显示全部楼层
eric2013 发表于 2024-12-16 15:08
你这个网站竟然还备案成功了,相当可以啊

另外我有个问题想请教下,有没有办法doc文件方便转换成网 ...

可以看一下这个,巨硬出品 https://github.com/microsoft/markitdown
回复

使用道具 举报

1

主题

16

回帖

19

积分

新手上路

积分
19
发表于 2025-7-13 16:19:35 | 显示全部楼层
我最近也写了个modbus RTU 库,实现了与底层硬件无关,收发本身不与串口硬件和中断耦合,依靠轮询方式工作,只要底层串口驱动封装成类似Arduino 那种有内部缓冲的接口就行。这样做最大的优点就是,使用时不要求严格的时序控制,也不用管底层驱动实现,拿来就可以用。库的核心是MODBUS 帧收发器,然后在收发器的基础上实现了简单的从机和主机,目前我只支持了保持寄存器相关的操作。
回复

使用道具 举报

1

主题

16

回帖

19

积分

新手上路

积分
19
发表于 2025-7-13 16:29:30 | 显示全部楼层
不过我根本没管所谓的寄存器映射之类的活,太繁杂了,不好使。我的从机是用类似网络服务器那种风格实现的,请求来了以后就分别调用读取或写入回调,类似网络服务器那种on_get,on_post。对不同寄存器地址的请求本身没有相互关系。比如要写入寄存器0x01,不管写入的长度有多少字节,也不会牵涉到寄存器0x02,除非用户自己实现了相应的逻辑。

简单的从机例子:

[C] 纯文本查看 复制代码
#pragma once

#include <Arduino.h>

// #include <scheduler_tick.hpp>

#include "basic_property_server.hpp"
#include "rtu/non_block_serial.hpp"

namespace modpash {

    template <typename ModpashTransceiverType>
    class DemoServer : public BasicPropertyServer<ModpashTransceiverType> {
        static_assert(sizeof(float) == 4, "Float size must be 4 bytes");

       private:
        union {
            struct {
                uint16_t value_0;
                uint16_t value_1;
                uint32_t value_2;
                float value_3;
            } v{0};

            uint16_t d[6];  // 两个uint16 加一个uint32_t、float == 6 个 uint16
        } _value;

       public:
        DemoServer(ModpashTransceiverType &rtx) noexcept :
            BasicPropertyServer<ModpashTransceiverType>(rtx, 3) {
            // 给三个属性分配个初始值
            _value.v.value_0 = 0xaabb;
            _value.v.value_1 = 0xccdd;
            _value.v.value_2 = 0xaabbccdd;
            _value.v.value_3 = 3.14f;
        }

        virtual int_fast8_t on_read(uint16_t address, uint8_t count) override {
            // DEBUG
            // Serial.printf("Addr= %d, ", address);
            // Serial.printf("Count= %d\n", count);

            if (count > (sizeof(_value.d) / 2)) {
                return RESPONSE_ERROR_INVALID_VALUE;
            }

            // 异常响应必须在begin_response 之前全部处理掉,
            // 否则会导致帧结构错误
            this->begin_response();

            switch (address) {
                case 0:
                    for (uint_fast8_t i = 0; i < count; ++i) {
                        this->send_property(_value.d[i]);
                    }
                    break;

                case 1:
                    this->send_property(_value.v.value_1);
                    break;

                case 2:
                    this->send_property(_value.v.value_2, count == 1);
                    break;

                case 3:
                    this->send_property(_value.v.value_3, count == 1);
                    break;
            }

            this->end_response();
            return RESPONSE_TYPE_OK;
        }

        virtual int_fast8_t on_write(uint16_t address, uint8_t count) override {
            // 处理写入请求时,响应帧是根据返回值生成的,所以异常响应可以随便在中间哪里处理
            switch (address) {
                case 0:
                    if (count > (sizeof(_value.d) / 2)) {
                        return RESPONSE_ERROR_INVALID_VALUE;
                    }

                    for (uint_fast8_t i = 0; i < count; ++i) {
                        _value.d[i] = this->template read_property<uint16_t>();
                    }
                    break;

                case 1:
                    if (count != 1) {
                        return RESPONSE_ERROR_INVALID_VALUE;
                    }

                    _value.v.value_1 = this->template read_property<uint16_t>();
                    break;

                case 2:
                    if (count != 2) {
                        return RESPONSE_ERROR_INVALID_VALUE;
                    }

                    _value.v.value_2 = this->template read_property<uint32_t>();
                    break;

                case 3:
                    if (count != 2) {
                        return RESPONSE_ERROR_INVALID_VALUE;
                    }

                    _value.v.value_3 = this->template read_property<float>();
                    break;
            }


            return RESPONSE_TYPE_OK;
        }
    };

}  // namespace modpash
回复

使用道具 举报

13

主题

174

回帖

213

积分

高级会员

H7 TOOL 大法好!

积分
213
发表于 2025-7-28 12:50:27 | 显示全部楼层
太完美了啊!  而且老师有这样的分享精神, 为后人提供很好的指引, 感谢老师您!
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|小黑屋|Archiver|手机版|硬汉嵌入式论坛

GMT+8, 2025-8-12 06:50 , Processed in 0.043879 second(s), 24 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2023, Tencent Cloud.

快速回复 返回顶部 返回列表