Winform:记录下串口调试

记录下串口通讯

 

因为FXSerialPort不好用,所以也自已试着去调试了串口,可是一调就不开心起来了。本来串口就一个读,一个写,就是这样的事,可不知为什么调试起来有时老回读不到数据。最后还是用了VBMSCom才搞定,尽管搞定了,可还是不知道问题出在那,在这里给自已标志一下吧。

http://www.vckbase.com/document/viewdoc/?id=1734

VCKBase里就找到一篇很好的例子,直接通过API操作串口的。

1.       CreateFile打开串口一下,

2.       配置一下DCBDCB结构包含了诸如波特率、数据位数、奇偶校验和停止位数等信息。在查询或配置串口的属性时,都要用DCB结构来作为缓冲区。

[StructLayout(LayoutKind.Sequential)]

public struct DCB

{

//taken from c struct in platform sdk

public int DCBlength;            // sizeof(DCB)

public int BaudRate;             // 指定当前波特率 current baud rate

// these are the c struct bit fields, bit twiddle flag to set

public int fBinary;           // 指定是否允许二进制模式,windows95中必须主TRUE binary mode, no EOF check

public int fParity;           // 指定是否允许奇偶校验 enable parity checking

public int fOutxCtsFlow;       // 指定CTS是否用于检测发送控制,当为TRUECTSOFF,发送将被挂起。 CTS output flow control

public int fOutxDsrFlow;       // 指定CTS是否用于检测发送控制 DSR output flow control

public int fDtrControl;        // DTR_CONTROL_DISABLE值将DTR置为OFF, DTR_CONTROL_ENABLE值将DTR置为ON, DTR_CONTROL_HANDSHAKE允许DTR"握手" DTR flow control type

public int fDsrSensitivity;    // 当该值为TRUEDSROFF时接收的字节被忽略 DSR sensitivity

public int fTXContinueOnXoff; // 指定当接收缓冲区已满,并且驱动程序已经发送出XoffChar字符时发送是否停止。TRUE时,在接收缓冲区接收到缓冲区已满的字节XoffLim且驱动程序已经发送出XoffChar字符中止接收字节之后,发送继续进行。 FALSE时,在接收缓冲区接收到代表缓冲区已空的字节XonChar且驱动程序已经发送出恢复发送的XonChar之后,发送继续进行。XOFF continues Tx

public int fOutX;           // TRUE时,接收到XoffChar之后便停止发送接收到XonChar之后将重新开始 XON/XOFF out flow control

public int fInX;            // TRUE时,接收缓冲区接收到代表缓冲区满的XoffLim之后,XoffChar发送出去接收缓冲区接收到代表缓冲区空的XonLim之后,XonChar发送出去 XON/XOFF in flow control

public int fErrorChar;      // 该值为TRUEfParityTRUE时,用ErrorChar 成员指定的字符代替奇偶校验错误的接收字符 enable error replacement

public int fNull;           // eTRUE时,接收时去掉空(0值)字节 enable null stripping

public int fRtsControl;      // RTS flow control

/*RTS_CONTROL_DISABLE,RTS置为OFF

RTS_CONTROL_ENABLE, RTS置为ON

RTS_CONTROL_HANDSHAKE,

当接收缓冲区小于半满时RTSON

当接收缓冲区超过四分之三满时RTSOFF

RTS_CONTROL_TOGGLE,

当接收缓冲区仍有剩余字节时RTSON ,否则缺省为OFF*/

 

public int fAbortOnError;    // TRUE,有错误发生时中止读和写操作 abort on error

public int fDummy2;         // 未使用 reserved

 

public uint flags;

public ushort wReserved;           // 未使用,必须为0 not currently used

public ushort XonLim;              // 指定在XON字符发送这前接收缓冲区中可允许的最小字节数 transmit XON threshold

public ushort XoffLim;             // 指定在XOFF字符发送这前接收缓冲区中可允许的最小字节数 transmit XOFF threshold

public byte ByteSize;            // 指定端口当前使用的数据位    number of bits/byte, 4-8

public byte Parity;              // 指定端口当前使用的奇偶校验方法,可能为:EVENPARITY,MARKPARITY,NOPARITY,ODDPARITY   0-4=no,odd,even,mark,space

public byte StopBits;            // 指定端口当前使用的停止位数,可能为:ONESTOPBIT,ONE5STOPBITS,TWOSTOPBITS   0,1,2 = 1, 1.5, 2

public char XonChar;             // 指定用于发送和接收字符XON的值 Tx and Rx XON character

public char XoffChar;            // 指定用于发送和接收字符XOFF Tx and Rx XOFF character

public char ErrorChar;           // 本字符用来代替接收到的奇偶校验发生错误时的值 error replacement character

public char EofChar;             // 当没有使用二进制模式时,本字符可用来指示数据的结束 end of input character

public char EvtChar;             // 当接收到此字符时,会产生一个事件 received event character

public ushort wReserved1;          // 未使用 reserved; do not use

        }

