自动检测可用串口实现串口通讯程序(可实现串口热插拔检测)

项目中一直在用串口通讯,但没有实现可用串口的自动检测和热插拔检测。今天通过查找资料实现了这些功能,所以在这里坐下记录。

参考资料:http://blog.csdn.net/flydream0/article/details/8086976

实现环境:VC6.0

1、创建基于对话框的工程

2、在工程中添加串口通讯控件,添加方法如下

VC6.0菜单中:工程—>增加到工程—>Components and Controls Gallery双击打开Registered ActiveX Controls在下拉框里选择Microsoft Communications Control, version 6.0,如图所示

 

自动检测可用串口实现串口通讯程序(可实现串口热插拔检测)_第1张图片自动检测可用串口实现串口通讯程序(可实现串口热插拔检测)_第2张图片

在这里碰到问题了,win7下的vc6.0在添加控件的时候出错,所以要在此声明,使用的是XP+VC6.0,估计是两者的问

兼容题,在此就不说了,接着上面的记录

在添加控件成功之后,和添加其他控件一样拖拽至对话框内即可

 

 

3、为Comm Control控件添加变量和响应函数,如图所示

至此,控件添加完成

 

自动检测可用串口实现串口通讯程序(可实现串口热插拔检测)_第3张图片自动检测可用串口实现串口通讯程序(可实现串口热插拔检测)_第4张图片

 

4、下面实现自动检测串口

遍历所有串口代码如下:

void CCommDlg::foreachPort(CUIntArray& ports,CUIntArray& portse,CUIntArray& portsu)
{
	//清空数组内容
	ports.RemoveAll();//所有存在串口
	portse.RemoveAll();//可用串口
	portsu.RemoveAll();//已占用串口
	//清空数组内容

	//串口最多有255,所以这里遍历255个串口是否可以使用即可
	for (int i=1;i<=255;i++)
	{
		//形成串口名称
		CString portStr;
		portStr.Format("COM%d",i);
		//形成串口名称

		//尝试打开串口
		BOOL bSuccess=FALSE;
		HANDLE m_hCom=CreateFile(portStr,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);
		if (m_hCom==INVALID_HANDLE_VALUE)
		{
			DWORD dwError=GetLastError();

			if (dwError==ERROR_ACCESS_DENIED)
			{
				bSuccess=TRUE;
				portsu.Add(i);//已占用的串口号
			}
		} 
		else
		{
			bSuccess=TRUE;
			portse.Add(i);//可用串口号
			
			CloseHandle(m_hCom);
		}
		if (bSuccess)  ports.Add(i);//全部串口号
		//尝试打开串口
	}
}

在下拉框内显示可用窗口,实现代码如下:

 

