首页 > 其他分享 >03_仿Modbus工具案例

03_仿Modbus工具案例

时间:2024-05-07 16:58:22浏览次数:21  
标签:03 Slave Text dataGridView Modbus 案例 Master slave port

花了6个小时边学边写的Modbus通信案例,通信方式包括RTU,ASCII,TCP,UTP。 案例图:

 

 

 

using Modbus.Data;
using Modbus.Device;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO.Ports;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Net.Sockets;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using static System.Windows.Forms.AxHost;

namespace MyModbusPS
{
    public partial class Form1 : Form
    {
        private ModbusMaster master;//主站
        private ModbusSlave slave;//从站

        public delegate void Logdelegate(string log);
        private Logdelegate Log;


        public Form1()
        {
            InitializeComponent();

            InotMasterUI();
            InotSlaveUI();

            Log = new Logdelegate((s) =>
            {
                string time = DateTime.Now.ToString("HH:mm:ss");
                Slave_RZ.AppendText($"{time}:{s} \r\n");
                Slave_RZ.SelectionStart = Slave_RZ.Text.Length;
                Slave_RZ.ScrollToCaret();
            });
        }

        #region 初始化主站UI数据
        /// <summary>
        /// 初始化主站UI数据
        /// </summary>
        private void InotMasterUI()
        {
            Master_TXFS.Items.Add("SerialIPort");
            Master_TXFS.Items.Add("TCP");
            Master_TXFS.Items.Add("UDP");
            Master_TXFS.SelectedIndex = 0;
            Master_IP.Text = "COM1";
            Master_DK.Text = "";
            Master_RTU.Checked = true;

            Master_dataGridView.AllowUserToAddRows = false;
            Master_dataGridView.RowHeadersWidth = 60;
            Master_dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            Master_dataGridView.AllowUserToOrderColumns = false;
            //Master_dataGridView.Columns[1].SortMode=DataGridViewColumnSortMode.NotSortable;

            Master_dataGridView.Columns.Add("Alias", "Alias");
            Master_dataGridView.Columns.Add("00000", "00000");

            for (int i = 0; i < 10; i++)
            {
                Master_dataGridView.Rows.Add();
                Master_dataGridView.Rows[i].HeaderCell.Value = i.ToString();
            }

            //从站地址
            Master_CZDZ.Text = "1";
        }
        #endregion

        #region 主站通信方式选择事件
        /// <summary>
        /// 主站通信方式选择事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Master_TXFS_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (Master_TXFS.SelectedIndex == 0)
            {
                Master_IP.Text = "COM1";
                Master_DK.Text = "";
                Master_RTU.Visible = true;
                Master_ASCII.Visible = true;
                Master_RTU.Checked = true;
            }
            else
            {
                Master_IP.Text = "127.0.0.1";
                Master_DK.Text = "8080";
                Master_RTU.Visible = false;
                Master_ASCII.Visible = false;
                Master_RTU.Checked = false;
                Master_ASCII.Checked = false;
            }
        }
        #endregion

        #region 连接
        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Master_LJ_Click(object sender, EventArgs e)
        {
            if (Master_LJ.Text == "连接")
            {
                StartMaster();

            }
            else
            {
                StopMaster();
            }
        }

        /// <summary>
        /// 连接
        /// </summary>
        private void StartMaster()
        {
            try
            {
                if (Master_TXFS.SelectedIndex == 0)//开启RTU或Ascii
                {
                    SerialPort port = new SerialPort();
                    port.PortName = Master_IP.Text;//通信方式
                    port.BaudRate = 9600;//波特率
                    port.DataBits = 8;//数据位
                    port.Parity = Parity.Even;//奇偶校验
                    port.StopBits = StopBits.One;//停止位
                    port.Open();
                    if (Master_RTU.Checked)
                    {
                        master = ModbusSerialMaster.CreateRtu(port);
                    }
                    else if (Master_ASCII.Checked)
                    {
                        master = ModbusSerialMaster.CreateAscii(port);
                    }
                }
                else if (Master_TXFS.SelectedIndex == 1)//开启TCP
                {
                    string ip = Master_IP.Text;
                    ushort port = ushort.Parse(Master_DK.Text);
                    TcpClient tcpClient = new TcpClient(ip, port);

                    master = ModbusIpMaster.CreateIp(tcpClient);
                }
                else if (Master_TXFS.SelectedIndex == 2)//开启UTP
                {
                    string ip = Master_IP.Text;
                    ushort port = ushort.Parse(Master_DK.Text);
                    UdpClient udpClient = new UdpClient(ip, port);
                    master = ModbusIpMaster.CreateIp(udpClient);
                }
                master.Transport.ReadTimeout = 100;//读取数据超时100ms
                master.Transport.WriteTimeout = 100;//写入数据超时100ms
                master.Transport.Retries = 3;//重试次数
                master.Transport.WaitToRetryMilliseconds = 10;//重试间隔
                Master_LJ.Text = "停止";
            }
            catch (Exception e)
            {
                MessageBox.Show($"连接失败:{e.Message}");
            }

        }