3.       设置I/O缓冲区的大小和超时。Windows用I/O缓冲区来暂存串口输入和输出的数据。如果通信的速率较高,则应该设置较大的缓冲区。调用SetupComm函数可以设置串行口的输入和输出缓冲区的大小。

BOOL SetupComm(

    HANDLE hFile,      // 通信设备的句柄

    DWORD dwInQueue,   // 输入缓冲区的大小(字节数)

    DWORD dwOutQueue   // 输出缓冲区的大小(字节数)

);

4.    读:ReadFile
5.    写: WriteFile
注:ReadFile和WriteFile函数是同步还是异步由CreateFile函数决定,如果在调用CreateFile创建句柄时指定了 FILE_FLAG_OVERLAPPED标志,那么调用ReadFile和WriteFile对该句柄进行的操作就应该是重叠的;如果未指定重叠标志, 则读写操作应该是同步的。ReadFile和WriteFile函数的同步或者异步应该和CreateFile函数相一致。
6.    关闭串口:BOOL
 CloseHandle(
    HANDLE hObject; //handle to object to close 
);

7.    清空缓冲区:PurgeComm

PurgeComm(hCom, PURGE_TXABORT|
                PURGE_RXABORT|PURGE_TXCLEAR|PURGE_RXCLEAR);

Value

Description

PURGE_TXABORT

Terminates outstanding overlapped write operations and returns immediately, even if the write operations have not been completed.

PURGE_RXABORT

Terminates outstanding overlapped read operations and returns immediately, even if the read operations have not been completed.

PURGE_TXCLEAR

Clears the output buffer (if the device driver has one).

PURGE_RXCLEAR

Clears the input buffer (if the device driver has one).

 

8.    清除串口错误

在使用ReadFile 函数进行读操作前,应先使用ClearCommError函数清除错误。ClearCommError函数的原型如下:

BOOL ClearCommError(

    HANDLE hFile,      // 串口句柄

    LPDWORD lpErrors, // 指向接收错误码的变量

    LPCOMSTAT lpStat   // 指向通讯状态缓冲区

   );  

 

而在网上也有对这一段代码的C#版的封装,搜下CommPort就知道了。
 
可不知为什么,有时串口断开后再连接进去,有时数据老写不进去,用串口监控工具(Serial Port Monitor)看才知道。这是一个很好用的工具,把串口操作的每一步都打印出来了。最近因为进度的问题没法深究下去,用上了非常好用的MSCom了,哈哈
http://www.yes-tele.com/mscomm.html
在这里提供了这个控件很好的详解。
http://hi.baidu.com/wolfwhite/blog/item/5ec742164bb4604820a4e9b1.html
http://topic.csdn.net/t/20061227/22/5260726.html
 
这里也是。。。。关于这个就不想多说了,太经典的一个了。。。。
 
最后记下CRC校验,本来是自已专业课教的,可毕业两年就给忘光了,说不清楚了,大概就是这样

发送方:发出的传输字段为1 0 1 1 0 0 1 1 0 10

                          信息字段       校验字段

