亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

C#?NModbus?RTU通信實現(xiàn)方法詳解

 更新時間:2024年11月07日 09:30:32   作者:熊來闖一闖  
Modbus協(xié)議時應(yīng)用于電子控制器上的一種通用語言,通過此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò)/串口和其它設(shè)備之間可以進(jìn)行通信,下面我們就來看看具體實現(xiàn)吧

Modbus協(xié)議時應(yīng)用于電子控制器上的一種通用語言。通過此協(xié)議,控制器相互之間、控制器經(jīng)由網(wǎng)絡(luò)/串口和其它設(shè)備之間可以進(jìn)行通信。它已經(jīng)成為了一種工業(yè)標(biāo)準(zhǔn)。有了這個通信協(xié)議,不同的廠商生成的控制設(shè)備就可以連城工業(yè)網(wǎng)絡(luò),進(jìn)行集中監(jiān)控。

本文實現(xiàn)需要借用一個開源的NModbus庫來完成,通過在菜單欄,工具-----NuGet包管理器-----管理解決方案的NuGet程序包,安裝NModbus的開源庫。

本次實例的基本框架和實現(xiàn)效果如下所示:

可自動識別當(dāng)前設(shè)備的可用串口。

 Modbus RTU通信的具體的實現(xiàn)如下:

