代码比较长,希望高手可以耐心点看,多谢了!串口类头文件:
// CESeries.h: interface for the CCESeries class.
//
//////////////////////////////////////////////////////////////////////typedef void (CALLBACK* ONSERIESREAD)(CWnd*,BYTE* buf,int bufLen);class CCESeries
{public:
CCESeries();
virtual ~CCESeries();
public:
BOOL OpenPort(CWnd* pPortOwner,
  UINT portNo = 1,
  UINT baud = 9600,
  UINT parity = NOPARITY,
  UINT databits = 8,
  UINT stopbits = 0     
  );

void ClosePort();

BOOL SetSeriesTimeouts(COMMTIMEOUTS CommTimeOuts);

BOOL WritePort(const BYTE *buf,DWORD bufLen);
private:
    
    static  DWORD WINAPI ReadThreadFunc(LPVOID lparam);

    static DWORD WINAPI WriteThreadFunc(LPVOID lparam); static BOOL WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen);

void CloseReadThread(); void CloseWriteThread();
private: HANDLE m_hComm;
CWnd* m_pPortOwner;

HANDLE m_hReadThread;
HANDLE m_hWriteThread; DWORD m_dwReadThreadID;
DWORD m_dwWriteThreadID; HANDLE m_hReadCloseEvent;
HANDLE m_hWriteCloseEvent;
public:
ONSERIESREAD m_OnSeriesRead; 
ONSERIESREAD m_OnSeriesRead2;
};
串口类源文件,相关实现部分:
// CESeries.cpp: implementation of the CCESeries class.
//
//////////////////////////////////////////////////////////////////////
const int CM_THREADCOMMWRITE = WM_USER+110;//写串口消息//打开串口并初始化;
BOOL CCESeries::OpenPort(CWnd* pPortOwner,
 UINT portNo ,
 UINT baud ,
 UINT parity ,
 UINT databits ,
 UINT stopbits
 )
{
................设置串口部分省略..........
m_hReadCloseEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//TRUE
m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);//Run thread immediately after creating.
m_hWriteThread = CreateThread(NULL,0,WriteThreadFunc,this,0,&m_dwWriteThreadID);
return TRUE;
}xxxDlg.cpp中通过调用此函数来发送“写串口”消息
BOOL CCESeries::WritePort(const BYTE *buf,DWORD bufLen)  //-------------------------------------(1)
{
if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
WPARAM(bufLen), LPARAM(buf)))
{
return TRUE;
}
return FALSE;
}监控并接收写串口消息CM_THREADCOMMWRITE,并调用(3)函数
DWORD CCESeries::WriteThreadFunc(LPVOID lparam)   //--------------------------------------------(2)
{
CCESeries *ceSeries = (CCESeries*)lparam;
MSG msg;
DWORD dwWriteLen = 0;
BYTE * buf = NULL;

while (TRUE)
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.hwnd != 0 )
{
TranslateMessage(&msg);
DispatchMessage(&msg);
continue;
}
if (msg.message == CM_THREADCOMMWRITE)
{
buf = (BYTE*)msg.lParam;
dwWriteLen = msg.wParam;
WritePort(ceSeries->m_hComm,buf,dwWriteLen); //-----------调用(3)
delete[] buf;
}
} if (WaitForSingleObject(ceSeries->m_hWriteCloseEvent,500) == WAIT_OBJECT_0)// WAIT_TIMEOUT WAIT_OBJECT_0
{
break;
}
ceSeries->m_hWriteThread = NULL;
}
return 0;
}直接向串口写命令的函数
BOOL CCESeries::WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen) //----------------------------(3)
{
DWORD dwNumBytesWritten;
DWORD dwHaveNumWritten =0 ; 

ASSERT(hComm != INVALID_HANDLE_VALUE);
do
{
if (WriteFile (hComm,
buf+dwHaveNumWritten,
bufLen - dwHaveNumWritten,          
&dwNumBytesWritten,
NULL))
{
dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;

if (dwHaveNumWritten == bufLen)
{
break;
}
Sleep(10);
}
else
{
return FALSE;
}
}while (TRUE);

return TRUE;
}下面部分是调用(1)的xxxDlg.cpp文件的“写串口”按钮事件内容:
void CMFCWinCEDlg::OnBnClickedMfg()
{
BYTE buf1[]={0x44,0x69,0x72,0x65,0x63,0x74,0x42,0x61,0x6E,0x64,0x20,0x4F,0x4B}; //DirectBand OK
BYTE buf2[]={0x10,0x01,0xDF,0xED,0x84,0xC5,0x01,0x00,0x0B,0x00,0x00,0x05,0x00,0x00,0x10,0x03};
BYTE buf3[]={0x10,0x01,0xB0,0xA7,0xA6,0x77,0x01,0x00,0x0B,0x00,0x01,0x0B,0x00,0x00,0x10,0x03};
BYTE buf4[]={0x0D};
BYTE bufTemp[]={0x00};
HWND hRecvEdit = ::GetDlgItem(this->GetSafeHwnd(), IDC_EDIT_RECV);
WriteFlag = nEnterMFG;//set write flag as EnterMFG.
if (!m_ceSeries.WritePort(buf1,13))
{
OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.");
return;
}
OutputString(hRecvEdit,L"\r\nCommand 1 OK.");  //---------(4) Sleep(1000);
if (!m_ceSeries.WritePort(buf2,16))
{
OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.\r\n");
return;
}
OutputString(hRecvEdit,L"\r\nCommand 2 OK.");  //--------(5)

Sleep(1000);             
if (!m_ceSeries.WritePort(buf3,16))
{
OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.\r\n");
return;
}
OutputString(hRecvEdit,L"\r\nCommand 3 OK.");//----------(6)


Sleep(1000);
OutputString(hRecvEdit,L"\r\nCommand 4 OK.");//----------(7)
if (!m_ceSeries.WritePort(buf4,1))
{
OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.\r\n");
return;

OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command ok.\r\n");
OutputString(hRecvEdit,L"\r\nWaiting for receiver to reboot ...\r\n"); 
}
调用这里是,可以显示出(4),(5),(6)的信息,
(7)的信息显示不出系统就自动退出了很是郁闷。代码比较长,希望高手可以耐心点看,多谢了!

解决方案 »

  1.   

    CSDN有点很不好,写了半天,不注意按了一个什么按钮,全没了,
    Ctrl+Z又不能撤销操作,害得俺又重写一遍。
      

  2.   

    你在每个OutputString后面都加一个Sleep看看执行结果是否相同。
      

  3.   

    代码比较长,用C++效果重发一遍,希望高手可以耐心点看,多谢了!串口类头文件:// CESeries.h: interface for the CCESeries class.
    //
    //////////////////////////////////////////////////////////////////////typedef void (CALLBACK* ONSERIESREAD)(CWnd*,BYTE* buf,int bufLen);class CCESeries
    {public:
    CCESeries();
    virtual ~CCESeries();
    public:
    BOOL OpenPort(CWnd* pPortOwner,
      UINT portNo = 1,
      UINT baud = 9600,
      UINT parity = NOPARITY,
      UINT databits = 8,
      UINT stopbits = 0     
      );

    void ClosePort();

    BOOL SetSeriesTimeouts(COMMTIMEOUTS CommTimeOuts);

    BOOL WritePort(const BYTE *buf,DWORD bufLen);
    private:
        
        static  DWORD WINAPI ReadThreadFunc(LPVOID lparam);

        static DWORD WINAPI WriteThreadFunc(LPVOID lparam); static BOOL WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen);

    void CloseReadThread(); void CloseWriteThread();
    private: HANDLE m_hComm;
    CWnd* m_pPortOwner;

    HANDLE m_hReadThread;
    HANDLE m_hWriteThread; DWORD m_dwReadThreadID;
    DWORD m_dwWriteThreadID; HANDLE m_hReadCloseEvent;
    HANDLE m_hWriteCloseEvent;
    public:
    ONSERIESREAD m_OnSeriesRead; 
    ONSERIESREAD m_OnSeriesRead2;
    };
    串口类源文件,相关实现部分:// CESeries.cpp: implementation of the CCESeries class.
    //
    //////////////////////////////////////////////////////////////////////
    const int CM_THREADCOMMWRITE = WM_USER+110;//写串口消息
    //打开串口并初始化;BOOL CCESeries::OpenPort(CWnd* pPortOwner,
     UINT portNo ,
     UINT baud ,
     UINT parity ,
     UINT databits ,
     UINT stopbits
     )
    {
    ................设置串口部分省略..........
    m_hReadCloseEvent = CreateEvent(NULL,FALSE,FALSE,NULL);//TRUE
    m_hWriteCloseEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
    m_hReadThread = CreateThread(NULL,0,ReadThreadFunc,this,0,&m_dwReadThreadID);//Run thread immediately after creating.
    m_hWriteThread = CreateThread(NULL,0,WriteThreadFunc,this,0,&m_dwWriteThreadID);
    return TRUE;
    }xxxDlg.cpp中通过调用此函数来发送“写串口”消息BOOL CCESeries::WritePort(const BYTE *buf,DWORD bufLen)  //-------------------------------------(1)
    {
    if (PostThreadMessage(m_dwWriteThreadID,CM_THREADCOMMWRITE,
    WPARAM(bufLen), LPARAM(buf)))
    {
    return TRUE;
    }
    return FALSE;
    }
    监控并接收写串口消息CM_THREADCOMMWRITE,并调用(3)函数DWORD CCESeries::WriteThreadFunc(LPVOID lparam)   //--------------------------------------------(2)
    {
    CCESeries *ceSeries = (CCESeries*)lparam;
    MSG msg;
    DWORD dwWriteLen = 0;
    BYTE * buf = NULL;

    while (TRUE)
    {
    if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
    {
    if (msg.hwnd != 0 )
    {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
    continue;
    }
    if (msg.message == CM_THREADCOMMWRITE)
    {
    buf = (BYTE*)msg.lParam;
    dwWriteLen = msg.wParam;
    WritePort(ceSeries->m_hComm,buf,dwWriteLen); //-----------调用(3)
    delete[] buf;
    }
    } if (WaitForSingleObject(ceSeries->m_hWriteCloseEvent,500) == WAIT_OBJECT_0)// WAIT_TIMEOUT WAIT_OBJECT_0
    {
    break;
    }
    ceSeries->m_hWriteThread = NULL;
    }
    return 0;
    }
    直接向串口写命令的函数
    BOOL CCESeries::WritePort(HANDLE hComm,const BYTE *buf,DWORD bufLen) //----------------------------(3)
    {
    DWORD dwNumBytesWritten;
    DWORD dwHaveNumWritten =0 ; 

    ASSERT(hComm != INVALID_HANDLE_VALUE);
    do
    {
    if (WriteFile (hComm,
    buf+dwHaveNumWritten,
    bufLen - dwHaveNumWritten,          
    &dwNumBytesWritten,
    NULL))
    {
    dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;

    if (dwHaveNumWritten == bufLen)
    {
    break;
    }
    Sleep(10);
    }
    else
    {
    return FALSE;
    }
    }while (TRUE);

    return TRUE;
    }下面部分是调用(1)的xxxDlg.cpp文件的“写串口”按钮事件内容:
    void CMFCWinCEDlg::OnBnClickedMfg()
    {
    BYTE buf1[]={0x44,0x69,0x72,0x65,0x63,0x74,0x42,0x61,0x6E,0x64,0x20,0x4F,0x4B}; //DirectBand OK
    BYTE buf2[]={0x10,0x01,0xDF,0xED,0x84,0xC5,0x01,0x00,0x0B,0x00,0x00,0x05,0x00,0x00,0x10,0x03};
    BYTE buf3[]={0x10,0x01,0xB0,0xA7,0xA6,0x77,0x01,0x00,0x0B,0x00,0x01,0x0B,0x00,0x00,0x10,0x03};
    BYTE buf4[]={0x0D};
    BYTE bufTemp[]={0x00};
    HWND hRecvEdit = ::GetDlgItem(this->GetSafeHwnd(), IDC_EDIT_RECV);
    WriteFlag = nEnterMFG;//set write flag as EnterMFG.
    if (!m_ceSeries.WritePort(buf1,13))
    {
    OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.");
    return;
    }
    OutputString(hRecvEdit,L"\r\nCommand 1 OK.");  //---------(4) Sleep(1000);
    if (!m_ceSeries.WritePort(buf2,16))
    {
    OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.\r\n");
    return;
    }
    OutputString(hRecvEdit,L"\r\nCommand 2 OK.");  //--------(5)

    Sleep(1000);             
    if (!m_ceSeries.WritePort(buf3,16))
    {
    OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.\r\n");
    return;
    }
    OutputString(hRecvEdit,L"\r\nCommand 3 OK.");//----------(6)


    Sleep(1000);
    OutputString(hRecvEdit,L"\r\nCommand 4 OK.");//----------(7)
    if (!m_ceSeries.WritePort(buf4,1))
    {
    OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command failed.\r\n");
    return;

    OutputString(hRecvEdit,L"\r\nSend Entering Manufacturing Mode command ok.\r\n");
    OutputString(hRecvEdit,L"\r\nWaiting for receiver to reboot ...\r\n"); 
    }
    调用这里是,可以显示出(4),(5),(6)的信息,
    (7)的信息显示不出系统就自动退出了很是郁闷。
    代码比较长,希望高手可以耐心点看,多谢了!
      

  4.   

    多谢cnzdgs 的回复,
    OutputString函数的内容如下,
    主要是往CEdit里写一些提示信息。#define nTempBuf 20000    //The maximum number of characters allowed is STRSAFE_MAX_CCH.
    #define nExitMFG  5
    #define nListen   0
    //......TCHAR TempBuf[nTempBuf];
    bool FirstOutput;
    unsigned int WriteFlag=0; //void OutputString(HWND hRecvEdit, TCHAR *Str)
    {  
    if (FirstOutput)
    {
    StringCchPrintf(TempBuf, nTempBuf, Str);
    FirstOutput = false;
    }
    else
    {
    int CurLen = wcslen(TempBuf);
    int StrLen = wcslen(Str); // Append or overwrite?
    if (CurLen + StrLen > nTempBuf - 1)
    {
    memcpy(TempBuf, TempBuf + (StrLen+1)*2, (CurLen-(StrLen+1)+1)*2);
    } StringCchCat(TempBuf, nTempBuf, Str);
    }
    // Set the new text
    SendMessage(hRecvEdit, WM_SETTEXT, 0, (LPARAM )TempBuf);
    ::SendMessage(hRecvEdit,EM_LINESCROLL,nTempBuf,(int)::SendMessage(hRecvEdit,EM_GETLINECOUNT,0,0));

      

  5.   

    在(7)之前GetLastError()试试,看看是不是已经出错了
      

  6.   

    把CCESeries::WriteThreadFunc中的delete去掉,最好把BYTE buf1[](2、3、4)都定义为全局量并在前面加上const。
      

  7.   

    为什么每次都delete啊?写程序写大方点,用数组不是挺好的吗?
      

  8.   

    delete[] buf;
    后加上buf = NULL;看看实在看不出哪错了,自动退出应该是内存错误
      

  9.   

    感觉你的程序吧,...........,问题之一就是delete局部数组变量了。
      

  10.   

    多谢各位的回复!如果在xxxDlg.cpp中写一函数直接对串口写数据,该如何写?
      

  11.   

    因为HANDLE    m_hComm;
    是private成员,
    不知道如何在外部调用,希望大家提点一下,
      

  12.   

    写个函数如GetHandle将m_hComm开放出去不就行了
      

  13.   

    非常感谢Jennyvenus,youyingbo,你们说的对,写串口没必要用线程,
    感谢各位!揭帖了。
      

  14.   

    虽然揭帖了,
    但是还想请问一下这个写串口的函数有没有问题?
    现在发现一奇怪现象:如果先点击A按钮去的发A命令,
    然后再点击B按钮去发B命令,
    但是,点击完B之后,本来应该是发B命令的,但是却发了A命令,
    排除代码写错的原因了,
    这是为什么?BOOL CCESeries::WriteCommData(HANDLE hComm,const BYTE *buf,DWORD bufLen)//Add 20080219
    {
    DWORD dwNumBytesWritten;
    DWORD dwHaveNumWritten =0 ; 

    ASSERT(hComm != INVALID_HANDLE_VALUE);
    do
    {
    if (WriteFile (hComm,
    buf+dwHaveNumWritten,
    bufLen - dwHaveNumWritten,          
    &dwNumBytesWritten,
    NULL))
    {
    dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;

    if (dwHaveNumWritten == bufLen)
    {
    break;
    }
    Sleep(10);
    }
    else
    {
    return FALSE;
    }
    }while (TRUE);

    return TRUE;
    }
      

  15.   

    //你这段程序本身没有大的问题,不过你的逻辑可能得不到完全实现
    BOOL CCESeries::WriteCommData(HANDLE hComm,const BYTE *buf,DWORD bufLen)//Add 20080219
    {
        DWORD dwNumBytesWritten;
        DWORD dwHaveNumWritten =0 ; 
        
        ASSERT(hComm != INVALID_HANDLE_VALUE);
        do //用do循环表明你想将大数据块分批写串口
        {
            if (WriteFile (hComm,                    
                buf+dwHaveNumWritten,               //起始地址没有问题
                bufLen - dwHaveNumWritten,          //长度并没有合理控制,比如第一次执行,bufLen - dwHaveNumWritten就是bufLen,理论上就将全部数据都写进去了
                &dwNumBytesWritten,                 //这并没有错   
                NULL))                                
            {
                dwHaveNumWritten = dwHaveNumWritten + dwNumBytesWritten;
                
                if (dwHaveNumWritten == bufLen)
                {
                    break;
                }
                Sleep(10);
            }
            else
            {
                return FALSE;
            }
        }while (TRUE);
        
        return TRUE;        
    }//这段函数本身应该是没问题的