接收方:使用相同的生成码进行校验:接收到的字段/生成码(二进制除法)

                  如果能够除尽,则正确,

 
 public class CRC
    {
        // Fields
        private static byte[] ArrayCRCHigh = new byte[] { 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40, 0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 
        0, 0xc1, 0x81, 0x40, 1, 0xc0, 0x80, 0x41, 1, 0xc0, 0x80, 0x41, 0, 0xc1, 0x81, 0x40
     };
        private static byte[] checkCRCLow = new byte[] { 
        0, 0xc0, 0xc1, 1, 0xc3, 3, 2, 0xc2, 0xc6, 6, 7, 0xc7, 5, 0xc5, 0xc4, 4, 
        0xcc, 12, 13, 0xcd, 15, 0xcf, 0xce, 14, 10, 0xca, 0xcb, 11, 0xc9, 9, 8, 200, 
        0xd8, 0x18, 0x19, 0xd9, 0x1b, 0xdb, 0xda, 0x1a, 30, 0xde, 0xdf, 0x1f, 0xdd, 0x1d, 0x1c, 220, 
        20, 0xd4, 0xd5, 0x15, 0xd7, 0x17, 0x16, 0xd6, 210, 0x12, 0x13, 0xd3, 0x11, 0xd1, 0xd0, 0x10, 
        240, 0x30, 0x31, 0xf1, 0x33, 0xf3, 0xf2, 50, 0x36, 0xf6, 0xf7, 0x37, 0xf5, 0x35, 0x34, 0xf4, 
        60, 0xfc, 0xfd, 0x3d, 0xff, 0x3f, 0x3e, 0xfe, 250, 0x3a, 0x3b, 0xfb, 0x39, 0xf9, 0xf8, 0x38, 
        40, 0xe8, 0xe9, 0x29, 0xeb, 0x2b, 0x2a, 0xea, 0xee, 0x2e, 0x2f, 0xef, 0x2d, 0xed, 0xec, 0x2c, 
        0xe4, 0x24, 0x25, 0xe5, 0x27, 0xe7, 230, 0x26, 0x22, 0xe2, 0xe3, 0x23, 0xe1, 0x21, 0x20, 0xe0, 
        160, 0x60, 0x61, 0xa1, 0x63, 0xa3, 0xa2, 0x62, 0x66, 0xa6, 0xa7, 0x67, 0xa5, 0x65, 100, 0xa4, 
        0x6c, 0xac, 0xad, 0x6d, 0xaf, 0x6f, 110, 0xae, 170, 0x6a, 0x6b, 0xab, 0x69, 0xa9, 0xa8, 0x68, 
        120, 0xb8, 0xb9, 0x79, 0xbb, 0x7b, 0x7a, 0xba, 190, 0x7e, 0x7f, 0xbf, 0x7d, 0xbd, 0xbc, 0x7c, 
        180, 0x74, 0x75, 0xb5, 0x77, 0xb7, 0xb6, 0x76, 0x72, 0xb2, 0xb3, 0x73, 0xb1, 0x71, 0x70, 0xb0, 
        80, 0x90, 0x91, 0x51, 0x93, 0x53, 0x52, 0x92, 150, 0x56, 0x57, 0x97, 0x55, 0x95, 0x94, 0x54, 
        0x9c, 0x5c, 0x5d, 0x9d, 0x5f, 0x9f, 0x9e, 0x5e, 90, 0x9a, 0x9b, 0x5b, 0x99, 0x59, 0x58, 0x98, 
        0x88, 0x48, 0x49, 0x89, 0x4b, 0x8b, 0x8a, 0x4a, 0x4e, 0x8e, 0x8f, 0x4f, 0x8d, 0x4d, 0x4c, 140, 
        0x44, 0x84, 0x85, 0x45, 0x87, 0x47, 70, 0x86, 130, 0x42, 0x43, 0x83, 0x41, 0x81, 0x80, 0x40
     }; 
        // Methods
        public static short CRC16(byte[] data, int arrayLength)
        {
            byte num = 0xff;
            byte num2 = 0xff;
            int num4 = 0;
            while (arrayLength-- > 0)
            {
                byte index = (byte)(num ^ data[num4++]);
                num = (byte)(num2 ^ ArrayCRCHigh[index]);
                num2 = checkCRCLow[index];
            }
            return (short)((num << 8) | num2);
        }
}
回读的时候判断下
if (b.Length == 8)
{
short h = CRC.CRC16(b, 6);
byte hight = (byte)(h >> 8);//取高字节
byte low = (byte)(h & 0xFF);//取低字节 
//校验
if (b[6] == hight &&b[7] == low)
{}
else
{
throw new System.IO.IOException("机器未打开");
}
} 
感谢这个COM,让我第一阶段如期完成了,真开心。不过留下问题了,以后要多加注意,下次一定调通。
 

 

 

posted @ 2009-04-07 20:00  yellowyu  阅读(1383)  评论(3编辑  收藏  举报