【WinForm】C# Modbus RTU 通信学习过程-通信连接
学习想法:前面进行了Modbus RTU通信连接的学习,现在就开始学习运用NModbus4进行数据读取和写入了;
第一步:在上一次学习通信连接的基础上添加控件;
GroupBox : GroupBox3-读写;
ComboBox : cbxPort-读写模式选择;
numericUpDown : nudSlaveID-从站地址、nudStartAdr-起始地址、nudLength-地址长度;
Button : btnRW-读写按钮;
TextBox : rbxRWMsg-读写信息;

第二步:ComboBox cbxPort-读写模式选择控件中添加相应选择信息
“读取输出线圈”、“读取离散输入”、“读取保持型寄存器”、“读取输入寄存器”、“写入单个线圈”、“写入多个线圈”、“写入单个寄存器”、“写入多个寄存器”;

第三步:对 cbxPort-读写模式选择、nudSlaveID-从站地址、nudStartAdr-起始地址、nudLength-地址长度这些控件添加Form1_Load事件进行默认选择和最小值限制;
//设置读写窗口默认选中项
cbxMode.SelectedIndex = 0;
nudSlaveID.Minimum = 1;
nudStartAdr.Minimum = 0;
nudLength.Minimum = 1;
//设置为默认输入法,即为英文半角
rbxRWMsg.ImeMode = ImeMode.Disable;
第四步:添加SetMsg方法,以便于在rbxRWMsg-读写信息显示读取结果
private void SetMsg<T>(List<T> result)//界面显示读取结果
{
string msg = string.Empty;
result.ForEach(m => msg += $"{m} ");
rbxRWMsg.Text = msg.Trim();
}
第五步:添加rbxRWMsg_TextChanged事件,以便于后续做“读”事件更新写入长度计数
private void rbxRWMsg_TextChanged(object sender, EventArgs e)//更新写入值计数
{
nudLength.Value = Regex.Matches(rbxRWMsg.Text, ",").Count + 1;
}
第六步:添加cbxMode_SelectedIndexChanged事件,当ComboBox : cbxPort-读写模式选择发生变化时切换Button : btnRW-读写按钮字样、TextBox : rbxRWMsg-读写信息控件是否有效;
private void cbxMode_SelectedIndexChanged(object sender, EventArgs e)// 模式切换事件
{
tbMessage.Clear();
if (cbxMode.SelectedItem.ToString().Contains("读取"))
{
btnRW.Text = "读取";
rbxRWMsg.Enabled = false;
}
else
{
btnRW.Text = "写入";
rbxRWMsg.Enabled = true;
}
}
第七步:添加事件“写入单个线圈-WriteSingleCoil”、“写入多个线圈-WriteArrayCoil”、“写入单个寄存器-WriteSingleRegister”、“写入多个寄存器-WriteArrayRegister”、“读取输出线圈-ReadCoils”、“读取输入线圈-ReadInputs”、“读取保持型寄存器-ReadHoldingRegisters”、“读取输入寄存器-ReadInputRegisters”;
/// <summary>
/// 写入单个线圈
/// </summary>
private void WriteSingleCoil()
{
bool result = false;
if (rbxRWMsg.Text.Equals("true", StringComparison.OrdinalIgnoreCase) || rbxRWMsg.Text.Equals("1", StringComparison.OrdinalIgnoreCase))
{
result = true;
}
master.WriteSingleCoil((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result);
}
/// <summary>
/// 批量写入线圈
/// </summary>
private void WriteArrayCoil()
{
List<string> strList = rbxRWMsg.Text.Split(',').ToList();
List<bool> result = new List<bool>();
strList.ForEach(m => result.Add(m.Equals("true", StringComparison.OrdinalIgnoreCase) || m.Equals("1", StringComparison.OrdinalIgnoreCase)));
master.WriteMultipleCoils((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result.ToArray());
}
/// <summary>
/// 写入单个寄存器
/// </summary>
private void WriteSingleRegister()
{
ushort result = Convert.ToUInt16(rbxRWMsg.Text);
master.WriteSingleRegister((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result);
}
/// <summary>
/// 批量写入寄存器
/// </summary>
private void WriteArrayRegister()
{
List<string> strList = rbxRWMsg.Text.Split(',').ToList();
List<ushort> result = new List<ushort>();
strList.ForEach(m => result.Add(Convert.ToUInt16(m)));
master.WriteMultipleRegisters((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, result.ToArray());
}
/// <summary>
/// 读取输出线圈
/// </summary>
/// <returns></returns>
private bool[] ReadCoils()
{
return master.ReadCoils((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
}
/// <summary>
/// 读取输入线圈
/// </summary>
/// <returns></returns>
private bool[] ReadInputs()
{
return master.ReadInputs((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
}
/// <summary>
/// 读取保持型寄存器
/// </summary>
/// <returns></returns>
private ushort[] ReadHoldingRegisters()
{
return master.ReadHoldingRegisters((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
}
/// <summary>
/// 读取输入寄存器
/// </summary>
/// <returns></returns>
private ushort[] ReadInputRegisters()
{
return master.ReadInputRegisters((byte)nudSlaveID.Value, (ushort)nudStartAdr.Value, (ushort)nudLength.Value);
}
第八步:添加Button : btnRW-读写按钮 btnRW_Click按钮读写事件;
private void btnRW_Click(object sender, EventArgs e)//读写事件
{
if (serialPort.IsOpen)
{
//根据选择的模式进行读写
switch (cbxMode.SelectedItem.ToString())
{
case "读取输出线圈":
SetMsg(ReadCoils().ToList());
break;
case "读取离散输入":
SetMsg(ReadInputs().ToList());
break;
case "读取保持型寄存器":
SetMsg(ReadHoldingRegisters().ToList());
break;
case "读取输入寄存器":
SetMsg(ReadInputRegisters().ToList());
break;
case "写入单个线圈":
if (rbxRWMsg.Text.Contains(","))
{
MessageBox.Show("输入值过多");
return;
}
WriteSingleCoil();
break;
case "写入多个线圈":
WriteArrayCoil();
break;
case "写入单个寄存器":
if (rbxRWMsg.Text.Contains(","))
{
MessageBox.Show("输入值过多");
return;
}
WriteSingleRegister();
break;
case "写入多个寄存器":
WriteArrayRegister();
break;
default:
break;
}
}
}
第九步:程序验证
首先完成通信连接



1)写入单个线圈

2)写入多个线圈(多个地址数据以“,”隔开,更新时会自动计算并更新地址长度)

3)写入单个寄存器

4)写入多个寄存器(多个地址数据以“,”隔开,更新时会自动计算并更新地址长度)

5)读取输出线圈

6)读取离散输入

7)读取保持型寄存器

8)读取输入寄存器

最终交互画面

以上就是这次【WinForm】C# Modbus RTU 通信学习过程之数据读取、写入了。