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

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

参考资料: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,如图所示

 

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

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

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

 

 

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

至此,控件添加完成

 

 

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<portse.GetSize();i++)
		{
			str.Format("COM%d",portse.ElementAt(i));
			m_portComBox.AddString(str);			
		}
	}
}


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

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()

<pre class="cpp" name="code"><pre class="cpp" name="code">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<m_Num;i++)
	{
		m_portComBox.DeleteString(m_Num-1-i);
	}
	//清除Combo Box 内容

	//重新填充,并设置第一个串口为默认串口
	fillPortComm();
	m_portComBox.SetCurSel(0);
	//重新填充,并设置第一个串口为默认串口
}
//实现串口热插拔


最后界面如下图所示

 

 

另外在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()


 

  • 2
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值