(SerialPort)串口编程知识整理:(一)基本概念和项目实践概述

1、基本概念

      MS .NET FrameWork2.0中对串口通讯进行了封装,我们可以在.net2.0及以上版本开发时直接使用SerialPort类对串口进行读写操作。

SerialPort类的属性主要包括:

串口名称(PortName 

波特率(BaudRate

数据位 DataBits

停止位 StopBits

奇偶校验 Parity

握手协议 Handshake

SerialPort类的事件主要包括:

DataReceived:用于异步接收串口数据

SerialPort类的方法主要包括:

Open();Close();Read();Write()等。

相关内容可以参考MSDN或者博文

 http://www.cnblogs.com/tony-yang/archive/2009/06/03/learnserialport.html

         http://www.cnblogs.com/hocylan/archive/2008/03/13/1103624.html

  

2、需求和场景介绍

      本文是基于之前开发的一个油站项目,主要功能是实现对加油机数据的采集和对加油机的一些控制,例如停开机、设置单价、定量定额加油等操作。

系统通过PC机串口,与下位机进行通讯,下位机和加油机进行通讯,负责采集加油机数据和控制加油机的操作。

 

3、设计思想

         (1)在界面设计上,由于系统启动后要始终实时监控加油数据,采用了SDI展示方式。

截图如下:

(SerialPort)串口编程知识整理:(一)基本概念和项目实践概述_第1张图片

    (2)在系统设计方面,加油机监控软件具有一定的实时性、稳定性和数据并发的非功能性需求。所以在对加油数据采集时,使用事件DataReceived,用于异步接收串口数据。使用watchdog方式监控系统消息,通过缓存池对数据进行过滤,减轻数据库的压力,提高系统性能。

 

4、代码演示

         系统采用CS结构,使用SerialPort类进行串口通讯。对SerialPort类进行了封装,以保证多个窗体间对串口实例的调用。

         封装的串口通讯类参考:http://blog.csdn.net/yefanqiu/archive/2007/03/27/1543187.aspx

串口通讯类:SerialPortDao.cs
/* ----------------------------------------------------------------
           // Copyright (C) 北京****科技有限公司
           // 版权所有。 
           //
           // 文件名:SerialPortDao
           // 文件功能描述:封装串口组件,实现对串口的统一访问和操作
           //
           // 
           // 创建标识:** 2009-5-23
           //
           // 修改标识:**
           // 修改描述:
//----------------------------------------------------------------
*/
using  System;
using  System.Collections.Generic;
using  System.Text;
using  System.IO.Ports;

namespace  LY.FuelStationPOS.Protocol
{
    
///   <summary>
    
///  提供对串口的统一访问
    
///   </summary>
     public   sealed   class  SerialPortDao
    {
        
#region  事件和字段定义
        
public   event  PortDataReceivedEventHandle Received;
        
public  SerialPort serialPort  =   null ;
        
public   bool  ReceiveEventFlag  =   false ;   // 接收事件是否有效 false表示有效

        
private   static   readonly  SerialPortDao instance  =   new  SerialPortDao();

        
#endregion

        
#region  属性定义
        
private   string  protName;
        
public   string  PortName
        {
            
get  {  return  serialPort.PortName; }
            
set  
            { 
                serialPort.PortName 
=  value;
                protName 
=  value;
            }
        }
        
#endregion

        
#region  构造函数
        
private  SerialPortDao()
        {
            LoadSerialPort();
        }

        
private   void  LoadSerialPort()
        {
            serialPort 
=   new  SerialPort();
            serialPort.BaudRate 
=   9600 ;
            serialPort.Parity 
=  Parity.Even;
            serialPort.DataBits 
=   8 ;
            serialPort.StopBits 
=  StopBits.One;
            serialPort.Handshake 
=  Handshake.None;
            serialPort.RtsEnable 
=   true ;
            serialPort.ReadTimeout 
=   2000 ;
            serialPort.DataReceived 
+=   new  SerialDataReceivedEventHandler(DataReceived);
        }

      
        
#endregion       
     
        
#region  串口操作集合
        
///   <summary>
        
///  返回串口对象的单个实例
        
///   </summary>
        
///   <returns></returns>
         public   static  SerialPortDao GetSerialPortDao()
        {         
            
return  instance;
        }       

        
///   <summary>
        
///  释放串口资源
        
///   </summary>
         ~ SerialPortDao()
        {
            Close();
        }

        
///   <summary>
        
///  打开串口
        
///   </summary>
         public   void  Open()
        {
            
try
            {
                
if  ( ! serialPort.IsOpen)
                {
                    serialPort.Open();                    
                }
            }
            
catch  (Exception ex)
            {
                
throw  ex;
            }           
        }

        
///   <summary>
        
///  关闭串口
        
///   </summary>
         public   void  Close()
        {
            
if  (serialPort.IsOpen)
            {
                serialPort.Close();
            }
        }

        
///   <summary>
        
///  串口是否打开
        
///   </summary>
        
///   <returns></returns>
         public   bool  IsOpen()
        {
            
return  serialPort.IsOpen;
        }

       

        
///   <summary>
        
///  数据发送
        
///   </summary>
        
///   <param name="data"> 要发送的数据字节 </param>
         public   void  SendData( byte [] data)
        {
            
try
            {
                serialPort.DiscardInBuffer();
                serialPort.Write(data, 
0 , data.Length);
            }
            
catch  (Exception ex)
            {
                
throw  ex;
            }
        }

        
///   <summary>
        
///  发送命令
        
///   </summary>
        
///   <param name="SendData"> 发送数据 </param>
        
///   <param name="ReceiveData"> 接收数据 </param>
        
///   <param name="Overtime"> 超时时间 </param>
        
///   <returns></returns>
         public   int  SendCommand( byte [] SendData,  ref   byte [] ReceiveData,  int  Overtime)
        {
            
if  (serialPort.IsOpen)
            {
                
try
                {
                    ReceiveEventFlag 
=   true ;         // 关闭接收事件
                    serialPort.DiscardInBuffer();    // 清空接收缓冲区                 
                    serialPort.Write(SendData,  0 , SendData.Length);
                    System.Threading.Thread.Sleep(
50 );
                    
int  num  =   0 , ret  =   0 ;
                    
while  (num ++   <  Overtime)
                    {
                        
if  (serialPort.BytesToRead  >=  ReceiveData.Length)
                        {
                            
break ;
                        }
                        System.Threading.Thread.Sleep(
50 );
                    }
                    
if  (serialPort.BytesToRead  >=  ReceiveData.Length)
                    {
                        ret 
=  serialPort.Read(ReceiveData,  0 , ReceiveData.Length);
                    }
                    
else
                    {
                        ret 
=  serialPort.Read(ReceiveData,  0 , serialPort.BytesToRead);
                    }
                    ReceiveEventFlag 
=   false ;        // 打开事件
                     return  ret;
                }
                
catch  (Exception ex)
                {
                    ReceiveEventFlag 
=   false ;
                    
throw  ex;
                }
            }
            
return   - 1 ;
        }

        
/// <summary>
        
/// 数据发送
        
/// </summary>
        
/// <param name="data"> 要发送的数据字符串 </param>
         public   void  SendData( string  data)
        {
            
// 禁止接收事件时直接退出
             if  (ReceiveEventFlag)
            {
                
return ;
            }
            
if  (serialPort.IsOpen)
            {
                serialPort.Write(data);
            }
        }

         
/// <summary>
         
/// 将指定数量的字节写入输出缓冲区中的指定偏移量处。
         
/// </summary>
         
/// <param name="data"> 发送的字节数据 </param>
         
/// <param name="offset"> 写入偏移量 </param>
         
/// <param name="count"> 写入的字节数 </param>
         public   void  SendData( byte [] data,  int  offset,  int  count)
        {
            
// 禁止接收事件时直接退出
             if  (ReceiveEventFlag)
            {
                
return ;
            }
            
if  (serialPort.IsOpen)
            {
                serialPort.Write(data, offset, count);
            }
        }
               

        
///   <summary>
        
///  数据接收
        
///   </summary>
        
///   <param name="sender"></param>
        
///   <param name="e"></param>
         public   void  DataReceived( object  sender, SerialDataReceivedEventArgs e)
        {
            
// 禁止接收事件时直接退出
             if  (ReceiveEventFlag)
            {
                
return ;
            }

            
try
            {
                
byte [] data  =   new   byte [serialPort.BytesToRead];
                serialPort.Read(data, 
0 , data.Length);
                
if  (Received  !=   null )
                {
                    Received(sender, 
new  PortDataReciveEventArgs(data));
                }
            }
            
catch  (Exception ex)
            {
                
// throw ex;
            }
            
        }
    }
}
串口通讯数据类:PortDataReciveEventArgs
/* ----------------------------------------------------------------
           // Copyright (C) 北京****科技有限公司
           // 版权所有。 
           //
           // 文件名:PortDataReciveEventArgs
           // 文件功能描述:重写PortDataReciveEventArgs参数类
           //
           // 
           // 创建标识:** 2009-5-23
           //
           // 修改标识:
           // 修改描述:
           //
           // 修改标识:
           // 修改描述:
//----------------------------------------------------------------
*/
using  System;
using  System.Collections.Generic;
using  System.Text;

namespace  LY.FuelStationPOS.Protocol
{
    
public   delegate   void  PortDataReceivedEventHandle( object  sender, PortDataReciveEventArgs e);

    
public   class  PortDataReciveEventArgs : EventArgs
    {
        
private   byte [] data;

        
public   byte [] Data
        {
            
get  {  return  data; }
            
set  { data  =  value; }
        }

        
public  PortDataReciveEventArgs()
        {
            
this .data  =   null ;
        }

        
public  PortDataReciveEventArgs( byte [] data)
        {
            
this .data  =  data;
        }

        
    }
}

 

5、声明

     本文来源于实际项目,并且系统的串口通讯很稳定,各位朋友可以放心使用。本文的参考内容都已经标示,如果有任何问题欢迎回复。

     接下来准备要分享的内容包括:

 

本系列文章:

(1)(SerialPort)串口编程知识整理:(一)基本概念和项目实践概述

(2)(SerialPort)串口编程知识整理:(二)串口编程中经常用到的进制转换和其他公共方法

 (3)(SerialPort)串口编程知识整理:(三)串口编程的系统设计实用经验总结

(4)(SerialPort)串口编程知识整理:(四)多串口系统的分布式架构设计

你可能感兴趣的:(port)