当前位置:网站首页>Écrire et tester le Protocole Modbus

Écrire et tester le Protocole Modbus

2022-01-15 02:08:26 La lave de Rodinia

ModbusCréation d'outils,
MODBUSAccord:
1、Lire la bobine de sortie(Code de fonction:01)

Tx:01 01 00 00 00 0A BC 0D
Adresse de la station esclave(01)+Code de fonction(01)+Adresse de départ(00 00)+Nombre de bobines10(00 0A)+CRC(BC 0D)
Rx:01 01 02 0F 00 BC 0C
Adresse de la station esclave(01)+Code de fonction(01)+Nombre d'octets 2(02)+État de la bobine(0F 00)+CRC(BC 0C)

2、Force une seule bobine(Code de fonction05)

Tx:01 05 00 03 00 00 3D CA
Adresse de la station esclave(01)+Code de fonction(05)+Adresse de la bobine(00 03)+Opérande(00 00)+CRC(3D CA)
Rx:01 05 00 03 00 00 3D CA
Retour du message original

3、Lire le registre de conservation(Code de fonction03)

Tx:01 03 00 00 00 0A C5 CD
Adresse de la station esclave(01)+Code de fonction(03)+Adresse de départ(00 00)+Nombre de registres(00 0A)+CRC(C5 CD)
Rx:01 03 14 00 37 00 2C 00 21 00 0A 00 00 00 00 00 00 00 00 00 00 00 00 7C CC
Adresse de la station esclave(01)+Code de fonction(03)+Nombre d'octets(14)+ Byte Status (00 37 00 2C 00 21 00 0A 00 00 00 00 00 00 00 00 00 00 00 00)+CRC(7C CC)

4、 Préréglage de plusieurs registres (Code de fonction10【10Décimal16】)

Tx:01 10 00 00 00 02 04 42 C8 00 00 66 29
Adresse de la station esclave(01)+Code de fonction(10)+Adresse de départ(00 00)+Nombre de registres(00 02)+Nombre d'octets(04)+ Nombre de préréglages (42 C8 00 00)+CRC(66 29)
Rx:01 10 00 00 00 02 41 C8
Adresse de la station esclave(01)+Code de fonction(10)+Adresse de départ(00 00)+Nombre de registres(00 02)+CRC(41 C8)

using System;
using System.Collections.Generic;
using System.IO.Ports;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;

namespace DAL
{
    
    public class Modbus_
    {
    
        private SerialPort _myCom;
        private byte ucCRCHi = 0xFF;
        private byte ucCRCLo = 0xFF;
        // Définir un tableau d'octets de réception 
        byte[] bData = new byte[1024];
        byte mReceiveByte; // Pour recevoir des octets 
        int mReceiveByteCount = 0; // Nombre d'octets reçus 
        // Définir l'adresse de l'appareil 
        int CurrentAddr;
        int iMWordLen;
        int iMBitLen;
        // Définir le message de retour 
        string strUpData;



        //Propriétés
        public SerialPort MyCom {
     get => _myCom; set => _myCom = value; }
        public Modbus_()//Constructeur
        {
    
            this.MyCom = new SerialPort();
        }

        #region  Activer et désactiver la méthode de port série 
        /// <summary>
        ///  Méthode d'ouverture du port série  [9600 N 8 1] 8: Aucune validation  1:Stop bit
        /// </summary>
        /// <param name="iBaudRate">Taux de Baud</param>
        /// <param name="IPortNo">Numéro de port</param>
        /// <param name="iDataBits">Bits de données</param>
        /// <param name="iParity">Bit de parité</param>
        /// <param name="iStopBits">Stop bit</param>
        /// <returns></returns>
        //Taux de Baud, Numéro de port, Bits de données, Parité, Stop bit
        public bool OpenMyComm(int iBaudRate, string IPortNo, int iDataBits, Parity iParity, StopBits iStopBits)
        {
    
            try
            {
    
                if (MyCom.IsOpen)
                {
    
                    MyCom.Close();
                }
                // Définir les propriétés du port série ;
                MyCom.BaudRate = iBaudRate;
                MyCom.PortName = IPortNo;
                MyCom.DataBits = iDataBits;
                MyCom.Parity = iParity;
                MyCom.StopBits = iStopBits;
                MyCom.ReceivedBytesThreshold = 1;// Définir le nombre d'octets de cache d'entrée 
                MyCom.DataReceived += MyCom_DataReceived; //Lier les événements

                MyCom.Open();
                return true;
            }
            catch (Exception ex)
            {
    
                throw new Exception(ex.Message);
            }

        }
        /// <summary>
        /// Fermez le port série
        /// </summary>
        /// <returns></returns>
        private bool ClosePort()
        {
    
            if (MyCom.IsOpen == true)
            {
    
                MyCom.Close();
                return true;
            }
            else
                return false;
        }
        #endregion

