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

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

参考资料: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、下面实现自动检测串口

遍历所有串口代码如下:

[cpp]  view plain  copy
  1. void CCommDlg::foreachPort(CUIntArray& ports,CUIntArray& portse,CUIntArray& portsu)  
  2. {  
  3.     //清空数组内容  
  4.     ports.RemoveAll();//所有存在串口  
  5.     portse.RemoveAll();//可用串口  
  6.     portsu.RemoveAll();//已占用串口  
  7.     //清空数组内容  
  8.   
  9.     //串口最多有255,所以这里遍历255个串口是否可以使用即可  
  10.     for (int i=1;i<=255;i++)  
  11.     {  
  12.         //形成串口名称  
  13.         CString portStr;  
  14.         portStr.Format("COM%d",i);  
  15.         //形成串口名称  
  16.   
  17.         //尝试打开串口  
  18.         BOOL bSuccess=FALSE;  
  19.         HANDLE m_hCom=CreateFile(portStr,GENERIC_READ|GENERIC_WRITE,0,0,OPEN_EXISTING,0,0);  
  20.         if (m_hCom==INVALID_HANDLE_VALUE)  
  21.         {  
  22.             DWORD dwError=GetLastError();  
  23.   
  24.             if (dwError==ERROR_ACCESS_DENIED)  
  25.             {  
  26.                 bSuccess=TRUE;  
  27.                 portsu.Add(i);//已占用的串口号  
  28.             }  
  29.         }   
  30.         else  
  31.         {  
  32.             bSuccess=TRUE;  
  33.             portse.Add(i);//可用串口号  
  34.               
  35.             CloseHandle(m_hCom);  
  36.         }  
  37.         if (bSuccess)  ports.Add(i);//全部串口号  
  38.         //尝试打开串口  
  39.     }  
  40. }  

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

 

[html]  view plain  copy
  1. void CCommDlg::fillPortComm()  
  2. {  
  3.     foreachPort(ports,portse,portsu);//所有串口号,可用串口号,已占用串口号  
  4.     CString str;  
  5.   
  6. //  unsigned short portNum;  
  7. //  unsigned short portSerialNum;  
  8. //  portNum=ports.GetSize();  
  9.   
  10.     if (portse.GetSize()>0)  
  11.     {  
  12.         for (int i=0;i<portse.GetSize();i++)  
  13.         {  
  14.             str.Format("COM%d",portse.ElementAt(i));  
  15.             m_portComBox.AddString(str);              
  16.         }  
  17.     }  
  18. }  


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

[cpp]  view plain  copy
  1. void CCommDlg::OnOpenport()   
  2. {  
  3.     // TODO: Add your control notification handler code here  
  4.     CString strname;  
  5.     int comNum=portse.ElementAt(((CComboBox *)GetDlgItem(IDC_PORTCOMBO))->GetCurSel());  
  6.   
  7.     if (GetDlgItemText(IDC_OPENPORT,strname),strname=="OpenPort")  
  8.     {  
  9.         if(m_Comm.GetPortOpen())//如果串口是打开的,则关闭串口   
  10.         {   
  11.             m_Comm.SetPortOpen(FALSE);  
  12.         }     
  13.         try  
  14.         {  
  15.             m_Comm.SetCommPort(comNum); //串口  
  16.             m_Comm.SetInputMode(1); //设置输入方式为二进制方式  
  17.             m_Comm.SetInBufferSize(1024); //设置输入缓冲区的大小,Bytes   
  18.             m_Comm.SetOutBufferSize(512); //设置输入缓冲区的大小,Bytes   
  19.             m_Comm.SetSettings("9600,n,8,1"); //设置波特率等参数   
  20.             m_Comm.SetPortOpen(TRUE);  
  21.         }  
  22.         catch (CException* e)  
  23.         {  
  24.             e-> Delete(); //防止显示“Invalid   Port   Number”对话框  
  25.             strname.Format("COM%d打开失败!",comNum);  
  26.             AfxMessageBox(strname);  
  27.             return;  
  28.         }  
  29.           
  30.         m_Comm.SetRThreshold(1); //为1表示有一个字符即引发事件  
  31.         m_Comm.SetInputLen(0);  
  32.         m_Comm.GetInput();  
  33.   
  34.         SetDlgItemText(IDC_OPENPORT,"Close");  
  35.         //SetTimer(1,500,NULL);//设置定时器,循环发送时使用  
  36.   
  37.         //display status  
  38.         strname.Format("COM%d打开成功",comNum);  
  39.         SetDlgItemText(IDC_STATUS,strname);  
  40.         //display status  
  41.   
  42.         GetDlgItem(IDC_SENDBtn)->EnableWindow(TRUE);  
  43.   
  44.     }   
  45.     else  
  46.     {  
  47.         m_Comm.SetPortOpen(FALSE);  
  48.   
  49.         SetDlgItemText(IDC_OPENPORT,"OpenPort");  
  50.         //KillTimer(1);//设置定时器,循环发送时使用  
  51.   
  52.         //display status  
  53.         strname.Format("COM%d关闭成功",comNum);  
  54.         SetDlgItemText(IDC_STATUS,strname);  
  55.         //display status  
  56.   
  57.         GetDlgItem(IDC_SENDBtn)->EnableWindow(FALSE);  
  58.     }  
  59.   
  60. }  


 

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

