【Linux/C++:modebus通信示例】(带初习配置概括)

2023-11-20

        以modbus RTU为例,模拟modbus简单通信原理的代码实现

        首先需要配置串口。

        这里使用的为Configure Virtual Serial Port Driver虚拟串口调试工具

 创建COM1,COM2虚拟端口,或另创建一对串口互作收发信号端。

创建完成后虚拟工具COM后会有已启动端口的状态,这里我们以波特率9600 8N1为基准进行设定。

        接着,我对modbus slave开始设定,这里用slave而不用poll,我们后面会用虚拟机做主机,而slave为从机服务器。一般slave使用COM2端口

 

简单模拟,就以03保存寄存器01线圈为例。

按规格设定好后,进入linux ubuntu,进行串口配置,在开机之前,需先添加串口。

后选择COM1端口,一般约定主机COM1连接。要在VMware上面菜单中找到对应的串口组件并点击连接。

 

//P.S.modbus TCP设定是网络设定,检验连接可用wireshark抓包检测连通,一般slave使用502端口,假如使用虚拟机与PC做连通测试,要注意填写ip为相应虚拟机或PC的ip,而127.0.0.1本地回环测试的本质是本机回环,虚拟机也是独立的。

接着我们进入linux,下载minicom模块。

终端输入:

sudo apt-get install minicom

当连接上虚拟串口后,在终端输入dmesg | grep tty,可以查看到对应的设备文件,其中默认的会有ttyS0文件,剩下的就是虚拟串口对应的设备文件。

虚拟机在终端执行sudo minicom -s

主要使用setup进行波特率等属性设置,并记得保存。

 

配置完成,可先使用 UartAssist串口调试工具通信测试。

调试助手关闭时尽量选关闭而不是最小化,不然频繁使用造成打开一堆在后台,占用资源

接着就可以进行真正的通信了。

这里是基于C++的通信,故要使用对应的类库

 基类.h

#include <stdint.h>             //uint

class AbsPoll   
{
protected:
    //从机地址
    int sid;
    //打开文件需要打文件描述符
    int fd; 
public:
    AbsPoll();
    ~AbsPoll();

    //从C++相应库modbus相关类函数里找到需要的函数

    int setSlave(int id);                             //初始id
    //以下多个纯虚函数,代表这是抽象类,之后派生类使用,不能直接创建对象,所以函数定义写在派生类
    virtual int Connect() = 0;                           //连接,打开文件
    virtual int writeData(uint8_t *data, int len) = 0;     //写数据(发送
    virtual int readData(uint8_t *data, int len) = 0;       //读数据(接受
    virtual int buildRequest(int func, int addr, int nb, uint8_t *req) = 0;     //封装请求码
    int read_registers(int addr, int nb, uint16_t *dest);           //读寄存器数据并存放于指定数组
    int write_bit(int addr, int status);        //如05写线圈状态时可以写一种
};

基类.cpp

#include "AbsPoll.h"

AbsPoll::AbsPoll()
{
}

AbsPoll::~AbsPoll()
{
}

//初始化id(从机地址)
int AbsPoll::setSlave(int id)
{
    sid = id;
}


//读寄存器数据操作
int AbsPoll::read_registers(int addr, int nb, uint16_t *dest)
{
    uint8_t req[32] = "";       
    uint8_t data[32] = "";
    int len;                             
    len = buildRequest(3, addr, nb, req); //请求码的实际长度
    writeData(req, len);//写数据
    readData(data, 32); //1:tcp:7+1+4=12 RTU:1+1+4+2=8      读数据
    //modebus TCP和RTU格式和长度是不同的,读取位置也是不同的
    if(len == 8)//RTU
    {
        for(int i = 0,j = 0; i < data[2]; i+=2,j++)
            dest[j] = data[3+i] << 8 | data[4+i];   
    }
    else //TCP
    {
        for(int i = 0,j = 0; i < data[8]; i+=2,j++)
            dest[j] = data[9+i] << 8 | data[10+i];
    } 
}
int write_bit(int addr, int status)
{

}

派生.h(RTU样例)


#include "AbsPoll.h"
#include "Crc_Calc.h"
#include <stdint.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include "head.h"
#include <iostream>

using namespace std;

class RTUPoll : public AbsPoll                        //使用抽象类创建派生类
{
private:
    string devname;         //注意string类型

public:
    RTUPoll(string name);           //直接构造初始化文件路径
    ~RTUPoll();
    //下在基类为纯虚函数继承下来要写声明,并定义
    int Connect();                  
    int writeData(uint8_t *data, int len);
    int readData(uint8_t *data, int len);
    int buildRequest(int func, int addr, int nb, uint8_t *req);
};

 

 派生.cpp

 

#include "RTUPoll.h"

//初始化设备路径
RTUPoll::RTUPoll(string name)
{
    devname = name;
}

