1. 程式人生 > >手持嵌入式wince6.0串列埠通訊除錯

手持嵌入式wince6.0串列埠通訊除錯

 前幾天在手持的wince裝置上進行除錯串列埠通訊,著實讓人撓頭啊,串列埠能開啟也能關閉,但就是收發資料不行,搞了好長時間,才發現,是硬體連線有問題。

我用的是vs2008+C#,系統跑的是wince6.0,用C#開發串列埠通訊其實最簡單的就是直接拖控制元件,很方便,但欠缺靈活性,這裡就不說了,我用程式碼實現的串列埠程式如下:

已經跑通,可以直接用的。

using System;
using System.Linq;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;

namespace SmartDeviceProject1
{
    class wincecom
    {
        #region 變數、函式宣告定義部分
        //裝置控制塊結構體型別
        [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是否用於檢測傳送控制,當為TRUE是CTS為OFF,傳送將被掛起。 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;   // 當該值為TRUE時DSR為OFF時接收的位元組被忽略 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;     // 該值為TRUE且fParity為TRUE時,用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時,
                     當接收緩衝區小於半滿時RTS為ON
                      當接收緩衝區超過四分之三滿時RTS為OFF
                     RTS_CONTROL_TOGGLE時,
                     當接收緩衝區仍有剩餘位元組時RTS為ON ,否則預設為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 byte XonChar;            // 指定用於傳送和接收字元XON的值 Tx and Rx XON character
            public byte XoffChar;           // 指定用於傳送和接收字元XOFF值 Tx and Rx XOFF character
            public byte ErrorChar;          // 本字元用來代替接收到的奇偶校驗發生錯誤時的值 error replacement character
            public byte EofChar;            // 當沒有使用二進位制模式時,本字元可用來指示資料的結束 end of input character
            public byte EvtChar;            // 當接收到此字元時,會產生一個事件 received event character
            public ushort wReserved1;         // 未使用 reserved; do not use
        }

        //串列埠超時時間結構體型別 ,以毫秒為單位
        [StructLayout(LayoutKind.Sequential)]
        public struct COMMTIMEOUTS
        {
            public int ReadIntervalTimeout;           //讀間隔超時
            public int ReadTotalTimeoutMultiplier;    //讀時間係數
            public int ReadTotalTimeoutConstant;      //讀時間常量
            public int WriteTotalTimeoutMultiplier;   //寫時間係數
            public int WriteTotalTimeoutConstant;     //寫時間常量
        }

        //溢位緩衝區結構體型別
        [StructLayout(LayoutKind.Sequential)]
        public struct OVERLAPPED
        {
            public int Internal;
            public int InternalHigh;
            public int Offset;
            public int OffsetHigh;
            public int hEvent;
        }
       
