前几天制作了一个基于Win32控制台的串口通讯接收端的程序。 今天利用MFC制作了一个类似超级终端的应用程序。包含了发送端和接收端。
界面如下图
关键代码如下:
Button connect响应函数, 打开串口, 配置串口参数, 设置事件掩码, 建立接收端线程。
void CMFC_CommDlg::OnButtonConnect()
{
// TODO: Add your control notification handler code here
DCB dcb;
char tempBuf[100];
CString testStr;
m_hComm = CreateFile("COM6",
GENERIC_READ | GENERIC_WRITE,
0,
0,
OPEN_EXISTING,
FILE_FLAG_OVERLAPPED,
0);
if (m_hComm == INVALID_HANDLE_VALUE)
MessageBox("Open comm failed!");
else
MessageBox("COM6 is opened! Don't open it again!");
/*set comm inqueue&outqueue buffer*/
if(!SetupComm(m_hComm,1024,1024))
{
MessageBox("Setup Comm in&out queue buffer failed!");
}
/*Set Comm info*/
if (!GetCommState(m_hComm,&dcb))
{
// Handle the error.
sprintf(tempBuf,"GetCommState failed with error %d.\n", GetLastError());
MessageBox(tempBuf);
memset(tempBuf,0,100);
return;
}
dcb.BaudRate = CBR_115200; // set the baud rate
dcb.ByteSize = 8; // data size, xmit, and rcv
dcb.Parity = NOPARITY; // no parity bit
dcb.StopBits = ONESTOPBIT; // one stop bit
if (!SetCommState(m_hComm, &dcb))
{
sprintf(tempBuf,"GetCommState failed with error %d.\n", GetLastError());
MessageBox(tempBuf);
memset(tempBuf,0,100);
return;
}
/*Set Comm Mask*/
if(!SetCommMask(m_hComm,EV_RXCHAR|EV_RXFLAG))
{
MessageBox("SetCommMask failed!");
return;
}
MessageBox("Open and Connect COM6 with baudRate 115200 seccussfully!");
/*Test GetDlgItemText function. Yes it is the member function of class CMFC_CommDlg*/
/*
this->GetDlgItemText(IDC_EDIT_RECV,testStr);
testStr.Format("%s","hello world!");
this->SetDlgItemText(IDC_EDIT_RECV,testStr);
*/
m_hReadThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ReadThreadFunc,this,0,NULL);
CloseHandle(m_hReadThread);
}
接收端线程, 利用重叠I\O WaitCommEvent 等待EV_RXCHAR和EV_RXFLAG事件产生。并利用WaitForSingleObject等待Event产生。
DWORD WINAPI ReadThreadFunc(
LPVOID lpParameter // thread data
)
{
char buff[1024]={0};
char str[2048]={0};
LPTSTR tb;
CString cStr;
DWORD res,factbyte;
COMSTAT rst;
int fError,commEvError;
DWORD dwEvtMask,CommResult,readResult;
BOOL bRet;
BOOL fWaitingOnStat=FALSE; // indicate if wait comm event is pending.
OVERLAPPED osComm = {0}; // overlapped structure for comm event operations
OVERLAPPED osReader = {0}; // overlapped structure for read operations
osComm.hEvent = CreateEvent(NULL,TRUE,FALSE,NULL);
if (osComm.hEvent == NULL)
AfxMessageBox("Create comm Event failed!");
osReader.hEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
if (osReader.hEvent == NULL)
AfxMessageBox("Create reader Event failed!\n");
HANDLE m_hComm=(HANDLE)(((CMFC_CommDlg *)lpParameter)->m_hComm);
HWND m_hWnd=(HWND)(((CMFC_CommDlg *)lpParameter)->m_hWnd);
CEdit *m_EditRecv=(CEdit *)(&(((CMFC_CommDlg *)lpParameter)->m_Edit_Recv));
while(1)
{
if(!fWaitingOnStat)
{
bRet=WaitCommEvent(m_hComm,&dwEvtMask,&osComm);
if(!bRet)
{
commEvError=GetLastError();
ASSERT(commEvError==ERROR_IO_PENDING);
fWaitingOnStat=TRUE;
}
else
{
//WaitCommEvent always will return FALSE for overlapped I/O
}
}
/*wait for pending operations to complete*/
if(fWaitingOnStat)
{
CommResult=WaitForSingleObject(osComm.hEvent,500);//Now it can't get the event???Block for ever!!
switch(CommResult)
{
case WAIT_OBJECT_0:
ClearCommError(m_hComm,&res,&rst);
if(!ReadFile(m_hComm,buff,rst.cbInQue,&factbyte,&osReader))
{
fError=GetLastError();
ASSERT(fError==ERROR_IO_PENDING);
readResult=WaitForSingleObject(osReader.hEvent,500);
switch(readResult)
{
case WAIT_OBJECT_0:
buff[rst.cbInQue]=0;
((CMFC_CommDlg *)lpParameter)->GetDlgItemText(IDC_EDIT_RECV,cStr);
//GetDlgItemText(m_hWnd,IDC_EDIT_RECV,str,2048);/*using WUI(Windows user interface)*/
tb=cStr.GetBuffer(2048);
cStr.Format(_T("%s%s"),tb,buff);
((CMFC_CommDlg *)lpParameter)->SetDlgItemText(IDC_EDIT_RECV,cStr);
//(((CMFC_CommDlg *)lpParameter)->m_Edit_Recv).LineScroll((((CMFC_CommDlg *)lpParameter)->m_Edit_Recv).GetLineCount());
m_EditRecv->LineScroll(m_EditRecv->GetLineCount());
//strcat(str,buff);
//SetDlgItemText(m_hWnd,IDC_EDIT_RECV,str);
memset(buff,0,1024);
fWaitingOnStat=FALSE;
case WAIT_TIMEOUT:
//ClearCommError(m_hCommPort,&res,&rst);
//SetCommMask(m_hCommPort,EV_RXCHAR|EV_RXFLAG);
break;
default:
//do nothing!
break;
}
}
else
{
buff[rst.cbInQue]=0;
((CMFC_CommDlg *)lpParameter)->GetDlgItemText(IDC_EDIT_RECV,cStr);
//GetDlgItemText(m_hWnd,IDC_EDIT_RECV,str,2048);/*using WUI(Windows user interface)*/
tb=cStr.GetBuffer(2048);
cStr.Format(_T("%s%s"),tb,buff);
((CMFC_CommDlg *)lpParameter)->SetDlgItemText(IDC_EDIT_RECV,cStr);
//(((CMFC_CommDlg *)lpParameter)->m_Edit_Recv).LineScroll((((CMFC_CommDlg *)lpParameter)->m_Edit_Recv).GetLineCount());
m_EditRecv->LineScroll(m_EditRecv->GetLineCount());
//strcat(str,buff);
//SetDlgItemText(m_hWnd,IDC_EDIT_RECV,str);
memset(buff,0,1024);
fWaitingOnStat=FALSE;
}
break;
case WAIT_TIMEOUT:
//ClearCommError(m_hCommPort,&res,&rst);
//SetCommMask(m_hCommPort,EV_RXCHAR|EV_RXFLAG);
break;
default:
//do nothing!
break;
}
}
}
return 0L;
}
Button send的响应函数, 获得字串, 建立发送端线程。(其实不必建立该线程, 可以直接在send的响应函数中加while循环,只要WriteFile成功后, 就推出该循环, 也是可以的。)
void CMFC_CommDlg::OnButtonSend()
{
// TODO: Add your control notification handler code here
GetDlgItemText(IDC_EDIT_SEND,pSendStr);
pSendStr+="\r\n";
m_Edit_Input.SetFocus();
//m_hWriteThread=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)WriteThreadFunc,this,0,NULL);
//CloseHandle(m_hWriteThread);
m_hWriteThread=AfxBeginThread((AFX_THREADPROC)WriteThreadFunc,this,THREAD_PRIORITY_NORMAL,NULL,NULL);
}
发送端线程,利用重叠I\O WriteFile, WaitForSingleObject等待写操作完成。
DWORD WINAPI WriteThreadFunc(
LPVOID lpParameter // thread data
)
{
DWORD factdata = 0;
DWORD wRes;
BOOL fWaitingForWrite=FALSE;
BOOL bWrite=FALSE;
int wError;
OVERLAPPED osWriter = {0}; // overlapped structure for write operations
CMFC_CommDlg* pCommDlg=(CMFC_CommDlg*)lpParameter;
HANDLE hWriterThread=pCommDlg->m_hWriteThread;
HANDLE hCom=pCommDlg->m_hComm;
CString pWriteStr=pCommDlg->pSendStr;
osWriter.hEvent=CreateEvent(NULL, TRUE, FALSE, NULL);
if(osWriter.hEvent==NULL)
AfxMessageBox("Create writer event failed!");
if(!hCom)
{
AfxMessageBox("Please Open the Comm first!");
AfxEndThread(0);
}
while(1)
{
if(!fWaitingForWrite)
{
bWrite=WriteFile(hCom,pWriteStr,pWriteStr.GetLength(),&factdata,&osWriter);
if(!bWrite)
{
wError=GetLastError();
ASSERT(wError==ERROR_IO_PENDING);
fWaitingForWrite=TRUE;
}
else
{
//do nothing temporarily
fWaitingForWrite=FALSE;
}
}
/*wait for write pending operations to complete*/
if(fWaitingForWrite)
{
wRes=WaitForSingleObject(osWriter.hEvent,500);
switch(wRes)
{
case WAIT_OBJECT_0:
fWaitingForWrite=FALSE;
AfxEndThread(0);
break;
case WAIT_TIMEOUT:
break;
default:
break;
}
}
}
return 0L;
}
本应用基本实现超级终端发送端和接收端的功能,用手机测试正常运行。
但程序有点粗糙, 待以后有时间再将其完善。