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

news2024/12/22 20:30:09

一.编译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:");
                }
            }
        }

运行结果如下:

工业设备端:

 

 完结

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

IDEA社区版插件汇总

1. Smart Tomcat 顾名思义就是配置tomcat的,跟专业版配置小猫类似。 2. Database Navigator 类似专业版的数据库管理工具。 3. Spring Boot Assistant SpringBoot开发插件。(可以识别springboot主配置文件,以及代码提示,我这个版本…

深度学习与计算机相结合:直播实时美颜SDK的创新之路

时下,实时美颜技术就成为了直播主们的得力工具,它可以在直播过程中即时处理视频画面。而支持实时美颜功能的SDK更是推动了这项技术的发展,让直播主和普通用户都能轻松使用美颜功能。 一、美颜技术的演进 早期的美颜技术主要依赖于简单的图…

TPC-DS 标准介绍、工具下载地址

目录 一、TPC-DS标准介绍 1. DMS介绍 2. TCP-DS概念 二、数据库模型 1. 数据库模型介绍 2. 数据库模型包含内容 三、数据生成器 1. 数据生成器介绍 2. 数据生成器包含内容 四、查询集合 1. 查询集合介绍 2. 查询集合包含的88个标准化查询和17个基准统计函数 五、性…

外卖多门店小程序开源版开发

外卖多门店小程序开源版开发 外卖多门店小程序开源版的开发可以按照以下步骤进行: 确定需求:明确外卖多门店小程序的功能和特点,包括用户注册登录、浏览菜单、下单支付、订单管理等。技术选型:选择适合开发小程序的技术框架&…

Red Hat 安装MySQL 8.0与 Navicat

目录 Red Hat 安装 MySQL 8.0 1、更新软件包列表 2、安装MySQL服务器和客户端 3、启动MySQL服务 4、确保MySQL服务器正在运行 5、root 用户的密码 6、登录MySQL,输入mysql密码 7、MySQL默认位置 Red Hat 安装 Navicat 1、下载 Navicat 2、执行命令 Red H…

Django笔记之使用原生SQL查询数据库

Django 提供了两种方式来执行原生 SQL 代码。 一种是使用 raw() 函数,一种是 使用 connection.cursor()。 但是官方还是推荐在使用原生 SQL 之前,尽量的先去探索一下 QuerySet 提供的各种 API。 目前而言,官方文档提供的各种 API 是能够满…

修改cuda软链接(实操演示)

文章目录 1 找到已存在的CUDA软链接2 确认当前软链接真实路径3 删除现有软链接4 创建新的软链接5 验证新的软链接 要修改CUDA的软链接,需要找到已经存在的软链接并重新创建它指向新的目录。 1 找到已存在的CUDA软链接 首先,需要找到之前创建的CUDA软链…

编程:必备技能还是浪费时间?

当下,学习编程正变得越来越受欢迎,许多人都在探讨这个话题,但仍有很多人产生疑问:学习编程是否有必要?我们可以从学习编程的好处和应用领域来进行分析。好处方面,乔布斯曾说:“人人都应该学习编…

安装企业级高负载web服务器tomcat,并部署应用

web服务器Tocamt 1.Tocmat简介2.Tocmat安装1.安装jdk2.部署Tomcat1.配置环境变量2.启动tocmat3.Tomcat web管理功能 3.部署jpress应用 1.Tocmat简介 Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由…

【小白篇】Vscode配置Python和C++环境

文章目录 一、配置python环境二、配置C环境2.1 安装MinGW编译器2.2 安装C/C扩展2.3 配置C/C环境(1)配置编译器(2)配置构建任务(3)配置调试设置 2.4 测试例子2.5 注意事项 三、插件Reference 一、配置python…

MongoDB文档--基本概念

阿丹: 不断拓展自己的技术栈,不断学习新技术。 基本概念 MongoDB中文手册|官方文档中文版 - MongoDB-CN-Manual mongdb是文档数据库 MongoDB中的记录是一个文档,它是由字段和值对组成的数据结构。MongoDB文档类似于JSON对象。字段的值可以包…

网络安全【黑客技术】自学

1.网络安全是什么 网络安全可以基于攻击和防御视角来分类,我们经常听到的 “红队”、“渗透测试” 等就是研究攻击技术,而“蓝队”、“安全运营”、“安全运维”则研究防御技术。 2.网络安全市场 一、是市场需求量高; 二、则是发展相对成…

windows mysql5.7 开启binlog

查看binlog是否开启 show variables like %log_bin%; 找到安装目录的mysql配置文件 my.ini 编辑 my.ini文件 log-bin D:\Program Files\mysql\logs\log-bin binlog_format ROW server_id 2 按照 log-bin D:\Program Files\mysql\logs\log-bin 创建文件 重启mysql服务 重启…

医疗知识图谱问答 —— 数据同步

前言 前面的文章已经介绍了 neo4j 服务的本地安装,以及数据的增删改查操作方法。那么这里就要进入 python 项目,来完成医疗知识的构建,问答机器人的代码实现。但篇幅较长,本文就主要介绍知识图谱的构建吧。 环境 Anaconda3 Pyth…

外贸国际企业邮箱选择指南:哪家提供更优质的服务?

在当今的数字时代,跨国企业需要与世界各地的客户和合作伙伴保持联系。这就是为什么选择适合其全球运营的功能的正确的业务邮箱是至关重要的。 国际企业邮箱最受欢迎的选择是专门为外贸设计的邮箱服务。它们提供了一系列工具,如国际域名和自动语言翻译&am…

用代码获取每天热点内容信息,并发送到自己的邮箱

前言 大家早好、午好、晚好吖 ❤ ~欢迎光临本文章 本篇文章内容主要为如何用代码,把你想要的内容,以邮件的形式发送出去 内容可以自己完善,还可以设置一个定时发送,或者开机启动自动运行代码 开发环境: python 3.8 运行代码 p…

python算法指南程序员经典,python算法教程pdf百度云

大家好,小编来为大家解答以下问题,你也能看懂的python算法书 pdf,python算法教程这本书怎么样,现在让我们一起来看看吧! 给大家带来的一篇关于算法相关的电子书资源,介绍了关于算法、详解、算法基础方面的内…

无涯教程-Lua - 面向对象

面向对象编程(OOP)是现代编程时代中使用最广泛的编程技术之一。 OOP的特征 类(Class) - 类是用于创建对象的可扩展模板。 对象(Objects) - 它是类的实例,并为其分配了单独的内存空间。 继承(Inheritance) - 这是一个概…

操作系统第二章——进程与线程(圆满)

欲渡黄河冰塞川,将登太行雪满山 文章目录 2.3.7 生产者消费者问题能否改变相邻的PV操作的顺序知识回顾 2.3.8 多生产者多消费者问题问题描述关系分析各个进程之间的PV操作设置信号量若是不设置互斥信号量缓冲区大于一知识回顾 2.3.9 吸烟者问题知识回顾2.3.10读者写…