⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 terminatordoc.cpp

📁 该程序演示了如何在windows平台下使用WindowsAPI函数来操作串口
💻 CPP
字号:
// TerminatorDoc.cpp : implementation of the CTerminatorDoc class
//

#include "stdafx.h"
#include "Terminator.h"
#include"CommSetupDlg.h"
#include "TerminatorDoc.h"
#include"PropertyDlg.h"
#include"TerminatorView.h"
#include"MainFrm.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CTerminatorDoc

IMPLEMENT_DYNCREATE(CTerminatorDoc, CDocument)

BEGIN_MESSAGE_MAP(CTerminatorDoc, CDocument)
	//{{AFX_MSG_MAP(CTerminatorDoc)
	ON_COMMAND(IDM_CONNECT, OnConnect)
	ON_COMMAND(IDM_DISCONNECT, OnDisconnect)
	ON_COMMAND(IDM_COMSETTINGS, OnComsettings)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTerminatorDoc construction/destruction
UINT CommProc(LPVOID pParam)
{
	
	OVERLAPPED os;
	DWORD dwMask,dwTrans;
	//定义一个COMSTAT对象,用于判断接收缓冲区中是否有数ComStat.cbInque
	COMSTAT ComStat;
	//用于接收出错标志
	DWORD dwErrorFlags;
	CTerminatorDoc* pDoc=(CTerminatorDoc*)pParam;
	//为先前定义的异步对象分配具体的存贮空间
	memset(&os,0,sizeof(OVERLAPPED));
	//为异步对象生成一个事件对象,且初始化为无效状态
	os.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL);
	if(os.hEvent==NULL)
	{
		AfxMessageBox("Can't create event object!");
		return (UINT)-1;
	}
	while(pDoc->m_bConnected)
	{//每次在准备接收或者判断接收缓冲区中是否有数之前都要清除串口错误
		ClearCommError(pDoc->m_hCom,&dwErrorFlags,&ComStat);
		if(ComStat.cbInQue)
		{	
			//由于m_hPostMsgEvent在最开始生成的时候其状态为有效,所以下面的语句得以执行
			//否则,将等待m_hPostMsgEvent事件为有效,而m_hPostMsgEvent表示的是视图已经
			//显示了接收到的字符,可以开始下次的接收
			WaitForSingleObject(pDoc->m_hPostMsgEvent,INFINITE);
			ResetEvent(pDoc->m_hPostMsgEvent);
			//通知视图从接收缓冲区中取数
			PostMessage(pDoc->m_hTermWnd,WM_COMMNOTIFY,EV_RXCHAR,0);
			continue;
		}
		dwMask=0;
		//判断是否有所监视的串口事件发生
		if(!WaitCommEvent(pDoc->m_hCom,&dwMask,&os))
		{
			if(GetLastError()==ERROR_IO_PENDING)
				GetOverlappedResult(pDoc->m_hCom,&os,&dwTrans,TRUE);
			else
			{
				CloseHandle(os.hEvent);
				return (UINT)-1;
			}
		}
	}
	CloseHandle(os.hEvent);
	return 0;
}


CTerminatorDoc::CTerminatorDoc()
{
	m_bConnected=FALSE;
	m_pThread=NULL;
	m_nBaud=9600;
	m_nFlowCtrl=0;
	m_nParity=0;
	m_sPort="COM1";
	m_nStopBit=0;
	m_bEcho=TRUE;
	m_bNewLine=TRUE;
	m_hCom=NULL;
	m_ParityPos=0;
	m_StopBitPos=0;
	m_PortPos=0;
	m_BaudPos=4;

}

CTerminatorDoc::~CTerminatorDoc()
{
	if(m_bConnected)
		CloseConnect(TRUE);
	if(m_hPostMsgEvent)
		CloseHandle(m_hPostMsgEvent);
	if(m_osRead.hEvent)
		CloseHandle(m_osRead.hEvent);
	if(m_osWrite.hEvent)
		CloseHandle(m_osWrite.hEvent);
}

