标签:
1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 //using System.Threading.Tasks; 6 using System.IO.Ports; 7 using System.Timers; 8 using System.Windows.Forms; 9 using System.Threading; 10 11 //串口通信 12 namespace Utility.Plc.BaseSerialPort 13 { 14 //注:串口类,在此系统中使用这一个,不使用MyUtility中的,那个有问题 15 16 /// <summary> 17 /// PLC异步串口类(开头字符|仆站号码|命令号码|本文资料|检验码|结尾字符) 18 /// 调用:1,PLC开始工作 ConnectDeveice(); 19 /// 2,执行指令 RunPlcCommandText(); 20 /// 3,关闭COM串口 DisconnectDeveice(); 21 /// 4, 是否异步 IsAsyRead=true; //true or false同步 22 /// </summary> 23 public class PortDataDisplay 24 { 25 #region 字段 26 27 /// <summary> 28 /// 定义了一个写入PLC指令后读取返回信息的委托类型 29 /// </summary> 30 public delegate void AsyncDataReceivedEventArgs(); 31 32 /// <summary> 33 /// 解析得到数据后触发事件 34 /// </summary> 35 public event AsyncDataReceivedEventArgs DataReceived; 36 37 /// <summary> 38 /// 处理串口的线程 39 /// </summary> 40 private SerialDataReceivedEventHandler threadCallHandler; 41 42 /// <summary> 43 /// 系统串口类 44 /// </summary> 45 public System.IO.Ports.SerialPort _serialPort = null; // = new SerialPort("COM1", 19200); 46 public static System.IO.Ports.Handshake _Handshake = System.IO.Ports.Handshake.XOnXOff; //串口通信时的传送控制协议 47 48 /// <summary> 49 /// 准备关闭串口=true 50 /// </summary> 51 public bool m_IsTryToClosePort = false; 52 53 public bool m_IsOpen = false; 54 55 /// <summary> 56 /// true表示正在接收数据 57 /// </summary> 58 public bool m_IsReceiving = false; 59 60 private byte _STX = Utility.Plc.BLL.PLCPortDataBLL._STX; //开头 61 private byte _ETX = Utility.Plc.BLL.PLCPortDataBLL._ETX; //结尾 62 private StringBuilder ReturnAllSbuilder = null; //new StringBuilder(); //用于接收数据时的叠加的变量 63 private string ReturnString = ""; //从上面叠加变量ReturnAddString里取出完整的一段返回代码(真正要得到的结果) 64 65 #endregion 66 67 #region 静态字段 68 69 //COM串口 70 private static string PlcPortName = string.Empty; 71 private static string PlcBaudRate = string.Empty; 72 private static string PlcStopBits = "1"; 73 private static int PlcParity = 2; 74 private static int PlcDataBits = 7; 75 private static int PlcTimeOut = 100; 76 private static int RBTold = 4; 77 private static bool PlcIsAsyRead = true; 78 79 //通信指令格式 80 private static string PlcPid = "01"; 81 private static string PlcCmd = string.Empty; 82 private static string PlcValueText = string.Empty; 83 84 #endregion 85 86 #region 公共参数(输出) 87 88 private string dataSrc; 89 /// <summary> 90 /// 对外的数据类型定义 91 /// </summary> 92 public string DataSrc 93 { 94 get { return dataSrc; } 95 //set { dataSrc = value; } 96 } 97 98 #endregion 99 100 #region 公共参数(输入) 101 102 #region COM口参数 103 private string portName; 104 /// <summary> 105 /// 串口名称(COM1) 106 /// </summary> 107 public string PortName 108 { 109 get { return portName; } 110 set { portName = value; } 111 } 112 113 private string baudRate; 114 /// <summary> 115 /// 串口的波特率(9600,19200,38400) 116 /// </summary> 117 public string BaudRate 118 { 119 get { return baudRate; } 120 set { baudRate = value; } 121 } 122 123 private int iparity; 124 /// <summary> 125 /// 奇偶检查协议(0无,1不发生,2偶,3奇) 126 /// </summary> 127 public int iParity 128 { 129 get { return iparity; } 130 set { iparity = value; } 131 } 132 133 private int dataBits; 134 /// <summary> 135 /// 资料位数(6,7,8) 136 /// </summary> 137 public int DataBits 138 { 139 get { return dataBits; } 140 set { dataBits = value; } 141 } 142 143 private int outTime; 144 /// <summary> 145 /// PLC超时时间 146 /// </summary> 147 public int OutTime 148 { 149 get { return outTime; } 150 set { outTime = value; } 151 } 152 153 private string stopBitsStr; 154 /// <summary> 155 /// 停止位(默认为"1") 156 /// </summary> 157 public string StopBitsStr 158 { 159 get { return stopBitsStr; } 160 set { stopBitsStr = value; } 161 } 162 163 public bool isAsyRead ; 164 /// <summary> 165 /// 是否异步(true:异步;false:同步) 166 /// </summary> 167 public bool IsAsyRead 168 { 169 get { return isAsyRead; } 170 set { isAsyRead = value; } 171 } 172 173 #endregion 174 175 #region PLC通迅格式 176 177 private string stx; 178 /// <summary> 179 /// 开头字符(STX) 180 /// </summary> 181 public string STX 182 { 183 get { return stx; } 184 set { stx = value; } 185 } 186 187 private string etx; 188 /// <summary> 189 /// 结尾字符(ETX) 190 /// </summary> 191 public string ETX 192 { 193 get { return etx; } 194 set { etx = value; } 195 } 196 197 private string pid; 198 /// <summary> 199 /// 仆站号码(01-FF) 200 /// </summary> 201 public string PID 202 { 203 get { return pid; } 204 set { pid = value; } 205 } 206 207 private string cmdText; 208 /// <summary> 209 /// 命令号码(40-53) 210 /// </summary> 211 public string CmdText 212 { 213 get { return cmdText; } 214 set { cmdText = value; } 215 } 216 217 private string valueText; 218 /// <summary> 219 /// 含本文资料(0-500个ASCII码)[除开头,站号,命令号,结尾等之外,在命令号与校验码的中间所有内容] 220 /// </summary> 221 public string ValueText 222 { 223 get { return valueText; } 224 set { valueText = value; } 225 } 226 227 #endregion 228 229 #endregion 230 231 #region 事件处理 232 233 /// <summary> 234 /// 接收数据事件(当通知到有数据达到时处理(读取,与分析)) 235 /// </summary> 236 /// <param name="sender"></param> 237 /// <param name="e"></param> 238 private void _serialPort_DataReceived(object sender, SerialDataReceivedEventArgs e) 239 { 240 if (m_IsTryToClosePort) 241 { 242 return; 243 } 244 m_IsReceiving = true; 245 try 246 { 247 //处理数据接收的线程 248 if (threadCallHandler == null) 249 { 250 threadCallHandler = new SerialDataReceivedEventHandler(_serialPort_DataReceived); 251 } 252 if (isAsyRead == true) 253 { 254 //异步 255 AsyReceiveData(); 256 } 257 else if (isAsyRead == false) 258 { 259 //同步 260 SynReceiveData(); 261 } 262 263 #region 原来没分异同步时,直接写在此处的异步方式的代码,先暂时留着 264 265 ////因为COM串口是实时读取的,不能保证每次都是读完要返回的全部数据, 266 ////所以,此处要处理一下,让它读到结束了再将读取的结果返回; 267 //int BufferDataNumStart = 0; 268 //int BufferDataNumEnd = 0; 269 //while (true) 270 //{ 271 // System.Threading.Thread.Sleep(50); //延时50毫秒,以确保数据完全接收 272 // BufferDataNumEnd = _serialPort.ReadBufferSize; //再次读取缓冲区内字节个数 273 // if (BufferDataNumStart == BufferDataNumEnd) break; //如果BufferDataNumStart==BufferDataNumEnd,说明本帧数据已经读完,退出循环 274 // BufferDataNumStart = BufferDataNumEnd; //否则,将BufferDataNumEnd赋给BufferDataNumStart,并继续循环,直到完全接收 275 //} 276 277 ////read 278 //dataSrc = _serialPort.ReadExisting();//读出缓冲区所有数据 279 //if (dataSrc != "" && this.DataReceived != null) 280 //{ 281 // this.DataReceived(); //前台执行委托来取数据 282 //} 283 284 #endregion 285 } 286 finally 287 { 288 _serialPort.ReceivedBytesThreshold = 1; 289 m_IsReceiving = false; 290 } 291 } 292 293 /// <summary> 294 /// 异步读取 295 /// </summary> 296 private void AsyReceiveData() 297 { 298 #region 异步原形 299 ////SerialPort serialPort = (SerialPort)serialPortobj; 300 //System.Threading.Thread.Sleep(500); 301 //try 302 //{ 303 // //txtReceive.Text = serialPort.ReadExisting(); 304 //} 305 //catch (Exception e) 306 //{ 307 // MessageBox.Show(e.Message); 308 // //处理错误 309 //} 310 //_serialPort.Close(); 311 #endregion 312 313 //异步读取代码 314 if (m_IsTryToClosePort) 315 { 316 return; 317 } 318 m_IsReceiving = true; 319 try 320 { 321 if (threadCallHandler == null) 322 { 323 threadCallHandler = new SerialDataReceivedEventHandler(_serialPort_DataReceived); 324 } 325 326 #region 保数据完全接收 327 328 //因为COM串口是实时读取的,不能保证每次都是读完要返回的全部数据, 329 //所以,此处要处理一下,让它读到结束了再将读取的结果返回; 330 int BufferDataNumStart = 0; //保存已经读了多少帧 331 int BufferDataNumEnd = 0; //当前读了多少帧 332 333 //此循环的意思是:循环读取缓存,将读到的个数记下,再继续读, 334 //如果读到和记下的个数一致,则说明缓存的数据已全部读完 335 //因执行下面这个循环,多做了一次循环对比,会有50MS的延迟 336 while (true) 337 { 338 System.Threading.Thread.Sleep(100); //延时50毫秒,以确保数据完全接收(重要) 339 BufferDataNumEnd = _serialPort.ReadBufferSize; //再次读取缓冲区内字节个数 340 if (BufferDataNumStart == BufferDataNumEnd) break; //如果BufferDataNumStart==BufferDataNumEnd,说明本帧数据已经读完,退出循环 341 BufferDataNumStart = BufferDataNumEnd; //否则,将BufferDataNumEnd赋给BufferDataNumStart,并继续循环,直到完全接收 342 } 343 #endregion 344 345 //read 346 //dataSrc = _serialPort.ReadExisting();//异步读出缓冲区所有数据 347 348 ReturnString = ""; 349 ReturnString = _serialPort.ReadExisting();//读出缓冲区所有数据 350 //读取完后,要返回的值 351 if (ReturnString != "" && this.DataReceived != null) 352 { 353 #region 如果读到完整的代码,就返回 354 ReturnAllSbuilder.Append(ReturnString.Replace("\0", "")); //叠加累积起来 355 if (ReturnAllSbuilder.Length > 0) 356 { 357 this.dataSrc = ReturnString; 358 ReturnString = ""; //用完后要重置 359 this.DataReceived(); //前台执行委托事件来取数据 360 return; 361 //测试用,查看完整的返回 362 //txtInfo.Text = txtInfo.Text + m_portDispl.DataSrc.Replace("\0", "") + "\r\n"; 363 364 byte[] byteData = System.Text.Encoding.ASCII.GetBytes(ReturnAllSbuilder.ToString()); 365 //如果读到STX开头与ETX结尾标记 366 if ((byteData.Where(c => c == _STX).Count() > 0) && (byteData.Where(c => c == _ETX).Count() > 0)) 367 { 368 int iStartIndex = -1; 369 int iEndIndex = -1; 370 //查找开起与结尾标记的位置 371 //1,先从最左到右找第一个止符 372 for (int i = 0; i < byteData.Length; i++) 373 { 374 if (byteData[i] == _ETX) 375 { 376 iEndIndex = i; 377 break; 378 } 379 } 380 //1,再从止符位置从右到左找第一个起始符 381 for (int i = iEndIndex; i >= 0; i--) 382 { 383 if (byteData[i] == _STX) 384 { 385 iStartIndex = i; 386 break; 387 } 388 } 389 390 //有开始,也有结束标记,且起始符位置小于止符位置,就调用委托返回,否则,继续读取 391 //返回时的数据,包含完整的起止符号 392 if ((iStartIndex >= 0 && iEndIndex > 0) && (iStartIndex < iEndIndex)) 393 { 394 ReturnString = ""; //重置返回代码变量 395 ReturnString = ReturnAllSbuilder.ToString().Substring(iStartIndex, iEndIndex - iStartIndex + 1); //变量返回代码 396 ReturnAllSbuilder.Remove(0, iEndIndex + 1); //去掉要返回的完整代码字符串,保留用做下一个开始 397 // 398 this.dataSrc = ReturnString; 399 ReturnString = ""; //用完后要重置 400 this.DataReceived(); //前台执行委托事件来取数据 401 } 402 else 403 { 404 //否则不处理,继续读取 405 } 406 //如果叠加字符串的长度太长,则清空它 407 if (ReturnAllSbuilder.Length > 65534) 408 { 409 //ReturnAllSbuilder.Clear(); 410 ReturnAllSbuilder.Remove(0, iEndIndex + 1); 411 } 412 } 413 } 414 #endregion 415 } 416 } 417 catch (Exception ex) 418 { 419 //https://social.msdn.microsoft.com/Forums/lync/zh-TW/cbdca564-459c-4810-bc69-bd5599070e8f/netserialportio 420 //我在.net的serialport类中读取串口数据的时候我捕获到如下的异常:“读串口错误:由于线程退出或应用程序请求,已放弃I/O操作” 421 //MSDN: 422 // 你好! 423 // 这段代码没有什么可以体现问题本质的信息! 424 // 我估计是你从中获取数据的线程已经结束了! 425 //周雪峰 426 //有什么方法处理这个线程已经结束,而I/O中还有读取数据的队列呢?? 427 // catch 428 // { 429 // } 430 // 把try,catch去掉后也出现这个问问题,不过加上后就解决问题了呵呵。 431 432 //MessageBox.Show(ex.ToString(), "Error"); //即,如果抛这个异常的话,则把这句去掉;不显示错误; 433 return; 434 } 435 finally 436 { 437 //重置为有1个字节就即时读取 438 _serialPort.ReceivedBytesThreshold = 1; 439 m_IsReceiving = false; 440 } 441 } 442 443 //MSDN: 444 #region 445 446 //bool flag = false;//是否读完整包数据 447 // try 448 // { 449 // while (this.serialport.BytesToRead >= 0) 450 // { 451 // //如果数据包长度等于13,获取数据长度 452 // //if (ReceiveData.Length == 13) 453 // //{ 454 // // int length = int.Parse(ReceiveData.Substring(4, 2));//数据的长度 455 // // PackgeLength = 3 + 2 + length;//数据包的总长度(字节个数) 456 // //} 457 458 // if ((ReceiveData.Length > 0) && (ReceiveData.Length == 13))//如果一整包数据读取完毕 459 // { 460 // //一包数据已经结束 461 // flag = true; 462 // break; 463 // } 464 // //如果没有读取完一整包,则继续读取 465 // int data = 0x00; 466 467 // data = this.serialport.ReadByte(); 468 // ReceiveData += (char)data; 469 470 // //ReceiveData = ReceiveData.ToUpper(); 471 // } 472 473 // if (flag) 474 // { 475 // //safeAddtrText(ReceiveData);//显示数据的委托 476 // PrintCommand(ReceiveData); 477 // ReceiveData = "";//清空已经接收的数据 478 // } 479 // } 480 // catch 481 // { 482 // } 483 // 把try,catch去掉后也出现这个问问题,不过加上后就解决问题了呵呵。 484 485 #endregion 486 487 /// <summary> 488 /// 同步阻塞读取 489 /// </summary> 490 private void SynReceiveData() 491 { 492 #region 同步原形 493 494 ////SerialPort serialPort = (SerialPort)serialPortobj; 495 //System.Threading.Thread.Sleep(0); 496 //_serialPort.ReadTimeout = 1000; 497 //try 498 //{ 499 // //阻塞到读取数据或超时(这里为2秒) 500 // byte firstByte = Convert.ToByte(_serialPort.ReadByte()); 501 // int bytesRead = _serialPort.BytesToRead; 502 // byte[] bytesData = new byte[bytesRead + 1]; 503 // bytesData[0] = firstByte; 504 // for (int i = 1; i <= bytesRead; i++) 505 // bytesData[i] = Convert.ToByte(_serialPort.ReadByte()); 506 // //txtReceive.Text = System.Text.Encoding.Default.GetString(bytesData); 507 //} 508 //catch (Exception e) 509 //{ 510 // MessageBox.Show(e.Message); 511 // //处理超时错误 512 //} 513 514 #endregion 515 516 //同步阻塞读取 517 if (m_IsTryToClosePort) 518 { 519 return; 520 } 521 m_IsReceiving = true; 522 try 523 { 524 if (threadCallHandler == null) 525 { 526 threadCallHandler = new SerialDataReceivedEventHandler(_serialPort_DataReceived); 527 } 528 529 #region 保数据完全接收 530 531 //因为COM串口是实时读取的,不能保证每次都是读完要返回的全部数据, 532 //所以,此处要处理一下,让它读到结束了再将读取的结果返回; 533 int BufferDataNumStart = 0; 534 int BufferDataNumEnd = 0; 535 while (true) 536 { 537 System.Threading.Thread.Sleep(100); //延时50毫秒,以确保数据完全接收 538 BufferDataNumEnd = _serialPort.ReadBufferSize; //再次读取缓冲区内字节个数 539 if (BufferDataNumStart == BufferDataNumEnd) break; //如果BufferDataNumStart==BufferDataNumEnd,说明本帧数据已经读完,退出循环 540 BufferDataNumStart = BufferDataNumEnd; //否则,将BufferDataNumEnd赋给BufferDataNumStart,并继续循环,直到完全接收 541 } 542 543 #endregion 544 545 //read 546 //同步读取数据 547 //阻塞到读取数据或超时 548 byte firstByte = Convert.ToByte(_serialPort.ReadByte()); //同步读取 549 int bytesRead = _serialPort.BytesToRead; 550 byte[] bytesData = new byte[bytesRead + 1]; 551 bytesData[0] = firstByte; 552 for (int i = 1; i <= bytesRead; i++) 553 { 554 bytesData[i] = Convert.ToByte(_serialPort.ReadByte()); 555 } 556 //读取完后,要返回的值 557 ReturnString = ""; 558 ReturnString = System.Text.Encoding.Default.GetString(bytesData); 559 560 //read 561 //dataSrc = _serialPort.ReadExisting();//异步读出缓冲区所有数据 562 if (ReturnString != "" && this.DataReceived != null) 563 { 564 #region 如果读到完整的代码,就返回 565 ReturnAllSbuilder.Append(ReturnString.Replace("\0", "")); //叠加累积起来 566 if (ReturnAllSbuilder.Length > 0) 567 { 568 //测试用,查看完整的返回 569 //txtInfo.Text = txtInfo.Text + m_portDispl.DataSrc.Replace("\0", "") + "\r\n"; 570 571 byte[] byteData = System.Text.Encoding.ASCII.GetBytes(ReturnAllSbuilder.ToString()); 572 //如果读到STX开头与ETX结尾标记 573 if ((byteData.Where(c => c == _STX).Count() > 0) && (byteData.Where(c => c == _ETX).Count() > 0)) 574 { 575 int iStartIndex = -1; 576 int iEndIndex = -1; 577 //查找开起与结尾标记的位置 578 //1,先从最左到右找第一个止符 579 for (int i = 0; i < byteData.Length; i++) 580 { 581 if (byteData[i] == _ETX) 582 { 583 iEndIndex = i; 584 break; 585 } 586 } 587 //1,再从止符位置从右到左找第一个起始符 588 for (int i = iEndIndex; i >= 0; i--) 589 { 590 if (byteData[i] == _STX) 591 { 592 iStartIndex = i; 593 break; 594 } 595 } 596 597 //有开始,也有结束标记,且起始符位置小于止符位置,就调用委托返回,否则,继续读取 598 //返回时的数据,包含完整的起止符号 599 if ((iStartIndex >= 0 && iEndIndex > 0) && (iStartIndex < iEndIndex)) 600 { 601 ReturnString = ""; //重置返回代码变量 602 //ReturnString = ReturnAllSbuilder.ToString().Substring(iStartIndex, iEndIndex + 1); //变量返回代码 603 //上面这句,括号里第二个参数,还要减去起始的长度-iStartIndex,不然会溢出 604 ReturnString = ReturnAllSbuilder.ToString().Substring(iStartIndex, iEndIndex - iStartIndex + 1); //变量返回代码 605 //上面这句,括号里第二个参数,还要减去起始的长度,不然会溢出 606 607 ReturnAllSbuilder.Remove(0, iEndIndex + 1); //去掉要返回的完整代码字符串,保留用做下一个开始 608 // 609 this.dataSrc = ReturnString; 610 ReturnString = ""; //用完后要重置 611 this.DataReceived(); //前台执行委托事件来取数据 612 } 613 else 614 { 615 //否则不处理,继续读取 616 } 617 //如果叠加字符串的长度太长,则清空它 618 if (ReturnAllSbuilder.Length > 65534) 619 { 620 //ReturnAllSbuilder.Clear(); 621 ReturnAllSbuilder.Remove(0, iEndIndex + 1); 622 } 623 } 624 } 625 #endregion 626 } 627 } 628 catch (Exception ex) 629 { 630 //https://social.msdn.microsoft.com/Forums/lync/zh-TW/cbdca564-459c-4810-bc69-bd5599070e8f/netserialportio 631 //我在.net的serialport类中读取串口数据的时候我捕获到如下的异常:“读串口错误:由于线程退出或应用程序请求,已放弃I/O操作” 632 //MSDN: 633 // 你好! 634 // 这段代码没有什么可以体现问题本质的信息! 635 // 我估计是你从中获取数据的线程已经结束了! 636 //周雪峰 637 //有什么方法处理这个线程已经结束,而I/O中还有读取数据的队列呢?? 638 // catch 639 // { 640 // } 641 // 把try,catch去掉后也出现这个问问题,不过加上后就解决问题了呵呵。 642 643 //MessageBox.Show(ex.ToString(), "Error"); //即,如果抛这个异常的话,则把这句去掉;不显示错误; 644 return; 645 } 646 finally 647 { 648 _serialPort.ReceivedBytesThreshold = 1; 649 m_IsReceiving = false; 650 } 651 652 } 653 654 #endregion 655 656 #region 串口操作 657 658 /// <summary> 659 /// 构造函数 660 /// </summary> 661 public PortDataDisplay() 662 { 663 } 664 665 /// <summary> 666 /// 串口初始化(外部变量在此赋值给自己) 667 /// </summary> 668 private void InitComPort() 669 { 670 #region COM口名称,波特率,资料位数,超时时间,停止位,奇偶校验, 671 PlcPortName = portName == string.Empty ? PlcPortName : portName; 672 PlcBaudRate = baudRate == string.Empty ? PlcBaudRate : baudRate; 673 PlcDataBits = dataBits <= 0 ? PlcDataBits : dataBits; 674 PlcTimeOut = outTime <0 ? PlcTimeOut : outTime; 675 PlcStopBits = stopBitsStr == null ? PlcStopBits : stopBitsStr; 676 PlcParity = iparity <= 0 ? 2 : iparity; 677 PlcIsAsyRead = isAsyRead; 678 679 switch (PlcStopBits) 680 { 681 case "0": 682 PlcStopBits = "0"; 683 break; 684 case "1.5": 685 PlcStopBits = "1.5"; 686 break; 687 case "2": 688 PlcStopBits = "2"; 689 break; 690 default: 691 PlcStopBits = "1"; 692 break; 693 } 694 switch (iparity) 695 { 696 case 0: 697 PlcParity = 0; 698 break; 699 case 1: 700 PlcParity = 1; 701 break; 702 case 3: 703 PlcParity = 3; 704 break; 705 default: 706 PlcParity = 2; 707 break; 708 } 709 710 _serialPort = new System.IO.Ports.SerialPort(); 711 _serialPort.PortName = PlcPortName; 712 _serialPort.BaudRate = Convert.ToInt32(PlcBaudRate); 713 _serialPort.DataBits = Convert.ToInt32(PlcDataBits); ; 714 _serialPort.WriteTimeout = 100; 715 //serialPort.ReceivedBytesThreshold = 4; 716 //默认为1 717 switch (PlcStopBits) 718 { 719 case "0": 720 _serialPort.StopBits = StopBits.None; 721 break; 722 case "1.5": 723 _serialPort.StopBits = StopBits.OnePointFive; 724 break; 725 case "2": 726 _serialPort.StopBits = StopBits.Two; 727 break; 728 default: 729 _serialPort.StopBits = StopBits.One; 730 break; 731 } 732 733 //默认为偶 734 switch (PlcParity) 735 { 736 case 0: 737 _serialPort.Parity = Parity.Space; 738 break; 739 case 1: 740 _serialPort.Parity = Parity.None; 741 break; 742 case 3: 743 _serialPort.Parity = Parity.Odd; 744 break; 745 default: 746 _serialPort.Parity = Parity.Even; 747 break; 748 } 749 #endregion 750 } 751 752 /// <summary> 753 /// 初始化PLC要发送的指令 754 /// </summary> 755 private void InitCmdText() 756 { 757 #region 通信指令格式参数设置 758 759 PlcStopBits = stopBitsStr == null ? PlcStopBits : stopBitsStr; 760 PlcCmd = cmdText == null ? PlcCmd : cmdText; 761 PlcValueText = cmdText == null ? PlcValueText : valueText; 762 763 #endregion 764 } 765 766 /// <summary> 767 /// 初始化并打开串口,并开始工作 768 /// </summary> 769 public void ConnectDeveice() 770 { 771 try 772 { 773 InitComPort(); //初始化COM口 774 _serialPort.Handshake = _Handshake; //此句为增加的 775 776 if (_serialPort == null) return; 777 778 //0.注册事件 779 _serialPort.DataReceived -= _serialPort_DataReceived; 780 _serialPort.DataReceived += _serialPort_DataReceived; 781 //1.再设置一下串口参数 782 if (!this._serialPort.IsOpen) 783 { 784 //此处不指定输入缓冲区的大小(不指定,则系统默认为4096) 785 //this.serialPort.ReadBufferSize = serialPort.BytesToRead + 1; //1000; 786 this._serialPort.ReadBufferSize = 1024; 787 788 //触发数据接收的阀值 789 this._serialPort.ReceivedBytesThreshold = 1; //数据来就触发 790 //2.打开串口开始工作 791 m_IsTryToClosePort = false; 792 this._serialPort.Open(); 793 _serialPort.DiscardInBuffer(); //清空接收缓冲区 794 ReturnAllSbuilder = new StringBuilder(); //叠加 795 } 796 m_IsOpen = true; 797 } 798 catch (Exception ex) 799 { 800 //MessageBox.Show(ex.ToString(), "打开串口:" + PlcPortName); 801 m_IsOpen = false; 802 return; 803 } 804 } 805 806 /// <summary> 807 /// 接收数据并关闭串口(注:调用此关闭串口方法时,要等接收完数据了才执行Close来关闭) 808 /// </summary> 809 public void DisconnectDeveice() 810 { 811 if (_serialPort == null) return; 812 813 m_IsTryToClosePort = true; 814 while (m_IsReceiving) 815 { 816 //线程后台运行 817 System.Windows.Forms.Application.DoEvents(); 818 System.Threading.Thread.Sleep(1000); 819 break; //1秒钟后强制关闭 820 } 821 if (_serialPort.IsOpen) 822 { 823 //如果打开了,则关,否则重复关闭会出错 824 _serialPort.Close(); 825 } 826 } 827 828 #endregion 829 830 #region PLC命令发送 831 832 /// <summary> 833 /// 执行生成PLC命令并写入PLC(拼接生成)[开头字符|仆站号码|命令号码|本文资料(此处未例的均包含在此)|检验码|结尾字符] 834 /// </summary> 835 /// <returns></returns> 836 public void RunPlcCommandText() 837 { 838 if (_serialPort == null) return; 839 InitCmdText(); //初始化指令 840 841 //(开头字符|仆站号码|命令号码|本文资料|检验码|结尾字符) 842 //指令格式的1-4组累加,截取最末两位转16进制后返回 843 string strErr = ""; 844 string strCmd = ""; 845 strCmd = PlcPid + PlcCmd + PlcValueText; 846 if (string.IsNullOrEmpty(strCmd)) 847 { 848 strErr += "没有填写要发送的命令。\n"; 849 } 850 if (!_serialPort.IsOpen) 851 { 852 strErr += "没有打开串口。\n"; 853 } 854 if (strErr.Length > 0) 855 { 856 //MessageBox.Show(strErr.ToString(), "提示"); 857 return; 858 } 859 860 //例:将PLC启动的代码, 861 //byte[] chArr = new byte[9] { 0x02, 0x30, 0x31, 0x34, 0x31, 0x31, 0x46, 0x39, 0x03 }; 862 863 //string sLrc = "80"; 864 string sLrc = Utility.Plc.BLL.PLCPortDataBLL.LrcCheckSum(strCmd); 865 if (string.IsNullOrEmpty(sLrc)) 866 { 867 //生成校验码失败则直接返回 868 return; 869 } 870 871 byte[] stx = new byte[1] { 0x02 }; //开头 872 byte[] etx = new byte[1] { 0x03 }; //结尾 873 byte[] bLrc = Utility.Plc.BLL.PLCPortDataBLL.StringToAscii(sLrc); 874 byte[] bData = Utility.Plc.BLL.PLCPortDataBLL.StringToAscii(strCmd); //校验码 875 byte[] Full = new byte[stx.Length + bData.Length + bLrc.Length + 1]; //(加上尾)总长度 876 stx.CopyTo(Full, 0); 877 bData.CopyTo(Full, stx.Length); 878 bLrc.CopyTo(Full, stx.Length + bData.Length); 879 etx.CopyTo(Full, stx.Length + bData.Length + bLrc.Length); 880 881 _serialPort.DiscardInBuffer(); //清空接收缓冲区 882 //_serialPort.Write(Full, 0, Full.Length); 883 //this.ReturnAllSbuilder.Clear(); //发送命令前创建 884 SendData(Full, 0, Full.Length); 885 } 886 887 /// <summary> 888 /// PLC指令执行发送 889 /// </summary> 890 /// <param name="data">要发送的数据字节</param> 891 private void SendData(byte[] data, int offset, int count) 892 { 893 //禁止接收事件时直接退出 894 //if (ReceiveEventFlag) 895 //{ 896 // return; 897 //} 898 try 899 { 900 if (_serialPort.IsOpen) 901 { 902 //_serialPort.DiscardInBuffer();//清空接收缓冲区 903 _serialPort.Write(data, offset, count); 904 } 905 } 906 catch (Exception ex) 907 { 908 MessageBox.Show(ex.ToString(), "向PLC写入通讯信息失败"); 909 return; 910 } 911 } 912 913 #endregion 914 915 } 916 } 917 918 //PLC业务类相关的 919 namespace Utility.Plc.BLL 920 { 921 922 /// <summary> 923 /// PLC常用方法的业务类 924 /// 925 /// 常用静态常量变量,方法等 926 /// 为了后续维护方便使用 927 /// </summary> 928 public static class PLCPortDataBLL 929 { 930 #region 字段 931 932 /// <summary> 933 /// 定义PLC起止位 934 /// </summary> 935 public static byte _STX = 0x02; //开头 936 public static byte _ETX = 0x03; //结尾 937 938 #endregion 939 940 #region PLC串口操作相关需要的方法 941 942 /// <summary> 943 /// 校验码,取LRC(将前面1-4段全部ASCII码的16进制码[8位长度]累加,取最末两位,不足则前面补“0”) 944 /// </summary> 945 /// <param name="dats"></param> 946 /// <returns></returns> 947 public static string LrcCheckSum(string DataValue) 948 { 949 string CheckSumStr = ""; 950 DataValue = DataValue.Replace(" ", ""); 951 if (string.IsNullOrEmpty(DataValue)) return null; 952 //1,转成ASCII码,2,累计和;3,+2补0,并返回对应的16进制码 953 //dynamic i = null; 954 //dynamic sum = null; 955 int i = 0; 956 int sum = 0; 957 sum = 0; 958 sum = sum + 2; //加上起始位(0x02H);先加,防止结果不符 959 try 960 { 961 byte[] b = System.Text.Encoding.ASCII.GetBytes(DataValue); 962 for (i = 0; i < b.Length; i++) 963 { 964 sum = sum + (int)(b[i]); 965 //防止溢出(中间这里计算的时候要考虑进位, 966 //ASCII码最大是三位0-255,所以至少要保证 967 //5位以上的计算结果是正确的, 968 //否则计算出来的CHECKNUM值不对) 969 string str = Convert.ToString(sum); 970 971 //防止溢出,且保证最少3位完全有效数据 972 if (str.Length > 5) //此处重要 973 { 974 sum = Convert.ToInt32(str.Substring(str.Length - 3, 3)); 975 } 976 } 977 CheckSumStr = sum.ToString("X").ToString(); 978 if (CheckSumStr.Length == 1) 979 { 980 CheckSumStr = "0" + CheckSumStr; 981 } 982 else if (CheckSumStr.Length > 2) 983 { 984 CheckSumStr = CheckSumStr.Substring(CheckSumStr.Length - 2, 2); 985 } 986 return CheckSumStr; 987 } 988 catch (Exception ex) 989 { 990 MessageBox.Show(ex.ToString(), "生成校检码失败"); 991 return null; 992 } 993 finally 994 { 995 // 996 } 997 } 998 999 /// <summary> 1000 /// 列举出本机电脑上的所有实际存在的COM串口 1001 /// </summary> 1002 /// <returns></returns> 1003 public static string[] GetPcPortName() 1004 { 1005 string[] ArrName = System.IO.Ports.SerialPort.GetPortNames(); 1006 return ArrName; 1007 } 1008 1009 /// <summary> 1010 /// 返回指定错误代码的对应信息 1011 /// </summary> 1012 /// <param name="ErrorCode">16进制字符串:错误代码(0,2,4,5,6,7,9,A)</param> 1013 public static string GetErrCodeText(string ErrorCode) 1014 { 1015 string Err = ""; 1016 if (!string.IsNullOrEmpty(ErrorCode)) 1017 { 1018 switch (ErrorCode) 1019 { 1020 case "0": 1021 Err = "PlcInfo:通迅正常(没有错误情形发生)"; 1022 break; 1023 case "2": 1024 Err = "PlcInfo:不合法数值(例如10进制格式中有16进制数字等)"; 1025 break; 1026 case "4": 1027 Err = "PlcInfo:不合法的命令格式(含不合法的命令码),或通讯命令无法执行"; 1028 break; 1029 case "5": 1030 Err = "PlcInfo:不能起动(下RUN命令但Ladder Checksum不合)"; 1031 break; 1032 case "6": 1033 Err = "PlcInfo:不能起动(下RUN命令但PLC ID != Ladder ID)"; 1034 break; 1035 case "7": 1036 Err = "PlcInfo:不能起动(下RUN命令但程序语法错误)"; 1037 break; 1038 case "9": 1039 Err = "PlcInfo:不能起动(下RUN命令,但Ladder的程序指令PLC无法执行)"; 1040 break; 1041 case "A": 1042 Err = "PlcInfo:不合法的地址"; 1043 break; 1044 default: 1045 Err = ""; 1046 break; 1047 } 1048 } 1049 return Err; 1050 } 1051 1052 #endregion 1053 1054 #region PLC返回内容的格式化处理() 1055 1056 /// <summary> 1057 /// PLC命令40返回代码格式化 1058 /// PLC返回的实际格式:|站号|命令号|错误码|STATU S1|STATU S2|STATU S3|校验码| 1059 /// STATU S1:B7,B6,B5,B4,B3,B2,B1,B0(BO:RUN/STOP;B1:BAT LOW/正常;b2:Ladder checksum error/正常;B3:使用MEMORY PACK/未使用; B4:WDT Timeout/正常;B5:设定ID/未设ID;B6:紧急停机/正常;B7:0(PLC保留供未来使用)) 1060 /// STATU S2/S3:PLC未使用 1061 /// </summary> 1062 /// <param name="ReturnString">要处理的PLC返回数据(传进来时先去掉首尾标记STX,ETX)</param> 1063 /// <returns></returns> 1064 public static string GetPlcFormatCommand40(string ReturnString) 1065 { 1066 string Rstring = ""; 1067 1068 1069 return Rstring; 1070 } 1071 1072 /// <summary> 1073 /// PLC命令41返回代码格式化 1074 /// PLC返回的实际格式:|站号|命令号|错误码|校验码| 1075 /// </summary> 1076 /// <param name="ReturnString">16进制字符串:要处理的PLC返回数据(传进来时先去掉首尾标记STX,ETX)</param> 1077 /// <returns></returns> 1078 public static string GetPlcFormatCommand41(string ReturnString) 1079 { 1080 string Rstring = ""; 1081 if (!string.IsNullOrEmpty(ReturnString) && ReturnString.Length >= 4) 1082 { 1083 Rstring = "PlcID:" + ReturnString.Substring(0, 2) + " " + GetErrCodeText(ReturnString.Substring(2, 2)); 1084 } 1085 1086 return Rstring; 1087 } 1088 1089 /// <summary> 1090 /// PLC命令46返回代码格式化(返回N个连续缓存的数据资料) 1091 /// 1092 /// PLC返回的实际格式:|站号|命令号|错误码|连续的N块的资料|校验码| 1093 /// </summary> 1094 /// <param name="InCmdString">16进制字符串:输入的指令(传进来时先去掉首尾标记STX,ETX)</param> 1095 /// <param name="ReturnString">16进制字符串:要处理的PLC返回数据(传进来时先去掉首尾标记STX,ETX)</param> 1096 /// <returns></returns> 1097 public static List<string> GetPlcFormatCommand46(string InCmdString, string ReturnString) 1098 { 1099 List<string> list = new List<string>(); 1100 if (!string.IsNullOrEmpty(ReturnString) && ReturnString.Length >= 7) 1101 { 1102 int iTotal = 0; //缓存器个数 1103 iTotal = hexStringToNumber(InCmdString.Substring(4, 2)); 1104 if (iTotal > 0) 1105 { 1106 string strAll = ""; 1107 strAll = ReturnString.Substring(5, 4 * iTotal); 1108 //string strTemp = ""; 1109 for (int i = 0; i < strAll.Length / 4; i++) 1110 { 1111 //strTemp += strAll.Substring(i * 4, 4) + "%"; 1112 list.Add(strAll.Substring(i * 4, 4)); 1113 } 1114 //string[] arry = strTemp.Split(‘%‘); 1115 } 1116 } 1117 return list; 1118 } 1119 1120 /// <summary> 1121 /// PLC命令47返回代码格式化(返回N个连续缓存的数据资料) 1122 /// 1123 /// PLC返回的实际格式:|站号|命令号|错误码|连续的N块的资料|校验码| 1124 /// </summary> 1125 /// <param name="InCmdString">16进制字符串:输入的指令(传进来时先去掉首尾标记STX,ETX)</param> 1126 /// <param name="ReturnString">16进制字符串:要处理的PLC返回数据(传进来时先去掉首尾标记STX,ETX)</param> 1127 /// <returns></returns> 1128 public static List<string> GetPlcFormatCommand47(string InCmdString, string ReturnString) 1129 { 1130 List<string> list = new List<string>(); 1131 if (!string.IsNullOrEmpty(ReturnString) && ReturnString.Length >= 7) 1132 { 1133 int iTotal = 0; //缓存器个数 1134 iTotal = hexStringToNumber(InCmdString.Substring(4, 2)); 1135 if (iTotal > 0) 1136 { 1137 string strAll = ""; 1138 strAll = ReturnString.Substring(5, 4 * iTotal); 1139 //string strTemp = ""; 1140 for (int i = 0; i < strAll.Length / 4; i++) 1141 { 1142 //strTemp += strAll.Substring(i * 4, 4) + "%"; 1143 list.Add(strAll.Substring(i * 4, 4)); 1144 } 1145 //string[] arry = strTemp.Split(‘%‘); 1146 } 1147 } 1148 return list; 1149 } 1150 1151 #endregion 1152 1153 #region 自定义方法:常用数据类型及进间的互相转换 1154 1155 /// <summary> 1156 /// 将字符串转换成对应的8位ASCII码字节数组 1157 /// </summary> 1158 /// <param name="strValue"></param> 1159 /// <returns></returns> 1160 public static byte[] StringToAscii(string strValue) 1161 { 1162 byte[] byteArray = System.Text.Encoding.ASCII.GetBytes(strValue); 1163 return byteArray; 1164 } 1165 1166 /// <summary> 1167 /// 将字符串转换成对应的16进制字符串(如将Message转换成4D657373616765) 1168 /// </summary> 1169 /// <param name="strValue">要转换的字符串</param> 1170 /// <returns></returns> 1171 public static string StringToHexString(string strValue) 1172 { 1173 //此处为别的其它常用的格式转换,待写成方法 1174 //int iValue; 1175 //byte[] bs; 1176 //string sValue; 1177 //iValue = Convert.ToInt32("0C", 16); // 16进制->10进制 1178 //bs = System.BitConverter.GetBytes(iValue); //int->byte[] 1179 //sValue = System.Text.Encoding.ASCII.GetString(bs); //byte[]-> ASCII 1180 1181 //strValue = "Message"; 1182 StringBuilder stringBuilder = new StringBuilder(strValue.Length * 2); 1183 for (int i = 0; i < strValue.Length; i++) 1184 { 1185 stringBuilder.Append(((int)strValue[i]).ToString("X2"));//且大写方式显示,如果是格式x2是小写 1186 } 1187 //MessageBox.Show(stringBuilder.ToString());//结果4D657373616765 1188 return stringBuilder.ToString(); 1189 } 1190 1191 /// <summary> 1192 /// 将16进制字符串转换成对应的字符串(如将4D657373616765转换成Message) 1193 /// </summary> 1194 /// <param name="strValue">要转换的16进制格式的字符串</param> 1195 /// <returns></returns> 1196 public static string HexStringToString(string strValue) 1197 { 1198 //strValue = "4D657373616765"; 1199 strValue = strValue.Replace(" ", ""); 1200 strValue = strValue.Replace("\0", ""); 1201 StringBuilder stringBuilder = new StringBuilder(strValue.Length / 2); 1202 for (int i = 0; i < strValue.Length; i += 2) 1203 { 1204 //转成10进制数字,然后转成对应的ASCII码的字符 1205 stringBuilder.Append(Convert.ToChar(hexStringToNumber(strValue.Substring(i, 2)))); 1206 } 1207 //MessageBox.Show(stringBuilder.ToString());//结果Message 1208 return stringBuilder.ToString(); 1209 } 1210 1211 /// <summary> 1212 /// 16进制字符串怎样转换成对应的btye[] 1213 /// </summary> 1214 /// <param name="strValue">要转换的16进制字符串(如4D657373616765)</param> 1215 /// <returns></returns> 1216 public static byte[] HexStringToByteArray(string strValue) 1217 { 1218 strValue = strValue.Replace(" ", ""); //去掉空格 1219 strValue = strValue.Replace("\0", ""); //去掉太多的字符串结尾符号 1220 //strValue = strValue.Replace("\n", ""); //去掉太多的换行符 1221 1222 byte[] buffer = new byte[strValue.Length / 2]; 1223 for (int i = 0; i < strValue.Length; i += 2) 1224 { 1225 buffer[i / 2] = (byte)Convert.ToByte(strValue.Substring(i, 2), 16); 1226 } 1227 return buffer; 1228 } 1229 1230 /// <summary> 1231 /// 将16进制字符串转成10进制的数字(默认返回0) 1232 /// </summary> 1233 /// <param name="hexString"></param> 1234 public static Int32 hexStringToNumber(string hexString) 1235 { 1236 int num = 0; 1237 if (hexString.Length > 0) 1238 { 1239 num = Int32.Parse(hexString, System.Globalization.NumberStyles.HexNumber); 1240 //MessageBox.Show(num.ToString(), "num"); 1241 } 1242 return num; 1243 } 1244 1245 /// <summary> 1246 /// 字节数组转字符串 1247 /// </summary> 1248 /// <param name="bArray"></param> 1249 /// <returns></returns> 1250 public static String bytesToHexString(byte[] bArray) 1251 { 1252 StringBuilder sb = new StringBuilder(bArray.Length); 1253 String sTemp = ""; 1254 for (int i = 0; i < bArray.Length; i++) 1255 { 1256 //sTemp = Integer.toHexString(0xFF & bArray[i]); 1257 sTemp += bArray[i].ToString(); 1258 if (sTemp.Length < 2) 1259 sb.Append(sTemp); 1260 sb.Append(sTemp.ToUpper()); 1261 } 1262 return sb.ToString(); 1263 } 1264 1265 #endregion 1266 1267 } 1268 } 1269 1270 #region 调用示例 1271 1272 /* 1273 using System; 1274 using System.Collections.Generic; 1275 using System.ComponentModel; 1276 using System.Data; 1277 using System.Drawing; 1278 using System.Linq; 1279 using System.Text; 1280 using System.Threading.Tasks; 1281 using System.Windows.Forms; 1282 using System.Linq; 1283 1284 namespace SenderTest 1285 { 1286 public partial class Form1 : Form 1287 { 1288 /// <summary> 1289 /// 封装好的串口类 1290 /// </summary> 1291 private Utility.Plc.BaseSerialPort.PortDataDisplay m_portDispl = new Utility.Plc.BaseSerialPort.PortDataDisplay(); 1292 //此处不能写死,改成读常量值 1293 //byte _STX = 0x02; //开头 1294 //byte _ETX = 0x03; //结尾 1295 byte _STX = Utility.Plc.BLL.PLCPortDataBLL._STX; //开头 1296 byte _ETX = Utility.Plc.BLL.PLCPortDataBLL._ETX; //结尾 1297 private string ReturnAddString = ""; //用于接收数据时的叠加的变量 1298 private string ReturnString = ""; //从上面叠加变量ReturnAddString里取出完整的一段返回代码(真正要得到的结果) 1299 1300 /// <summary> 1301 /// 委托事件 1302 /// </summary> 1303 private void portDispl_DataReceived() 1304 { 1305 WhenGetNew ehan = delegate 1306 { 1307 //这里返回的有可能没一次读完; 1308 //累计后,查找起止位标记,截取完整返回字符串后,再进行处理 1309 //接收到的返回代码,有可能止位符在中间出现 1310 ReturnAddString += m_portDispl.DataSrc; 1311 ////如果有返回代码,则处理 1312 //if (ReturnAddString.Length > 0) 1313 //{ 1314 // //测试用,查看完整的返回 1315 // txtInfo.Text = txtInfo.Text + m_portDispl.DataSrc.Replace("\0", "") + "\r\n"; 1316 1317 // byte[] byteData = System.Text.Encoding.ASCII.GetBytes(ReturnAddString); 1318 // //if (dataOne.Where(c => c == _STX && c == _ETX).Count() > 0) 1319 // //如果读到ETX结尾标记 1320 // if (byteData.Where(c => c == _ETX).Count() > 0) 1321 // { 1322 // int iIndex = 0; 1323 // //查找结尾标记的位置 1324 // for (int i = 0; i < byteData.Length; i++) 1325 // { 1326 // if (byteData[i] == _ETX) 1327 // { 1328 // iIndex = i; 1329 // } 1330 // } 1331 // ReturnString = ""; //重置返回代码变量 1332 // ReturnString = ReturnAddString.Substring(0 + 1, iIndex - 1); //变量返回代码 1333 // ReturnAddString = ReturnAddString.Substring(iIndex, ReturnAddString.Length - iIndex - 1); //去掉要返回的完整代码字符串,保留用做下一个开始 1334 // //处理返回代码的格式,得到结果 1335 // txtLast.Text=""; 1336 // txtLast.Text += Utility.Plc.BLL.PLCPortDataBLL.GetErrCodeText(ReturnString.Substring(4, 1)); 1337 1338 // List<string> list = null; // Utility.Plc.BaseSerialPort.PLCPortDataBLL.GetPlcFormatCommand46(m_portDispl.PID.ToString() + m_portDispl.CmdText.ToString() + m_portDispl.ValueText.ToString(), ReturnString); 1339 // if (list != null && list.Count > 0) 1340 // { 1341 // for (int i = 0; i < list.Count; i++) 1342 // { 1343 // txtLast.Text += list[i].ToString() + "\r\n"; 1344 // } 1345 // } 1346 1347 // if (list != null && list.Count > 0) 1348 // { 1349 // txtLast.Text += "对应十进制数字:\r\n"; 1350 // for (int i = 0; i < list.Count; i++) 1351 // { 1352 // txtLast.Text += Utility.Plc.BLL.PLCPortDataBLL.hexStringToNumber(list[i].ToString()).ToString() + "\r\n"; 1353 // } 1354 // } 1355 // } 1356 // else 1357 // { 1358 // //MessageBox.Show(dataOne.Where(c => c == _ETX).Count().ToString(), "b"); 1359 // //如果没有返回代码,则不用理会 1360 // } 1361 //} 1362 }; 1363 try 1364 { 1365 //是否调用Invoke方法;这个处理可能后面要改 1366 if (InvokeRequired) 1367 { 1368 //在拥有此控件的基础窗体句柄的线程上执行指定的委托代理方法 1369 this.Invoke(ehan); 1370 } 1371 } 1372 catch(Exception ex) 1373 { 1374 MessageBox.Show(ex.ToString(), "System Information"); 1375 return; 1376 } 1377 } 1378 1379 public Form1() 1380 { 1381 InitializeComponent(); 1382 } 1383 1384 private void Form1_Load(object sender, EventArgs e) 1385 { 1386 GetComName(); 1387 } 1388 1389 private void GetComName() 1390 { 1391 this.cbxSerial.Items.Clear(); 1392 this.cbxBaudRate.Items.Clear(); 1393 this.cbxDateBit.Items.Clear(); 1394 this.cbxParity.Items.Clear(); 1395 this.cbxStop.Items.Clear(); 1396 string[] arry = Utility.Plc.BLL.PLCPortDataBLL.GetPcPortName(); 1397 if (arry.Length > 0) 1398 { 1399 for (int i = 0; i < arry.Length; i++) 1400 { 1401 this.cbxSerial.Items.Add(arry[i].ToString()); 1402 } 1403 } 1404 this.cbxBaudRate.Items.Add("38400"); 1405 this.cbxDateBit.Items.Add("7"); 1406 this.cbxParity.Items.Add("2"); 1407 this.cbxStop.Items.Add("1"); 1408 1409 this.cbxSerial.SelectedIndex = 0; 1410 this.cbxBaudRate.SelectedIndex = 0; 1411 this.cbxDateBit.SelectedIndex = 0; 1412 this.cbxParity.SelectedIndex = 0; 1413 this.cbxStop.SelectedIndex = 0; 1414 } 1415 1416 private void btnOpen_Click(object sender, EventArgs e) 1417 { 1418 if (btnOpen.Text == "打开串口") 1419 { 1420 m_portDispl.DataReceived -= portDispl_DataReceived; 1421 m_portDispl.DataReceived += new Utility.Plc.BaseSerialPort.PortDataDisplay.AsyncDataReceivedEventArgs(portDispl_DataReceived); 1422 1423 m_portDispl.PortName = this.cbxSerial.Text; 1424 m_portDispl.BaudRate = this.cbxBaudRate.Text; 1425 m_portDispl.DataBits = int.Parse(this.cbxDateBit.Text); 1426 m_portDispl.iParity = int.Parse(this.cbxParity.Text); 1427 m_portDispl.StopBitsStr = this.cbxStop.Text; 1428 m_portDispl.OutTime = 100; 1429 m_portDispl.isAsyRead = false; //是否异步读取 1430 m_portDispl.ConnectDeveice(); //PLC联机开始工作 1431 //m_portDispl.RunPlcCommandText(); 1432 btnOpen.Text = "关闭串口"; 1433 } 1434 else if (btnOpen.Text == "关闭串口") 1435 { 1436 m_portDispl.DisconnectDeveice(); //读取完并关闭串口 1437 btnOpen.Text = "打开串口"; 1438 } 1439 } 1440 1441 private void btnSender_Click(object sender, EventArgs e) 1442 { 1443 if (m_portDispl == null) return; 1444 1445 m_portDispl.PID = this.txtPid.Text.Trim(); 1446 m_portDispl.CmdText = this.textBox1.Text.Trim(); 1447 m_portDispl.ValueText = this.txtCommandText.Text.Trim().ToString().Replace(" ", "").Replace("\r", "").Replace("\n", ""); 1448 1449 m_portDispl.RunPlcCommandText(); 1450 } 1451 1452 } 1453 } 1454 1455 */ 1456 1457 #endregion
标签:
原文地址:http://www.cnblogs.com/yuyuanfeng/p/4949161.html