using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using Modbus.Device;
using System.Net.Sockets;
using System.Threading;
using System.IO.Ports;
using System.Drawing.Text;
using System.Windows.Forms.VisualStyles;
using System.Timers;
using System.CodeDom.Compiler;
namespace ModbusRtuMaster
{
    public partial class Form1 : Form
    {
        #region 參數(shù)配置
        private static IModbusMaster master;
        private static SerialPort port;
        //寫線圈或?qū)懠拇嫫鲾?shù)組
        private bool[] coilsBuffer;
        private ushort[] registerBuffer;
        //功能碼
        private string functionCode;
        //功能碼序號
        private int functionOder;
        //參數(shù)(分別為從站地址,起始地址,長度)
        private byte slaveAddress;
        private ushort startAddress;
        private ushort numberOfPoints;
        //串口參數(shù)
        private string portName;
        private int baudRate;
        private Parity parity;
        private int dataBits;
        private StopBits stopBits;
        //自動測試標(biāo)志位
        private bool AutoFlag = false;
        //獲取當(dāng)前時間
        private System.DateTime Current_time;
        //定時器初始化
        private System.Timers.Timer t = new System.Timers.Timer(1000);
        private const int WM_DEVICE_CHANGE = 0x219;            //設(shè)備改變
        private const int DBT_DEVICEARRIVAL = 0x8000;          //設(shè)備插入
        private const int DBT_DEVICE_REMOVE_COMPLETE = 0x8004; //設(shè)備移除
        #endregion
        public Form1()
        {
            InitializeComponent();
            GetSerialLstTb1();
        }
        private void Form1_Load(object sender, EventArgs e)
        {
            //界面初始化
            cmb_portname.SelectedIndex = 0;
            cmb_baud.SelectedIndex = 5;
            cmb_parity.SelectedIndex = 2;
            cmb_databBits.SelectedIndex = 1;
            cmb_stopBits.SelectedIndex = 0;
        }
        #region 定時器
        //定時器初始化,失能狀態(tài)
        private void init_Timer()
        {
            t.Elapsed += new System.Timers.ElapsedEventHandler(Execute);
            t.AutoReset = true;//設(shè)置false定時器執(zhí)行一次,設(shè)置true定時器一直執(zhí)行
            t.Enabled = false;//定時器使能true,失能false
            //t.Start();
        }
        private void Execute(object source,System.Timers.ElapsedEventArgs e)
        {
            //停止定時器后再打開定時器,避免重復(fù)打開
            t.Stop();
            //ExecuteFunction();可添加執(zhí)行操作
            t.Start();
        }
        #endregion
        #region 串口配置
        /// <summary>
        /// 串口參數(shù)獲取
        /// </summary>
        /// <returns></返回串口配置參數(shù)>
        private SerialPort InitSerialPortParameter()
        {
            if (cmb_portname.SelectedIndex < 0 || cmb_baud.SelectedIndex < 0 || cmb_parity.SelectedIndex < 0 || cmb_databBits.SelectedIndex < 0 || cmb_stopBits.SelectedIndex < 0)
            {
                MessageBox.Show("請選擇串口參數(shù)");
                return null;
            }
            else
            {
                portName = cmb_portname.SelectedItem.ToString();
                baudRate = int.Parse(cmb_baud.SelectedItem.ToString());
                switch (cmb_parity.SelectedItem.ToString())
                {
                    case "奇":
                        parity = Parity.Odd;
                        break;
                    case "偶":
                        parity = Parity.Even;
                        break;
                    case "無":
                        parity = Parity.None;
                        break;
                    default:
                        break;
                }
                dataBits = int.Parse(cmb_databBits.SelectedItem.ToString());
                switch (cmb_stopBits.SelectedItem.ToString())
                {
                    case "1":
                        stopBits = StopBits.One;
                        break;
                    case "2":
                        stopBits = StopBits.Two;
                        break;
                    default:
                        break;
                }
                port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
                return port;
            }
        }
        #endregion
        #region 串口收/發(fā)
        private async void ExecuteFunction()
        {
            Current_time = System.DateTime.Now;
            try
            {
                if (port.IsOpen == false)
                {
                    port.Open();
                }
                if (functionCode != null)
                {
                    switch (functionCode)
                    {
                        case "01 Read Coils"://讀取單個線圈
                            SetReadParameters();
                            try
                            {
                                coilsBuffer = master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
                            }
                            catch(Exception)
                            {
                                MessageBox.Show("參數(shù)配置錯誤");
                                //MessageBox.Show(e.Message);
                                AutoFlag = false;
                                break;
                            }
                            SetMsg("[" + Current_time.ToString("yyyy-MM-dd HH:mm:ss" + "]" + " "));
                            for (int i = 0; i < coilsBuffer.Length; i++)
                            {
                                SetMsg(coilsBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "02 Read DisCrete Inputs"://讀取輸入線圈/離散量線圈
                            SetReadParameters();
                            try
                            {
                                coilsBuffer = master.ReadInputs(slaveAddress, startAddress, numberOfPoints);
                            }
                            catch(Exception)
                            {
                                MessageBox.Show("參數(shù)配置錯誤");
                                AutoFlag = false;
                                break;
                            }
                            SetMsg("[" + Current_time.ToString("yyyy-MM-dd HH:mm:ss" + "]" + " "));
                            for (int i = 0; i < coilsBuffer.Length; i++)
                            {
                                SetMsg(coilsBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "03 Read Holding Registers"://讀取保持寄存器
                            SetReadParameters();
                            try
                            {
                                registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
                            }
                            catch (Exception)
                            {
                                MessageBox.Show("參數(shù)配置錯誤");
                                AutoFlag = false;
                                break;
                            }
                            SetMsg("[" + Current_time.ToString("yyyy-MM-dd HH:mm:ss" + "]" + " "));
                            for (int i = 0; i < registerBuffer.Length; i++)
                            {
                                SetMsg(registerBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "04 Read Input Registers"://讀取輸入寄存器
                            SetReadParameters();
                            try
                            {
                                registerBuffer = master.ReadInputRegisters(slaveAddress, startAddress, numberOfPoints);
                            }
                            catch (Exception)
                            {
                                MessageBox.Show("參數(shù)配置錯誤");
                                AutoFlag = false;
                                break;
                            }
                            SetMsg("[" + Current_time.ToString("yyyy-MM-dd HH:mm:ss" + "]" + " "));
                            for (int i = 0; i < registerBuffer.Length; i++)
                            {
                                SetMsg(registerBuffer[i] + " ");
                            }
                            SetMsg("\r\n");
                            break;
                        case "05 Write Single Coil"://寫單個線圈
                            SetWriteParametes();
                            await master.WriteSingleCoilAsync(slaveAddress, startAddress, coilsBuffer[0]);
                            break;
                        case "06 Write Single Registers"://寫單個輸入線圈/離散量線圈
                            SetWriteParametes();
                            await master.WriteSingleRegisterAsync(slaveAddress, startAddress, registerBuffer[0]);
                            break;
                        case "0F Write Multiple Coils"://寫一組線圈
                            SetWriteParametes();
                            await master.WriteMultipleCoilsAsync(slaveAddress, startAddress, coilsBuffer);
                            break;
                        case "10 Write Multiple Registers"://寫一組保持寄存器
                            SetWriteParametes();
                            await master.WriteMultipleRegistersAsync(slaveAddress, startAddress, registerBuffer);
                            break;
                        default:
                            break;
                    }
                }
                else
                {
                    MessageBox.Show("請選擇功能碼!");
                }
                port.Close();
            }
            catch (Exception ex)
            {
                port.Close();
                MessageBox.Show(ex.Message);
            }
        }
        #endregion
        /// <summary>
        /// 設(shè)置讀參數(shù)
        /// </summary>
        private void SetReadParameters()
        {
            if (txt_startAddr1.Text == "" || txt_slave1.Text == "" || txt_length.Text == "")
            {
                MessageBox.Show("請?zhí)顚懽x參數(shù)!");
            }
            else
            {
                slaveAddress = byte.Parse(txt_slave1.Text);
                startAddress = ushort.Parse(txt_startAddr1.Text);
                numberOfPoints = ushort.Parse(txt_length.Text);
            }
        }
        /// <summary>
        /// 設(shè)置寫參數(shù)
        /// </summary>
        private void SetWriteParametes()
        {
            if (txt_startAddr2.Text == "" || txt_slave2.Text == "" || txt_data.Text == "")
            {
                MessageBox.Show("請?zhí)顚憣憛?shù)!");
            }
            else
            {
                slaveAddress = byte.Parse(txt_slave2.Text);
                startAddress = ushort.Parse(txt_startAddr2.Text);
                //判斷是否寫線圈
                if (functionOder == 4 || functionOder == 6)
                {
                    string[] strarr = txt_data.Text.Split(' ');
                    coilsBuffer = new bool[strarr.Length];
                    //轉(zhuǎn)化為bool數(shù)組
                    for (int i = 0; i < strarr.Length; i++)
                    {
                        // strarr[i] == "0" ? coilsBuffer[i] = false : coilsBuffer[i] = true;
                        if (strarr[i] == "0")
                        {
                            coilsBuffer[i] = false;
                        }
                        else
                        {
                            coilsBuffer[i] = true;
                        }
                    }
                }
                else
                {
                    //轉(zhuǎn)化ushort數(shù)組
                    string[] strarr = txt_data.Text.Split(' ');
                    registerBuffer = new ushort[strarr.Length];
                    for (int i = 0; i < strarr.Length; i++)
                    {
                        registerBuffer[i] = ushort.Parse(strarr[i]);
                    }
                }
            }
        }
        /// <summary>
        /// 創(chuàng)建委托,打印日志
        /// </summary>
        /// <param name="msg"></param>
        public void SetMsg(string msg)
        {
            richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(msg); }));
        }
        /// <summary>
        /// 清空日志
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button2_Click(object sender, EventArgs e)
        {
            richTextBox1.Clear();
        }
        /// <summary>
        /// 單擊button1事件,串口完成一次讀/寫操作
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button1_Click(object sender, EventArgs e)
        {
            //AutoFlag = false;
            //button_AutomaticTest.Enabled = true;
            try
            {
                //初始化串口參數(shù)
                InitSerialPortParameter();
                master = ModbusSerialMaster.CreateRtu(port);
                ExecuteFunction();
            }
            catch (Exception)
            {
                MessageBox.Show("初始化異常");
            }
        }
        /// <summary>
        /// 自動測試初始化
        /// </summary>
        private void AutomaticTest()
        {
            AutoFlag = true;
            button1.Enabled = false;
            InitSerialPortParameter();
            master = ModbusSerialMaster.CreateRtu(port);
            Task.Factory.StartNew(() =>
            {
                //初始化串口參數(shù)
                while (AutoFlag)
                {
                    try
                    {
                        ExecuteFunction();
                    }
                    catch (Exception)
                    {
                        MessageBox.Show("初始化異常");
                    }
                    Thread.Sleep(500);
                }
            });
        }
        /// <summary>
        /// 讀取數(shù)據(jù)時,失能寫數(shù)據(jù);寫數(shù)據(jù)時,失能讀數(shù)據(jù)
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (comboBox1.SelectedIndex >= 4)
            {
                groupBox2.Enabled = true;
                groupBox1.Enabled = false;
            }
            else
            {
                groupBox1.Enabled = true;
                groupBox2.Enabled = false;
            }
            //委托事件,在主線程中創(chuàng)建的控件,在子線程中讀取設(shè)置控件的屬性會出現(xiàn)異常,使用Invoke方法可以解決
            comboBox1.Invoke(new Action(() => { functionCode = comboBox1.SelectedItem.ToString(); functionOder = comboBox1.SelectedIndex; }));
        }
        /// <summary>
        /// 將打印日志顯示到最新接收到的符號位置
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void richTextBox1_TextChanged(object sender, EventArgs e)
        {
            this.richTextBox1.SelectionStart = int.MaxValue;
            this.richTextBox1.ScrollToCaret();
        }
        /// <summary>
        /// 自動化測試
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_AutomaticTest_Click(object sender, EventArgs e)
        {
            AutoFlag = false;
            button_AutomaticTest.Enabled = false; //自動收發(fā)按鈕失能,避免從復(fù)開啟線程
            if (AutoFlag == false)
            {
                AutomaticTest();
            }
        }
        /// <summary>
        /// 串口關(guān)閉,停止讀/寫
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void button_ClosePort_Click(object sender, EventArgs e)
        {
            AutoFlag = false;
            button1.Enabled = true;
            button_AutomaticTest.Enabled = true;
            t.Enabled = false;//失能定時器
            if (port.IsOpen)
            {
                port.Close();
            }
        }
        #region 串口下拉列表刷新
        /// <summary>
        /// 刷新下拉列表顯示
        /// </summary>
        private void GetSerialLstTb1()
        {
            //清除cmb_portname顯示
            cmb_portname.SelectedIndex = -1;
            cmb_portname.Items.Clear();
            //獲取串口列表
            string[] serialLst = SerialPort.GetPortNames();
            if (serialLst.Length > 0)
            {
                //取串口進(jìn)行排序
                Array.Sort(serialLst);
                //將串口列表輸出到cmb_portname
                cmb_portname.Items.AddRange(serialLst);
                cmb_portname.SelectedIndex = 0;
            }
        }
        /// <summary>
        /// 消息處理
        /// </summary>
        /// <param name="m"></param>
        protected override void WndProc(ref Message m)
        {
            switch (m.Msg)                                  //判斷消息類型
            {
                case WM_DEVICE_CHANGE:                      //設(shè)備改變消息
                    {
                        GetSerialLstTb1();                  //設(shè)備改變時重新花去串口列表
                    }
                    break;
            }
            base.WndProc(ref m);
        }
        #endregion
        private void label11_Click(object sender, EventArgs e)
        {
        }
        private void txt_slave1_TextChanged(object sender, EventArgs e)
        {
        }
        private void label7_Click(object sender, EventArgs e)
        {
        }
        private void txt_startAddr1_TextChanged(object sender, EventArgs e)
        {
        }
        private void label8_Click(object sender, EventArgs e)
        {
        }
        private void txt_length_TextChanged(object sender, EventArgs e)
        {
        }
    }
}

在線程中對控件的屬性進(jìn)行操作可能會出現(xiàn)代碼異常,可以使用Invoke委托方法完成相應(yīng)的操作:

public void SetMsg(string msg)
{
richTextBox1.Invoke(new Action(() => { richTextBox1.AppendText(msg); }));
}

在進(jìn)行自動讀/寫操作時,為避免多次點(diǎn)擊按鍵控件,多次重復(fù)建立新線程;在進(jìn)入自動讀寫線程中時,將對應(yīng)的按鍵控件失能,等待停止讀寫操作時再使能:

private void AutomaticTest()
{
    AutoFlag = true;
    button1.Enabled = false;

    InitSerialPortParameter();
    master = ModbusSerialMaster.CreateRtu(port);

    Task.Factory.StartNew(() =>
    {
        //初始化串口參數(shù)
        
        while (AutoFlag)
        {
            
            try
            {

                ExecuteFunction();
            
            }
            catch (Exception)
            {
                MessageBox.Show("初始化異常");
            }
            Thread.Sleep(500);
        }
    });
}

自動獲取當(dāng)前設(shè)備的可用串口實現(xiàn)如下:

#region 串口下拉列表刷新
/// <summary>
        /// 刷新下拉列表顯示
        /// </summary>
private void GetSerialLstTb1()
{
    //清除cmb_portname顯示
    cmb_portname.SelectedIndex = -1;
    cmb_portname.Items.Clear();
    //獲取串口列表
    string[] serialLst = SerialPort.GetPortNames();
    if (serialLst.Length > 0)
    {
        //取串口進(jìn)行排序
        Array.Sort(serialLst);
        //將串口列表輸出到cmb_portname
        cmb_portname.Items.AddRange(serialLst);
        cmb_portname.SelectedIndex = 0;
    }
}

/// <summary>
        /// 消息處理
        /// </summary>
        /// <param name="m"></param>
protected override void WndProc(ref Message m)
{
    switch (m.Msg)                                  //判斷消息類型
    {
        case WM_DEVICE_CHANGE:                      //設(shè)備改變消息
            {
                GetSerialLstTb1();                  //設(shè)備改變時重新花去串口列表
            }
            break;
    }
    base.WndProc(ref m);
}
#endregion

對本次實例進(jìn)行測試需要使用到串口模擬軟件,串口模擬器可以到網(wǎng)上下載

Modbus從站需要完成一下兩步操作:

一、菜單欄Connection-----Connect

二、菜單欄Setup-----Slave Definition

最后需要運(yùn)行自己創(chuàng)建的Modbus RTU Master上位機(jī),完成相應(yīng)的配置:

實現(xiàn)的最終效果:

到此這篇關(guān)于C# NModbus RTU通信實現(xiàn)方法詳解的文章就介紹到這了,更多相關(guān)C# NModbus RTU通信內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 二叉樹的遍歷算法(詳細(xì)示例分析)

