zoukankan      html  css  js  c++  java
  • 【转】如何在VC下检测当前存在的串口及串口热拔插

    当我们在用VS进行串口编程时,在打开串口前,经常想知道当前PC上存在多少个串口,哪些串口可用?哪些串口已经打开了,最好是在一个Combo Box中列表系统当前所有可用的串口以供选择,然而如何获取系统当前可用的串口有哪些呢?

    这里介绍的方法也是最简单也是最笨的一种方法,即一个一个去试,试完了就知道了。至于还有没有其它更好的方法,暂不在本文所讨论的范围之内。

    一个在对话框的OnInitDialog函数内做如下操作:

    1 初始化时检测串口

    [cpp] view plaincopy
     
    1. BOOL Ctbox_debug_viewDlg::OnInitDialog()  
    2. {  
    3.     CDialogEx::OnInitDialog();  
    4.   
    5.     // Add "About..." menu item to system menu.  
    6.   
    7.     // IDM_ABOUTBOX must be in the system command range.  
    8.     ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);  
    9.     ASSERT(IDM_ABOUTBOX < 0xF000);  
    10.   
    11.     CMenu* pSysMenu = GetSystemMenu(FALSE);  
    12.     if (pSysMenu != NULL)  
    13.     {  
    14.         BOOL bNameValid;  
    15.         CString strAboutMenu;  
    16.         bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);  
    17.         ASSERT(bNameValid);  
    18.         if (!strAboutMenu.IsEmpty())  
    19.         {  
    20.             pSysMenu->AppendMenu(MF_SEPARATOR);  
    21.             pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);  
    22.         }  
    23.     }  
    24.   
    25.     // Set the icon for this dialog.  The framework does this automatically  
    26.     //  when the application's main window is not a dialog  
    27.     SetIcon(m_hIcon, TRUE);         // Set big icon  
    28.     SetIcon(m_hIcon, FALSE);        // Set small icon  
    29.   
    30.     // TODO: Add extra initialization here  
    31.   
    32.     AddCom();//向组合框中添加串口设备    
    33.     m_CombolPort.SetCurSel(0);  
    34.          //...  
    35. }  

    AddCom函数如下定义:

    [cpp] view plaincopy
     
    1. void Ctbox_debug_viewDlg::AddCom(void)  
    2. {  
    3.     EnumerateSerialPorts(ports,portse,portsu);  
    4.     unsigned short uicounter;  
    5.     unsigned short uisetcom;  
    6.     CString str;  
    7.   
    8.     //获取可用串口个数  
    9.     uicounter = portse.GetSize();   
    10.     //如果个数大于0  
    11.     if(uicounter > 0)  
    12.     {  
    13.         //初始化串口列表框  
    14.         for(int i=0; i<uicounter; i++)  
    15.         {  
    16.             uisetcom = portse.ElementAt(i);  
    17.             str.Format(_T("COM%d "),uisetcom);  
    18.             m_CombolPort.AddString(str);  
    19.         }  
    20.     }  
    21. }  


    EnumerateSerialPorts函数如下:

    [cpp] view plaincopy
     
    1. void Ctbox_debug_viewDlg::EnumerateSerialPorts(CUIntArray& ports, CUIntArray& portse, CUIntArray& portsu)  
    2. {  
    3.     //清除串口数组内容  
    4.     ports.RemoveAll();  
    5.     portse.RemoveAll();  
    6.     portsu.RemoveAll();  
    7.     //因为至多有255个串口,所以依次检查各串口是否存在  
    8.     //如果能打开某一串口,或打开串口不成功,但返回的是 ERROR_ACCESS_DENIED错误信息,  
    9.     //都认为串口存在,只不过后者表明串口已经被占用  
    10.     //否则串口不存在  
    11.     for (int i=1; i<256; i++)  
    12.     {  
    13.         //Form the Raw device name  
    14.         CString sPort;  
    15.         sPort.Format(_T("\\.\COM%d"), i);  
    16.   
    17.         //Try to open the port  
    18.         BOOL bSuccess = FALSE;  
    19.         HANDLE hPort = ::CreateFile(sPort, GENERIC_READ | GENERIC_WRITE, 0, 0, OPEN_EXISTING, 0, 0);  
    20.         if (hPort == 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.             //The port was opened successfully  
    33.             bSuccess = TRUE;  
    34.             portse.Add(i);      ////可用的串口  
    35.             //Don't forget to close the port, since we are going to do nothing with it anyway  
    36.             CloseHandle(hPort);  
    37.         }  
    38.   
    39.         //Add the port number to the array which will be returned  
    40.         if (bSuccess)  
    41.             ports.Add(i);   //所有存在的串口  
    42.      }  
    43. }  


    如上操作即可将系统当前可用的所有串口添加到CombolPort所对应的Combol Box中了。

    2 打开串口

    代码如下:

    [cpp] view plaincopy
     
    1. void Ctbox_debug_viewDlg::OnBnClickedBtOpen()  
    2. {  
    3.     // TODO: Add your control notification handler code here  
    4.   
    5.     if(m_mscomm.get_PortOpen())  
    6.     {  
    7.         m_mscomm.put_PortOpen(FALSE);  
    8.         GetDlgItem(IDC_BT_OPEN)->SetWindowText(_T("打开"));  
    9.         ShowInfo(_T("关闭串口成功!"));  
    10.         m_OpenStatus =false;  
    11.         return;  
    12.     }  
    13.     UpdateData(TRUE);  
    14.     m_OpenStatus =true;  
    15.     //当前端口号  
    16.     int curPort =portse.ElementAt(m_CombolPort.GetCurSel());  
    17.     m_mscomm.put_CommPort(curPort);//端口号  
    18.     m_mscomm.put_InBufferSize(1024);//接收缓冲区   
    19.     m_mscomm.put_OutBufferSize(1024);//发送缓冲区   
    20.   
    21.     m_mscomm.put_InputLen(0);//设置当前接收区数据长度为0,表示全部读取     
    22.     m_mscomm.put_InputMode(1);//以二进制方式读写数据     
    23.     m_mscomm.put_RThreshold(1);//接收缓冲区有1个及1个以上字符时,将引发接收数据的OnComm事件     
    24.        
    25.        
    26.   
    27.     //波特率  
    28.     DWORD baudrate;  
    29.     switch(m_CombolBaudrate.GetCurSel())  
    30.     {  
    31.     case 0:  
    32.         baudrate =115200;  
    33.         break;  
    34.     case 1:  
    35.         baudrate =9600;  
    36.         break;  
    37.     default:  
    38.         ASSERT(FALSE);  
    39.         break;  
    40.     }  
    41.     CString setting;  
    42.     setting.Format(_T("%d,n,8,1"),baudrate);  
    43.     m_mscomm.put_Settings(setting/*_T("115200,n,8,1")*/);//波特率,无校验,8个数据位,1个停止1位  
    44.        
    45.     m_mscomm.put_PortOpen(TRUE);//打开串口    
    46.     GetDlgItem(IDC_BT_OPEN)->SetWindowText(_T("关闭"));  
    47.     ShowInfo(_T("打开串口成功!"));  
    48.    
    49. }  


    3 串口热拔插时检测串口

    这里主要利用Cwnd的ON_WM_DEVICECHANGE消息来处理。

    ON_WM_DEVICECHANGE消息在VS2010中好像只能通过手动来添加,反正我没找到可以通过对话的形式来添加的,后续有知道的兄台麻烦告知我一下。

    因此,首先得手动添加ON_WM_DEVICECHANGE消息:

    第一步:在消息映射BEGIN_MESSAGE_MAP(Ctbox_debug_viewDlg, CDialogEx)中添加:

    [cpp] view plaincopy
     
    1. ON_WM_DEVICECHANGE()  


    第二步:在头文件类的定义中添加函数声明:

    [cpp] view plaincopy
     
    1. afx_msg BOOL OnDeviceChange(UINT nEventType, DWORD dwData);  


    第三步:实现函数

    [cpp] view plaincopy
     
    1. BOOL Ctbox_debug_viewDlg::OnDeviceChange(UINT nEventType,DWORD dwData)  
    2. {  
    3.         //DEV_BROADCAST_DEVICEINTERFACE* dbd = (DEV_BROADCAST_DEVICEINTERFACE*) dwData;  
    4.     switch (nEventType)  
    5.     {  
    6.     case DBT_DEVICEREMOVECOMPLETE://移除设备  
    7.     case DBT_DEVICEARRIVAL://添加设备  
    8.         RefreshCom();//刷新组合框的内容  
    9.         break;  
    10.   
    11.     default:  
    12.         break;  
    13.     }  
    14.   
    15.     return TRUE;  
    16.   
    17. }  


    RefreshCom函数如下:

    [cpp] view plaincopy
     
    1. void Ctbox_debug_viewDlg::RefreshCom(void)  
    2. {  
    3.     int count =m_CombolPort.GetCount();  
    4.   
    5.     for(int i=0;i<count;i++)  
    6.     {  
    7.         m_CombolPort.DeleteString(count -1 -i);  
    8.     }  
    9.     AddCom();  
    10.     m_CombolPort.SetCurSel(0);  
    11. }  

    第四步:在.cpp文件中包含头文件

    [cpp] view plaincopy
     
    1. #include <Dbt.h>  


    这是因为DEV_BROADCAST_DEVICEINTERFACE,DBT_DEVICEREMOVECOMPLETE,DBT_DEVICEARRIVAL这几个东东在头文件Dbt.h中定义的,这样才能编译通过。


    而AddCom函数已经在之前讲到过,回过头去看看。

    这里的思想是通过检测到设备的插入和拔出时刷新组合框的内容,是通过重新测试串口的方式来实现的。

    另:需要注意的是,当插入和拔出设备时,系统会检测到两次"设备改变事件",因此会两次调用OnDeviceChange函数,第一次调用时传入的函数nEventType的值固定为0x07,第二次调用时nEventType才是上述代码switch中所定义的事件,这与网上所说的需要注册是相悖的,不知道为什么网上有些文章会说一定需要注册什么的才能检测到设备改变的事件,反正我这里不需要,我用的是VS2010.

    完!

    见:http://blog.csdn.net/flydream0/article/details/8086976

  • 相关阅读:
    测试运行效率
    识别字符串中的表达式(续二)
    FireScript在SharePoint中的应用
    加入了静态类的语义分析引擎
    这是我在C#中测试速度的代码
    用自定义函数来实现代理类的实例化
    IF语句多分支识别
    FireScript调用DLL和COM
    JMETER在LINUX安装和使用
    转:Big List Of 20 Common Bottlenecks
  • 原文地址:https://www.cnblogs.com/zhanjxcom/p/4477976.html
Copyright © 2011-2022 走看看