网站首页 > 技术文章 正文
客户需要一个电子看板,类似一个电视大小的, 可以显示生产的型号,单号数量等信息. 电子看板是用Modbus TCP通讯的. 生产线每完成一件产品的测试,扫码打包后, 实际产量要增加1, 所以要和生产数据库连接起来
下载一个开源的C# Modbus的工具
https://github.com/stephan1827/modbusTCP-DotNET
里面关键代码就是构建Modbus TCP的Header
报文头 报文的序列号2字节, 00 00表示ModbusTCP协议,数据长度2字节,设备地址1字节,
功能码为1字节,寄存器地址2字节,读取长度2字节
Modbus的操作对象有四种:线圈、离散输入、保持寄存器、输入寄存器。
对象
Coil线圈 可读可写
DiscreteInputs离散量 只读
InputRegister输入寄存器 只读
HoldingRegiste保持寄存器 可读可写
//功能码
private const byte fctReadCoil = 1;
private const byte fctReadDiscreteInputs = 2;
private const byte fctReadHoldingRegister = 3;
private const byte fctReadInputRegister = 4;
private const byte fctWriteSingleCoil = 5;
private const byte fctWriteSingleRegister = 6;
private const byte fctWriteMultipleCoils = 15;
private const byte fctWriteMultipleRegister = 16;
private const byte fctReadWriteMultipleRegister = 23;
// ------------------------------------------------------------------------
// Create modbus header for read action
private byte[] CreateReadHeader(ushort id, byte unit, ushort startAddress, ushort length, byte function)
{
byte[] data = new byte[12];
byte[] _id = BitConverter.GetBytes((short)id);
data[0] = _id[1]; // Slave id high byte
data[1] = _id[0]; // Slave id low byte
data[5] = 6; // Message size ,数据长度
data[6] = unit; // Slave address 设备地址
data[7] = function; // Function code 功能码
byte[] _adr = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startAddress));
data[8] = _adr[0]; // Start address 寄存器地址
data[9] = _adr[1]; // Start address
byte[] _length = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)length));
data[10] = _length[0]; // Number of data to read 读取长度
data[11] = _length[1]; // Number of data to read
return data;
}
// ------------------------------------------------------------------------
// Create modbus header for write action
private byte[] CreateWriteHeader(ushort id, byte unit, ushort startAddress, ushort numData, ushort numBytes, byte function)
{
byte[] data = new byte[numBytes + 11];
byte[] _id = BitConverter.GetBytes((short)id);
data[0] = _id[1]; // Slave id high byte
data[1] = _id[0]; // Slave id low byte
byte[] _size = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)(5 + numBytes)));
data[4] = _size[0]; // Complete message size in bytes
data[5] = _size[1]; // Complete message size in bytes
data[6] = unit; // Slave address
data[7] = function; // Function code
byte[] _adr = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)startAddress));
data[8] = _adr[0]; // Start address
data[9] = _adr[1]; // Start address
if (function >= fctWriteMultipleCoils)
{
byte[] _cnt = BitConverter.GetBytes((short)IPAddress.HostToNetworkOrder((short)numData));
data[10] = _cnt[0]; // Number of bytes
data[11] = _cnt[1]; // Number of bytes
data[12] = (byte)(numBytes - 2);
}
return data;
}
了解了ModBus TCP协议后,我们看看怎么来读写寄存器的例子
try
{
// Create new modbus master and add event functions
MBmaster = new Master("192.168.8.1", 502, true);
MBmaster.OnResponseData += new ModbusTCP.Master.ResponseData(MBmaster_OnResponseData);
MBmaster.OnException += new ModbusTCP.Master.ExceptionData(MBmaster_OnException);
////取得工人人数等信息
ReadHoldingRegister();
lblMsg.Text = "连接成功";
}
catch (SystemException error)
{
MessageBox.Show(error.Message);
lblMsg.Text = error.Message;
}
// ------------------------------------------------------------------------
// read holding register
// 工人人数,计划数量,实际产量,已耗时长,已耗时长显示保留小数位数 存在地址1到6
//
// ------------------------------------------------------------------------
private void ReadHoldingRegister()
{
ushort ID = 3; //自己定义的序号
byte unit = Convert.ToByte("1"); //Modus 地址1
ushort StartAddress = 0; //开始地址
UInt16 Length =6; //长度
if (MBmaster != null)
{
MBmaster.ReadHoldingRegister(ID, unit, StartAddress, Length); //异步方法
}
}
private void MBmaster_OnResponseData(ushort ID, byte unit, byte function, byte[] values)
{
// ------------------------------------------------------------------
// Seperate calling threads
if (this.InvokeRequired)
{
this.BeginInvoke(new Master.ResponseData(MBmaster_OnResponseData), new object[] { ID, unit, function, values });
return;
}
// ------------------------------------------------------------------------
// Identify requested data
switch (ID)
{
case 3:
//"Read holding register";
//根据返回值数组大小,来判断哪个数据
int[] word = ConvertBytesToWords(values);
if(word.Length==6)
{
Console.WriteLine("return ActualCnt=" + ActualCnt);
WorkerCnt = word[0];
PlanCnt = word[1];
ActualCnt = word[2];
txtWorkerCnt.Text = WorkerCnt.ToString();
txtActual.Text = ActualCnt.ToString();
txtPlanCnt.Text = PlanCnt.ToString();
txtLeftCnt.Text = (PlanCnt - ActualCnt).ToString();
}
break;
case 8:
//grpData.Text = "Write multiple register";
break;
}
}
猜你喜欢
- 2025-07-24 Channels: C# 实现高效的线程间通信
- 2025-07-24 一路踩坑,被迫聊聊 C# 代码调试技巧和远程调试
- 2025-07-24 C# 获取Windows的系统信息(c# 获取本机的ip地址)
- 2025-07-24 C# 读取本地网络配置信息(c# 读取配置文件的方法)
- 2025-07-24 MODBUS协议在C#中的应用案例(c#modbus 程序)
- 2025-07-24 C#接口(c接口镜头)
- 2025-07-24 AngleSharp :在 C# 中轻松解析和操作 HTML/XML 文档
- 2025-07-24 C#中的9个“黑魔法”与“骚操作”
- 2025-07-24 C#.NET Ninject 详解(c#.net framework)
- 2025-07-24 C#.NET HttpClient 使用教程(c#开启http服务)
- 最近发表
-
- C语言重要吗?_c语言重要吗计算机专业
- 2024 年顶级 C# 面试问题和答案_c#面试题及答案2020
- C#调用C++编写的DLL需要通过P/Invoke机制实现
- 掌握 C# 和 .NET:常用术语与概念_c#.net教程
- C++ .NET与C# .NET:谁才是.NET开发的“真香”选择?
- 是C++好,带GC的Java、C#好?还是Rust好?
- 为什么有人一直喜欢 C 而不喜欢 C++?
- Python定时任务,三步实现自动化_python定时任务,三步实现自动化
- (三)Java基础知识复习(异常处理)_java异常处理规则(新手必看)
- 情人节脱单秘诀,程序员表白的情话大盘点!| CSDN 博文精选
- 标签列表
-
- cmd/c (90)
- c++中::是什么意思 (84)
- 标签用于 (71)
- 主键只能有一个吗 (77)
- c#console.writeline不显示 (95)
- pythoncase语句 (88)
- es6includes (74)
- sqlset (76)
- windowsscripthost (69)
- apt-getinstall-y (100)
- node_modules怎么生成 (87)
- chromepost (71)
- flexdirection (73)
- c++int转char (80)
- mysqlany_value (79)
- static函数和普通函数 (84)
- el-date-picker开始日期早于结束日期 (76)
- asynccallback (71)
- localstorage.removeitem (74)
- vector线程安全吗 (70)
- java (73)
- js数组插入 (83)
- mac安装java (72)
- 查看mysql是否启动 (70)
- 无效的列索引 (74)