工業軟體調試中往往會遇到需要與modbus tcp裝置進行通訊的情況,為減少程式設計中存在的Bug,通常我們需要對其進行簡單的模拟測試,便于縮短真機調試。
正常的幾種方法:
- 第一種方式,通過真實的裝置進行模拟,例如PLC等
但是這一方式,往往受制于PLC程式設計,PLC端需編寫完成相應的通訊子產品,且需配合PLC程式設計軟體手動模拟信号實作工業軟體測試,有部分位址還需由外部接線進行觸發,無法進行全部位址模拟。
- 第二種方式,通過市面上鎖提供的Modbus Tcp軟體進行模拟測試
該種方式雖然能滿足部分調試要求,但想找到一款比較全面的調試工具還是比較難的。有些調試工具無法同時滿足線圈、離散輸入、保持寄存器等位址的同時監控;有些調試工具隻支援線圈、保持寄存器的寫入操作;還有些調試工具對位址總數有一定限制,無法模拟全部位址效果。
-
第三種方式,自己建立Modbus Tcp服務端
由于工具是為自行開發,是以功能上相對市面上所提供的調試工具更加靈活與全面,最重要是設計出的調試工具更加符合自己的調試習慣。
關鍵代碼展示,程式使用C#進行開發
1、建立服務端監聽,啟動伺服器
try
{
IPAddress Ip;
int Port;
//擷取IP位址
try
{
Ip = IPAddress.Parse(this.txt_ip.Text);
}
catch
{
MessageBox.Show("請輸入正确的IP位址!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
//擷取端口号
try
{
Port = Convert.ToInt32(this.txt_port.Text);
}
catch
{
MessageBox.Show("請輸入正确的IP位址!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
System.Net.NetworkInformation.IPGlobalProperties iproperties = System.Net.NetworkInformation.IPGlobalProperties.GetIPGlobalProperties();
IPEndPoint[] ipEndPoints = iproperties.GetActiveTcpListeners();
foreach (var con in ipEndPoints)
{
if (con.Port == Port)
{
MessageBox.Show("目前端口已被占用!", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
return;
}
}
//建立通訊
_server = new TcpListener(Ip, Port);
_server.Start();
_slave = ModbusTcpSlave.CreateTcp(_deviceNo, _server);
_slave.DataStore = _dataStore;
_slave.ListenAsync();
this.btn_start.Enabled = false;
this.btn_stop.Enabled = true;
this.tr_CoilDiscretes.Enabled = true;
this.tr_InputDiscretes.Enabled = true;
this.tr_HoldingRegisters.Enabled = true;
this.tr_InputRegisters.Enabled = true;
}
catch (Exception r)
{
MessageBox.Show(r.Message.ToString(), "出錯", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
2、界面顯示
try
{
if (!this.dgv_CoilDiscretes.Focused)
{
ModbusDataCollection<bool> data_CoilDiscretes = _dataStore.CoilDiscretes;
dt_Coil.Clear();
for (int i = i_startAddress_Coil; i < i_lenght_Coil; i++)
{
dt_Coil.Rows.Add(i - 1, data_CoilDiscretes[i]);
}
this.dgv_CoilDiscretes.DataSource = dt_Coil;
}
}
catch (Exception r)
{
MessageBox.Show(r.Message.ToString(), "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
3、資料寫入
try
{
ushort address = Convert.ToUInt16(dt_Coil.Rows[e.RowIndex][0]);
bool value = Convert.ToBoolean(dt_Coil.Rows[e.RowIndex][1]);
_dataStore.CoilDiscretes[address + 1] = value;
this.tr_CoilDiscretes.Enabled = true;
this.gb1.Focus();
}
catch (Exception r)
{
MessageBox.Show(r.Message.ToString(), "錯誤", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
程式界面展示