RTUPoll::~RTUPoll()
{
}

//连接
int RTUPoll::Connect()
{
    fd = open(devname.c_str(), O_RDWR);
    //这里注意devname为string类型,而open参数为char*类型,所以使用c_str()转数据类型char
        if (fd < 0)
    {
        cout << "open err" << endl; //错误信息设置
        return -1;
    }
    //
    uart_init(fd); //这个地方是个初始化串口的函数,代码可以自己查查,我之后也会给一种示例。
    return 0;
}


int RTUPoll::writeData(uint8_t *data, int len)
{
    return write(fd, data, len); //写数据
}


int RTUPoll::readData(uint8_t *data, int len)
{
    return read(fd, data, len); //读数据
}

//封装请求码
int RTUPoll::buildRequest(int func, int addr, int nb, uint8_t *req)
{
    //这里控制的就是外部定义的req数组。下面按RTU的数据格式填充
    req[0] = sid;                  //从机地址
    req[1] = func;                 //功能码
    req[2] = (uint8_t)(addr >> 8); //理论上,有要分大小端存储的数,都可以拆分开。
    req[3] = (uint8_t)(addr & 0xff);

    if (func == 3)
    {
        req[4] = (uint8_t)(nb >> 8); //当功能码是03时完成的任务
        req[5] = (uint8_t)(nb & 0xff);
    }
    unsigned short crc = GetCRC16(req, 6); //这里是一个CSC校验,形成两字节的校验位
    req[6] = (uint8_t)(crc >> 8);          //上返回的unsigned short类型,转为uint8_t
    req[7] = (uint8_t)(crc & 0xff);
    return 8;
}

串口初始化

#include <termios.h>

void uart_init(int fd)
{
    struct termios options;
    //设置串口属性
	//获取串口原有属性
    tcgetattr(fd, &options);
	//激活选项CLOCAL(本地连接)和CREAD(接受使能)
    options.c_cflag |= ( CLOCAL | CREAD );
	//设置字符大小
    options.c_cflag &= ~CSIZE;
    //设置流控
    options.c_cflag &= ~CRTSCTS;
	//设置8位数据位
    options.c_cflag |= CS8;
	//设置停止位
    options.c_cflag &= ~CSTOPB;
    //忽略奇偶错字符
    options.c_iflag |= IGNPAR;
    //将输入的CR转换为NL和停止输出控制流起作用
    options.c_iflag &= ~(ICRNL | IXON);
    options.c_oflag = 0;
    options.c_lflag = 0;
	//设置波特率(输入和输出的波特率)
    cfsetispeed(&options, B9600);
    cfsetospeed(&options, B9600);
	//激活配置
    tcsetattr(fd, TCSANOW, &options);
}

接着就可以尝试互通消息了

modbus收发为一问一答,基于linux特性,可用直接读写串口文件来进行通信。

当这样的通信框架建成,就可融合其他功能了,如接入webserver等。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