        private void MyCom_DataReceived(object sender, SerialDataReceivedEventArgs e)
        {
    
            //Analyse
            while (MyCom.BytesToRead>0)
            {
    
                mReceiveByte = (byte)MyCom.ReadByte();
                bData[mReceiveByteCount] = mReceiveByte;//Si vous lisez, Alors la requête est tirée de l'augmentation 
                mReceiveByteCount += 1;
                if (mReceiveByteCount>=1024)
                {
    
                    mReceiveByteCount = 0;
                    MyCom.DiscardInBuffer();// Effacer le cache d'entrée 
                    return;
                }
                // Lire le registre de conservation  Code de fonction0x03.  Si le premier octet est une adresse esclave et que le deuxième octet est long 
                // iMWordLen La longueur du registre est8*2 Longueur des octets,  En plus de ce qui est occupé devant 5Bits
                if (bData[0] == (byte)CurrentAddr && bData[1] == 0x03 && mReceiveByteCount >= (iMWordLen * 2 + 5))
                {
    
                    strUpData = "";
                    for (int i = 0; i < iMWordLen * 2 + 5; i++)
                    {
    
                        strUpData = strUpData + " " + bData[i].ToString("X2");
                    }
                    MyCom.DiscardInBuffer();
                }
            };
        }

        #region Lire le registre de conservation Code de fonction03
        // MODBUSLire le registre de conservation iAddress Adresse de départ(0C'est parti.),iLength Nombre de registres
        // Demande de station principale :01 03 00 00 00 06 70 08
        //Adresse 1Octets
        //Code de fonction 1Octets 0x03
        // Adresse du registre de départ  2Octets 0x0000~0x0005
        //Nombre de registres 2Octets 0x01~0x06
        //CRCVérification 2Octets
        /*Tx:01 03 00 00 00 0A C5 CD Adresse de la station esclave(01)+Code de fonction(03)+Adresse de départ(00 00)+Nombre de registres(00 0A)+CRC(C5 CD) Rx:01 03 14 00 37 00 2C 00 21 00 0A 00 00 00 00 00 00 00 00 00 00 00 00 7C CC Adresse de la station esclave(01)+Code de fonction(03)+Nombre d'octets(14)+ Byte Status (00 37 00 2C 00 21 00 0A 00 00 00 00 00 00 00 00 00 00 00 00)+CRC(7C CC) */
        public byte[] ReadKeepReg(int iDevAdd,int iAddress,int iLength)
        {
    
            byte[] ResByte = null;
            CurrentAddr = iDevAdd;
            iMWordLen = iLength;
            //if (comBusying == true) Thread.Sleep(250);
            byte[] SendCommand = new byte[8];
            SendCommand[0] = (byte)iDevAdd; //Adresse de la station esclave
            SendCommand[1] = 0x03; //Code de fonction(03)
            SendCommand[2] = (byte)((iAddress-iAddress%256)/256);//Adresse élevée
            SendCommand[3] = (byte)((iAddress % 256) / 256); // Adresse basse 
            SendCommand[4] = (byte)((iLength - iLength % 256) / 256);// Longueur élevée 
            SendCommand[5] = (byte)(iLength % 256); // Longueur inférieure 
            Crc16(SendCommand, 6);
            SendCommand[6] = ucCRCLo;
            SendCommand[7] = ucCRCHi;
            //Deuxième étape, Envoyer un message
            try
            {
    
                //Envoyer la commande
                MyCom.Write(SendCommand, 0, 8);//Offset0, Longueur8
            }
            catch
            {
    
                return null;
            }
            //Troisième étape:Analyser le message
            mReceiveByteCount = 0;
            Thread.Sleep(100);

            ResByte = HexStringToByteArray(this.strUpData);
            return ResByte;

            //1,Message d'épissage
        }
        #endregion



