通用串口通信类

  以前串口通信一直用AxInterop.MSCommLib第三方串口通信类,但是发现那个东西用着很麻烦,因为需要设置ActiveX控件的持久状态OcxState,这个东西又蛋疼的一般在Winform的Designer里面,随意调整一下界面的布局,那个OcxState的设定就不见了。。。还有个蛋疼的地方就是打开和关闭串口需要比较久的时间。

  于是我就想要自己写一个串口通信类,就叫做SerialCommunication。

  首先需要一些DllImport

[DllImport("kernel32.dll")]
private static extern int CreateFile(
    string lpFileName, // file name 
    uint dwDesiredAccess, // access mode 
    int dwShareMode, // share mode 
    int lpSecurityAttributes, // SD 
    int dwCreationDisposition, // how to create 
    int dwFlagsAndAttributes, // file attributes 
    int hTemplateFile // handle to template file 
    );
[DllImport("kernel32.dll")]
private static extern bool GetCommState(
    int hFile, // handle to communications device 
    ref Dcb lpDcb // device-control block 
    );
//[DllImport("kernel32.dll")]
//private static extern bool BuildCommDCB(
//    string lpDef, // device-control string 
//    ref DCB lpDcb // device-control block 
//    );
[DllImport("kernel32.dll")]
private static extern bool SetCommState(
    int hFile, // handle to communications device 
    ref Dcb lpDcb // device-control block 
    );
//[DllImport("kernel32.dll")]
//private static extern bool GetCommTimeouts(
//    int hFile, // handle to comm device 
//    ref CommTimeouts lpCommTimeouts // time-out values 
//    );
[DllImport("kernel32.dll")]
private static extern bool SetCommTimeouts(
    int hFile, // handle to comm device 
    ref CommTimeouts lpCommTimeouts // time-out values 
    );
[DllImport("kernel32.dll")]
private static extern bool ReadFile(
    int hFile, // handle to file 
    byte[] lpBuffer, // data buffer 
    int nNumberOfBytesToRead, // number of bytes to read 
    ref int lpNumberOfBytesRead, // number of bytes read 
    ref Overlapped lpOverlapped // overlapped buffer 
    );
[DllImport("kernel32.dll")]
private static extern bool WriteFile(
    int hFile, // handle to file 
    byte[] lpBuffer, // data buffer 
    int nNumberOfBytesToWrite, // number of bytes to write 
    ref int lpNumberOfBytesWritten, // number of bytes written 
    ref Overlapped lpOverlapped // overlapped buffer 
    );
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(
    int hObject // handle to object 
    );
//[DllImport("kernel32.dll")]
//private static extern uint GetLastError();

  然后需要一些struct

[StructLayout(LayoutKind.Sequential)]
public struct CommTimeouts
{
    public UInt32 ReadIntervalTimeout;
    public UInt32 ReadTotalTimeoutMultiplier;
    public UInt32 ReadTotalTimeoutConstant;
    public UInt32 WriteTotalTimeoutMultiplier;
    public UInt32 WriteTotalTimeoutConstant;
}
[StructLayout(LayoutKind.Sequential)]
public struct Dcb
{
    public Int32 DCBlength;
    public Int32 BaudRate;
    public Int32 PackedValues;
    public Int16 wReserved;
    public Int16 XonLim;
    public Int16 XoffLim;
    public Byte ByteSize;
    public Byte Parity;
    public Byte StopBits;
    public Byte XonChar;
    public Byte XoffChar;
    public Byte ErrorChar;
    public Byte EofChar;
    public Byte EvtChar;
    public Int16 wReserved1;
}
[StructLayout(LayoutKind.Sequential)]
public struct Overlapped
{
    public UIntPtr Internal;
    public UIntPtr InternalHigh;
    public UInt32 Offset;
    public UInt32 OffsetHigh;
    public IntPtr hEvent;
}

  最后实现开关读写串口即可。开串口只需打开串口,设置串口两步操作,打开串口可能会失败,原因一般是该串口没有设备连接或者正在被其他设备使用中,设置串口也有可能会失败,原因一般是设置的参数不正确或者不够。关串口只需要执行CloseHandle即可

public void Open()
{
    // OPEN THE COMM PORT. 
    _hComm = CreateFile("COM" + PortNum, GenericRead | GenericWrite, 0, 0, OpenExisting, 0, 0);
    // IF THE PORT CANNOT BE OPENED, BAIL OUT. 
    if (_hComm == InvalidHandleValue)
    {
		throw (new Exception("Port Open Failure"));
    }
    CommTimeouts ctoCommPort = new CommTimeouts { ReadTotalTimeoutConstant = ReadTimeout };
    if (!SetCommTimeouts(_hComm, ref ctoCommPort))
    {
		throw (new Exception("Bad Timeout Settings"));
    }
    Dcb dcb = new Dcb();
    GetCommState(_hComm, ref dcb);
    dcb.BaudRate = BaudRate;
    dcb.Parity = Parity;
    dcb.ByteSize = ByteSize;
    dcb.StopBits = StopBits;
    if (!SetCommState(_hComm, ref dcb))
    {
		throw (new Exception("Bad Com Settings"));
    }
}
public void Close()
{
    if (_hComm != InvalidHandleValue)
    {
		CloseHandle(_hComm);
    }
}

  读串口执行ReadFile即可,可以在调用的地方开一个线程不断的读串口,不过需要考虑效率问题。写串口执行WriteFile即可,每次读、写串口不需要先关闭再打开串口,那样的话也会浪费效率,但是若串口号或者串口配置修改了,则需要关闭并重新打开串口。

  串口通信类源码

  

原文地址:https://www.cnblogs.com/hambert/p/3392779.html