当前位置:网站首页>É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
边栏推荐
- Jimureport building block report v1 Version 4.2 release, free visual low code report
- JVM - automatic memory management - 2 - garbage collector and memory allocation strategy
- Spotmax update: scalable statistics, instance preheating, intelligent storage, providing multiple cost reduction guarantees
- 黑五 圣诞节
- 【TiChoo资讯站】
- 行业分享 | TiChoo数据CEO 陆诗冬展望全球视频电商未来蓝图
- TiChoo数据分析选品 { 资讯站 }
- 【TiChoo资讯站】TikTok及跨境电商周报
- 行业分享 | TiChoo数据即将出席2022年海外短视频行业峰会
- tiktok 数据分析平台
猜你喜欢
随机推荐
- nuget的几个地址
- 使用Text.json解析Json文件
- 常用的SQL语句
- 使用多线程写winform程序
- Modbus协议编写与测试
- 使用多线程,Invoke和Action 访问SQL数据库
- Access数据库练习
- 泛型类, 泛型接口的继承, 委托
- 泛型类,泛型接口
- is 和 as的用法
- 多线程的深入理解
- 异步调用,多线程
- 跨域请求无法携带Cookie的问题
- Jenkins 入门
- Jenkins 分布式架构
- Jenkins 配置中文显示(汉化)
- Jenkins 通过API 执行 grovvy 脚本
- Jenkins API接入指南
- Jenkins 通过API获取从节点的secret
- 浅析npm run serve命令
- I think code is a work of art. She's beautiful
- Push failed Dst refspec V1.0.0 matches more than one.
- 微服务系列--深入理解RPC底层原理与设计实践
- Try the map and slice of the model version in go 1.18
- [highcharts] 04_ wrap
- (highly recommended) mobile audio and video from zero to start
- 微服務系列--深入理解RPC底層原理與設計實踐
- Push failed Dst refspec V1.0.0 matches more than one.
- Série de microservices - compréhension approfondie des principes sous - jacents et des pratiques de conception du CPR
- Push failed DST refspec v1. 0,0 matches more than one.
- Analyse de la commande NPM Run Service
- Jenkins obtient le secret du noeud via l'API
- Jenkins API Access Guide
- Quickly write a vs code plug-in
- Yyds dry goods inventory trunk (I)
- Modify a value to make Scrollview and listview elastic and APK volume optimized
- Jenkins exécute le script grovvy via l'API
- Jenkins configure l'affichage chinois (chinois)
- Jenkins Distributed Architecture
- Introduction à Jenkins