码迷,mamicode.com
首页 > Web开发 > 详细

.NET串口类(COM口),真正实际可用的串口类。

时间:2015-11-09 10:54:34      阅读:1561      评论:0      收藏:0      [点我收藏+]

标签:

注:这是旧的代码,可用于生产环境,下面的校验码计算处,计算那里少取了一位,这个是用于永宏PLC的,如果是别的,只要改下校验码计算方式就行了。代码较乱,未整理。
技术分享
   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
View Code

 

.NET串口类(COM口),真正实际可用的串口类。

标签:

原文地址:http://www.cnblogs.com/yuyuanfeng/p/4949161.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!