C#——通过webapi读写Modbus设备

2022/3/6 14:15:41

本文主要是介绍C#——通过webapi读写Modbus设备,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

调用webapi控制本地程序读写Modbus RTU设备

例如服务开启后,访问http://192.168.3.252:2000/api/home/ReadMultiCoil?slaveAdd=1&address=99&number=10,可以调用webapi实现读从站地址为1的设备中线圈起始地址为99的共十个线圈的值,返回值是JSON

其中192.168.3.252:2000为服务的HttpServer,ReadMultiCoil为定义的函数

运行的时候需要管理员权限,最好关闭防火墙或者开放端口

应该有更好的方法实现相同功能的,但我太菜了懒得找

Modbus RTU的代码是之前的代码改的,更改了串口关闭后没法重新打开的问题,顺便改了一下抄的代码里Http服务关不掉的问题

 

 1 <Window x:Class="******.MainWindow"
 2         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
 3         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 4         xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
 5         xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
 6         xmlns:local="clr-namespace:******"
 7         mc:Ignorable="d"
 8         Title="MainWindow" Height="450" Width="800">
 9     <Grid Loaded="Grid_Loaded">
10         <ComboBox x:Name="cmb_portname" HorizontalAlignment="Left" Margin="92,119,0,0" VerticalAlignment="Top" Width="120" MouseEnter="cmb_portname_MouseEnter"/>
11         <ComboBox x:Name="cmb_baud" HorizontalAlignment="Left" Margin="270,119,0,0" VerticalAlignment="Top" Width="120"/>
12         <ComboBox x:Name="cmb_parity" HorizontalAlignment="Left" Margin="440,119,0,0" VerticalAlignment="Top" Width="120"/>
13         <ComboBox x:Name="cmb_dataBits" HorizontalAlignment="Left" Margin="92,176,0,0" VerticalAlignment="Top" Width="120"/>
14         <ComboBox x:Name="cmb_stopBits" HorizontalAlignment="Left" Margin="270,176,0,0" VerticalAlignment="Top" Width="120"/>
15         <Label Content="串口" HorizontalAlignment="Left" Margin="47,119,0,0" VerticalAlignment="Top"/>
16         <Label Content="波特率" HorizontalAlignment="Left" Margin="224,119,0,0" VerticalAlignment="Top"/>
17         <Label Content="校验" HorizontalAlignment="Left" Margin="401,119,0,0" VerticalAlignment="Top"/>
18         <Label Content="数据位" HorizontalAlignment="Left" Margin="41,176,0,0" VerticalAlignment="Top"/>
19         <Label Content="停止位" HorizontalAlignment="Left" Margin="219,176,0,0" VerticalAlignment="Top"/>
20         <Button x:Name="btn_port" Content="打开串口" HorizontalAlignment="Left" Margin="440,176,0,0" VerticalAlignment="Top" Width="75" Click="btn_port_Click"/>
21         <Button x:Name="btn_StartService" Content="开启服务" HorizontalAlignment="Left" Margin="440,228,0,0" VerticalAlignment="Top" Width="75" Click="btn_start_Click"/>
22         <Button x:Name="btn_StopService" Content="关闭服务" HorizontalAlignment="Left" Margin="559,228,0,0" VerticalAlignment="Top" Width="75" Click="btn_close_Click"/>
23         <TextBox x:Name="tb_serviceIP" HorizontalAlignment="Left" Height="23" Margin="92,228,0,0" TextWrapping="Wrap" Text="192.168.3.252" VerticalAlignment="Top" Width="120"/>
24         <TextBox x:Name="tb_servicePort" HorizontalAlignment="Left" Height="23" Margin="270,228,0,0" TextWrapping="Wrap" Text="2000" VerticalAlignment="Top" Width="120"/>
25         <Label Content="服务IP" HorizontalAlignment="Left" Margin="41,228,0,0" VerticalAlignment="Top"/>
26         <Label Content="服务端口" HorizontalAlignment="Left" Margin="213,228,0,0" VerticalAlignment="Top"/>
27 
28     </Grid>
29 </Window>

 

 

  1 using System;
  2 using System.IO.Ports;
  3 using System.Threading.Tasks;
  4 using System.Web.Http;
  5 using System.Web.Http.SelfHost;
  6 using System.Windows;
  7 using Modbus.Device;
  8 
  9 namespace ******
 10 {
 11     /// <summary>
 12     /// MainWindow.xaml 的交互逻辑
 13     /// </summary>
 14     public partial class MainWindow : Window
 15     {
 16         private static IModbusMaster master;
 17         private static SerialPort port;
 18         //写线圈或写寄存器数组
 19         private bool[] coilsBuffer;
 20         private ushort[] registerBuffer;
 21         //串口参数
 22         private string portName;
 23         private int baudRate;
 24         private Parity parity;
 25         private int dataBits;
 26         private StopBits stopBits;
 27 
 28         private HttpServer httpServer = null;
 29 
 30 
 31         public static MainWindow x;
 32         public MainWindow()
 33         {
 34             InitializeComponent();
 35             x = this;
 36         }
 37 
 38         #region 串口下拉列表刷新
 39         /// <summary>
 40         /// 刷新串口下拉列表显示
 41         /// </summary>
 42         private void GetSerialLstTb1()
 43         {
 44             //清除cmb_portname显示
 45             cmb_portname.SelectedIndex = -1;
 46             cmb_portname.Items.Clear();
 47             string[] serialLst = SerialPort.GetPortNames();
 48             if (serialLst.Length > 0)
 49             {
 50                 //取串口进行排序
 51                 Array.Sort(serialLst);
 52                 //将串口列表输出到cmb_portname
 53                 for (int i = 0; i < serialLst.Length; i++)
 54                 {
 55                     cmb_portname.Items.Add(serialLst[i]);
 56                     cmb_portname.SelectedIndex = 0;
 57                 }
 58             }
 59         }
 60         /// <summary>
 61         /// 鼠标移入串口cmb触发刷新
 62         /// </summary>
 63         /// <param name="sender"></param>
 64         /// <param name="e"></param>
 65         private void cmb_portname_MouseEnter(object sender, System.Windows.Input.MouseEventArgs e)
 66         {
 67             GetSerialLstTb1();
 68         }
 69 
 70         #endregion
 71 
 72         /// <summary>
 73         /// 界面加载
 74         /// </summary>
 75         /// <param name="sender"></param>
 76         /// <param name="e"></param>
 77         private void Grid_Loaded(object sender, RoutedEventArgs e)
 78         {
 79             GetSerialLstTb1();
 80 
 81             cmb_baud.Items.Add("9600");
 82             cmb_baud.Items.Add("14400");
 83             cmb_baud.Items.Add("19200");
 84 
 85             cmb_parity.Items.Add("奇");
 86             cmb_parity.Items.Add("偶");
 87             cmb_parity.Items.Add("无");
 88 
 89             cmb_dataBits.Items.Add("7");
 90             cmb_dataBits.Items.Add("8");
 91 
 92             cmb_stopBits.Items.Add("1");
 93             cmb_stopBits.Items.Add("2");
 94 
 95             cmb_portname.SelectedIndex = -1;
 96             cmb_baud.SelectedIndex = 0;
 97             cmb_parity.SelectedIndex = 2;
 98             cmb_dataBits.SelectedIndex = 1;
 99             cmb_stopBits.SelectedIndex = 0;
100         }
101         #region 串口配置
102         /// <summary>
103         /// 串口参数获取
104         /// </summary>
105         /// <returns></返回串口配置参数>
106         private SerialPort InitSerialPortParameter()
107         {
108             if (cmb_portname.SelectedIndex < 0 || cmb_baud.SelectedIndex < 0 || cmb_parity.SelectedIndex < 0 || cmb_dataBits.SelectedIndex < 0 || cmb_stopBits.SelectedIndex < 0)
109             {
110                 MessageBox.Show("请选择串口参数");
111                 return null;
112             }
113             else
114             {
115                 portName = cmb_portname.SelectedItem.ToString();
116                 baudRate = int.Parse(cmb_baud.SelectedItem.ToString());
117 
118                 switch (cmb_parity.SelectedItem.ToString())
119                 {
120                     case "奇":
121                         parity = Parity.Odd;
122                         break;
123                     case "偶":
124                         parity = Parity.Even;
125                         break;
126                     case "无":
127                         parity = Parity.None;
128                         break;
129                     default:
130                         break;
131                 }
132                 dataBits = int.Parse(cmb_dataBits.SelectedItem.ToString());
133                 switch (cmb_stopBits.SelectedItem.ToString())
134                 {
135                     case "1":
136                         stopBits = StopBits.One;
137                         break;
138                     case "2":
139                         stopBits = StopBits.Two;
140                         break;
141                     default:
142                         break;
143                 }
144 
145                 port = new SerialPort(portName, baudRate, parity, dataBits, stopBits);
146                 return port;
147 
148             }
149         }
150         #endregion
151         /// <summary>
152         /// 开闭端口
153         /// </summary>
154         /// <param name="sender"></param>
155         /// <param name="e"></param>
156         private void btn_port_Click(object sender, RoutedEventArgs e)
157         {
158             if (cmb_portname.Items.Count != 0)
159             {
160                 try
161                 {
162                     if ((string)btn_port.Content == "关闭串口")
163                     {
164                         btn_port.Content = "打开串口";
165                         port.Close();
166                     }
167                     else
168                     {
169                         InitSerialPortParameter();
170                         port.PortName = cmb_portname.SelectedItem.ToString();
171                         port.BaudRate = int.Parse(cmb_baud.SelectedValue.ToString());
172                         port.Open();
173                         btn_port.Content = "关闭串口";
174                     }
175                 }
176                 catch (Exception ex)
177                 {
178                     MessageBox.Show(ex.GetType().ToString());
179                     MessageBox.Show("端口被占用\n请选择正确的端口", "错误");
180                 }
181             }
182             else
183             {
184                 MessageBox.Show("请选择正确的端口", "错误");
185             }
186         }
187 
188         public class HttpServer
189         {
190             private HttpSelfHostServer server;
191 
192             public HttpServer(string ip, int port)
193             {
194                 var config = new HttpSelfHostConfiguration($"http:\\{ip}:{port}");
195                 config.MapHttpAttributeRoutes();
196                 config.Routes.MapHttpRoute("DefaultApi", "api/{controller}/{action}");
197                 server = new HttpSelfHostServer(config);
198             }
199 
200             public Task StartHttpServer()
201             {
202                 return server.OpenAsync();
203             }
204             public Task CloseHttpServer()
205             {
206                 return server.CloseAsync();
207             }
208         }
209 
210         private async void btn_start_Click(object sender, RoutedEventArgs e)
211         {
212             try
213             {
214                 httpServer = new HttpServer("\\" + tb_serviceIP.Text, int.Parse(tb_servicePort.Text));
215                 await httpServer.StartHttpServer();
216                 MessageBox.Show("服务开启");
217             }
218             catch (Exception ex)
219             {
220                 MessageBox.Show("服务开启失败" + ex.Message);
221             }
222         }
223 
224         private async void btn_close_Click(object sender, RoutedEventArgs e)
225         {
226             try
227             {
228                 //httpServer = new HttpServer("\\" + tb_serviceIP.Text, int.Parse(tb_servicePort.Text));
229                 await httpServer.CloseHttpServer();
230                 MessageBox.Show("服务关闭");
231             }
232             catch (Exception ex)
233             {
234                 MessageBox.Show("服务关闭失败" + ex.Message);
235             }
236         }
237 
238 
239         public class HomeController : ApiController
240         {
241             /// <summary>
242             /// 读多个寄存器
243             /// http://192.168.3.252:2000/api/home/ReadKeepReg?slaveAdd=1&address=99&number=10
244             /// </summary>
245             /// <param name="slaveAdd">从站地址</param>
246             /// <param name="address">寄存器首地址</param>>
247             /// <param name="number">寄存器数量</param>
248             /// <returns></returns>
249             [HttpGet]
250             public IHttpActionResult ReadKeepReg(string slaveAdd, string address, string number)
251             {
252                 master = ModbusSerialMaster.CreateRtu(port);
253 
254                 string message = "";
255                 byte slaveAddress = byte.Parse(slaveAdd);
256                 ushort startAddress = ushort.Parse(address);
257                 ushort numberOfPoints = ushort.Parse(number);
258                 try
259                 {
260                     x.registerBuffer = master.ReadHoldingRegisters(slaveAddress, startAddress, numberOfPoints);
261                 }
262                 catch (Exception e)
263                 {
264                     MessageBox.Show(e.Message);
265                 }
266                 for (int i = 0; i < x.registerBuffer.Length; i++)
267                 {
268                     message = message + x.registerBuffer[i].ToString("X4") + " ";
269                 }
270                 //MessageBox.Show(message);
271                 return Json(message);
272             }
273             /// <summary>
274             /// 写多个寄存器
275             /// http://192.168.3.252:2000/api/home/WriteKeepReg?slaveAdd=1&address=99&message=1234%201235%201236%201237
276             /// </summary>
277             /// <param name="slaveAdd">从站地址</param>
278             /// <param name="address">寄存器首地址</param>
279             /// <param name="message">信息,以空格分开。例1111 2222,就是写两个寄存器</param>
280             [HttpGet]
281             public void WriteKeepReg(string slaveAdd, string address, string message)
282             {
283                 master = ModbusSerialMaster.CreateRtu(port);
284                 byte slaveAddress = byte.Parse(slaveAdd);
285                 ushort startAddress = ushort.Parse(address);
286 
287                 slaveAddress = byte.Parse(slaveAdd);
288                 startAddress = ushort.Parse(address);
289 
290                 //转化ushort数组
291                 string[] strarr = message.Split(' ');
292                 x.registerBuffer = new ushort[strarr.Length];
293                 for (int i = 0; i < strarr.Length; i++)
294                 {
295                     x.registerBuffer[i] = ushort.Parse(strarr[i], System.Globalization.NumberStyles.HexNumber);
296                 }
297                 master.WriteMultipleRegisters(slaveAddress, startAddress, x.registerBuffer);
298                 return;
299             }
300             /// <summary>
301             /// 读多个线圈
302             /// http://192.168.3.252:2000/api/home/ReadMultiCoil?slaveAdd=1&address=99&number=10
303             /// </summary>
304             /// <param name="slaveAdd">从站地址</param>
305             /// <param name="address">线圈首地址</param>
306             /// <param name="number">线圈数量</param>
307             /// <returns></returns>
308             [HttpGet]
309             public IHttpActionResult ReadMultiCoil(string slaveAdd, string address, string number)
310             {
311                 master = ModbusSerialMaster.CreateRtu(port);
312 
313                 string message = ""; 
314                 byte slaveAddress = byte.Parse(slaveAdd);
315                 ushort startAddress = ushort.Parse(address);
316                 ushort numberOfPoints = ushort.Parse(number);
317                 try
318                 {
319                     x.coilsBuffer = master.ReadCoils(slaveAddress, startAddress, numberOfPoints);
320                 }
321                 catch (Exception e)
322                 {
323                     MessageBox.Show(e.Message);
324                 }
325                 for (int i = 0; i < x.coilsBuffer.Length; i++)
326                 {
327                     message = message + x.coilsBuffer[i] + " ";
328                 }
329                 //MessageBox.Show(message);
330                 return Json(message);
331             }
332             /// <summary>
333             /// 写多个线圈
334             /// http://192.168.3.252:2000/api/home/WriteMultiCoil?slaveAdd=1&address=99&message=1%200%200%200%201%201%201%201
335             /// </summary>
336             /// <param name="slaveAdd">从站地址</param>
337             /// <param name="address">线圈首地址</param>
338             /// <param name="message">信息,空格分开</param>
339             [HttpGet]
340             public void WriteMultiCoil(string slaveAdd, string address, string message)
341             {
342                 master = ModbusSerialMaster.CreateRtu(port);
343                 byte slaveAddress = byte.Parse(slaveAdd);
344                 ushort startAddress = ushort.Parse(address);
345 
346                 slaveAddress = byte.Parse(slaveAdd);
347                 startAddress = ushort.Parse(address);
348 
349                 //转化ushort数组
350                 string[] strarr = message.Split(' ');
351                 x.coilsBuffer = new bool[strarr.Length];
352                 for (int i = 0; i < strarr.Length; i++)
353                 {
354                     if (strarr[i] == "0")
355                     {
356                         x.coilsBuffer[i] = false;
357                     }
358                     else
359                     {
360                         x.coilsBuffer[i] = true;
361                     }
362                 }
363                 master.WriteMultipleCoilsAsync(slaveAddress, startAddress, x.coilsBuffer);
364                 return;
365 
366             }
367         }
368     }
369 }

 



这篇关于C#——通过webapi读写Modbus设备的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程