您当前的位置: 首页 > 

txwtech

暂无认证

  • 2浏览

    0关注

    813博文

    0收益

  • 0浏览

    0点赞

    0打赏

    0留言

私信
关注
热门博文

vs2010基于Win32API串口通信MFC实例

txwtech 发布时间:2019-05-17 09:57:47 ,浏览量:2

介绍如何使用win32API函数进行通信端口的编程,因为串口数据接收需要不停地监视串口和处理串口事件,因此,再本实例中将其封装为单个线程执行类。

创建串口线程类并初始化,由CThreadCom1对象的构造函数完成,它实现串口工作变量的初始化工作。

CThreadCom1::CThreadCom1(HANDLE hCom)
{
	m_hCom=hCom;
	m_bInit=false;
	m_sCom="";
	m_sError="No Error!";
	m_hThread=NULL;
	m_dwSendMsgToParent=0;
	m_dwRecvMsgToParent=0;
	m_pWndParent=NULL;
	memset((unsigned char*)&m_overRead,0,sizeof(OVERLAPPED));
	memset((unsigned char*)&m_overWrite,0,sizeof(OVERLAPPED));
	m_overRead.hEvent=CreateEvent(NULL,true,false,NULL);
	m_overWrite.hEvent=CreateEvent(NULL,true,false,NULL);
	
}

CThreadCom1::~CThreadCom1()
{
	CloseHandle(m_overRead.hEvent);
	CloseHandle(m_overWrite.hEvent);
}

BOOL CThreadCom1::InitInstance()
{
	// TODO: 在此执行任意逐线程初始化
	m_bAutoDelete=false;
	m_bDone=false;
	return TRUE;
}

int CThreadCom1::ExitInstance()
{
	// TODO: 在此执行任意逐线程清理
	BOOL bFlag=CloseCom();
	return CWinThread::ExitInstance();
}

串口接收线程的处理工作由CThreadCom1对象的Run()函数完成。它实现

循环从串口读取数据,并将接收的数据发送给处理函数的功能。