        private void StopMaster()
        {

            master.Dispose();
            master = null;
            Master_LJ.Text = "连接";
        }

        #endregion

        #region 03读一个或多个报持寄存器
        /// <summary>
        /// 03读一个或多个报持寄存器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Master_03_Click(object sender, EventArgs e)
        {
            if (master == null) return;
            try
            {
                byte slaveld = byte.Parse(Master_CZDZ.Text);//从站位置 
                ushort StartAddress = 0; //从0开始读
                ushort EndAddress = 10; //读10个
                ushort[] data = master.ReadHoldingRegisters(slaveld, StartAddress, EndAddress);
                for (int i = 0; i < 10; i++)
                {
                    Master_dataGridView.Rows[i].Cells[1].Value = data[i];
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 06写单个保持寄存器
        /// <summary>
        /// 06写单个保持寄存器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Master_06_Click(object sender, EventArgs e)
        {
            if (master == null) return;
            try
            {
                byte slaveld = byte.Parse(Master_CZDZ.Text);//从站位置 
                ushort Address = 9;//写入值的地址
                ushort value = 99;//写入的值(写死了)
                master.WriteSingleRegister(slaveld, Address, value);//写单个保持寄存器
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 16写多个保持寄存器
        /// <summary>
        /// 16写多个保持寄存器
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Master_16_Click(object sender, EventArgs e)
        {
            if (master == null) return;
            try
            {
                byte slaveld = byte.Parse(Master_CZDZ.Text);//从站位置 
                ushort Address = 1;//起始位置
                ushort[] value = { 11, 22, 33 };//写入的值
                master.WriteMultipleRegisters(slaveld, Address, value);//写多个保持寄存器
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 01读多个线圈状态
        /// <summary>
        /// 01读多个线圈状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Master_01_Click(object sender, EventArgs e)
        {
            if (master == null) return;
            try
            {
                byte slaveld = byte.Parse(Master_CZDZ.Text);//从站位置 
                ushort Address = 0;//起始位置
                ushort value = 10;//读取的值
                bool[] data = master.ReadCoils(slaveld, Address, value);//读多个线圈状态
                for (int i = 0; i < data.Length; i++)
                {
                    Master_dataGridView.Rows[i].Cells[1].Value = data[i] == true ? 1 : 0;
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 05写单个线圈状态
        /// <summary>
        /// 05写单个线圈状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            if (master == null) return;
            try
            {
                byte slaveld = byte.Parse(Master_CZDZ.Text);//从站位置 
                ushort Address = 1;//写入值的地址
                bool value = true;//写入的值
                master.WriteSingleCoil(slaveld, Address, value);//写单个线圈状态
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 15写多个线圈状态
        /// <summary>
        /// 15写多个线圈状态
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Master_15_Click(object sender, EventArgs e)
        {
            if (master == null) return;
            try
            {
                byte slaveld = byte.Parse(Master_CZDZ.Text);//从站位置 
                ushort Address = 1;//起始位置
                bool[] value = { true, true, true };//写入的值
                master.WriteMultipleCoils(slaveld, Address, value);//写多个线圈状态
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }
        #endregion

        #region 初始化从站UI数据
        /// <summary>
        /// 初始化主站UI数据
        /// </summary>
        private void InotSlaveUI()
        {
            Slave_TXFS.Items.Add("SerialIPort");
            Slave_TXFS.Items.Add("TCP");
            Slave_TXFS.Items.Add("UDP");
            Slave_TXFS.SelectedIndex = 0;
            Slave_IP.Text = "COM2";
            Slave_DK.Text = "";

            Slave_dataGridView.AllowUserToAddRows = false;
            Slave_dataGridView.RowHeadersWidth = 60;
            Slave_dataGridView.AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill;

            Slave_dataGridView.AllowUserToOrderColumns = false;
            //Master_dataGridView.Columns[1].SortMode=DataGridViewColumnSortMode.NotSortable;

            Slave_dataGridView.Columns.Add("Alias", "Alias");
            Slave_dataGridView.Columns.Add("00000", "00000");

            for (int i = 0; i < 10; i++)
            {
                Slave_dataGridView.Rows.Add();
                Slave_dataGridView.Rows[i].HeaderCell.Value = i.ToString();
            }

            //从站地址
            Slave_CZDZ.Text = "1";

            //表类型
            Slave_BLX.Items.Add(ModbusDataType.HoldingRegister);//保持寄存器,读写
            Slave_BLX.Items.Add(ModbusDataType.InputRegister);//输入寄存器,只读
            Slave_BLX.Items.Add(ModbusDataType.Coil);//线圈,读写
            Slave_BLX.Items.Add(ModbusDataType.Input);//离撒输入,只读
            Slave_BLX.SelectedIndex = 0;
        }
        #endregion

        #region 从站通信方式选择事件
        /// <summary>
        /// 从站通信方式选择事件
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slave_TXFS_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (Slave_TXFS.SelectedIndex == 0)
            {
                Slave_IP.Text = "COM2";
                Slave_DK.Text = "";
                Slave_RTU.Visible = true;
                Slave_ASCII.Visible = true;
                Slave_RTU.Checked = true;
            }
            else
            {
                Slave_IP.Text = "127.0.0.1";
                Slave_DK.Text = "8080";
                Slave_RTU.Visible = false;
                Slave_ASCII.Visible = false;
                Slave_RTU.Checked = false;
                Slave_ASCII.Checked = false;
            }
        }







        #endregion

        #region 开启
        /// <summary>
        /// 开启
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slave_KQ_Click(object sender, EventArgs e)
        {
            if (Slave_KQ.Text == "开启")
            {
                StartSlave();
            }
            else
            {
                StopSlave();
            }
        }

        private void StartSlave()
        {
            try
            {
                byte slaveld = byte.Parse(Slave_CZDZ.Text);//从站位置 
                if (Slave_TXFS.SelectedIndex == 0)//开启RTU或Ascii
                {
                    SerialPort port = new SerialPort();
                    port.PortName = Slave_IP.Text;//通信方式
                    port.BaudRate = 9600;//波特率
                    port.DataBits = 8;//数据位
                    port.Parity = Parity.Even;//奇偶校验
                    port.StopBits = StopBits.One;//停止位
                    port.Open();
                    if (Slave_RTU.Checked)
                    {
                        slave = ModbusSerialSlave.CreateRtu(slaveld, port);
                    }
                    else if (Slave_ASCII.Checked)
                    {
                        slave = ModbusSerialSlave.CreateAscii(slaveld, port);
                    }
                }
                else if (Slave_TXFS.SelectedIndex == 1)//开启TCP
                {
                    string ip = Slave_IP.Text;
                    ushort port = ushort.Parse(Slave_DK.Text);
                    TcpListener tcpListener = new TcpListener(IPAddress.Parse(ip),port);
                    //tcpListener.Start();
                    slave = ModbusTcpSlave.CreateTcp(slaveld, tcpListener);
                }
                else if (Slave_TXFS.SelectedIndex == 2)//开启UTP
                {
                    string ip = Slave_IP.Text;
                    ushort port = ushort.Parse(Slave_DK.Text);
                    IPEndPoint iPEnd=new IPEndPoint(IPAddress.Parse(ip), port);
                    UdpClient udpClient = new UdpClient(iPEnd);
                    slave = ModbusUdpSlave.CreateUdp(slaveld,udpClient);
                }
               // slave.Transport.ReadTimeout = 100;//读取数据超时100ms
                //slave.Transport.WriteTimeout = 100;//写入数据超时100ms
                slave.Transport.Retries = 3;//重试次数
                slave.Transport.WaitToRetryMilliseconds = 10;//重试间隔

                Task.Factory.StartNew(() =>
                {
                    slave.Listen();//开启监听
                });

                Slave_KQ.Text = "停止";

                //订阅一些事件
                //从站收到主站请求时
                slave.ModbusSlaveRequestReceived += new EventHandler<ModbusSlaveRequestEventArgs>((s, e) =>
                {
                    this.BeginInvoke(Log, "ModbusSlaveRequestReceived");

                });
                //从站写完数据之后的事件
                slave.WriteComplete += new EventHandler<ModbusSlaveRequestEventArgs>((s, e) =>
                {
                    this.BeginInvoke(Log, "WriteComplete");
                });

                //数据写入事件
                slave.DataStore.DataStoreWrittenTo += new EventHandler<DataStoreEventArgs>((s, e) =>
                {
                    this.BeginInvoke(Log, "DataStoreWrittenTo");
                });
                //数据读取事件
                slave.DataStore.DataStoreReadFrom += new EventHandler<DataStoreEventArgs>((s, e) =>
                {
                    this.BeginInvoke(Log, "DataStoreReadFrom");
                });

            }
            catch (Exception e)
            {
                MessageBox.Show($"开启失败:{e.Message}");
            }
        }

        private void StopSlave()
        {
            slave.Dispose();
            slave = null;
            Slave_KQ.Text = "开启";
        }

        #endregion

        #region 写入寄存器或线圈
        /// <summary>
        /// 写入寄存器或线圈
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slave_dataGridView_CellEndEdit(object sender, DataGridViewCellEventArgs e)
        {
            string table = Slave_BLX.SelectedItem.ToString();//获取从站存储表
            object value = Slave_dataGridView.Rows[e.RowIndex].Cells[e.ColumnIndex].Value;//获取当前dataGrid单元数据
            if (value != null)
            {
                ushort v = ushort.Parse(value.ToString());
                ModbusDataType dataType = (ModbusDataType)Enum.Parse(typeof(ModbusDataType), table);
                switch (dataType)
                {
                    case ModbusDataType.HoldingRegister:
                        slave.DataStore.HoldingRegisters[e.RowIndex + 1] = v;
                        break;
                    case ModbusDataType.InputRegister:
                        slave.DataStore.InputRegisters[e.RowIndex + 1] = v;
                        break;
                    case ModbusDataType.Coil:
                        slave.DataStore.CoilDiscretes[e.RowIndex + 1] = v != 0;
                        break;
                    case ModbusDataType.Input:
                        slave.DataStore.InputDiscretes[e.RowIndex + 1] = v != 0;
                        break;
                    default:
                        break;

                }
            }
        }
        #endregion

        #region 表类型选择
        /// <summary>
        /// 表类型选择
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slave_BLX_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (slave == null) return;
            string table = Slave_BLX.SelectedItem.ToString();
            ModbusDataType t = (ModbusDataType)Enum.Parse(typeof(ModbusDataType), table);
            switch (t)
            {
                case ModbusDataType.HoldingRegister:
                    for (int i = 0; i < 10; i++)
                    {
                        Slave_dataGridView.Rows[i].Cells[1].Value = slave.DataStore.HoldingRegisters[i + 1];
                    }
                    break;
                case ModbusDataType.InputRegister:
                    for (int i = 0; i < 10; i++)
                    {
                        Slave_dataGridView.Rows[i].Cells[1].Value = slave.DataStore.InputRegisters[i + 1];
                    }
                    break;
                case ModbusDataType.Coil:
                    for (int i = 0; i < 10; i++)
                    {
                        int v = slave.DataStore.CoilDiscretes[i + 1] == true ? 1 : 0;
                        Slave_dataGridView.Rows[i].Cells[1].Value = v;
                    }
                    break;
                case ModbusDataType.Input:
                    for (int i = 0; i < 10; i++)
                    {
                        int v= slave.DataStore.InputDiscretes[i + 1]==true ? 1 : 0;
                        Slave_dataGridView.Rows[i].Cells[1].Value = v;
                    }
                    break;
            }
        }
        #endregion

        #region 刷新
        /// <summary>
        /// 刷新
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Slave_SX_Click(object sender, EventArgs e)
        {
            Slave_BLX_SelectedIndexChanged(null, null);
        }
        #endregion

        #region 窗体关闭
        /// <summary>
        /// 窗体关闭
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if(master!=null)
            {
                master.Dispose();
            }
            if(slave!=null)
            {
                slave.Dispose();
            }
        }
        #endregion
    }
}

 

标签:03,Slave,Text,dataGridView,Modbus,案例,Master,slave,port
From: https://www.cnblogs.com/MingQiu/p/18177749

相关文章

  • [转]openEuler 22.03 (LTS-SP1)安装最新版Docker(踩坑及解决方案)
    原文地址:openEuler22.03(LTS-SP1)安装最新版Docker(踩坑及解决方案)_openeulerdocker-CSDN博客openEuler22.03LTS-SP1要是直接yuminstalldocker,默认安装docker是18.09.0,这个版本Docker有个bug,所以还是安装个最新版Docker。1、先增加docker官方仓库[[email protected]......
  • Summer '24来啦!15个最热门的功能抢先看!
    SalesforceSummer'24即将发布!本篇文章我们将深入了解Summer'24最热门的声明性功能。01自动化Lightning应用程序新的自动化Lightning应用程序中包含所有与自动化相关的内容。访问该应用程序的用户可以在主应用程序中看到Flow、错误信息和其他基于社区的链接。02Einsteinf......
  • AGC039F 做题记录
    link很厉害的一道Ad-hoc题!假定我们填写的矩阵为\(A\)。直接填写\(A\)计算贡献是基本做不到的,考虑挖掘一些神奇的东西。问题转化:考虑\(\prod\limits_{i=1}^n\prod\limits_{j=1}^mf(i,j)\)相当于构造另一个\(B\)矩阵,满足\(B_{i,j}\le\min(A_{i,1...m},A_{1...n,j})......
  • Unveiling the Enigma: Why Does Volvo 88890300 Vocom Communication Fail?
    Intheworldofautomotivediagnostics,Volvo88890300Vocomstandsasaprominenttoolfortechniciansandenthusiastsalike.ThisadvancedcommunicationdeviceenablesseamlessinteractionwithVolvovehicles,streamliningtroubleshootingandmaintenanc......
  • 远光九天平台入选2024全国企业数字化应用创新典型案例
    4月25日至29日,由科技部、国家发展改革委、工业和信息化部、国务院国资委、中国科学院、中国工程院、中国科协、北京市人民政府共同主办的2024中关村论坛在北京召开。远光软件受邀出席2024中关村论坛平行论坛之一——全球数字化应用创新论坛,其倾力打造的远光九天智能一体化云平台(简......
  • CCE云原生混部场景下的测试案例
    本文分享自华为云社区《CCE云原生混部场景下在线任务抢占、压制离线任务CPU资源、保障在线任务服务质量效果测试》,作者:可以交个朋友。背景企业的IT环境通常运行两大类进程,一类是在线服务,一类是离线作业。在线任务:运行时间长,服务流量及资源利用率有潮汐特征,时延敏感,对服务SLA......
  • 顺序栈实现进制转换 和 通过键盘输入一个包括 '(' 和 ')' 的字符串string ,判断字符串
    /********************************************************************************************************** filename: Zqh_栈实现.c* author : [email protected]* date : 2024/05/05* function: 顺序栈实现进制转换和通过键盘输入一个包括'('和')'......
  • 232自由口转Profinet网关接AB扫码枪与PLC通讯案例
     232自由口转Profinet网关(XD-PNR100/300),是一种用于将自由协议转换为Profinet协议的设备,可以实现不同网络之间的通信和数据交换。232自由口转Profinet网关高度的灵活性和可靠性使其成为工业自动化领域的重要工具,并将其与Profinet网络无缝集成,实现数据的快速传输和交换。另外23......
  • 02_Modbus的功能码与报文详解
     Modbus协议类型  Modbus从站四张表类型 主站常用功能码  ModbusTCP请求报文,功能码03ModbusTCP应答报文,功能码03 0017为23个字节:请求长度加应答长度06+17=23;14为20长度:14+06=20  ModbusUDP请求报文,功能码03ModbusUDP应答报文,功能码03  M......
  • Shell阶段02 shell变量运算(整数运算/小数运算), shell变量案例
    Shell变量运算加减乘除求余num1+num2num1-num2num1*num2num1/num2num1%num2求余整数运算expr$(())$[]let只支持整数运算,不支持小数运算expr数值之间必须要有空格进行分开,当使用*乘的时候,需要对其进行转义使用,不能进行次方运算[root@......