        #region LRCVérification
        private string LRC(string strLRC)
        {
    
            int d_lrc = 0;
            string h_lrc = "";
            int l = strLRC.Length;
            for (int c = 0; c < l; c = c + 2)
            {
    
                string c_data = strLRC.Substring(c, 2);
                d_lrc = d_lrc + (Int32)Convert.ToByte(c_data, 16);
                //d_lrc = d_lrc + Convert.ToInt32(c_data);
            }
            if (d_lrc >= 255)
                d_lrc = d_lrc % 0x100;
            h_lrc = Convert.ToInt32(~d_lrc + 1).ToString("X");
            if (h_lrc.Length > 2)
                h_lrc = h_lrc.Substring(h_lrc.Length - 2, 2);
            return h_lrc;
        }
        #endregion

        #region CRCVérification
        private static readonly byte[] aucCRCHi = {
    
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x00, 0xC1, 0x81, 0x40,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40, 0x01, 0xC0, 0x80, 0x41, 0x01, 0xC0, 0x80, 0x41,
             0x00, 0xC1, 0x81, 0x40
         };
        private static readonly byte[] aucCRCLo = {
    
             0x00, 0xC0, 0xC1, 0x01, 0xC3, 0x03, 0x02, 0xC2, 0xC6, 0x06, 0x07, 0xC7,
             0x05, 0xC5, 0xC4, 0x04, 0xCC, 0x0C, 0x0D, 0xCD, 0x0F, 0xCF, 0xCE, 0x0E,
             0x0A, 0xCA, 0xCB, 0x0B, 0xC9, 0x09, 0x08, 0xC8, 0xD8, 0x18, 0x19, 0xD9,
             0x1B, 0xDB, 0xDA, 0x1A, 0x1E, 0xDE, 0xDF, 0x1F, 0xDD, 0x1D, 0x1C, 0xDC,
             0x14, 0xD4, 0xD5, 0x15, 0xD7, 0x17, 0x16, 0xD6, 0xD2, 0x12, 0x13, 0xD3,
             0x11, 0xD1, 0xD0, 0x10, 0xF0, 0x30, 0x31, 0xF1, 0x33, 0xF3, 0xF2, 0x32,
             0x36, 0xF6, 0xF7, 0x37, 0xF5, 0x35, 0x34, 0xF4, 0x3C, 0xFC, 0xFD, 0x3D,
             0xFF, 0x3F, 0x3E, 0xFE, 0xFA, 0x3A, 0x3B, 0xFB, 0x39, 0xF9, 0xF8, 0x38,
             0x28, 0xE8, 0xE9, 0x29, 0xEB, 0x2B, 0x2A, 0xEA, 0xEE, 0x2E, 0x2F, 0xEF,
             0x2D, 0xED, 0xEC, 0x2C, 0xE4, 0x24, 0x25, 0xE5, 0x27, 0xE7, 0xE6, 0x26,
             0x22, 0xE2, 0xE3, 0x23, 0xE1, 0x21, 0x20, 0xE0, 0xA0, 0x60, 0x61, 0xA1,
             0x63, 0xA3, 0xA2, 0x62, 0x66, 0xA6, 0xA7, 0x67, 0xA5, 0x65, 0x64, 0xA4,
             0x6C, 0xAC, 0xAD, 0x6D, 0xAF, 0x6F, 0x6E, 0xAE, 0xAA, 0x6A, 0x6B, 0xAB,
             0x69, 0xA9, 0xA8, 0x68, 0x78, 0xB8, 0xB9, 0x79, 0xBB, 0x7B, 0x7A, 0xBA,
             0xBE, 0x7E, 0x7F, 0xBF, 0x7D, 0xBD, 0xBC, 0x7C, 0xB4, 0x74, 0x75, 0xB5,
             0x77, 0xB7, 0xB6, 0x76, 0x72, 0xB2, 0xB3, 0x73, 0xB1, 0x71, 0x70, 0xB0,
             0x50, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 0x96, 0x56, 0x57, 0x97,
             0x55, 0x95, 0x94, 0x54, 0x9C, 0x5C, 0x5D, 0x9D, 0x5F, 0x9F, 0x9E, 0x5E,
             0x5A, 0x9A, 0x9B, 0x5B, 0x99, 0x59, 0x58, 0x98, 0x88, 0x48, 0x49, 0x89,
             0x4B, 0x8B, 0x8A, 0x4A, 0x4E, 0x8E, 0x8F, 0x4F, 0x8D, 0x4D, 0x4C, 0x8C,
             0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 0x46, 0x86, 0x82, 0x42, 0x43, 0x83,
             0x41, 0x81, 0x80, 0x40
         };
        private void Crc16(byte[] pucFrame, int usLen)
        {
    
            int i = 0;
            ucCRCHi = 0xFF;
            ucCRCLo = 0xFF;
            UInt16 iIndex = 0x0000;

            while (usLen-- > 0)
            {
    
                iIndex = (UInt16)(ucCRCLo ^ pucFrame[i++]);
                ucCRCLo = (byte)(ucCRCHi ^ aucCRCHi[iIndex]);
                ucCRCHi = aucCRCLo[iIndex];
            }

        }