    二叉樹的遍歷算法(詳細(xì)示例分析)

    以下代碼是對二叉樹的遍歷算法進(jìn)行了分析介紹,需要的朋友可以參考下
    2013-05-05
  • C#操作XML方法詳解

    C#操作XML方法詳解

    對于XML讀寫操作,項目中經(jīng)常要用到,之前木有好好總結(jié)過,例如LINQ TO XML也用過,這篇文章主要介紹了C#操作XML的方法
    2021-11-11
  • C#圖片處理如何生成縮略圖的實現(xiàn)

    C#圖片處理如何生成縮略圖的實現(xiàn)

    本文主要介紹了C#圖片處理如何生成縮略圖的實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-02-02
  • C#實現(xiàn)中文日歷Calendar

    C#實現(xiàn)中文日歷Calendar

    這篇文章介紹了C#實現(xiàn)中文日歷Calendar的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-05-05
  • C#使用IronPython庫調(diào)用Python腳本

    C#使用IronPython庫調(diào)用Python腳本

    這篇文章介紹了C#使用IronPython庫調(diào)用Python腳本的方法,文中通過示例代碼介紹的非常詳細(xì)。對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-06-06
  • C#實現(xiàn)簡單過濾非法字符實例

    C#實現(xiàn)簡單過濾非法字符實例

