当前位置: 首页 > news >正文

【C#】CS学习之Modbus通讯


摘要
本文详细描述了如何在在C#的Winform应用程序中使用NModbus库实现Modbus通讯,包括读取保持寄存器、以及相应的UI界面设计和事件处理。


前言

​应用场景

Modbus 从站广泛应用于工业自动化领域:
1、传感器数据采集(如温度、压力等)
2、执行器控制(如电机、阀门等)
3、设备监控与故障诊断。

Modbus 从站(Slave)是 Modbus 通信协议中的响应设备,负责接收并执行来自主站(Master)的请求。

Modbus 从站是被动设备,它不能主动发起通信,只能响应主站的请求。从站的主要功能包括:
1、接收主站的指令(如读取数据或执行操作)。
2、执行相应的操作(如读取寄存器值或设置参数)。
3、返回响应数据或错误码给主站。

通信模式

Modbus 从站支持多种通信模式:
​1、Modbus RTU/ASCII:通过串口(如 RS485)进行通信,从站监听串口链路并响应主站指令。
​2、Modbus TCP:通过以太网进行通信,从站作为服务器监听 TCP 端口(默认 502 端口)并处理客户端请求。

​寄存器类型

Modbus 从站通常管理四种类型的寄存器:
1、线圈(Coils):可读写的二进制状态(如开关状态)。
2、离散输入(Discrete Inputs):只读的二进制状态。
3、保持寄存器(Holding Registers):可读写的16位数据。
4、输入寄存器(Input Registers):只读的16位数据。

实现步骤

1、创建TcpListener并启动 侦听
2、创建Modbus从站数据存储
3、初始化数据
4、创建Modbus从站
5、创建Modbus TCP从站网络
6、添加从站到网络
7、异步侦听网络

运行结果

在这里插入图片描述

代码