        #endregion

        #region  Suppression de l'en - tête et vérification du message ,Convertir un tableau d'octets
        /// <summary>
        ///  Message converti en tableau d'octets 
        /// </summary>
        /// <param name="s"></param>
        /// <returns></returns>
        private byte[] HexStringToByteArray(string s)
        {
    
            string Result = string.Empty;
            byte[] buffer = null;
            if (s != null && s.Length > 1)
            {
    
                string[] str = s.Trim().Split(' ');
                string[] Res = new string[str.Length - 5];
                for (int i = 0; i < str.Length - 5; i++)
                {
    
                    Res[i] = str[i + 3];
                }
                for (int i = 0; i < Res.Length; i++)
                {
    
                    Result += Res[i] + " ";
                }

                string[] strArr = Result.Trim().Split(' ');
                buffer = new byte[strArr.Length];
                for (int i = 0; i < strArr.Length; i++)
                {
    
                    buffer[i] = Convert.ToByte(strArr[i], 16);
                }
            }
            return buffer;
        }
        #endregion
    }
}

ÉtablissementwinformTests

using System;
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 DAL;
using System.IO.Ports;

namespace Modbus
{
    
    public partial class FrmModbus : Form
    {
    
        public FrmModbus()
        {
    
            InitializeComponent();
        }
        Modbus_ objMbus = new Modbus_(); 
        private void btn_Connect_Click(object sender, EventArgs e)
        {
    
            if (objMbus.OpenMyComm(9600, "COM4", 8, Parity.None, StopBits.One))
            {
    
                MessageBox.Show("Ouverture réussie");
            }
            else
                MessageBox.Show("Impossible d'ouvrir");
        }

        private void btn_ReadReg_Click(object sender, EventArgs e)
        {
    
            byte[] Res = objMbus.ReadKeepReg(1, 0, 10);// Numéro de station esclave ,Offset,Longueur
            if (Res.Length>0)
            {
    
                for (int i = 0; i < Res.Length; i++)
                {
    
                    this.listBox1.Items.Add(Res[i].ToString());
                }
            }
        }
    }
}

版权声明
本文为[La lave de Rodinia]所创,转载请带上原文链接,感谢
https://chowdera.com/2022/01/202201080558307369.html

随机推荐