C#使用libmodbus库与工业设备进行读写测试

一.编译libmodbus库供C#使用

如何编译?请移步:https://blog.csdn.net/weixin_42205408/article/details/119530811

上面博主的文章除了所写的modbus.cs内的代码有点问题外(可能上面博主和我的Win 10 64位 Visual Studio 2019平台不一样吧),其他写的很详细。

二.实际应用

把编译得到的modbus.dll文件添加到C#项目中

我在他的基础上更改了modbus.cs(我的是libmodbus.cs),其实类名可以自己定义。

1.libmodbus.cs类如下:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace Robotics_Studio
{
    class libmodbus
    {
        ///[modbus.h]MODBUS_API int modbus_set_slave(modbus_t *ctx, int slave);
        [DllImport("modbus.dll", EntryPoint = "modbus_set_slave", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_set_slave(IntPtr ctx, int slave);

        ///[modbus.h]MODBUS_API int modbus_get_slave(modbus_t *ctx);
        [DllImport("modbus.dll", EntryPoint = "modbus_get_slave", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_get_slave(IntPtr ctx);

        ///[modbus.h]MODBUS_API int modbus_set_socket(modbus_t *ctx, int s);
        [DllImport("modbus.dll", EntryPoint = "modbus_set_socket", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_set_socket(IntPtr ctx, int s);

        ///[modbus.h]MODBUS_API int modbus_get_socket(modbus_t *ctx);
        [DllImport("modbus.dll", EntryPoint = "modbus_get_socket", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_get_socket(IntPtr ctx);

        ///[modbus.h]MODBUS_API int modbus_get_response_timeout(modbus_t* ctx, uint32_t* to_sec, uint32_t* to_usec);
        [DllImport("modbus.dll", EntryPoint = "modbus_get_response_timeout", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_get_response_timeout(IntPtr ctx, UInt32[] to_sec, UInt32[] to_usec);

        ///[modbus.h]MODBUS_API int modbus_set_response_timeout(modbus_t* ctx, uint32_t to_sec, uint32_t to_usec);
        [DllImport("modbus.dll", EntryPoint = "modbus_set_response_timeout", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_set_response_timeout(IntPtr ctx, UInt32 to_sec, UInt32 to_usec);

        ///[modbus-rtu.h]MODBUS_API modbus_t *modbus_new_rtu(const char *device, int band, char parity, int data_bit, int stop_bit);
        [DllImport("modbus.dll", EntryPoint = "modbus_new_rtu", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr modbus_new_rtu(string device, int baud, char parity, int data_bit, int stop_bit);

        ///[modbus-tcp.h]MODBUS_API modbus_t *modbus_new_tcp(const char *ip_address, int port);
        [DllImport("modbus.dll", EntryPoint = "modbus_new_tcp", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr modbus_new_tcp(string ip_address, int port);

        ///[modbus-tcp.h]MODBUS_API int modbus_tcp_listen(modbus_t *ctx, int nb_connection);
        [DllImport("modbus.dll", EntryPoint = "modbus_tcp_listen", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr modbus_tcp_listen(IntPtr ctx, int nb_connection);

        ///[modbus-tcp.h]MODBUS_API int modbus_tcp_accept(modbus_t *ctx, int *s);
        [DllImport("modbus.dll", EntryPoint = "modbus_tcp_accept", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr modbus_tcp_accept(IntPtr ctx, int[] s);

        ///[modbus.h]MODBUS_API int modbus_connect(modbus_t *ctx);
        [DllImport("modbus.dll", EntryPoint = "modbus_connect", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_connect(IntPtr ctx);

        ///[modbus.h]MODBUS_API void modbus_close(modbus_t *ctx);
        [DllImport("modbus.dll", EntryPoint = "modbus_close", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void modbus_close(IntPtr ctx);

        ///[modbus.h]MODBUS_API void modbus_free(modbus_t *ctx);
        [DllImport("modbus.dll", EntryPoint = "modbus_free", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void modbus_free(IntPtr ctx);

        ///[modbus.h]MODBUS_API void modbus_flush(modbus_t *ctx);
        [DllImport("modbus.dll", EntryPoint = "modbus_flush", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern void modbus_flush(IntPtr ctx);

        ///[modbus.h]MODBUS_API int modbus_read_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
        [DllImport("modbus.dll", EntryPoint = "modbus_read_bits", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_read_bits(IntPtr ctx, int addr, int nb, byte[] dest);

        ///[modbus.h]MODBUS_API int modbus_read_input_bits(modbus_t *ctx, int addr, int nb, uint8_t *dest);
        [DllImport("modbus.dll", EntryPoint = "modbus_read_input_bits", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_read_input_bits(IntPtr ctx, int addr, int nb, byte[] dest);

        ///[modbus.h]MODBUS_API int modbus_read_registers(modbus_t *ctx, int addr, int nb, uint16_t *dest);
        [DllImport("modbus.dll", EntryPoint = "modbus_read_registers", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_read_registers(IntPtr ctx, int addr, int nb, UInt16[] dest);

        ///[modbus.h]MODBUS_API int modbus_read_input_registers(modbus_t* ctx, int addr, int nb, uint16_t* dest);
        [DllImport("modbus.dll", EntryPoint = "modbus_read_input_registers", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_read_input_registers(IntPtr ctx, int addr, int nb, UInt16[] dest);

        ///[modbus.h]MODBUS_API int modbus_write_bit(modbus_t *ctx, int coil_addr, int status);
        [DllImport("modbus.dll", EntryPoint = "modbus_write_bit", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_write_bit(IntPtr ctx, int coil_addr, int status);

        ///[modbus.h]MODBUS_API int modbus_write_register(modbus_t *ctx, int reg_addr, const uint16_t value);
        [DllImport("modbus.dll", EntryPoint = "modbus_write_register", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_write_register(IntPtr ctx, int reg_addr, UInt16 value);

        ///[modbus.h]MODBUS_API int modbus_write_bits(modbus_t *ctx, int addr, int nb, const uint8_t *data);
        [DllImport("modbus.dll", EntryPoint = "modbus_write_bits", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_write_bits(IntPtr ctx, int addr, int nb, byte[] data);

        ///[modbus.h]MODBUS_API int modbus_write_registers(modbus_t* ctx, int addr, int nb, const uint16_t* data);
        [DllImport("modbus.dll", EntryPoint = "modbus_write_registers", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_write_registers(IntPtr ctx, int addr, int nb, UInt16[] data);

        ///[modbus.h]MODBUS_API int modbus_write_and_read_registers(modbus_t *ctx, int write_addr, int write_nb, const uint16_t* src, int read_addr, int read_nb, uint16_t *dest);
        [DllImport("modbus.dll", EntryPoint = "modbus_write_and_read_registers", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]
        public static extern int modbus_write_and_read_registers(IntPtr ctx, int write_addr, int write_nb, UInt16[] scr, int read_addr, int read_nb, UInt16[] dest);
    }
}
2.C#逻辑主程序

注意事项:

2.1 假设你的类名叫 libmodbus.cs

需注意类中的引用部分,例如

[DllImport("modbus.dll", EntryPoint = "modbus_new_tcp", CharSet = CharSet.Ansi)]

全部都需要加上: CallingConvention = CallingConvention.Cdecl

即:

[DllImport("modbus.dll", EntryPoint = "modbus_new_tcp", CharSet = CharSet.Ansi, CallingConvention = CallingConvention.Cdecl)]

否则出现:原因可能是托管的PInvoke签名与非托管的目标签名不匹配

上面的libmodbus.cs就是已经改好过来的。

2.2 使用类时需注意

libmodbus modbus_tcp = new libmodbus();
modbus_tcp.modbus_set_slave(modbus_tcp.modbus_new_tcp(ip1, 502),2);//此行会报错,无法使用实例引用来访问成员,请改用类型名来限定它

应改为
 

//libmodbus modbus_tcp = new libmodbus();//注释掉此行
libmodbus.modbus_set_slave(modbus_tcp.modbus_new_tcp(ip1, 502),2);//更改后

2.3 已测试好的例子如下:

        private void button_Connect_Click(object sender, EventArgs e)
        {
            if (button_Connect.Text == "连接")
            {
                string RobotIP = this.textBox_IP.Text.Trim();
                //by libmodbus
                IntPtr Machine = libmodbus.modbus_new_tcp(RobotIP, 502);//创建TCP连接
                libmodbus.modbus_set_slave(Machine, 2);
                int connectSta = 0;
                int connectCnt = 0;
                while (true)
                {
                    connectSta = libmodbus.modbus_connect(Machine);
                    if (connectSta == 0)//连接状态
                    {
                        break;
                    }
                    connectCnt += 1;
                    if(connectCnt == 4)//连接失败次数计数
                    {
                        connectSta = -1;
                        break;
                    }
                }
                if (connectSta == -1)
                { 
                    MessageBox.Show("Try many times were failed,Try again please!", "Info:");
                    return;
                }
                try
                {
                    //读单个保持寄存器
                    ushort[] servoSta = { 0 };//伺服状态
                    libmodbus.modbus_read_registers(Machine, 0x0006, 1, servoSta);
                    Console.WriteLine("read servo status: {0}", servoSta[0]);

                    //读多个保持寄存器
                    ushort[] current_pos = new ushort[12];//位置坐标
                    libmodbus.modbus_read_registers(Machine, 0x00F0, 12, current_pos);
                    Console.WriteLine("read xH,xL: {0},{1}", current_pos[0], current_pos[1]);
                    Console.WriteLine("read yH,yL: {0},{1}", current_pos[2], current_pos[3]);
                    Console.WriteLine("read zH,zL: {0},{1}", (Int16)current_pos[4], (Int16)current_pos[5]);//(Int16)是把无符号16位整型转有符号16位整型
                    Console.WriteLine("read cH,cL: {0},{1}", current_pos[10], current_pos[11]);
                    Console.WriteLine("read x: {0}", Two16Int_2_One32Int(current_pos[0], current_pos[1]));
                    Console.WriteLine("read y: {0}", Two16Int_2_One32Int(current_pos[2], current_pos[3]));
                    Console.WriteLine("read z: {0}", Two16Int_2_One32Int(current_pos[4], current_pos[5]));
                    Console.WriteLine("read c: {0}", Two16Int_2_One32Int(current_pos[10], current_pos[11]));

                    //写单个保持寄存器
                    ushort value1 = 32767;//write Int16 (2^15)-1 = 32767
                    libmodbus.modbus_write_register(Machine, 0x2000, value1);

                    //写单个保持寄存器
                    ushort[] value2 = { 32767 };//write Int16 (2^15)-1 = 32767
                    libmodbus.modbus_write_registers(Machine, 0x2002, 1, value2);

                    //写多个保持寄存器
                    ushort[] value3 = { 65535,32767 };//write Int32 (2^31)-1 = 2147483647
                    libmodbus.modbus_write_registers(Machine, 0x2004, 2, value3);
                }
                catch(Exception ex)
                {
                    MessageBox.Show("Read error!\n" + ex.Message, "Info:");
                }
            }
        }

运行结果如下:

工业设备端:

 

 完结

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/63085.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Spring Boot集成Mybatis-Plus

Spring Boot集成Mybatis-Plus 1. pom.xml导包 <!--lombok--><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!--mysql驱动--><dependency><groupId>mysql<…

S系列数字源表为何如此受欢迎?

为什么选择S系列数字源表? 性能强大-作为电压源和或电流源&#xff0c;并同步测量电流和或电压&#xff0c;支持四象限工作。可以限定电压或电流输出大小&#xff0c;预防器件损坏。覆盖3pA-3A的电流范围100μV-300V的电压范围&#xff0c;全量程测量精度0.03%。 灵活多样-支…

数据结构 | 二叉树的应用

目录 一、解析树 二、树的遍历 一、解析树 我们可以用解析树来表示现实世界中像句子或数学表达式这样的构造。 我们可以将((73)*(5-2))这样的数学表达式表示成解析树。这是完全括号表达式&#xff0c;乘法的优先级高于加法和减法&#xff0c;但因为有括号&#xff0c;所以在…

今天面了一个来字节要求月薪24K,明显感觉他背了很多面试题...

最近有朋友去字节面试&#xff0c;面试前后进行了20天左右&#xff0c;包含4轮电话面试、1轮笔试、1轮主管视频面试、1轮hr视频面试。 据他所说&#xff0c;80%的人都会栽在第一轮面试&#xff0c;要不是他面试前做足准备&#xff0c;估计都坚持不完后面几轮面试。 其实&…

python:isdigit()、isalpha()、isalnum() 三个函数的区别和注意点

前言 嗨喽&#xff0c;大家好呀~这里是爱看美女的茜茜呐 一、isdigit() python关于 isdigit() 内置函数的官方定义&#xff1a; S.isdigit() -> bool Return True if all characters in S are digitsand there is at least one character in S, False otherwise.翻…

【开源项目--稻草】Day06

【开源项目--稻草】Day06 1. 学生提问与解答功能2. 显示create.html2.1 HomeController中代码2.2 复用网页的标签导航条 3. 创建问题发布界面3.1 富文本编辑器 4.多选下列框5.动态加载所有标签和老师6. 发布问题的业务处理 1. 学生提问与解答功能 学生提问: 提问时指定标签和回…

K8S系列文章 之 容器存储基础 Volume

Volume Volume是容器数据卷。我们经常创建删除一些容器&#xff0c;但有时候需要保留容器中的一些数据&#xff0c;这时候就用到了Volume。它也是容器之间数据共享的技术&#xff0c;可以将容器中产生的数据同步到本地。实际就是把容器中的目录挂载到运行着容器的服务器或个人…

云运维工具

企业通常寻找具有成本效益的方法来优化创收&#xff0c;维护物理基础架构以托管服务器和应用程序以提供服务交付需要巨大的空间和前期资金&#xff0c;最重要的是&#xff0c;物理基础设施会产生额外的运营支出以进行定期维护&#xff0c;这对收入造成了沉重的损失。 云使企业…

设计模式之策略模式(Strategy)

一、概述 定义一系列的算法&#xff0c;把它们一个个封装起来,并且使它们可相互替换。本模式使得算法可独立于使用它的类而变化。 二、适用性 1.许多相关的类仅仅是行为有异。“策略”提供了一种用多个行为中的一个行为来配置一个类的方法。 2.需要使用一个算法的不同变体。…

Grafana V10 告警推送

最近项目建设完成&#xff0c;一个城域网项目&#xff0c;相关zabbix和grafana展示已经完&#xff0c;想了想&#xff0c;不想天天看平台去盯网络监控平台&#xff0c;索性对告警进行分类调整&#xff0c;增加告警的推送&#xff0c;和相关部门的提醒&#xff0c;其他部门看不懂…

Collections工具类(java)

文章目录 7.1 常用方法 参考操作数组的工具类&#xff1a;Arrays&#xff0c;Collections 是一个操作 Set、List 和 Map 等集合的工具类。 7.1 常用方法 Collections 中提供了一系列静态的方法对集合元素进行排序、查询和修改等操作&#xff0c;还提供了对集合对象设置不可变、…

基于Mediapipe的姿势识别并同步到Unity人体模型中

如题&#xff0c;由于是商业项目&#xff0c;无法公开源码&#xff0c;这里主要说一下实现此功能的思路。 人体关节点识别 基于Mediapipe Unity插件进行开发&#xff0c;性能比较低的CPU主机&#xff0c;无法流畅地运行Mediapipe&#xff0c;这个要注意一下。 Mediapipe33个人体…

Microsoft Message Queuing Denial-of-Service Vulnerability

近期官方公布了一个MSMQ的拒绝服务漏洞&#xff0c;可能因为网络安全设备的更新&#xff0c;影响业务&#xff0c;值得大家关注。 漏洞具体描述参见如下&#xff1a; Name: Microsoft Message Queuing Denial-of-Service Vulnerability Description: Microsoft Message Queuing…

AI一键生成短视频

AI一键生成推文短视频 阅读时长&#xff1a;10分钟 本文内容&#xff1a; 结合开源AI&#xff0c;一键生成短视频发布到常见的某音&#xff0c;某手平台&#xff0c;狠狠赚一笔 前置知识&#xff1a; 1.基本的 python 编程知识 2.chatGPT 使用过 3.stable diffution 使用过 成果…

8.3一日总结

1.远程仓库的使用 a.克隆远程仓库 1>.在桌面克隆远程仓库 git clone 仓库名 2>.修改仓库内容 3>添加目录 git add. 4>提交: git commit -m 完成登录功能 5>推送提交远程仓库 : git push origin master -u 6>更改推送:git push(简写形式) 需要先添加,再提交,最…

怎么加密文件夹才更安全?安全文件夹加密软件推荐

文件夹加密可以让其中数据更加安全&#xff0c;但并非所有加密方式都能够提高极高的安全强度。那么&#xff0c;怎么加密文件夹才更安全呢&#xff1f;下面我们就来了解一下那些安全的文件夹加密软件。 文件夹加密超级大师 如果要评选最安全的文件夹加密软件&#xff0c;那么文…

FineBI 人力资源 专题

此处使用FineBI处理人力资源数据&#xff0c;数据来源于HR_database数据文件&#xff0c;将此文件拷贝到安装目录下 然后配置数据库连接 在【公共数据】中新建一个文件夹&#xff0c;并将之前数据库中需要用到的表放入此处&#xff0c;更新数据。显示如下。 这时候首先要建立…

goanno的简单配置-goland配置

手动敲注释太LOW,使用插件一步搞定 goanno 打开goanno的配置 点击之后弹窗如下 配置method /** Title ${function_name} * Description ${todo} * Author zhangguofu ${date} * Param ${params} * Return ${return_types} */相关效果如下 同理配置interface // ${interface…

使用TransBigData快速高效地处理、分析、挖掘出租车GPS数据

01、TransBigData简介 TransBigData是一个为交通时空大数据处理、分析和可视化而开发的Python包。TransBigData为处理常见的交通时空大数据&#xff08;如出租车GPS数据、共享单车数据和公交车GPS数据等&#xff09;提供了快速而简洁的方法。TransBigData为交通时空大数据分析的…

一篇万能英语作文范文怎么写?聪明灵犀英语作文写作工具分享

一篇万能英语作文范文怎么写&#xff1f;英语作文是英语学习中不可或缺的一环&#xff0c;但是对于很多人来说&#xff0c;写作并不是一件容易的事情。本文将分享一些实用的英语作文写作工具&#xff0c;帮助你更好地写作。 1. 明确主题 写作之前&#xff0c;首先需要明确主题…