【WinForm】C# Modbus RTU 通信学习过程-通信连接
学习想法:前面进行了Modbus RTU通信连接的学习,现在就开始学习运用NModbus4进行数据读取和写入了;
第一步:在上一次学习通信连接的基础上添加控件;
GroupBox : GroupBox3-读写;
ComboBox : cbxPort-读写模式选择;
numericUpDown : nudSlaveID-从站地址、nudStartAdr-起始地址、nudLength-地址长度;
Button : btnRW-读写按钮;
TextBox : rbxRWMsg-读写信息;
![](https://img-blog.csdnimg.cn/img_convert/3231dbaf98160b5f5c72936b085cc1f6.png)
第二步:ComboBox cbxPort-读写模式选择控件中添加相应选择信息
“读取输出线圈”、“读取离散输入”、“读取保持型寄存器”、“读取输入寄存器”、“写入单个线圈”、“写入多个线圈”、“写入单个寄存器”、“写入多个寄存器”;
![](https://img-blog.csdnimg.cn/img_convert/eee1a769db13e89cf9d78db653e864dc.png)
第三步:对 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;
}
}
}
第九步:程序验证
首先完成通信连接
![](https://img-blog.csdnimg.cn/img_convert/8ccf721aa18f481985bd8cd18ecf1e8a.png)
![](https://img-blog.csdnimg.cn/img_convert/88ac75dc53bd1d4bd16b5ce90c1d87e5.png)
![](https://img-blog.csdnimg.cn/img_convert/d6907603d4982be8f0da471633389c90.png)
1)写入单个线圈
![](https://img-blog.csdnimg.cn/img_convert/4213e2160cc26bae0c1f79507aacbf49.png)
2)写入多个线圈(多个地址数据以“,”隔开,更新时会自动计算并更新地址长度)
![](https://img-blog.csdnimg.cn/img_convert/1928784ae79cb3700bee0e2d14b53ffe.png)
3)写入单个寄存器
![](https://img-blog.csdnimg.cn/img_convert/060275f6521f685a09b8b241c764aaf7.png)
4)写入多个寄存器(多个地址数据以“,”隔开,更新时会自动计算并更新地址长度)
![](https://img-blog.csdnimg.cn/img_convert/3fa84be766fdcf7ba586c2f4f2dea6aa.png)
5)读取输出线圈
![](https://img-blog.csdnimg.cn/img_convert/49e2c6930b7ddd7142085a5332016982.png)
6)读取离散输入
![](https://img-blog.csdnimg.cn/img_convert/1901263e2445948dd649be9b990a4599.png)
7)读取保持型寄存器
![](https://img-blog.csdnimg.cn/img_convert/bcd8e71d7b71be59658be945ce860b16.png)
8)读取输入寄存器
![](https://img-blog.csdnimg.cn/img_convert/55bd92a6482d5734c7d2f6510f5df129.png)
最终交互画面
![](https://img-blog.csdnimg.cn/img_convert/54905ff5d50c3131705110f8b6e050ba.png)
以上就是这次【WinForm】C# Modbus RTU 通信学习过程之数据读取、写入了。