void CCommDlg::fillPortComm()
{
 	foreachPort(ports,portse,portsu);//所有串口号,可用串口号,已占用串口号
	CString str;

// 	unsigned short portNum;
// 	unsigned short portSerialNum;
// 	portNum=ports.GetSize();

	if (portse.GetSize()>0)
	{
		for (int i=0;i


添加打开串口按钮,并实现打开串口/关闭串口功能,实现代码如下:

void CCommDlg::OnOpenport() 
{
	// TODO: Add your control notification handler code here
	CString strname;
	int comNum=portse.ElementAt(((CComboBox *)GetDlgItem(IDC_PORTCOMBO))->GetCurSel());

	if (GetDlgItemText(IDC_OPENPORT,strname),strname=="OpenPort")
	{
		if(m_Comm.GetPortOpen())//如果串口是打开的,则关闭串口 
		{ 
			m_Comm.SetPortOpen(FALSE);
		}	
		try
		{
			m_Comm.SetCommPort(comNum); //串口
			m_Comm.SetInputMode(1); //设置输入方式为二进制方式
			m_Comm.SetInBufferSize(1024); //设置输入缓冲区的大小,Bytes 
			m_Comm.SetOutBufferSize(512); //设置输入缓冲区的大小,Bytes 
			m_Comm.SetSettings("9600,n,8,1"); //设置波特率等参数 
			m_Comm.SetPortOpen(TRUE);
		}
		catch (CException* e)
		{
			e-> Delete(); //防止显示“Invalid   Port   Number”对话框
			strname.Format("COM%d打开失败!",comNum);
			AfxMessageBox(strname);
			return;
		}
		
		m_Comm.SetRThreshold(1); //为1表示有一个字符即引发事件
		m_Comm.SetInputLen(0);
		m_Comm.GetInput();

		SetDlgItemText(IDC_OPENPORT,"Close");
		//SetTimer(1,500,NULL);//设置定时器,循环发送时使用

		//display status
		strname.Format("COM%d打开成功",comNum);
		SetDlgItemText(IDC_STATUS,strname);
		//display status

		GetDlgItem(IDC_SENDBtn)->EnableWindow(TRUE);

	} 
	else
	{
		m_Comm.SetPortOpen(FALSE);

		SetDlgItemText(IDC_OPENPORT,"OpenPort");
		//KillTimer(1);//设置定时器,循环发送时使用

		//display status
		strname.Format("COM%d关闭成功",comNum);
		SetDlgItemText(IDC_STATUS,strname);
		//display status

		GetDlgItem(IDC_SENDBtn)->EnableWindow(FALSE);
	}

}


 

为了实现自动检测串口热插拔,需手动添加消息ON_WM_DEVICECHANGE()

BEGIN_MESSAGE_MAP(CCommDlg, CDialog)
	//{{AFX_MSG_MAP(CCommDlg)
	ON_WM_DEVICECHANGE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()
 
  
 
  

 

在工程的头文件中添加如下代码,对应消息ON_WM_DEVICECHANGE

	afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);//实现串口热插拔


在*.CPP文件下,实现代码如下
  

//实现串口热插拔
BOOL CCommDlg::OnDeviceChange(UINT nEventType, DWORD dwData)
{
	switch(nEventType)
	{
	case DBT_DEVICEREMOVECOMPLETE:
		//refreshCom();
		//break;
	case DBT_DEVICEARRIVAL:
		refreshCom();
		break;
	default:
		break;
	}
	return TRUE;
}

void CCommDlg::refreshCom()
{
	//清除Combo Box 内容
	int m_Num=m_portComBox.GetCount();

	/*m_portComBox.GetCount()这里得到的数值是实时改变的,
	所以这里不能用m_portComBox.GetCount()判断循环是否结束*/
	for (int i=0;i


最后界面如下图所示

 

自动检测可用串口实现串口通讯程序(可实现串口热插拔检测)_第5张图片

 

另外在XP+VC6.0配合的情况下添加ON_WM_DEVICECHANGE之后再打开“建立类向导”会出现如下提示

Parsing error:Undrecognized macro

Input Line:"ON_WM_DEVICECHANGED"

 

BEGIN_MESSAGE_MAP(CCommDlg, CDialog)
	//{{AFX_MSG_MAP(CCommDlg)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

出现这样问题的原因在于上面语句中注释掉的语句具有特殊的作用。注释掉的语句被称为注释宏,注释宏为“建立类向导(class wizad)”服务,“建立类向导(class wizad)”通过注释宏来定位自动添加代码的位置。删除掉注释宏之后“建立类向导(class wizad)”将无法工作。

 

所以这里的解决办法是把自己定义消息的语句放到注释宏之外,既如下语句

 

BEGIN_MESSAGE_MAP(CCommDlg, CDialog)
	//{{AFX_MSG_MAP(CCommDlg)
	//}}AFX_MSG_MAP
	ON_WM_DEVICECHANGE()
END_MESSAGE_MAP()


 

你可能感兴趣的:(自动检测可用串口实现串口通讯程序(可实现串口热插拔检测))