[cpp]  view plain  copy
  1. <pre class="cpp" name="code"><pre class="cpp" name="code">BEGIN_MESSAGE_MAP(CCommDlg, CDialog)  
  2.     //{{AFX_MSG_MAP(CCommDlg)  
  3.     ON_WM_DEVICECHANGE()  
  4.     //}}AFX_MSG_MAP  
  5. END_MESSAGE_MAP()  
 
 
 
 

 

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

[cpp]  view plain  copy
  1. afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);//实现串口热插拔  


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

[cpp]  view plain  copy
  1. //实现串口热插拔  
  2. BOOL CCommDlg::OnDeviceChange(UINT nEventType, DWORD dwData)  
  3. {  
  4.     switch(nEventType)  
  5.     {  
  6.     case DBT_DEVICEREMOVECOMPLETE:  
  7.         //refreshCom();  
  8.         //break;  
  9.     case DBT_DEVICEARRIVAL:  
  10.         refreshCom();  
  11.         break;  
  12.     default:  
  13.         break;  
  14.     }  
  15.     return TRUE;  
  16. }  
  17.   
  18. void CCommDlg::refreshCom()  
  19. {  
  20.     //清除Combo Box 内容  
  21.     int m_Num=m_portComBox.GetCount();  
  22.   
  23.     /*m_portComBox.GetCount()这里得到的数值是实时改变的, 
  24.     所以这里不能用m_portComBox.GetCount()判断循环是否结束*/  
  25.     for (int i=0;i<m_Num;i++)  
  26.     {  
  27.         m_portComBox.DeleteString(m_Num-1-i);  
  28.     }  
  29.     //清除Combo Box 内容  
  30.   
  31.     //重新填充,并设置第一个串口为默认串口  
  32.     fillPortComm();  
  33.     m_portComBox.SetCurSel(0);  
  34.     //重新填充,并设置第一个串口为默认串口  
  35. }  
  36. //实现串口热插拔  


最后界面如下图所示

 

 

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

Parsing error:Undrecognized macro

Input Line:"ON_WM_DEVICECHANGED"

 

[cpp]  view plain  copy
  1. BEGIN_MESSAGE_MAP(CCommDlg, CDialog)  
  2.     //{{AFX_MSG_MAP(CCommDlg)  
  3.     //}}AFX_MSG_MAP  
  4. END_MESSAGE_MAP()  

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

 

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

 

[cpp]  view plain  copy
  1. BEGIN_MESSAGE_MAP(CCommDlg, CDialog)  
  2.     //{{AFX_MSG_MAP(CCommDlg)  
  3.     //}}AFX_MSG_MAP  
  4.     ON_WM_DEVICECHANGE()  
  5. END_MESSAGE_MAP()  

猜你喜欢

转载自blog.csdn.net/mfkjq/article/details/78017723
今日推荐