int CThreadCom1::Run(void)//重载线程类的Run()运行函数
{
	//return 0;
	DWORD dwError,dwReadNum,dwByteRead,dwEvent;
	COMSTAT	ComStat;//串口状态变量
	BYTE rBuf[MAXCOMINBUF];//输入缓冲区
	while(!m_bDone)
	{
		while(m_hCom!=INVALID_HANDLE_VALUE)
		{
			if(::WaitCommEvent(m_hCom,&dwEvent,NULL))//等待注册的串口事件发生
			{
				dwByteRead=0;//初始化读字节数
				if(dwEvent&EV_RXCHAR)
				{
					ClearCommError(m_hCom,&dwError,&ComStat);//清空当前串口事件
					if(ComStat.cbInQue!=0)//输入列队中的数据个数
					{
						dwReadNum=ComStat.cbInQue;
						dwByteRead=0;
						if(dwReadNum>200)
							dwReadNum=200;
						memset(rBuf,0,sizeof(rBuf));//清空接收缓冲区变量
						DWORD i=::ReadFile(m_hCom,rBuf,dwReadNum,&dwByteRead,&m_overRead);
						for(i=dwByteRead;iSendMessage(m_dwRecvMsgToParent,(DWORD)rBuf,dwByteRead);//读取的数据发送到父窗口
						
			}

		}
		Sleep(1000);
	}
	return CWinThread::Run();//调用基类的Run()函数
}

//打开串口,根据程序配置,打开指定工作串口的功能

BOOL CThreadCom1::OpenCom(CString strCom, CWnd* pWndParent, DWORD dwSendMsgToParent, DWORD dwRecvMsgToParent)
{
	//return 0;
	CloseCom();
	CString strLog;
	m_hCom=::CreateFile(strCom,GENERIC_READ|GENERIC_WRITE,0,NULL,OPEN_EXISTING,FILE_FLAG_OVERLAPPED,NULL);//打开串口
	if(m_hCom==INVALID_HANDLE_VALUE)
	{
		strLog.Format("Open %s Error",strCom);
		AfxMessageBox(strLog);
		return FALSE;
	}
	::SetupComm(m_hCom,MAXCOMINBUF,MAXCOMOUTBUF);//设置串口输入输出缓冲区
	DCB dcb;//定义DCB结构
	if(!GetCommState(m_hCom,&dcb))
	{
		AfxMessageBox("获取串口状态错误");
		CloseHandle(m_hCom);
		m_hCom=INVALID_HANDLE_VALUE;
		return FALSE;
	}
	if(!SetCommState(m_hCom,&dcb))
	{
		CloseHandle(m_hCom);
		m_hCom=INVALID_HANDLE_VALUE;
		strLog.Format("set %s CommState Error!",strCom);
		AfxMessageBox(strLog);
		return FALSE;
	}
	//

	m_sError="No Error";	
	m_pWndParent	=	pWndParent;//存储父窗口句柄
	m_dwSendMsgToParent	= dwSendMsgToParent;//存储接收发送消息的父窗口
	m_dwRecvMsgToParent	= dwRecvMsgToParent;//存储接收接收消息的父窗口



	//
	DWORD CommMask;
	CommMask=0|EV_BREAK|EV_CTS|EV_DSR|EV_ERR|EV_EVENT1|EV_EVENT2|EV_PERR|EV_RING|EV_RLSD|EV_RX80FULL|EV_RXCHAR|EV_RXFLAG|EV_TXEMPTY;
	::SetCommMask(m_hCom,CommMask);//注册要处理的事件
	::GetCommTimeouts(m_hCom,&m_Commtimeout);//读取超时时间设置
	m_Commtimeout.ReadTotalTimeoutMultiplier=5;
	m_Commtimeout.ReadTotalTimeoutConstant=100;
	m_bInit=true;
	return TRUE;


}

//关闭串口

BOOL CThreadCom1::CloseCom(void)
{
	//return 0;
	if(m_hCom!=INVALID_HANDLE_VALUE)
	{
		PurgeComm(m_hCom,PURGE_RXCLEAR);//释放串口事件
		CloseHandle(m_hCom);
		m_hCom=INVALID_HANDLE_VALUE;//设置句柄无效
	}
	m_bInit=false;
	return true;
}

//发送数据

BOOL CThreadCom1::SendData(BYTE* s, DWORD dwLen)
{
	//return 0;
	if(!dwLen)
		return false;
	::GetCommTimeouts(m_hCom,&m_Commtimeout);
	m_Commtimeout.WriteTotalTimeoutMultiplier=0;//设置读操作超时时间
	m_Commtimeout.WriteTotalTimeoutConstant=2*dwLen;//设置读操作超时常量

	::SetCommTimeouts(m_hCom,&m_Commtimeout);//设置超时时间设置
	if(m_hCom!=INVALID_HANDLE_VALUE)
	{
		DWORD dwSend;
		m_pWndParent->SendMessage(m_dwSendMsgToParent,(DWORD)s,dwLen);
	//发送日志
		if(!WriteFile(m_hCom,s,dwLen,&dwSend,&m_overWrite))//向串口发送数据
		{
			m_sError="串口发送数据失败";
			return false;
		}
		return true;
	}
	else
	{
		m_sError="串口句柄无效";
		return false;
	}
}

串口线程类代码结束后。界面的处理,对话框类中,实现相关按钮触发事件。

对话框类头文件相关声明:

public:
//	CString m_Log;
	CString m_editSend;
	CString m_editReceive;
	CComboBox m_comboComm;
	afx_msg void OnBnClickedButtonOpenserial();
	CThreadCom1* pThreadCom; 
	BOOL m_bCom;
	void WriteLog(CString log);
	afx_msg void OnBnClickedButtonSend();
//	void OnSendMsg(DWORD dwEvent, DWORD dwLen);
	CEdit m_Log;
//	void OnRecvMsg(DWORD dwEvent, DWORD dwLen);
	//HRESULT OnSendMsg(DWORD dwEvent, DWORD dwLen);
	HRESULT OnSendMsg(WPARAM dwEvent, LPARAM dwLen);
	//HRESULT OnRecvMsg(DWORD dwEvent, DWORD dwLen);
	HRESULT OnRecvMsg(WPARAM dwEvent, LPARAM dwLen);
	CEdit m_edit_Receive1;

//打开串口的按钮

void CTxwtechWin32API_CommDlg::OnBnClickedButtonOpenserial()
{
	// TODO: 在此添加控件通知处理程序代码
	if(pThreadCom!=NULL) return;
	CString str;
	CString com;
	//int com1;
	//com1=m_comboComm.GetCurSel();
	//com1+=1;
	//com=m_comboComm.GetWindowText();
	m_comboComm.GetWindowTextA(com);//获取组合框com的内容
	//com.Format("%s",com1);
	pThreadCom=(CThreadCom1*)AfxBeginThread(RUNTIME_CLASS(CThreadCom1));
	pThreadCom->SetComStr(com);//设置串口线程的串口名称变量
	if(pThreadCom->OpenCom(com,(CWnd*)this->GetSafeOwner(),WM_USER_COMSENDMESSAGE,WM_USER_COMRECVMESSAGE))
	{
		str.Format("打开串口%s成功",pThreadCom->GetComStr());
		WriteLog(str);
	}
	else
	{
		str.Format(pThreadCom->m_sError+",请重新配置串口");
		WriteLog(str);
		pThreadCom->m_bInit=FALSE;
		return;
	}
	m_bCom=TRUE;
	m_comboComm.EnableWindow(FALSE);
	return;
}

//发送按钮绑定的代码

void CTxwtechWin32API_CommDlg::OnBnClickedButtonSend()
{
	// TODO: 在此添加控件通知处理程序代码
	UpdateData(true);
	int iLen=m_editSend.GetLength();
	BYTE* s=new BYTE[iLen];
	memset(s,0x00,iLen);//初始化数据缓冲区
	memcpy(s,(LPCTSTR)m_editSend,iLen);//复制数据
	pThreadCom->SendData((unsigned char*)s,iLen);
}

//发送数据通知

HRESULT CTxwtechWin32API_CommDlg::OnSendMsg(WPARAM dwEvent, LPARAM dwLen)
{
	if(!dwLen)
		return 0;
	BYTE* temp=new BYTE[dwLen+1];
	memset(temp,0x00,dwLen+1);
	memcpy(temp,(const void*)dwEvent,dwLen);
	CString log;
	log.Format("\r\n发送数据%s",(LPCTSTR)temp);
	if(m_Log)
	{
		CEdit* editLog=(CEdit*)FromHandle(m_Log);
		if(editLog->GetWindowTextLength()>50000)
		{
			editLog->SetSel(0,-1);//把发送区的全部内容选中
			editLog->Clear();//清空全部内容
			editLog->SetSel(0,0);//设置光标到0字节处
			editLog->ReplaceSel(log);//更新新的内容
		}
		else
		{
			editLog->SetSel(editLog->GetWindowTextLength(),editLog->GetWindowTextLength());//光标指向句末
			editLog->ReplaceSel(log);//添加新内容
		}
	}
//	return;
	return E_NOTIMPL;
}

//接收消息通知

HRESULT CTxwtechWin32API_CommDlg::OnRecvMsg(WPARAM dwEvent, LPARAM dwLen)
{
	if(!dwLen) return 0;
	BYTE* temp=new BYTE[dwLen+1];
	memset(temp,0x00,dwLen+1);
	memcpy(temp,(const void*)dwEvent,dwLen);
	CString log;
	log.Format("\r\n接收数据=%s",(LPCTSTR)temp);
	if(m_editReceive.GetLength()>50000)
		m_editReceive="";
	m_editReceive+=log;
	CEdit* editLog=(CEdit*)FromHandle(m_edit_Receive1);
	editLog->SetSel(editLog->GetWindowTextLength(),editLog->GetWindowTextLength());
			editLog->ReplaceSel(log);
	//UpdateData(false);
	return E_NOTIMPL;
}

相关调试遇到的问题:

error C2511: “CThreadCom1::CThreadCom1(HANDLE)”:“CThreadCom1”中没有找到重载的成员函数 原因:头文件未定义。 CThreadCom1(HANDLE hCom=INVALID_HANDLE_VALUE); error C2668: “CThreadCom1::CThreadCom1”: 对重载函数的调用不明确 头文件中只有有一个重载函数,把默认的删除掉

TxwtechWin32API_Comm.exe 中的 0x100c14cf (msvcr100d.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x00000002 时发生访问冲突, rootcause:连接串口不能是数值,而是字符串COM1...

TxwtechWin32API_Comm.exe 中的 0x7898391c (mfc100d.dll) 处有未经处理的异常: 0xC0000005: 读取位置 0x00000020 时发生访问冲突 缺少如下两句://m_dwSendMsgToParent 没有获取父窗口的值 //m_dwSendMsgToParent = dwSendMsgToParent;  m_dwRecvMsgToParent = dwRecvMsgToParent;

接收框中无法接收消息,注意消息的映射与宏定义

#define WM_USER_COMSENDMESSAGE WM_USER+200 #define WM_USER_COMRECVMESSAGE WM_USER+201

BEGIN_MESSAGE_MAP(CTxwtechWin32API_CommDlg, CDialogEx)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BUTTON_OpenSerial, &CTxwtechWin32API_CommDlg::OnBnClickedButtonOpenserial)
	ON_BN_CLICKED(IDC_BUTTON_Send, &CTxwtechWin32API_CommDlg::OnBnClickedButtonSend)
	ON_MESSAGE(WM_USER_COMSENDMESSAGE,OnSendMsg)
	ON_MESSAGE(WM_USER_COMRECVMESSAGE,OnRecvMsg)
END_MESSAGE_MAP()

关注
打赏
1665060526
查看更多评论
立即登录/注册

微信扫码登录

0.0385s