大网站成本,wordpress竖文主题,wordpress qq登陆评论,做进化树的网站c#调api串口通讯 原文:c#调api串口通讯在调试ICU通信设备的时候#xff0c;由于串口通信老出现故障#xff0c;所以就怀疑CF实现的SerialPort类是否有问题#xff0c;所以最后决定用纯API函数实现串口读写。先从网上搜索相关代码#xff08;关键字#xff1a;C# API 串口由于串口通信老出现故障所以就怀疑CF实现的SerialPort类是否有问题所以最后决定用纯API函数实现串口读写。 先从网上搜索相关代码关键字C# API 串口发现网上相关的资料大约来源于一个版本那就是所谓的msdn提供的样例代码msdn的具体出处我没有考证其它的代码大都是它的变种。 其实这个示例代码是有问题的也就是说DCB结构体声明的有问题虽然该代码可以正常通信不过如果你设置了奇偶校验的话你会发现奇偶校验无效。 VC中的DCB结构声明如下 typedef struct _DCB { DWORD DCBlength; /* sizeof(DCB) */ DWORD BaudRate; /* Baudrate at which running */ DWORD fBinary: 1; /* Binary Mode (skip EOF check) */ DWORD fParity: 1; /* Enable parity checking */ DWORD fOutxCtsFlow:1; /* CTS handshaking on output */ DWORD fOutxDsrFlow:1; /* DSR handshaking on output */ DWORD fDtrControl:2; /* DTR Flow control */ DWORD fDsrSensitivity:1; /* DSR Sensitivity */ DWORD fTXContinueOnXoff: 1; /* Continue TX when Xoff sent */ DWORD fOutX: 1; /* Enable output X-ON/X-OFF */ DWORD fInX: 1; /* Enable input X-ON/X-OFF */ DWORD fErrorChar: 1; /* Enable Err Replacement */ DWORD fNull: 1; /* Enable Null stripping */ DWORD fRtsControl:2; /* Rts Flow control */ DWORD fAbortOnError:1; /* Abort all reads and writes on Error */ DWORD fDummy2:17; /* Reserved */ WORD wReserved; /* Not currently used */ WORD XonLim; /* Transmit X-ON threshold */ WORD XoffLim; /* Transmit X-OFF threshold */ BYTE ByteSize; /* Number of bits/byte, 4-8 */ BYTE Parity; /* 0-4None,Odd,Even,Mark,Space */ BYTE StopBits; /* 0,1,2 1, 1.5, 2 */ char XonChar; /* Tx and Rx X-ON character */ char XoffChar; /* Tx and Rx X-OFF character */ char ErrorChar; /* Error replacement char */ char EofChar; /* End of Input character */ char EvtChar; /* Received Event character */ WORD wReserved1; /* Fill for now. */ } DCB, *LPDCB; 有问题的代码DCB结构声明如下 [StructLayout(LayoutKind.Sequential)] public struct DCB { public int DCBlength; public int BaudRate; public int fBinary; public int fParity; public int fOutxCtsFlow; public int fOutxDsrFlow; public int fDtrControl; public int fDsrSensitivity; public int fTXContinueOnXoff; public int fOutX; public int fInX; public int fErrorChar; public int fNull; public int fRtsControl; public int fAbortOnError; public int fDummy2; public uint flags; public ushort wReserved; public ushort XonLim; public ushort 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 ushort wReserved1; } 对C比较熟悉网友应该知道结构体中这种格式的声明如DWORD fBinary: 1;是以位为单位进行变量设置的DCB中相关位一共占4个字节也就是相当于C#中的一个int变量所占的空间。很明显上面的DCB结构会有问题实际上后面你设置的串口参数如奇偶校验由于偏移有问题虽然你设置了其实都没有设置成功。 其实也不是我说人家的DCB声明错了就错了在SerialPort类中你就可以找到微软官方自己的DCB声明需要反编译SerialPort类声明如下 [StructLayout(LayoutKind.Sequential)] public struct DCB { public int DCBlength; public int BaudRate; public uint Flags; public ushort wReserved; public ushort XonLim; public ushort 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 ushort wReserved1; } 并且专门有一个设置位标志的函数如下 internal void SetDcbFlag(int whichFlag, int setting) { uint num; setting setting whichFlag; if ((whichFlag 4) || (whichFlag 12)) { num 3; } else if (whichFlag 15) { num 0x1ffff; } else { num 1; } dcb.flags ~(num whichFlag); dcb.flags | (uint)setting; } 经过修改能正确运行的API代码如下注意由于我是在WinCE平台上运行所以DLL的路径为//windows//coredll.dll你修改为kernel32后即可在PC机使用 ///summary /// API串口类 叶帆修改 http://blog.csdn.net/yefanqiu ////summary public class CommPort { ///summary ///端口名称(COM1,COM2...COM4...) ////summary public string Port COM1:; ///summary ///波特率9600 ////summary public int BaudRate 9600; ///summary ///数据位4-8 ////summary public byte ByteSize 8; //4-8 ///summary ///奇偶校验0-4no,odd,even,mark,space ////summary public byte Parity 0; //0-4no,odd,even,mark,space ///summary ///停止位 ////summary public byte StopBits 0; //0,1,2 1, 1.5, 2 ///summary ///超时长 ////summary public int ReadTimeout 200; ///summary ///串口是否已经打开 ////summary public bool Opened false; ///summary /// COM口句柄 ////summary private int hComm -1; #region API相关定义 private const string DLLPATH //windows//coredll.dll; // kernel32; ///summary /// WINAPI常量,写标志 ////summary private const uint GENERIC_READ 0x80000000; ///summary /// WINAPI常量,读标志 ////summary private const uint GENERIC_WRITE 0x40000000; ///summary /// WINAPI常量,打开已存在 ////summary private const int OPEN_EXISTING 3; ///summary /// WINAPI常量,无效句柄 ////summary private const int INVALID_HANDLE_VALUE -1; private const int PURGE_RXABORT 0x2; private const int PURGE_RXCLEAR 0x8; private const int PURGE_TXABORT 0x1; private const int PURGE_TXCLEAR 0x4; ///summary ///设备控制块结构体类型 ////summary [StructLayout(LayoutKind.Sequential)] public struct DCB { ///summary /// DCB长度 ////summary public int DCBlength; ///summary ///指定当前波特率 ////summary public int BaudRate; ///summary ///标志位 ////summary public uint flags; ///summary ///未使用,必须为0 ////summary public ushort wReserved; ///summary ///指定在XON字符发送这前接收缓冲区中可允许的最小字节数 ////summary public ushort XonLim; ///summary ///指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数 ////summary public ushort XoffLim; ///summary ///指定端口当前使用的数据位 ////summary public byte ByteSize; ///summary ///指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY 0-4no,odd,even,mark,space ////summary public byte Parity; ///summary ///指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS 0,1,2 1, 1.5, 2 ////summary public byte StopBits; ///summary ///指定用于发送和接收字符XON的值 Tx and Rx XON character ////summary public byte XonChar; ///summary ///指定用于发送和接收字符XOFF值 Tx and Rx XOFF character ////summary public byte XoffChar; ///summary ///本字符用来代替接收到的奇偶校验发生错误时的值 ////summary public byte ErrorChar; ///summary ///当没有使用二进制模式时,本字符可用来指示数据的结束 ////summary public byte EofChar; ///summary ///当接收到此字符时,会产生一个事件 ////summary public byte EvtChar; ///summary ///未使用 ////summary public ushort wReserved1; } ///summary ///串口超时时间结构体类型 ////summary [StructLayout(LayoutKind.Sequential)] private struct COMMTIMEOUTS { public int ReadIntervalTimeout; public int ReadTotalTimeoutMultiplier; public int ReadTotalTimeoutConstant; public int WriteTotalTimeoutMultiplier; public int WriteTotalTimeoutConstant; } ///summary ///溢出缓冲区结构体类型 ////summary [StructLayout(LayoutKind.Sequential)] private struct OVERLAPPED { public int Internal; public int InternalHigh; public int Offset; public int OffsetHigh; public int hEvent; } ///summary ///打开串口 ////summary ///param namelpFileName要打开的串口名称/param ///param namedwDesiredAccess指定串口的访问方式一般设置为可读可写方式/param ///param namedwShareMode指定串口的共享模式串口不能共享所以设置为0/param ///param namelpSecurityAttributes设置串口的安全属性WIN9X下不支持应设为NULL/param ///param namedwCreationDisposition对于串口通信创建方式只能为OPEN_EXISTING/param ///param namedwFlagsAndAttributes指定串口属性与标志设置为FILE_FLAG_OVERLAPPED(重叠I/O操作)指定串口以异步方式通信/param ///param namehTemplateFile对于串口通信必须设置为NULL/param [DllImport(DLLPATH)] private static extern int CreateFile(string lpFileName, uint dwDesiredAccess, int dwShareMode, int lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, int hTemplateFile); ///summary ///得到串口状态 ////summary ///param namehFile通信设备句柄/param ///param namelpDCB设备控制块DCB/param [DllImport(DLLPATH)] private static extern bool GetCommState(int hFile, ref DCB lpDCB); ///summary ///建立串口设备控制块(嵌入版没有) ////summary ///param namelpDef设备控制字符串/param ///param namelpDCB设备控制块/param //[DllImport(DLLPATH)] //private static extern bool BuildCommDCB(string lpDef, ref DCB lpDCB); ///summary ///设置串口状态 ////summary ///param namehFile通信设备句柄/param ///param namelpDCB设备控制块/param [DllImport(DLLPATH)] private static extern bool SetCommState(int hFile, ref DCB lpDCB); ///summary ///读取串口超时时间 ////summary ///param namehFile通信设备句柄/param ///param namelpCommTimeouts超时时间/param [DllImport(DLLPATH)] private static extern bool GetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts); ///summary ///设置串口超时时间 ////summary ///param namehFile通信设备句柄/param ///param namelpCommTimeouts超时时间/param [DllImport(DLLPATH)] private static extern bool SetCommTimeouts(int hFile, ref COMMTIMEOUTS lpCommTimeouts); ///summary ///读取串口数据 ////summary ///param namehFile通信设备句柄/param ///param namelpBuffer数据缓冲区/param ///param namenNumberOfBytesToRead多少字节等待读取/param ///param namelpNumberOfBytesRead读取多少字节/param ///param namelpOverlapped溢出缓冲区/param [DllImport(DLLPATH)] private static extern bool ReadFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToRead, ref int lpNumberOfBytesRead, ref OVERLAPPED lpOverlapped); ///summary ///写串口数据 ////summary ///param namehFile通信设备句柄/param ///param namelpBuffer数据缓冲区/param ///param namenNumberOfBytesToWrite多少字节等待写入/param ///param namelpNumberOfBytesWritten已经写入多少字节/param ///param namelpOverlapped溢出缓冲区/param [DllImport(DLLPATH)] private static extern bool WriteFile(int hFile, byte[] lpBuffer, int nNumberOfBytesToWrite, ref int lpNumberOfBytesWritten, ref OVERLAPPED lpOverlapped); [DllImport(DLLPATH, SetLastError true)] private static extern bool FlushFileBuffers(int hFile); [DllImport(DLLPATH, SetLastError true)] private static extern bool PurgeComm(int hFile, uint dwFlags); ///summary ///关闭串口 ////summary ///param namehObject通信设备句柄/param [DllImport(DLLPATH)] private static extern bool CloseHandle(int hObject); ///summary ///得到串口最后一次返回的错误 ////summary [DllImport(DLLPATH)] private static extern uint GetLastError(); #endregion ///summary ///设置DCB标志位 ////summary ///param namewhichFlag/param ///param namesetting/param ///param namedcb/param internal void SetDcbFlag(int whichFlag, int setting, DCB dcb) { uint num; setting setting whichFlag; if ((whichFlag 4) || (whichFlag 12)) { num 3; } else if (whichFlag 15) { num 0x1ffff; } else { num 1; } dcb.flags ~(num whichFlag); dcb.flags | (uint)setting; } ///summary ///建立与串口的连接 ////summary public int Open() { DCB dcb new DCB(); COMMTIMEOUTS ctoCommPort new COMMTIMEOUTS(); // 打开串口 hComm CreateFile(Port, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0); if (hComm INVALID_HANDLE_VALUE) { return -1; } // 设置通信超时时间 GetCommTimeouts(hComm, ref ctoCommPort); ctoCommPort.ReadTotalTimeoutConstant ReadTimeout; ctoCommPort.ReadTotalTimeoutMultiplier 0; ctoCommPort.WriteTotalTimeoutMultiplier 0; ctoCommPort.WriteTotalTimeoutConstant 0; SetCommTimeouts(hComm, ref ctoCommPort); //设置串口参数 GetCommState(hComm, ref dcb); dcb.DCBlength Marshal.SizeOf(dcb); dcb.BaudRate BaudRate; dcb.flags 0; dcb.ByteSize (byte)ByteSize; dcb.StopBits StopBits; dcb.Parity (byte)Parity; //------------------------------ SetDcbFlag(0, 1, dcb); //二进制方式 SetDcbFlag(1, (Parity 0) ? 0 : 1, dcb); SetDcbFlag(2, 0, dcb); //不用CTS检测发送流控制 SetDcbFlag(3, 0, dcb); //不用DSR检测发送流控制 SetDcbFlag(4, 0, dcb); //禁止DTR流量控制 SetDcbFlag(6, 0, dcb); //对DTR信号线不敏感 SetDcbFlag(9, 1, dcb); //检测接收缓冲区 SetDcbFlag(8, 0, dcb); //不做发送字符控制 SetDcbFlag(10, 0, dcb); //是否用指定字符替换校验错的字符 SetDcbFlag(11, 0, dcb); //保留NULL字符 SetDcbFlag(12, 0, dcb); //允许RTS流量控制 SetDcbFlag(14, 0, dcb); //发送错误后继续进行下面的读写操作 //-------------------------------- dcb.wReserved 0; //没有使用必须为0 dcb.XonLim 0; //指定在XOFF字符发送之前接收到缓冲区中可允许的最小字节数 dcb.XoffLim 0; //指定在XOFF字符发送之前缓冲区中可允许的最小可用字节数 dcb.XonChar 0; //发送和接收的XON字符 dcb.XoffChar 0; //发送和接收的XOFF字符 dcb.ErrorChar 0; //代替接收到奇偶校验错误的字符 dcb.EofChar 0; //用来表示数据的结束 dcb.EvtChar 0; //事件字符接收到此字符时会产生一个事件 dcb.wReserved1 0; //没有使用 if (!SetCommState(hComm, ref dcb)) { return -2; } Opened true; return 0; } ///summary ///关闭串口,结束通讯 ////summary public void Close() { if (hComm ! INVALID_HANDLE_VALUE) { CloseHandle(hComm); } } ///summary ///读取串口返回的数据 ////summary ///param nameNumBytes数据长度/param public int Read(ref byte[] bytData, int NumBytes) { if (hComm ! INVALID_HANDLE_VALUE) { OVERLAPPED ovlCommPort new OVERLAPPED(); int BytesRead 0; ReadFile(hComm, bytData, NumBytes, ref BytesRead, ref ovlCommPort); return BytesRead; } else { return -1; } } ///summary ///向串口写数据 ////summary ///param nameWriteBytes数据数组/param public int Write(byte[] WriteBytes, int intSize) { if (hComm ! INVALID_HANDLE_VALUE) { OVERLAPPED ovlCommPort new OVERLAPPED(); int BytesWritten 0; WriteFile(hComm, WriteBytes, intSize, ref BytesWritten, ref ovlCommPort); return BytesWritten; } else { return -1; } } ///summary ///清除接收缓冲区 ////summary ///returns/returns public void ClearReceiveBuf() { if (hComm ! INVALID_HANDLE_VALUE) { PurgeComm(hComm, PURGE_RXABORT | PURGE_RXCLEAR); } } ///summary ///清除发送缓冲区 ////summary public void ClearSendBuf() { if (hComm ! INVALID_HANDLE_VALUE) { PurgeComm(hComm, PURGE_TXABORT | PURGE_TXCLEAR); } } } 后记我的串口程序修改为API方式后实际发现与SerialPort类遇到同样的问题所以SerialPort类还是值得信任的。该API方式的代码在WinCE平台和PC平台都调试通过。 posted on 2018-09-30 08:58 NET未来之路 阅读(...) 评论(...) 编辑 收藏 转载于:https://www.cnblogs.com/lonelyxmas/p/9727888.html