Frm_ModbusService

    public partial class Frm_ModbusService : Form
    {
        #region 字段
        //定时器
        Timer timer = null;
        ModbusService modbusService = null;
        #endregion

        #region 构造函数、初始化
        public Frm_ModbusService()
        {
            InitializeComponent();
            CenterToParent();
            CenterToScreen();
        }
        private void ModbusService_Load(object sender, EventArgs e)
        {
            Initialize();
        }
        private void ModbusService_FormClosing(object sender, FormClosingEventArgs e)
        {
            modbusService.Stop();
        }
        #endregion
        /// <summary>
        /// 初始化控件状态
        /// </summary>
        public void InitializeControlsState()
        {
            tbx_IPAddress.Text = modbusService.IpAddress.ToString();
            tbx_OpenPort.Text = modbusService.Port.ToString();
            tbx_StartAddress.Text = modbusService.StartAddress.ToString();
            tbx_SlaveID.Text = modbusService.SlaveId.ToString();  
        }
        /// <summary>
        /// 初始化
        /// </summary>
        public void Initialize()
        {
            modbusService = new ModbusService();
            modbusService.MessageUpdateHandler += OnUpdataMessage;

            InitializeControlsState();
            UpdataControlsState(modbusService.IsRunning);
            timer = new Timer();
            timer.Interval = 100;
            timer.Tick += Timer_Tick;

            dataGridView.Columns[0].Width = 100;
            dataGridView.Columns[1].Width = 100;
            dataGridView.Columns[0].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
            dataGridView.Columns[1].DefaultCellStyle.Alignment = DataGridViewContentAlignment.MiddleCenter;
            dataGridView.RowHeadersVisible = false;
            
            //10行
            dataGridView.Rows.Add(new object[] { 0, 0});
            dataGridView.Rows.Add(new object[] { 1, 0 });
            dataGridView.Rows.Add(new object[] { 2, 0 });
            dataGridView.Rows.Add(new object[] { 3, 0 });
            dataGridView.Rows.Add(new object[] { 4, 0 });
            dataGridView.Rows.Add(new object[] { 5, 0 });
            dataGridView.Rows.Add(new object[] { 6, 0 });
            dataGridView.Rows.Add(new object[] { 7, 0 });
            dataGridView.Rows.Add(new object[] { 8, 0 });
            dataGridView.Rows.Add(new object[] { 9, 0 });
        }

        /// <summary>
        /// 定时器方法
        /// </summary>
        private void Timer_Tick(object sender, EventArgs e)
        {
            var array = modbusService.DataStore.HoldingRegisters.ReadPoints(modbusService.StartAddress, 10);
            for (int i = 0; i < array.Length; i++)
            {
                dataGridView.Rows[i].Cells[0].Value = (modbusService.StartAddress+ i);
                dataGridView.Rows[i].Cells[1].Value = array[i];
            }
        }
        /// <summary>
        /// 启动按钮
        /// </summary>
        private void btn_Start_Click(object sender, EventArgs e)
        {
            try
            {
                if (!modbusService.IsRunning)
                {
                    modbusService.Start();
                    timer.Start();
                    UpdataControlsState(modbusService.IsRunning);
                }
                else
                {
                    modbusService.Stop();
                    timer.Stop();
                    UpdataControlsState(modbusService.IsRunning);
                    UpdataMessage("Modbus服务停止");
                }
            }
            catch (Exception ex)
            {
                modbusService.Stop();
                timer.Stop();
                UpdataControlsState(modbusService.IsRunning);
                UpdataMessage($"Modbus服务异常停止:{ex.Message}");
            }
        }

        /// <summary>
        /// 更新消息
        /// </summary>
        private void UpdataMessage(string message)
        {
            tbx_Output.BeginInvoke(new Action(() =>
            {
                if (tbx_Output.Lines.Length>100)
                {
                    tbx_Output.Clear();
                }
                tbx_Output.AppendText($"{DateTime.Now.ToString()}{message}\r\n");
            }));
        }
        /// <summary>
        /// 更新消息
        /// </summary>
        private void OnUpdataMessage(object sender, string message)
        {
            UpdataMessage(message);
        }

        /// <summary>
        /// 更新控件状态
        /// </summary>
        private void UpdataControlsState(bool isRunning)
        {
            if (isRunning)
            {
                tbx_IPAddress.Enabled = false;
                tbx_OpenPort.Enabled = false;
                tbx_SlaveID.Enabled = false;
                btn_Start.Text = "关闭";
            }
            else
            {
                tbx_IPAddress.Enabled = true;
                tbx_OpenPort.Enabled = true;
                tbx_SlaveID.Enabled = true;
                btn_Start.Text = "启动";
            }
        }
        #region 参数变更
        /// <summary>
        /// IP地址变更
        /// </summary>
        private void tbxIPAddress_TextChanged(object sender, EventArgs e)
        {
            if (IPAddress.TryParse(tbx_IPAddress.Text,out IPAddress result))
            {
                modbusService.IpAddress = result;
            }
            else
            {
                tbx_IPAddress.Text = modbusService.IpAddress.ToString();
            }
        }

        /// <summary>
        /// 端口变更
        /// </summary>
        private void tbxOpenPort_TextChanged(object sender, EventArgs e)
        {
            if (ushort.TryParse(tbx_OpenPort.Text, out ushort result))
            {
                modbusService.Port = result;
            }
            else
            {
                tbx_OpenPort.Text = modbusService.Port.ToString();
            }
        }
        /// <summary>
        /// 起始地址变更
        /// </summary>
        private void tbx_StartAddress_TextChanged(object sender, EventArgs e)
        {
            if (ushort.TryParse(tbx_StartAddress.Text, out ushort result))
            {
                modbusService.StartAddress = result;
            }
            else
            {
                tbx_StartAddress.Text = modbusService.StartAddress.ToString();
            }
        }
        /// <summary>
        /// 站ID变更
        /// </summary>
        private void tbx_SlaveID_TextChanged(object sender, EventArgs e)
        {
            if (byte.TryParse(tbx_SlaveID.Text, out byte result))
            {
                modbusService.SlaveId = result;
            }
            else
            {
                tbx_SlaveID.Text = modbusService.SlaveId.ToString();
            }
        }
        #endregion
    }
}

ModbusService

public class ModbusService
{
    #region 字段、属性
    public event EventHandler<string> MessageUpdateHandler;
    private IPAddress ipAddress = IPAddress.Parse("127.0.0.1");
    private int port = 502;    			//端口
    private byte slaveId = 1;    		// 从站地址
    private ushort startAddress = 0;    //起始地址
    private bool isRunning = false;     //运行状态
    private TcpListener tcpListener = null;    			//创建Modbus服务器
    private DefaultSlaveDataStore dataStore = null;    //默认从站数据存储
    private ModbusFactory factory = null;    			//Bodbus工厂
    private IModbusSlave slave = null;    			//modbus从站
    IModbusTcpSlaveNetwork slaveNetwork = null;    	//ModbusTcp从站网络