【Linux/C++:modebus通信示例】(带初习配置概括) 的相关文章

  • 如何使用 GOPATH 的 Samba 服务器位置?

    我正在尝试将 GOPATH 设置为共享网络文件夹 当我进入 export GOPATH smb path to shared folder I get go GOPATH entry is relative must be absolute
  • 如何在 Bash 中给定超时后终止子进程?

    我有一个 bash 脚本 它启动一个子进程 该进程时不时地崩溃 实际上是挂起 而且没有明显的原因 闭源 所以我对此无能为力 因此 我希望能够在给定的时间内启动此进程 如果在给定的时间内没有成功返回 则将其终止 有没有simple and r
  • 是否可以创建一个脚本来保存和恢复权限?

    我正在使用 Linux 系统 需要对一组嵌套文件和目录进行一些权限实验 我想知道是否没有某种方法可以保存文件和目录的权限 而不保存文件本身 换句话说 我想保存权限 编辑一些文件 调整一些权限 然后将权限恢复到目录结构中 将更改的文件保留在适
  • 我不明白 execlp() 在 Linux 中如何工作

    过去两天我一直在试图理解execlp 系统调用 但我还在这里 让我直奔主题 The man pageexeclp 将系统调用声明为int execlp const char file const char arg 与描述 execl exe
  • Linux - 从第二个选项卡获取文本

    假设我们有这样的文件 一些文本11 一些文本12 一些文本13 一些文本21 一些文本22 一些文本23 文本由制表符分隔 我们知道第 1 列中的一些文本 但希望从第 2 列中获取文本 我知道我可以通过以下方式获取线路 grep somet
  • 使用 Grep 查找两个短语之间的文本块(包括短语)

    是否可以使用 grep 来高亮所有以以下内容开头的文本 mutablePath CGPathCreateMutable 并以以下内容结尾 CGPathAddPath skinMutablePath NULL mutablePath 这两个短
  • 快速像素绘图库

    我的应用程序以每像素的方式生成 动画 因此我需要有效地绘制它们 我尝试过不同的策略 库 但结果并不令人满意 尤其是在更高分辨率的情况下 这是我尝试过的 SDL 好的 但是慢 OpenGL 像素操作效率低下 xlib 更好 但仍然太慢 svg
  • 如何构建任务“gems:install”

    我正在将 Rails 应用程序部署到 Linux 服务器 并且缺少一些 rake 任务 包括 rake gems install 和 rake db 我正在运行来自 GEM 的 Rails 2 3 4 为什么是这样 我该如何解决 我可以以某
  • 高效的内存屏障

    我有一个多线程应用程序 其中每个线程都有一个整数类型的变量 这些变量在程序执行期间递增 在代码中的某些点 线程将其计数变量与其他线程的计数变量进行比较 现在 我们知道在多核上运行的线程可能会无序执行 一个线程可能无法读取其他线程的预期计数器
  • 如何查询X11显示分辨率?

    这似乎是一个简单的问题 但我找不到答案 如何查询 通过 X11 存在哪些监视器及其分辨率 查看显示宏 http tronche com gui x xlib display display macros html and 屏幕宏 http
  • 在 Mac OSX 上交叉编译 x86_64-unknown-linux-gnu 失败

    我尝试将我的 Rust 项目之一编译到 x86 64 unknown linux gnu 目标 cargo build target x86 64 unknown linux gnu Compiling deployer v0 1 0 fi
  • 捕获实时流量时如何开启纳秒精度?

    如何告诉 libpcap v1 6 2 将纳秒值存储在struct pcap pkthdr ts tv usec 而不是微秒值 捕获实时数据包时 Note This question is similar to How to enable
  • Python 脚本作为 Linux 服务/守护进程

    Hallo 我试图让 python 脚本作为服务 守护进程 在 ubuntu linux 上运行 网络上存在多种解决方案 例如 http pypi python org pypi python daemon http pypi python
  • 如何从 PROC 获取有关子进程的信息

    我正在尝试编写一个以几个进程作为参数的程序 然后父进程执行每个子进程并打印出一些相关的统计信息 示例 generate ls l 将生成一个程序 打印出有关 ls l 的一些统计信息 特别是其系统时间 用户时间和上下文切换次数 我不想使用
  • linux命令中括号的用途是什么[重复]

    这个问题在这里已经有答案了 我在 Linux 终端中运行以下命令 谁能告诉我 Linux 终端中括号和以下命令的用途是什么 echo GET HTTP 1 0 echo 主机 www google com echo 数控 www googl
  • 在 Ubuntu 中找不到 X11/Xlib.h

    我试图在 Linux 上使用 open gl 编写一个相当简单的程序 但在编译时它说 编译拇指 egl 我对 GL 完全陌生 不知道出了什么问题 快速搜索使用 apt search Xlib h 打开 libx11 dev 包 但纯 Ope
  • 在 Linux 上访问 main 之外的主要参数

    是否可以访问参数main在外面main 即在共享库构造函数中 在 Linux 上除了通过解析之外 proc self cmdline 您可以通过将构造函数放入 init array部分 功能在 init array 不像 init 使用相同
  • C - 为什么我无法映射较小(256UL 或更小)的内存?

    请告诉我 为什么我的简单应用程序无法映射较小的内存 而且 为什么有这样一个特定的边界 257UL define MAP SIZE 256UL or below fail define MAP SIZE 257UL ok include
  • 推荐用于小型站点的 IRC 服务器 (ircd)? [关闭]

    Closed 这个问题不符合堆栈溢出指南 help closed questions 目前不接受答案 情况 我想使用 IRC 机器人作为我正在研究的其他代码的通用通信接口 服务器硬件陈旧且内存不足 但运行在相对最新的 Debian GNU
  • 找出 Linux 上的默认语言

    有没有办法从C语言中找出Linux系统的默认语言 有 POSIX API 可以实现这个功能吗 例如 我想要一个人类可读格式的字符串 即德语系统上的 German 或 Deutsch 法语系统上的 French 或 Francais 等 有类