    這篇文章主要介紹了C#實現(xiàn)簡單過濾非法字符的方法,涉及C#針對字符串遍歷與判斷的相關(guān)技巧,非常簡單實用,需要的朋友可以參考下
    2015-11-11
  • C#固定大小緩沖區(qū)及使用指針復(fù)制數(shù)據(jù)詳解

    C#固定大小緩沖區(qū)及使用指針復(fù)制數(shù)據(jù)詳解

    這篇文章主要為大家介紹了C#固定大小緩沖區(qū)及使用指針復(fù)制數(shù)據(jù)詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-12-12
  • C#建立測試用例系統(tǒng)的示例代碼

    C#建立測試用例系統(tǒng)的示例代碼

    這篇文章主要介紹了C#建立測試用例系統(tǒng)的方法,文中示例代碼非常詳細(xì),幫助大家更好的理解和學(xué)習(xí),感興趣的朋友可以了解下
    2020-07-07
  • 最好用的WPF加載動畫功能

    最好用的WPF加載動畫功能

    當(dāng)開發(fā)應(yīng)用程序時,提供良好的用戶體驗(UX)是至關(guān)重要的,加載動畫作為一種有效的溝通工具,它不僅能告知用戶系統(tǒng)正在工作,還能夠通過視覺上的吸引力來增強(qiáng)整體用戶體驗,本文給大家介紹了最好用的WPF加載動畫功能,需要的朋友可以參考下
    2025-01-01
  • C#面向切面編程之AspectCore用法詳解

    C#面向切面編程之AspectCore用法詳解

    AspectCore?是Lemon名下的一個國產(chǎn)Aop框架,提供了一個全新的輕量級和模塊化的Aop解決方案,下面我們就來深入了解下AspectCore在C#中的具體使用吧
    2024-01-01

最新評論