        [DllImport("coredll.dll")]
        public static extern int CreateFile(
            string lpFileName,                         // 要開啟的串列埠名稱
            uint dwDesiredAccess,                      // 指定串列埠的訪問方式,一般設定為可讀可寫方式
            int dwShareMode,                           // 指定串列埠的共享模式,串列埠不能共享,所以設定為0
            int lpSecurityAttributes,                  // 設定串列埠的安全屬性,WIN9X下不支援,應設為NULL
            int dwCreationDisposition,                 // 對於串列埠通訊,建立方式只能為OPEN_EXISTING
            int dwFlagsAndAttributes,                  // 指定串列埠屬性與標誌,設定為FILE_FLAG_OVERLAPPED(重疊I/O操作),指定串列埠以非同步方式通訊
            int hTemplateFile                          // 對於串列埠通訊必須設定為NULL
            );
        [DllImport("coredll.dll")]
        public 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
            //int r
            );
        [DllImport("coredll.dll")]
        public 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
            //int s
            );
        [DllImport("coredll.dll")]
        public static extern bool CloseHandle(
            int hObject                                // handle to object
            );
        [DllImport("coredll.dll")]
        public static extern bool GetCommState(
            int hFile,                                 //通訊裝置控制代碼
            ref DCB lpDCB                              // 裝置控制塊DCB
            );
        [DllImport("coredll.dll")]
        public static extern bool SetCommState(
            int hFile,                                 // 通訊裝置控制代碼
            ref DCB lpDCB                              // 裝置控制塊
            );
        [DllImport("coredll.dll")]
        public static extern bool GetCommTimeouts(
            int hFile,                                 // 通訊裝置控制代碼 handle to comm device
            ref COMMTIMEOUTS lpCommTimeouts            // 超時時間 time-out values
            );
        [DllImport("coredll.dll")]
        public static extern bool SetCommTimeouts(
            int hFile,                                 // 通訊裝置控制代碼 handle to comm device
            ref COMMTIMEOUTS lpCommTimeouts            // 超時時間 time-out values
            );
        //清空讀寫緩衝區
        [DllImport("coredll.dll")]
        public static extern bool PurgeComm(
            int hFile,
            uint dwFlags
            );
        //設定讀寫緩衝區
        [DllImport("coredll.dll")]
        public static extern bool SetupComm(
            int hFile,                    // 通訊裝置控制代碼 handle to file
            int dwInQueue,                //輸入緩衝區的大小
            int dwOutQueue                //輸出緩衝區的大小
            );

        //得到串列埠最後一次返回的錯誤
        [DllImport("coredll.dll")]
        private static extern uint GetLastError();

        //設定DCB標誌位
        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;
        }

        //comm port win32 file handle
        static int hComm = -1;       
        //win32 api constants
        const uint GENERIC_READ = 0x80000000;// WINAPI常量,寫標誌
        const uint GENERIC_WRITE = 0x40000000;// WINAPI常量,讀標誌
        const int OPEN_EXISTING = 3;   // WINAPI常量,開啟已存在  
        //清空讀寫緩衝區
        const int PURGE_REABORT = 0x2;
        const int PURGE_REACLEAR = 0x8;
        const int PURGE_TXABORT = 0x1;
        const int PURGE_TXACLEAR = 0x4;
        int ReadTimeout = 1000;  //超時長
        string comPort = "COM4:";//埠名稱(COM1,COM2...COM4...)
        //string PortNum="4";//埠號
        //string comPort = string.Format("COM{0}:", PortNum);//將埠號格式化
        DCB dcbCommPort = new DCB();
        COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
        //OVERLAPPED ovlCommPort = new OVERLAPPED();//溢位緩衝區
        #endregion

        // 開啟串列埠 OPEN THE COMM PORT.
        public int OpenCom()
        {
            hComm = CreateFile(comPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);
            if (!SetupComm(hComm, 1024, 1024))//輸入輸出緩衝區大小都是1024個位元組
                return -1;
            // 設定通訊超時時間 SET THE COMM TIMEOUTS.
            if (!GetCommTimeouts(hComm, ref ctoCommPort))
                return -2;
            ctoCommPort.ReadTotalTimeoutConstant = ReadTimeout;
            ctoCommPort.ReadTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutMultiplier = 0;
            ctoCommPort.WriteTotalTimeoutConstant = 0;
            if (!SetCommTimeouts(hComm, ref ctoCommPort))
                return -3;

            // 設定串列埠 SET BAUD RATE, PARITY, WORD SIZE, AND STOP BITS.
            if (!GetCommState(hComm, ref dcbCommPort))
                return -4;
            dcbCommPort.DCBlength = Marshal.SizeOf(dcbCommPort);
            dcbCommPort.BaudRate = 115200;
            dcbCommPort.flags = 0;
            dcbCommPort.ByteSize = (byte)8;
            dcbCommPort.Parity = (byte)0;
            dcbCommPort.StopBits = 0;
            //if (dcbCommPort.Parity > 0)
            //{
            //    dcbCommPort.fParity = 1;
            //dcbCommPort.flags |= 2;
            //}
            //dcbCommPort.flags |= 1;
            //dcbCommPort.wReserved = 0;
          //------------------------------
/*            SetDcbFlag(0, 1, dcbCommPort);            //二進位制方式
            SetDcbFlag(1, (dcbCommPort.Parity == 0) ? 0 : 1, dcbCommPort);
            SetDcbFlag(2, 0, dcbCommPort);            //不用CTS檢測傳送流控制
            SetDcbFlag(3, 0, dcbCommPort);            //不用DSR檢測傳送流控制
            SetDcbFlag(4, 0, dcbCommPort);            //禁止DTR流量控制
            SetDcbFlag(6, 0, dcbCommPort);            //對DTR訊號線不敏感
            SetDcbFlag(9, 1, dcbCommPort);            //檢測接收緩衝區
            SetDcbFlag(8, 0, dcbCommPort);            //不做傳送字元控制
            SetDcbFlag(10, 0, dcbCommPort);           //是否用指定字元替換校驗錯的字元
            SetDcbFlag(11, 0, dcbCommPort);           //保留NULL字元
            SetDcbFlag(12, 0, dcbCommPort);           //允許RTS流量控制
            SetDcbFlag(14, 0, dcbCommPort);           //傳送錯誤後,繼續進行下面的讀寫操作

            //------------------------------
            dcbCommPort.wReserved = 0;                       //沒有使用,必須為0 
            dcbCommPort.XonLim = 0;                          //指定在XOFF字元傳送之前接收到緩衝區中可允許的最小位元組數
            dcbCommPort.XoffLim = 0;                         //指定在XOFF字元傳送之前緩衝區中可允許的最小可用位元組數
            dcbCommPort.XonChar = 0;                         //傳送和接收的XON字元
            dcbCommPort.XoffChar = 0;                        //傳送和接收的XOFF字元
            dcbCommPort.ErrorChar = 0;                       //代替接收到奇偶校驗錯誤的字元
            dcbCommPort.EofChar = 0;                         //用來表示資料的結束 
            dcbCommPort.EvtChar = 0;                         //事件字元,接收到此字元時,會產生一個事件 
            dcbCommPort.wReserved1 = 0;                      //沒有使用
*/
            if(!SetCommState(hComm, ref dcbCommPort))
                return -5;
            return hComm;
        }

        //串列埠傳送函式
        public int SendCom(byte[] BufWrite, int SendNum)
        {
            if (hComm != -1)
            {
                int intRealWrite = 0;
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                //PurgeComm(hComm, PURGE_REABORT | PURGE_REACLEAR | PURGE_TXABORT | PURGE_TXACLEAR );
                //向串列埠傳送資料
                bool a = WriteFile(hComm, BufWrite, SendNum, ref intRealWrite, ref ovlCommPort);
                return intRealWrite;
            }
            return -6;
        }


        // 清除接收緩衝區
        public void ClearReceiveBuf()
        {
            if (hComm != -1)
            {
                PurgeComm(hComm, PURGE_REABORT | PURGE_REACLEAR);
            }
        }

        // 清除傳送緩衝區
        public void ClearSendBuf()
        {
            if (hComm != -1)
            {
                PurgeComm(hComm, PURGE_TXABORT | PURGE_TXACLEAR);
            }
        }

        //從串列埠讀取資料
        public int ReadCom(ref byte[] BufRead, int NumBytes)
        {
            if (hComm != -1)
            {
                //byte[] BufRead = new byte[NumBytes];//接收資料的緩衝區
                int intBytesRead = 0;//實際接收的多少位元組
                OVERLAPPED ovlCommPort = new OVERLAPPED();
                //PurgeComm(hComm, PURGE_REABORT | PURGE_REACLEAR | PURGE_TXABORT | PURGE_TXACLEAR | PURGE_TXACLEAR);
                //接收從串列埠返回來的資料
                bool b = ReadFile(hComm, BufRead, NumBytes, ref intBytesRead, ref ovlCommPort);
                return intBytesRead;
            }
            return -1;
        }

        //關閉串列埠
        public bool CloseCom()
        {
            bool c = CloseHandle(hComm);
            return c;
        }


        // 傳送命令
        public int SendCommand(byte[] SendData, ref  byte[] ReceiveData, int Overtime)
        {
            if (hComm != -1)
            {
                COMMTIMEOUTS ctoCommPort = new COMMTIMEOUTS();
                // 設定通訊超時時間
                GetCommTimeouts(hComm, ref ctoCommPort);
                ctoCommPort.ReadTotalTimeoutConstant = Overtime;
                ctoCommPort.ReadTotalTimeoutMultiplier = 0;
                ctoCommPort.WriteTotalTimeoutMultiplier = 0;
                ctoCommPort.WriteTotalTimeoutConstant = 200; 
                SetCommTimeouts(hComm, ref ctoCommPort);

                ClearSendBuf();
                ClearReceiveBuf();

                int a = SendCom(SendData, SendData.Length);
                //return a;
                return ReadCom(ref ReceiveData, ReceiveData.Length);
            }
            return -1;
        }
    }
}