随机推荐

  • 使用css 动画实现,水波纹的效果

    每日鸡汤 每个你想要学习的瞬间都是未来的你向自己求救 需求 实现水波纹动画效果 要求中心一个圆点 然后有3个圈 一圈一圈的向里面缩小 说实话我第一个想到了给3个圈设置不同的宽高 然后设置动画0 100 一次缩小宽高 但是 我转念一想 我是不
  • Intellisense and NAnt .build files in VS.NET

    Intellisense and NAnt build files in VS NET This has been blogged about before here and there but I wanted to share it a
  • 最大k乘积问题--动态规划

    问题 问题描述 设x是一个n位十进制整数 如果将x划分为k段 则可得到k个整数 这k个整数的乘积称为x的一个k乘积 试设计一个算法 对于给定的x和k 求出x的最大k乘积 编程任务 对于给定的x和k 编程计算x的最大k 乘积 示例 Sampl
  • 深入理解数据库事务(超详细)

    一 事务的介绍 事务是一组操作的集合 事务会把所有操作作为一个整体一起向系统提交或撤销操作请求 即这些操作要么同时成功 要么同时失败 二 事务的基本操作 2 1 事务操作方式一 例子 转账场景 张三向李四转账 1 查询张三账户余额 sele
  • mac下搭建cocos2d-x3.2开发环境

    1 软件 Xcode Ant apache ant 1 9 4 bin tar gz Jdk jdk 8u45 macosx x64 dmg 有的mac系统上没有自带 Ndk android ndk r10d darwin x86 64 b
  • 如何成为一名优秀的开发人员?

    如何成为一名优秀的开发人员 1 你不需要知道一切 没有人知道所有的细节 2 存在错误对于学习至关重要 3 谷歌搜索是一项合法的技能 4 尝试思考而不是编码 5 慎重对待教程 1 你不需要知道一切 没有人知道所有的细节 作为一名开发人员 你可
  • C++STL总结笔记(二)——仿函数(函数对象)

    文章目录 一 概念 总结 一 概念 仿函数又称函数对象 即重载了函数调用运算符 的类的对象 优势 1 仿函数对象的内部可以有自己的状态 可以实现一些其他的功能 2 函数对象可以作为参数进行传递 当仿函数类内重载的返回值是bool类型被称为谓
  • Python爬虫网易云音乐--JS逆向-补充笔记

    课程地址 https www bilibili com video BV1Mi4y147Yb up主省略掉的 用报错信息来一一回溯的方式把js文件补全的过程 主要把握的几个点 把以下部分代码找到粘贴到js中即可补全并顺利运行 CryptoJ
  • 《数据库系统概论》重点整理

    Word文档链接 https wenku baidu com view 063d7656f9c75fbfc77da26925c52cc58bd69088 第一章 数据模型的三个要素 数据结构 数据操作 完整性约束 数据库领域常用的逻辑模型
  • minikube start启动集群失败Unable to find image gcr.io/k8s-minikube/kicbase:v0.0.10

    配套视频教程 minikube带你玩转k8s集群 1 minikube启动集群 minikube start vm driver docker image mirror country cn image repository registr
  • Intel CPU5种不同的CPU频率标定方式

    作者 cici xiang 链接 https www zhihu com question 271509706 answer 364246338 来源 知乎 著作权归作者所有 商业转载请联系作者获得授权 非商业转载请注明出处 Intel C
  • G - Ginger的NB数(二分)

    G Ginger的NB数 SDUT OnlineJudge include
  • pyopencv基础操作指南

    个人学习整理 欢迎指正 实验版本 python版本 3 6 13 opencv版本 2 4 9 1 opencv简介 官网 http docs opencv org 3 0 beta doc py tutorials py tutorial
  • python无法导入自定义类

    问题描述是python3环境 在C Python36 Lib site packages mekk xmind目录下有 init py document py id gen py和xmlutil py四个文件 但是在引入mekk xmind
  • Linux 版本的 SQL Server 快速安装

    SQL Server 2017 版本已经支持 Linux 安装了 出来了很长时间 我还没有实现过在 Linux 上面的应用 包括安装和高可用配置 本文就先尝试完成 Linux 版 SQL Server 的安装 经常在 Windows 下安装
  • VLC for unity 插件如何使用

    VLC for unity 插件如何使用 先去下载一个VLC播放器 安装完成后 然后导入插件链接https download csdn net my 这个插件我的另一个上传资源里有 或者到商店去下载 这个插件链接下载完是一个txt文档 里面
  • settings.json是什么?VS Code的“用户”和“工作区”

    setting json settings json是VS Code众多配置文件中的一个 可以对VS Code进行页面风格 代码格式 字体颜色大小等的编辑设置 比如可能编辑器默认的一个tab为4个空格 用户可以在setting json里面
  • C++11-14 第10讲 template template parameter(模板模板参数)

    template
  • QML类型——ListModel

    正文 列表数据Model 可以自定义格式 详细说明 ListModel是定义ListElement的容器 内容可以动态定义 也可以在QML中明确定义 可以通过count属性获得模型中数据的数量 可以使用模型的setProperty 方法来操
  • 【Linux/C++:modebus通信示例】(带初习配置概括)

    以modbus RTU为例 模拟modbus简单通信原理的代码实现 首先需要配置串口 这里使用的为Configure Virtual Serial Port Driver虚拟串口调试工具 创建COM1 COM2虚拟端口 或另创建一对串口互作