用C#五分钟搭一个Modbus TCP主站上位机从环境到代码全流程
Modbus协议在工控领域算是应用*广的数据交互协议了,串口和以太网都能跑。大部分场景用组态王或者触摸屏就够了,但如果想做个带自定义逻辑或者界面比较灵活的上位机,用C#加WinForm自己搭一个其实没那么难。下面从环境搭建到代码编写,把整个流程走一遍。
一、搭开发环境装Visual Studio的时候,在"工作负荷"菜单勾选".NET桌面开发"组件就行。装完打开VS,依次点"文件"、"新建"、"项目",选Visual C#的Windows窗体应用。工程名字随便起,这里叫ModbusMaster。创建完成后会看到一个默认的窗体界面,先不管界面设计,先把Modbus库装上。
二、装EasyModbusTcp库在解决方案资源管理器的引用上右键,点"管理NuGet程序包",在浏览菜单搜索框输入"easy modbusTCP"。找到EasyModbusTCP库后点下载安装。这个库基于.NET Framework,支持C#、VB.NET、Java、C++等多种语言,同时支持Modbus TCP、UDP和RTU三种协议。安装成功后在引用里能看到这个扩展库。
选这个库的原因很简单,API设计得比较友好,不需要自己拼Modbus报文帧。读取请求和写入请求都封装好了,Connect、ReadHoldingRegisters、WriteSingleCoil这些方法名一看就懂。用TCP连接保证数据传输可靠性,通信前建立连接,通信结束后断开就行。
三、界面和代码结构界面设计上放几个按钮和文本框就够了。从机IP地址输入框默认填192.168.3.7,端口默认502,再加连接按钮和几个DO通道的开关按钮。代码结构上,Form1构造函数里实例化ModbusClient对象,设置从机IP和端口,UnitIdentifier设为2表示从站地址。
连接按钮的点击事件里调用Master.Connect方法,传入IP和端口。窗体关闭事件里调用Master.Disconnect断开连接,这个别忘了,不然程序退出后TCP连接还挂着,再连的时候从机可能会拒绝。
四、读写线圈的代码写单个线圈用一个封装方法SlaveCoilWrite,传入寄存器地址和布尔状态,内部调用Master.WriteSingleCoil。try-catch包一下,写失败返回false。DO1到DO4的ON按钮分别调用SlaveCoilWrite(0, true)到SlaveCoilWrite(3, true),OFF按钮同理传false。
批量操作用WriteMultipleCoils,传入起始地址0和布尔数组。比如四个通道全开,传一个四个元素全为true的数组。这个比循环调用WriteSingleCoil效率高,一次TCP请求搞定四个通道的写入,网络延迟只算一次。
五、几个实战注意点Modbus TCP的端口号标准是502,但有些设备出厂默认改成503或者其他端口,连接前确认一下从机配置。UnitIdentifier在Modbus TCP里其实不太用得到,但有些从机会校验这个值,跟从机站号保持一致比较保险。
Connect方法如果连不上会抛异常,建议外面包try-catch,给用户一个友好提示而不是程序直接崩。长时间运行的采集程序里,连接断开后要有自动重连机制,可以在catch里加个延时然后重新Connect。
读保持寄存器用ReadHoldingRegisters,传起始地址和读取数量,返回short数组。如果寄存器里存的是浮点数,需要两个连续寄存器拼成32位浮点,用BitConverter.ToInt32转一下再除以对应的精度系数。写寄存器用WriteSingleRegister写单个或者WriteMultipleRegisters写多个。
这个demo虽然简单,但核心逻辑跟实际项目里用的采集程序是一样的。在此基础上加定时器轮询读寄存器、加数据库存储、加趋势图显示,就是一个完整的上位机监控系统了。C#做上位机的优势就是生态好,第三方库多,界面灵活,跟PLC通讯只是其中一个环节。