BOOL CTerminatorDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	((CEditView*)m_viewList.GetHead())->SetWindowText(NULL);
	if((m_hPostMsgEvent=CreateEvent(NULL,TRUE,TRUE,NULL))==NULL)
		return false;
	memset(&m_osRead,0,sizeof(OVERLAPPED));
	memset(&m_osWrite,0,sizeof(OVERLAPPED));
	if((m_osRead.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL))==NULL)
		return false;
	if((m_osWrite.hEvent=CreateEvent(NULL,TRUE,FALSE,NULL))==NULL)
		return false;
	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}



/////////////////////////////////////////////////////////////////////////////
// CTerminatorDoc serialization

void CTerminatorDoc::Serialize(CArchive& ar)
{
	// CEditView contains an edit control which handles all serialization
	((CEditView*)m_viewList.GetHead())->SerializeRaw(ar);
}

/////////////////////////////////////////////////////////////////////////////
// CTerminatorDoc diagnostics

#ifdef _DEBUG
void CTerminatorDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CTerminatorDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/////////////////////////////////////////////////////////////////////////////
// CTerminatorDoc commands

void CTerminatorDoc::OnConnect() 
{
	if(!OpenConnection())
	{
		if(m_bConnected)
			AfxMessageBox("You have open the com!");
		else
			AfxMessageBox("Can't open the com");
	}
}

void CTerminatorDoc::OnDisconnect() 
{
	CloseConnect(false);
}

void CTerminatorDoc::OnComsettings() 
{
	CCommSetupDlg dlg;
	CString str;
	dlg.m_bConnected=m_bConnected;
	if(dlg.DoModal()==IDOK)
	{
		if(m_bConnected)
			if(!ConfigConnection())
				AfxMessageBox("Can't realize the settings !");
	}
}

BOOL CTerminatorDoc::ConfigConnection()
{

	DCB dcb;
	DWORD Error;
	CString str;
	//先从系统中获得一个当前的DCB结构,然后在修改,最后是设置修改后的DCB使之有效
	if(!GetCommState(m_hCom,&dcb))
		return false;
	//是否为二进制流模式
	dcb.fBinary=TRUE;
	//设置波特率
	dcb.BaudRate=m_nBaud;
	dcb.ByteSize=8;
	//是否奇偶校验
	dcb.fParity=TRUE;
	switch(m_nParity)
	{
	case 0:	dcb.Parity=NOPARITY;
		break;
	case 1: dcb.Parity=EVENPARITY;
		break;
	case 2: dcb.Parity=ODDPARITY;
		break;
	default:; 
	}
	switch(m_StopBitPos)
	{
	case '0':
		dcb.StopBits=ONESTOPBIT;
		break;
	case '1':
		dcb.StopBits=ONE5STOPBITS;
		break;
	case '2':
		dcb.StopBits=TWOSTOPBITS;
		break;
	default:;
	}
	dcb.fOutxCtsFlow=m_nFlowCtrl==1;
	dcb.fRtsControl=m_nFlowCtrl==1?
	RTS_CONTROL_HANDSHAKE:RTS_CONTROL_ENABLE;

	if(!(SetCommState(m_hCom,&dcb)))
	{
		Error=GetLastError();
		str.Format(_T("Error code is %ld"),Error);
		AfxMessageBox(str);
		return false;
	}
	return TRUE;
}

