串口通讯简单实例

前几天制作了一个基于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;
}


 

本应用基本实现超级终端发送端和接收端的功能,用手机测试正常运行。

但程序有点粗糙, 待以后有时间再将其完善。

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值