• Modbus TCP学习笔记


    1. 功能码列表:     

                0x01 读线圈状态(Read Coils)
                0x02 读离散输入状态(Read Discrete Inputs )            
                0x03 读保持寄存器(Read Holding Registers )                 
                0x04 读输入寄存器(Read Input Registers)            
                0x05 写单线圈(Write Single Coil )            
                0x06 写单寄存器(Write Single Register)            
                0x07 读取异常状态(限串行线)(Read Exception Status (Serial Line only) )        
                0x08 通信系统诊断(限串行线)(Diagnostics (Serial Line only) )    
                0x09-0x0A无    
                0x0B 获取串行通信事件计数器(Get Comm Event Counter (Serial Line only) )    
                0x0C 获取串行通信事件日志 ( Get Comm Event Log (Serial Line only) )    
                0x0D-0x0E无    
                0x0F 写多个线圈(Write Multiple Coils)    
                0x10 写多个寄存器(Write Multiple registers)    
                0x11 报告服务器ID(仅串行线)(Report Server ID (Serial Line only) )    
                0x12-0x13无    
                0x14 读文件记录(Read File Record )    
                0x15 写文件记录(Write File Record)    
                0x16 带屏蔽字写入寄存器(Mask Write Register )    
                0x17 读/写多个寄存器(Read/Write Multiple registers)    
                0x18 读取先进先出(FIFO)队列(Read FIFO Queue)    
                0x19-0x2A无        
                0x2B 封装接口传输(Encapsulated Interface Transport .)

    2. 分主站,从站,主站是客户端,从站是服务端。启动时先启动从站(服务端),然后主站再连上从站,获取信息。

    3. Device and Modbus 地址表(最大地址看设备)

    Device addressModbus addressDescriptionFunctionR/WComments
    1...10000address-1Coils(outputs)01Read/Write05 and 15
    10001...20000address-10001Discrete Inputs02Read
    40001...50000address-40001Holding Registers03Read/Write06,16,22 and 23
    30001...40000address-30001Input Registers04Read

    4. 用C#做了一个小工具,用作Modbus TCP 学习的总结,链接见:https://download.csdn.net/download/garyaofq/88396590 

    界面左侧启动从站(自动门),右侧启动主站(RDS控制系统),启动3秒后锁定地址和端口。在右侧界面可以读,写线圈和寄存器。同时实时显示地址0-9的值。 帮助和左侧窗口显示功能码说明。

    C#代码,引用EasyModbus,下面是详细的代码:

    1. /*
    2. * Created by SharpDevelop.
    3. * User: yaof
    4. * Date: 2023/10/3
    5. * Time: 19:19
    6. *
    7. * To change this template use Tools | Options | Coding | Edit Standard Headers.
    8. */
    9. using System;
    10. using System.Collections.Generic;
    11. using System.ComponentModel;
    12. using System.Data;
    13. using System.Drawing;
    14. using System.Linq;
    15. using System.Text;
    16. using System.Threading.Tasks;
    17. using System.Windows.Forms;
    18. using EasyModbus;
    19. namespace Modbus_Slave
    20. {
    21. ///
    22. /// Description of MainForm.
    23. ///
    24. public partial class MainForm : Form
    25. {
    26. EasyModbus.ModbusServer modbusServer=null;
    27. System.Data.DataTable dt=new System.Data.DataTable ();
    28. System.Threading.Thread th;
    29. System.Threading.Thread thc;
    30. System.Threading.Thread thcc;
    31. EasyModbus.ModbusClient Master = null;
    32. public MainForm()
    33. {
    34. //
    35. // The InitializeComponent() call is required for Windows Forms designer support.
    36. //
    37. InitializeComponent();
    38. thcc=new System.Threading.Thread (new System.Threading.ThreadStart(counterclock));
    39. //创建一个服务,作为从站设备,等待主站查询或设置
    40. //从站可以不设置IP
    41. modbusServer = new ModbusServer();
    42. th=new System.Threading.Thread (new System.Threading.ThreadStart(monitor));
    43. System.Data.DataColumn dc=new System.Data.DataColumn ("address");
    44. dt.Columns.Add(dc);
    45. dc=new System.Data.DataColumn ("value");
    46. dt.Columns.Add(dc);
    47. for(var m=0;m<10;m++)
    48. {
    49. System.Data.DataRow dr=dt.NewRow();
    50. dr[0]=m.ToString();
    51. dr[1]="0";
    52. dt.Rows.Add(dr);
    53. }
    54. dataGridView1 .DataSource=dt;
    55. dataGridView1.Columns[0].Width=50;
    56. dataGridView1 .Columns[1].Width=50;
    57. dataGridView1 .ScrollBars=ScrollBars.None;
    58. //
    59. // TODO: Add constructor code after the InitializeComponent() call.
    60. //
    61. this.Master = new ModbusClient();
    62. this.slaveIP.Text = "127.0.0.1";
    63. this.slavePort.Text = "502";
    64. this.SlaveAddress.Text="1";
    65. var slaveid=int.Parse(this.SlaveAddress.Text);
    66. byte[] bytes = BitConverter.GetBytes(slaveid);//将int32转换为字节数组
    67. Master.UnitIdentifier =bytes[0];
    68. thc=new System.Threading.Thread (new System.Threading.ThreadStart(connectequipment));
    69. string bodystr="
      Device and Modbus address ranges
      "
      ;
    70. bodystr+="";
    71. bodystr+="
    72. ";
    73. bodystr+="
    74. ";
    75. bodystr+="
    76. ";
    77. bodystr+="
    78. ";
    79. bodystr+="
    80. Device addressModbus addressDescriptionFunctionR/WComments
      1...10000address-1Coils(outputs)01Read/Write05 and 15
      10001...20000address-10001Discrete Inputs02Read
      40001...50000address-40001Holding Registers03Read/Write06,16,22 and 23
      30001...40000address-30001Input Registers04Read
      "
      ;
    81. webBrowser1.DocumentText=bodystr;
    82. button3.BackColor =Color.Red;
    83. button5.BackColor =Color.Red;
    84. button6.BackColor =Color.Red;
    85. button3.Enabled =true;
    86. button5.Enabled =true;
    87. button6.Enabled =true;
    88. }
    89. private bool UpdateCoil(int modbusaddress,int mvalue)
    90. {
    91. var slaveid=int.Parse(this.SlaveAddress.Text);
    92. byte[] bytes = BitConverter.GetBytes(slaveid);//将int32转换为字节数组
    93. modbusServer.UnitIdentifier=bytes[0];
    94. try
    95. {
    96. Master.WriteSingleCoil(modbusaddress, mvalue==1?true:false);
    97. }
    98. catch
    99. {
    100. return false;
    101. }
    102. return true;
    103. }
    104. private void UpdateRegister(int modbusaddress,int mvalue)
    105. {
    106. var slaveid=int.Parse(this.SlaveAddress.Text);
    107. byte[] bytes = BitConverter.GetBytes(slaveid);//将int32转换为字节数组
    108. modbusServer.UnitIdentifier=bytes[0];
    109. Master.WriteSingleRegister(modbusaddress,mvalue);
    110. }
    111. public void counterclock()
    112. {
    113. for(var m=3;m>=0;m--)
    114. {
    115. if(counter.InvokeRequired)
    116. {
    117. counter.Invoke(new Action(()=>{
    118. counter.Text=m.ToString();
    119. }));
    120. }else
    121. {
    122. counter.Text=m.ToString();
    123. }
    124. System.Threading .SpinWait.SpinUntil(() => false, 1000);
    125. //System.Threading .Thread.Sleep(1000);
    126. }
    127. }
    128. public void connectequipment()
    129. {
    130. //延时9秒启动服务,在此期间可以设置端口
    131. System.Threading .Thread.Sleep(3000);
    132. var SlaveIP="";
    133. var SlavePort="";
    134. if(slaveIP.InvokeRequired)
    135. {
    136. slaveIP.Invoke(new Action(()=>{
    137. SlaveIP =slaveIP.Text;
    138. slaveIP.Enabled=false;
    139. }));
    140. }else
    141. {
    142. SlaveIP =slaveIP.Text;
    143. slaveIP.Enabled=false;
    144. }
    145. if(slavePort.InvokeRequired)
    146. {
    147. slavePort.Invoke(new Action(()=>{
    148. SlavePort =slavePort.Text;
    149. slavePort.Enabled=false;
    150. }));
    151. }else
    152. {
    153. SlavePort =slavePort.Text;
    154. slavePort.Enabled=false;
    155. }
    156. Master.Connect(this.slaveIP.Text, int.Parse(this.slavePort.Text));
    157. }
    158. public void monitor()
    159. {
    160. //延时9秒启动服务,在此期间可以设置端口
    161. System.Threading .Thread.Sleep(3000);
    162. if(serverPort.InvokeRequired)
    163. {
    164. serverPort.Invoke(new Action(()=>{
    165. serverPort.Enabled =false;
    166. modbusServer.Port=int.Parse(this.serverPort.Text);
    167. }));
    168. }else
    169. {
    170. serverPort.Enabled =false;
    171. modbusServer.Port=int.Parse(this.serverPort.Text);
    172. }
    173. modbusServer.Listen();
    174. while(true)
    175. {
    176. //主站监控
    177. if(Master.Connected)
    178. {
    179. bool[] coilvalue=Master.ReadCoils(0,10);
    180. for(var m=0;m<10;m++)
    181. {
    182. System.Data.DataRow dr=dt.Rows[m];
    183. dr[0]=m;
    184. dr[1]=coilvalue[(m)% 10000]==true?1:0;
    185. }
    186. }
    187. System.Threading .Thread.Sleep(500);
    188. }
    189. }
    190. void Button2Click(object sender, EventArgs e)
    191. {
    192. if(comboBox1.SelectedItem.ToString()=="05")
    193. {
    194. UpdateCoil(int.Parse(address.Text),int.Parse(value.Text));
    195. }else if(comboBox1.SelectedItem.ToString()=="06")
    196. {
    197. UpdateRegister(40000+int.Parse(address.Text),int.Parse(value.Text));
    198. }
    199. }
    200. void MainFormFormClosing(object sender, FormClosingEventArgs e)
    201. {
    202. th.Abort();
    203. Master.Disconnect();
    204. }
    205. void HelpToolStripMenuItemClick(object sender, EventArgs e)
    206. {
    207. string funstr="Function 01 (01hex) Read Coils\r\n";
    208. funstr+="Function 02(02hex) Read Discrete Inputs\r\n";
    209. funstr+="Function 03 (03hex) Read Holding Registers\r\n";
    210. funstr+="Function 04 (04hex) Read Input Registers\r\n";
    211. funstr+="Function 05 (05hex) Write Single Coil\r\n";
    212. funstr+="Function 06 (06hex) Write Single Register\r\n";
    213. funstr+="Function 15 (0Fhex) Write Multiple Coils\r\n";
    214. funstr+="Function 16 (10hex) Write Multiple Registers\r\n";
    215. MessageBox.Show(funstr);
    216. }
    217. void Button1Click(object sender, EventArgs e)
    218. {
    219. var slaveid=int.Parse(this.SlaveAddress.Text);
    220. byte[] bytes = BitConverter.GetBytes(slaveid);//将int32转换为字节数组
    221. modbusServer.UnitIdentifier=bytes[0];
    222. try
    223. {
    224. if(comboBox2.SelectedItem.ToString()=="01")
    225. {
    226. bool[] coilstatus=Master.ReadCoils(int.Parse(saddress.Text),1);
    227. svalue.Text=coilstatus[0]==true?"1":"0";
    228. }else if(comboBox2.SelectedItem.ToString()=="02")
    229. {
    230. bool[] coilstatus=Master.ReadDiscreteInputs(10000+int.Parse(saddress.Text),1);
    231. svalue.Text=coilstatus[0]==true?"1":"0";
    232. }else if(comboBox2.SelectedItem.ToString()=="03")
    233. {
    234. int[] coilstatus=Master.ReadHoldingRegisters(40000+int.Parse(saddress.Text),1);
    235. svalue.Text=coilstatus[0].ToString();
    236. }else if(comboBox2.SelectedItem.ToString()=="04")
    237. {
    238. int[] coilstatus=Master.ReadInputRegisters(30000+int.Parse(saddress.Text),1);
    239. svalue.Text=coilstatus[0].ToString();
    240. }
    241. }
    242. catch
    243. {
    244. }
    245. }
    246. void Button3Click(object sender, EventArgs e)
    247. {
    248. thcc.Start();
    249. th.Start();
    250. thc.Start();
    251. button3.BackColor =Color.Green;
    252. button5.BackColor =Color.Gray;
    253. button6.BackColor =Color.Gray;
    254. button5.Enabled =false;
    255. button6.Enabled =false;
    256. }
    257. void Button4Click(object sender, EventArgs e)
    258. {
    259. if(comboBox1.SelectedItem.ToString()=="05")
    260. {
    261. UpdateCoil(int.Parse(address.Text),1);
    262. }else if(comboBox1.SelectedItem.ToString()=="06")
    263. {
    264. UpdateRegister(40000+int.Parse(address.Text),1);
    265. }
    266. }
    267. void Button5Click(object sender, EventArgs e)
    268. {
    269. //仅启动从站
    270. thcc.Start();
    271. th.Start();
    272. button5.BackColor =Color.Green;
    273. button3.Enabled =false;
    274. button3.BackColor =Color.Gray;
    275. }
    276. void Button6Click(object sender, EventArgs e)
    277. {
    278. //仅启动主站
    279. thc.Start();
    280. button6.BackColor =Color.Green;
    281. }
    282. /**************************************************************************************
    283. * 0x01 读线圈状态(Read Coils)
    284. 0x02 读离散输入状态(Read Discrete Inputs )
    285. 0x03 读保持寄存器(Read Holding Registers )
    286. 0x04 读输入寄存器(Read Input Registers)
    287. 0x05 写单线圈(Write Single Coil )
    288. 0x06 写单寄存器(Write Single Register)
    289. 0x07 读取异常状态(限串行线)(Read Exception Status (Serial Line only) )
    290. 0x08 通信系统诊断(限串行线)(Diagnostics (Serial Line only) )
    291. 0x09-0x0A无
    292. 0x0B 获取串行通信事件计数器(Get Comm Event Counter (Serial Line only) )
    293. 0x0C 获取串行通信事件日志 ( Get Comm Event Log (Serial Line only) )
    294. 0x0D-0x0E无
    295. 0x0F 写多个线圈(Write Multiple Coils)
    296. 0x10 写多个寄存器(Write Multiple registers)
    297. 0x11 报告服务器ID(仅串行线)(Report Server ID (Serial Line only) )
    298. 0x12-0x13无
    299. 0x14 读文件记录(Read File Record )
    300. 0x15 写文件记录(Write File Record)
    301. 0x16 带屏蔽字写入寄存器(Mask Write Register )
    302. 0x17 读/写多个寄存器(Read/Write Multiple registers)
    303. 0x18 读取先进先出(FIFO)队列(Read FIFO Queue)
    304. 0x19-0x2A无
    305. 0x2B 封装接口传输(Encapsulated Interface Transport .)
    306. ********************************************************************************/
    307. }
    308. }

  • 相关阅读:
    Halcon 双相机标定与拼图(一)
    解释一下分库分表的概念和优缺点。如何设计一个高性能的数据库架构?
    【电商运营】不知道怎么做网站优化?这里有你需要知道的一切!
    在Web服务器(IIS)上安装SSL证书并绑定网站
    STM32SDIO外设详解
    Java并发(1)--线程,进程,以及缓存
    视频降噪一些原理
    redis异常:OOM command not allowed when used memory > ‘maxmemory‘
    LabVIEW中管理项目
    比特集训营第一课
  • 原文地址:https://blog.csdn.net/garyaofq/article/details/133580240