Bonjour,
j'essais de recréer un programme qui était à l'origine en vb6 (visual basic ) en C # pouvez me dire
s'il est bon s'il vous plait ?
Pour communiquer avec mon appareil j'utilise le protocole de liaison suivant :
Protocol MODBUS/JBUS en mode RTU .(9600 Bds,1 bit start,8 bit de données, 1 bit stop, sans parité
(RS485)
la liaison série n'étant pas la tâche la plus prioritaire de l'appareil le logiciel de liaison doit prévoir 3 essais de dialogue avant de conclure à un défaut de transmission. il est inutile et déconseillé d'interroger l'appareil plus d'une fois toutes les 500 ms.
L'appareil peut renvoyer les 3 codes d'erreur suivant à une demande de données :
01 : Fonction non reconnue
02 : Adresse de données incorrecte
03 : Valeur des données incorrecte
Programme en vb6 :
Public Sub ModBus(c() As Byte)
Dim Buffer
Dim x(100) As Byte
Dim Tentative, j As Integer
Dim td As Double
Dim delairep As Double
On Error GoTo finProcedure
Err.Clear
Tentative = 0
Form1.MSComm1.InputLen = 0 'Lecture du buffer par 1
début:
t = Timer
While Abs(t - Timer) < 0.05
Wend
Tentative = Tentative + 1
If Tentative > 3 Then 'Si à la troisième interrogation la réponse est toujours erronée opération abandonnée
Call MessageErreur(MessageMod(26), 1)
CodeErreur = 0
Exit Sub
End If
'test remote ADAC
If (Fonction = 5 And AdataL = 7) Then
x(0) = AdresADAC
Else
x(0) = AdresseModbus
End If
x(1) = Fonction
x(2) = AdataH
x(3) = AdataL
x(4) = LdataH
x(5) = LdataL
For i = 0 To 5
If x(i) < 0 Or x(i) > 255 Then
CodeErreur = 2
Exit Sub
End If
Next i
Call CalculCRC(x(), 5, CrcH, CrcL)
If Form1.MSComm1.PortOpen = False Then
CodeErreur = 3
Exit Sub
End If
Form1.MSComm1.InBufferCount = 0
If ToxGain = True Then '???
ToxGain = False
Form1.MSComm1.Output = Chr(x(0)) + Chr(x(1)) + Chr(x(2)) + Chr(x(3)) + Chr(x(4)) + Chr(x(5)) + Chr(CrcL) + Chr(CrcH)
Else
Form1.MSComm1.Output = Chr(x(0)) + Chr(Fonction) + Chr(AdataH) + Chr(AdataL) + Chr(LdataH) + Chr(LdataL) + Chr(CrcL) + Chr(CrcH)
End If
td = Timer
If Fonction = 3 Then
Buffer = (2 * LdataL + 5)
Else
Buffer = 8
End If
Do Until Form1.MSComm1.InBufferCount >= Buffer 'Nous attendons d'avoir au moins 1 réponse
'Debug.Print (Timer - td)
delairep = 0.4
If (x(2) = 0) Then
If x(3) = 31 Then
delairep = 4
End If
End If
If (Timer - td) > delairep Then 'Si le temps de récupération des données dépasse 0.1 seconde nous sortons de la boucle
Debug.Print " appel :"; AppelBloc; " inbuf= "; Form1.MSComm1.InBufferCount; "bufferdemande = "; Buffer
DoEvents
GoTo début
End If
If Form1.MSComm1.PortOpen = False Then 'L'utilisateur a décidé de couper la communication avec la sonde
CodeErreur = 0
Exit Sub
End If
Loop
'Debug.Print "temps de réponse = "; (Timer - td)
frmSequenceur.tmrMiseEnService.Enabled = True
Buffer = Form1.MSComm1.Input
For i = 0 To 2 'Boucle pour récupérer les trois premiers caractères
c(i) = AscB(MidB(Buffer, i + 1, 1))
Next i
'Ce n'est pas la bonne adresse de l'appareil
If Val(GetSetting(App.EXEName, "Général", "AdresseModBus", Setting)) <> AdresseModbus Then AdresseModbus = Val(GetSetting(App.EXEName, "Général", "AdresseModBus", Setting))
If c(0) <> AdresseModbus Then
Call MessageErreur(MessageMod(28) & AdresseModbus & MessageMod(99) & c(0), 1)
GoTo début
End If
'La sonde renvoi un code erreur
If c(1) >= 128 Then
Tentative = Tentative + 1
If c(2) = 1 And Tentative > 3 Then Call MessageErreur(MessageMod(29), 1)
If c(2) = 2 And Tentative > 3 Then Call MessageErreur(MessageMod(30), 1)
If c(2) = 3 And Tentative > 3 Then Call MessageErreur(MessageMod(31), 1)
Exit Sub
End If
On Error Resume Next
If Fonction = 3 Then
For j = 3 To (2 * LdataL + 4)
c(j) = AscB(MidB(Buffer, j + 1, 1))
Next j
Call CalculCRC(c(), j - 3, CrcH, CrcL)
If c(j - 1) <> CrcH Or c(j - 2) <> CrcL Then
GoTo début
End If
End If
If Fonction = 5 Or Fonction = 6 Then
For j = 3 To 7
c(j) = AscB(MidB(Buffer, j + 1, 1))
Next j
Call CalculCRC(c(), 5, CrcH, CrcL)
If c(6) <> CrcL Or c(7) <> CrcH Then
GoTo début
End If
End If
If Mid(Form1.lstInformations.List(Form1.lstInformations.ListIndex), 18, Len(Form1.lstInformations.List(Form1.lstInformations.ListIndex)) - 11) = MessageMod(26) Then
Call MessageErreur(MessageMod(32), 0)
End If
CodeErreur = 1
Exit Sub
finProcedure:
If Err.Number <> 0 Then MsgBox "l'erreur n° " & Err.Number & " est sur venu (" & Err.Description & " ). ", vbCritical, "ERREUR !!"
Resume Next
Err.Clear
End Sub
et voici le programme qui j'ai fait en c# :
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO.Ports;
using System.Diagnostics;
using System.Timers;
using System.Drawing;
namespace Test
{
public static class Com
{
static byte[] c = new byte[100];
public static byte[] b = new byte[100];
public static int AdresseModBus = 161;
public static int Fonction;
public static int AdataH;
public static int AdataL;
public static int LdataH;
public static int LdataL;
public static int ret = 0;
public static int r = 0;
public static int Demande;
public static long CodeErreur;
………
……..
}
public static byte[] ModBus(byte[] c)
{
// byte[] b = new byte[100];
int Tentative, j;
double td, delairep;
byte Buffer;
int t;
int crch, crcl;
int[] crchcrcl = new int[2];
Tentative = 0;
Program.principale_.serialPort1.ReceivedBytesThreshold = 1;
début:
t = DateTime.Now.Millisecond + DateTime.Now.Millisecond;
Console.Write(t - DateTime.Now.Millisecond);
while ((t - DateTime.Now.Second) <0.05) { }
Tentative++;
if (Tentative > 3)
{
CodeErreur = 0;
Program.principale_.Invoke(new messagecombobox(messageboxx), Program.principale_.Heure + " : Pas de réponse");
Program.principale_.ledcom.BackColor = Color.Red;
Application.Exit();
}
c[0] = (byte)AdresseModBus;
c[1] = (byte)Fonction;
c[2] = (byte)AdataH;
c[3] = (byte)AdataL;
c[4] = (byte)LdataH;
c[5] = (byte)LdataL;
c[6] = (byte)CalculCRC(c, 5)[1];
c[7] = (byte)CalculCRC(c, 5)[0];
for (int i = 0; i < 6; i++)
{
if (c[i] < 0 || c[i] > 255)
Application.Exit();
}
Program.principale_.serialPort1.DiscardInBuffer();
Program.principale_.serialPort1.Write(c, 0, 8);
if (Program.principale_.serialPort1.IsOpen == false)
{
CodeErreur = 3;
Program.principale_.lstInformations.Text = Program.principale_.Heure + "Pas de réponse du boitier";
Program.principale_.serialPort1.Close();
Program.principale_.ledcom.BackColor = Color.Red;
Application.Exit();
}
for (int i = 0; i <=2*LdataL+5; i++)
{
try
{
x[i] = (byte)Program.principale_.serialPort1.ReadByte();
}
catch { break; }
}
td = ((double)DateTime.Now.TimeOfDay.TotalSeconds);
if (Fonction == 3)
{
Buffer = Convert.ToByte(2 * LdataL + 5);
}
else
{
Buffer = 8;
}
int nbreOctetsRecu;
do
{
delairep = 1;
if (c[2] == 0)
{
if (c[3] == 98)
delairep = 4;
}
Console.WriteLine(((double)DateTime.Now.TimeOfDay.TotalSeconds) - td);
if ((((double)DateTime.Now.TimeOfDay.TotalSeconds) - td) > delairep)
{
Debug.Print(" inbuf = " + Program.principale_.serialPort1.BytesToRead + " bufferdemande = " + Buffer);
Application.DoEvents();
goto début;
}
if (Program.principale_.serialPort1.IsOpen == false)
{
CodeErreur = 0;
Program.principale_.lstInformations.Text = "Vous avez coupez la communication";
Application.Exit();
}
nbreOctetsRecu = Program.principale_.serialPort1.BytesToRead;
}
while (nbreOctetsRecu < Buffer);
Buffer = (byte)Program.principale_.serialPort1.ReadByte();
for (int i = 0; i <= 2; i++)
{
c[i] = (byte)("" + Buffer).ElementAt(i + 1);
}
if (c[0] != AdresseModBus)
{
MessageBox.Show("Ce n'est pas la bonne addresse" + " " + AdresseModBus + " " + c[0]);
goto début;
}
if (c[1] >= 128)
{
Tentative++;
Program.principale_.lstInformations.Text = "Pas de réponse du boitier";
}
if (Fonction == 3) // permet de lire des mots 16 bits
{
for (j = 3; j <= (2 * LdataL + 4); j++)
x[j] = (byte)("" + Buffer).ElementAt(j + 1);
crchcrcl = CalculCRC(x, j - 3);
crch = crchcrcl[0];
crcl = crchcrcl[1];
if (x[j - 1] != crch || x[j - 2] != crcl)
{ goto début; }
}
if (Fonction == 6 || Fonction == 5)// la fonction 6 permet d'écrire des mots de 16 bits; la fonction 5 permet de forcer un bit de commande à 1 ou a 0
{
for (j = 3; j <= 7; j++)
x[j] = (byte)("" + Buffer).ElementAt(j + 1);
crchcrcl = CalculCRC(x, j - 3);
crch = crchcrcl[0];
crcl = crchcrcl[1];
if (x[j - 1] != crch || x[j - 2] != crcl)
{ goto début; }
}
return x;
}
Partager