调用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 }