    public IPAddress IpAddress { get => ipAddress; set => ipAddress = value; }
    public int Port { get => port; set => port = value; }
    public byte SlaveId { get => slaveId; set => slaveId = value; }
    public ushort StartAddress { get => startAddress; set => startAddress = value; }
    public bool IsRunning { get => isRunning; set => isRunning = value; }
    public TcpListener TcpListener { get => tcpListener; set => tcpListener = value; }
    public DefaultSlaveDataStore DataStore { get => dataStore; set => dataStore = value; }
    public ModbusFactory Factory { get => factory; set => factory = value; }
    public IModbusSlave Slave { get => slave; set => slave = value; }
    public IModbusTcpSlaveNetwork SlaveNetwork { get => slaveNetwork; set => slaveNetwork = value; }
    #endregion
    public ModbusService() {}
    /// <summary>
    /// 初始化从站数据存储
    /// </summary>
    private void InitializeDataStore(DefaultSlaveDataStore dataStore)
    {
        // 初始化保持寄存器
        dataStore.HoldingRegisters.WritePoints(0, new ushort[] { 0 });
        // 初始化输入寄存器
        dataStore.InputRegisters.WritePoints(0, new ushort[] { 0 });
        // 初始化线圈
        dataStore.CoilDiscretes.WritePoints(0, new bool[] { false });
        // 初始化离散输入
        dataStore.CoilInputs.WritePoints(0, new bool[] { false });
    }
    /// <summary>
    /// 启动按钮
    /// </summary>
    public void Start()
    {
        try
        {
            if (!IsRunning)
            {
                // 创建TcpListener并启动
                TcpListener = new TcpListener(IpAddress, Port);
                //启动侦听
                TcpListener.Start();
                // 创建Modbus从站数据存储
                DataStore = new DefaultSlaveDataStore();
                // 初始化数据
                InitializeDataStore(DataStore);
                // 创建Modbus从站
                Factory = new ModbusFactory();
                Slave = Factory.CreateSlave(1, DataStore);
                // 创建Modbus TCP从站网络
                SlaveNetwork = Factory.CreateSlaveNetwork(TcpListener);
                // 添加从站到网络
                SlaveNetwork.AddSlave(Slave);
                //异步侦听网络
                SlaveNetwork.ListenAsync();
                IsRunning = true;
                OnUpdataMessage("Modbus服务启动");
            }
        }
        catch (Exception ex)
        {
            Stop();
            OnUpdataMessage($"Modbus服务异常停止:{ex.Message}");
        }
    }

    public void Stop()
    {
        TcpListener?.Stop();
        SlaveNetwork?.Dispose();
        DataStore = null;
        Factory = null;
        Slave = null;
        IsRunning = false;
    }
    /// <summary>
    /// 消息更新
    /// </summary>
    private void OnUpdataMessage(string message)
    {
        MessageUpdateHandler?.Invoke(this,message);
    }
}

结语

总结来说,Modbus 从站是 Modbus 网络中的关键组成部分,负责响应主站指令并执行相应操作。广泛应用于工业自动化和设备控制。

相关文章:

  • 微信小程序计算属性与监听器:miniprogram-computed
  • 【Mybatis】动态sql
  • HarmonyOS NEXT 组件状态管理的对比
  • IoT设备测试:从协议到硬件的全栈验证体系与实践指南
  • 某公司制造业研发供应链生产数字化蓝图规划P140(140页PPT)(文末有下载方式)
  • 论文笔记(七十三)Gemini Robotics: Bringing AI into the Physical World
  • fastapi 使用 TORTOISE-ORM
  • stm32HAL库驱动gt911触摸屏
  • 麦肯锡咨询某著名企业数字化转型创新驱动与智慧企业构建(40页PPT)(文末有下载方式)
  • 计算机体系结构作业2
  • dfs(二十四)47. 全排列 II
  • 【项目合集】基于ESP32的智能盲人饮水机
  • Pygame实现记忆拼图游戏14
  • 价值流图分析VSM(75页PPT)(文末有下载方式)
  • 前端项目中应该如何选择正确的图片格式
  • 高并发编程有哪些规范?
  • LeetCode hot 100 每日一题(12)——238.除自身以外数组的乘积
  • 单调队列【C/C++】
  • 在 Linux 系统上部署 Deepseek AI 的全面指南‌
  • (* IOB = “FORCE“ *) 的使用分享
  • 就规范涉企行政执法专项行动有关问题,司法部发布解答
  • 李成钢出席中国与《数字经济伙伴关系协定》成员部级会议
  • 江西3人拟提名为县(市、区)长候选人
  • 董军在第六届联合国维和部长级会议上作大会发言
  • 《大风杀》导演张琪:为了不算计观众,拍了部不讨好的警匪片
  • 美国调整对华加征关税