BOOL CTerminatorDoc::OpenConnection()
{
	
	//COMMTIMEOUTS是系统自带的一个读写操作超时的结构
	COMMTIMEOUTS TimeOuts;
	//获得当前视图的句柄,用于访问视图
	POSITION firstViewPos;
	CTerminatorView* pView;
	firstViewPos=GetFirstViewPosition();
	pView=(CTerminatorView*)GetNextView(firstViewPos);
	m_hTermWnd=pView->GetSafeHwnd();
	
	//判断是否已经打开过串口,如果已经打开过,则先关闭原来打开的串口,在打开新的串口
	if(m_hCom!=NULL)
		CloseConnect(false);
	if(m_bConnected)
		return false;
	//打开指定的串口
	//m_sPort:"COM1","COM2","COM3","COM3"
	m_hCom=CreateFile(m_sPort,
						GENERIC_READ|GENERIC_WRITE,//指定可读写
						0,//共享方式0:独占
						NULL,//安全属性:0,不设置
						OPEN_EXISTING,
						FILE_ATTRIBUTE_NORMAL|FILE_FLAG_OVERLAPPED,//重叠IO操作
						NULL);
//判断打开指定串口所返回的句柄是否有效
	if(m_hCom==INVALID_HANDLE_VALUE)
		return false;
	//打开串口,并获得对串口操作的句柄后,就设置串口的一些超时常数,和缓冲区大小
	SetupComm(m_hCom,MAXBLOCK,MAXBLOCK);
	//设置监视的串口事件
	SetCommMask(m_hCom,EV_RXCHAR);
	TimeOuts.ReadIntervalTimeout=MAXDWORD;
	TimeOuts.ReadTotalTimeoutMultiplier=0;
	TimeOuts.ReadTotalTimeoutConstant=0;
	TimeOuts.WriteTotalTimeoutMultiplier=50;
	TimeOuts.WriteTotalTimeoutConstant=2000;
	SetCommTimeouts(m_hCom,&TimeOuts);
	if(ConfigConnection())
	{
	//产生一个专么用于在后台接收数据的线程
		m_pThread=AfxBeginThread(CommProc,//线程的回调函数名
									this,
									THREAD_PRIORITY_NORMAL,
									0,//默认堆栈的大小等同于应用程序
									CREATE_SUSPENDED,
									NULL);//安全属性0:不设置安全属性
		if(m_pThread==NULL)
		{
			CloseHandle(m_hCom);//如果上一步不成功则关闭串口
			return false;
		}
		else
		{
			m_bConnected=TRUE;
			pView->NotifySetPane(2,m_sPort);
			pView->NotifySetPane(4,"开启");
			m_pThread->ResumeThread();//开始回调函数的运行
		}
	}
	else
	{
		CloseHandle(m_hCom);//如果配置串口的函数ConfigConnection()不成功则返回
		return false;
	}
	return TRUE;
}

void CTerminatorDoc::CloseConnect(BOOL destroy)
{
	if(destroy!=TRUE)
	{
		POSITION firstViewPos;
		CTerminatorView* pView;
		firstViewPos=GetFirstViewPosition();
		pView=(CTerminatorView*)GetNextView(firstViewPos);
		pView->NotifySetPane(4,"关闭");
	}
	if(!m_bConnected)return;
	m_bConnected=FALSE;
	//将m_hPostMsgEvent事件设为有效,通知辅助线程函数CommProc()退出等待
	SetEvent(m_hPostMsgEvent);
	//不监视串口事件
	SetCommMask(m_hCom,0);
	//如果辅助线程函数CommProc()返回则自动的会设置m_hThread事件为有效
	WaitForSingleObject(m_pThread->m_hThread,INFINITE);
	m_pThread=NULL;
	CloseHandle(m_hCom);
	
}

DWORD CTerminatorDoc::ReadComm(char *buf, DWORD dwLength)
{
	DWORD length=0;
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	ClearCommError(m_hCom,&dwErrorFlags,&ComStat);
	if(dwLength>=ComStat.cbInQue)length=ComStat.cbInQue;
	else length=dwLength;
	ReadFile(m_hCom,buf,length,&length,&m_osRead);
	return length;
}

DWORD CTerminatorDoc::WriteComm(char *buf, DWORD dwLength)
{
	BOOL fState;
	DWORD length=dwLength;
	COMSTAT ComStat;
	DWORD dwErrorFlags;
	ClearCommError(m_hCom,&dwErrorFlags,&ComStat);
	fState=WriteFile(m_hCom,buf,length,&length,&m_osWrite);
	if(!fState)
	{
		if(GetLastError()==ERROR_IO_PENDING)
			GetOverlappedResult(m_hCom,&m_osWrite,&length,TRUE);
		else
			length=0;
	}
	return length;
}




⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -