在串口通信开发中实现自动查找串口端口的方法
生活随笔
收集整理的這篇文章主要介紹了
在串口通信开发中实现自动查找串口端口的方法
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
開發工具:visual studio 2010
本機可用串口信息如下:
1 、查詢注冊表
查詢注冊表的方法是比較常見的方法,通過查看“ HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM ”項來獲取串口信息。該方法就是使用編程方法讀取注冊表內信息,相當于用戶通過在運行框內輸入 ”regedit” (或 regedit32 )直接打開注冊表。源代碼如下: ?int i = 0;
?CHAR Name[25];
?UCHAR szPortName[25];
?LONG Status;
?DWORD dwIndex = 0;
?DWORD dwName;
?DWORD dwSizeofPortName;
?DWORD Type; ?HKEY hKey;
?CString?? strSerialList[256];? // 臨時定義 256 個字符串組,因為系統最多也就 256 個
?LPCTSTR data_Set="HARDWARE\\DEVICEMAP\\SERIALCOMM\\"; ?dwName = sizeof(Name);
?dwSizeofPortName = sizeof(szPortName); ?//long ret0 = (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, data_Set, 0, KEY_READ, &hKey));
?long ret0 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, data_Set, 0, KEY_READ, &hKey); //打開一個制定的注冊表鍵,成功返回ERROR_SUCCESS即“0”值 ?if(ret0 == ERROR_SUCCESS)
?{ ??do
??{
???Status = RegEnumValue(hKey, dwIndex++, Name, &dwName, NULL, &Type, szPortName, &dwSizeofPortName);//讀取鍵值
???if((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA))
???{
????strSerialList[i] = CString(szPortName);?????? // 串口字符串保存
????printf("serial:%s\n",strSerialList[i]);
????i++;// 串口計數
???}
? ?//每讀取一次dwName和dwSizeofPortName都會被修改?
??//注意一定要重置,否則會出現很離奇的錯誤,本人就試過因沒有重置,出現先插入串口號大的(如COM4),再插入串口號小的(如COM3),此時雖能發現兩個串口,但都是同一串口號(COM4)的問題,同時也讀不了COM大于10以上的串口?
dwName = sizeof(Name);? dwSizeofPortName = sizeof(szPortName);? ??} while((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA));
?
??RegCloseKey(hKey);
?}
調試輸出信息如下: 該方法在 1ms內即可完成查找;同時也可解決 usb 轉串口設備的問題,比較實用,唯一缺點是,如果用戶在裝某些軟硬件時在注冊表中注冊了虛擬串口之類的,用此法枚舉得到的該類串口實際上是不能當串口用的。
2、使用 SetupAPI 函數集的方法 此種方法是最簡單的方法,之所以簡單是因為已經有人將復雜的代碼封裝起來了,只需像傻子一樣調用就可以完成工作了,具體的說明請看 http://www.codeguru.com/Cpp/W-P/system/hardwareinformation/article.php/c5721/ ,使用該方法要在你的程序中,添加“ EnumSerial.cpp ”和“ EnumSerial.h ”兩個文件,并且將 Setupapi.lib 包含進你的工程,方法在項目屬性-配置屬性-連接器-輸入-附加依賴項中添加setupapi.lib,然后在EnumSerial.cpp中添加包含"setupapi.h"?,你的應用程序添加包含EnumSerial.h頭文件就行了, 下面給出調用該方法的例子代碼: ?????? int m_nSerialPortNum(0);// 串口計數
?????? CString????????? strSerialList[256];? // 臨時定義 256 個字符串組
?????? CArray<SSerInfo,SSerInfo&> asi;
?????? EnumSerialPorts(asi,TRUE);// 參數為 TRUE 時枚舉當前可以打開的串口,
// 否則枚舉所有串口
?????? m_nSerialPortNum = asi.GetSize();
?????? for (int i=0; i<asi.GetSize(); i++)
?????? {
????????????? CString str = asi[i].strFriendlyName;
???? printf("serialinfo:%s\n",str);
?????? } 調試輸出信息如下: 該方法查找一個串口就要 15ms 左右,但可以看到該方法獲取的串口完完全全就是硬件設備管理器中的串口。 3、使用 EnumPort 方法 該方法調用 EnumPort () API 函數,該函數本身就是枚舉電腦端口用的,它枚舉的并非只有串口,所以必須對其所得串口進行分析選擇,使用這種方法要在源碼中添加#include <winspool.h>頭文件 以下是源代碼: ?????? int i=0;
?????? int m_nSerialPortNum(0);// 串口計數
?????? CString????????? strSerialList[256];? // 臨時定義 256 個字符串組
?????? LPBYTE pBite? = NULL;
?????? DWORD pcbNeeded = 0;? // bytes received or required
?????? DWORD pcReturned = 0;? // number of ports received
?????? m_nSerialPortNum = 0; ?????? // 獲取端口信息,能得到端口信息的大小 pcbNeeded
?????? EnumPorts(NULL, 2, pBite, 0, &pcbNeeded, &pcReturned);
?????? pBite = new BYTE[pcbNeeded];
?????? // 枚舉端口,能得到端口的具體信息 pBite 以及端口的的個數 pcReturned ?????? EnumPorts(NULL, 2, pBite, pcbNeeded, &pcbNeeded, &pcReturned);
?????? PORT_INFO_2 *pPort;
?????? pPort = (PORT_INFO_2*)pBite;
?????? for ( i = 0; i < pcReturned; i++)
?????? {
????????????? CString str = pPort[i].pPortName;
???? printf("hardwareinfo:%s\n",str);
????????????? // 串口信息的具體確定
????????????? if (str.Left(3) == "COM")
????????????? {??????????????????
???????????????????? strSerialList[m_nSerialPortNum] = str.Left(strlen(str) - 1);
???????????????????? //CString temp = str.Right(strlen(str) - 3);// 下面兩行注釋獲取串口序號用
???????????????????? //m_nSerialPortNo[m_nSerialPortNum] = atoi(temp.Left(strlen(temp) - 1));
????? printf("serialinfo:%s\n",strSerialList[m_nSerialPortNum]);
???????????????????? m_nSerialPortNum++;??????
?????
????????????? }
?????? } 調試輸出信息如下: 可以看出該方法除了串口,還可以枚舉所有的并口和打印機等接口,而且能找到虛擬串口(這些串口有些未使用時,在注冊表和硬件設備管理器中是不能取得的)。但是該方法稍微耗時些,大概需要幾十 ms ,主要問題是該方法有些 usb 串口并不能查到,系統中沒有的串口它都例出來了,所以該方法并不可靠。 4、依次打開串口的方法 該方法就是中規中矩的依次打開串口,看打開是否成功來判斷串口的有無,一般查找一個串口就要 15ms 左右 以上方法個人覺得可取的是第一、二種方法。最可靠的是第二種方法。 與50位技術專家面對面20年技術見證,附贈技術全景圖
查詢注冊表的方法是比較常見的方法,通過查看“ HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM ”項來獲取串口信息。該方法就是使用編程方法讀取注冊表內信息,相當于用戶通過在運行框內輸入 ”regedit” (或 regedit32 )直接打開注冊表。源代碼如下: ?int i = 0;
?CHAR Name[25];
?UCHAR szPortName[25];
?LONG Status;
?DWORD dwIndex = 0;
?DWORD dwName;
?DWORD dwSizeofPortName;
?DWORD Type; ?HKEY hKey;
?CString?? strSerialList[256];? // 臨時定義 256 個字符串組,因為系統最多也就 256 個
?LPCTSTR data_Set="HARDWARE\\DEVICEMAP\\SERIALCOMM\\"; ?dwName = sizeof(Name);
?dwSizeofPortName = sizeof(szPortName); ?//long ret0 = (::RegOpenKeyEx(HKEY_LOCAL_MACHINE, data_Set, 0, KEY_READ, &hKey));
?long ret0 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, data_Set, 0, KEY_READ, &hKey); //打開一個制定的注冊表鍵,成功返回ERROR_SUCCESS即“0”值 ?if(ret0 == ERROR_SUCCESS)
?{ ??do
??{
???Status = RegEnumValue(hKey, dwIndex++, Name, &dwName, NULL, &Type, szPortName, &dwSizeofPortName);//讀取鍵值
???if((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA))
???{
????strSerialList[i] = CString(szPortName);?????? // 串口字符串保存
????printf("serial:%s\n",strSerialList[i]);
????i++;// 串口計數
???}
? ?//每讀取一次dwName和dwSizeofPortName都會被修改?
??//注意一定要重置,否則會出現很離奇的錯誤,本人就試過因沒有重置,出現先插入串口號大的(如COM4),再插入串口號小的(如COM3),此時雖能發現兩個串口,但都是同一串口號(COM4)的問題,同時也讀不了COM大于10以上的串口?
dwName = sizeof(Name);? dwSizeofPortName = sizeof(szPortName);? ??} while((Status == ERROR_SUCCESS)||(Status == ERROR_MORE_DATA));
?
??RegCloseKey(hKey);
?}
調試輸出信息如下: 該方法在 1ms內即可完成查找;同時也可解決 usb 轉串口設備的問題,比較實用,唯一缺點是,如果用戶在裝某些軟硬件時在注冊表中注冊了虛擬串口之類的,用此法枚舉得到的該類串口實際上是不能當串口用的。
2、使用 SetupAPI 函數集的方法 此種方法是最簡單的方法,之所以簡單是因為已經有人將復雜的代碼封裝起來了,只需像傻子一樣調用就可以完成工作了,具體的說明請看 http://www.codeguru.com/Cpp/W-P/system/hardwareinformation/article.php/c5721/ ,使用該方法要在你的程序中,添加“ EnumSerial.cpp ”和“ EnumSerial.h ”兩個文件,并且將 Setupapi.lib 包含進你的工程,方法在項目屬性-配置屬性-連接器-輸入-附加依賴項中添加setupapi.lib,然后在EnumSerial.cpp中添加包含"setupapi.h"?,你的應用程序添加包含EnumSerial.h頭文件就行了, 下面給出調用該方法的例子代碼: ?????? int m_nSerialPortNum(0);// 串口計數
?????? CString????????? strSerialList[256];? // 臨時定義 256 個字符串組
?????? CArray<SSerInfo,SSerInfo&> asi;
?????? EnumSerialPorts(asi,TRUE);// 參數為 TRUE 時枚舉當前可以打開的串口,
// 否則枚舉所有串口
?????? m_nSerialPortNum = asi.GetSize();
?????? for (int i=0; i<asi.GetSize(); i++)
?????? {
????????????? CString str = asi[i].strFriendlyName;
???? printf("serialinfo:%s\n",str);
?????? } 調試輸出信息如下: 該方法查找一個串口就要 15ms 左右,但可以看到該方法獲取的串口完完全全就是硬件設備管理器中的串口。 3、使用 EnumPort 方法 該方法調用 EnumPort () API 函數,該函數本身就是枚舉電腦端口用的,它枚舉的并非只有串口,所以必須對其所得串口進行分析選擇,使用這種方法要在源碼中添加#include <winspool.h>頭文件 以下是源代碼: ?????? int i=0;
?????? int m_nSerialPortNum(0);// 串口計數
?????? CString????????? strSerialList[256];? // 臨時定義 256 個字符串組
?????? LPBYTE pBite? = NULL;
?????? DWORD pcbNeeded = 0;? // bytes received or required
?????? DWORD pcReturned = 0;? // number of ports received
?????? m_nSerialPortNum = 0; ?????? // 獲取端口信息,能得到端口信息的大小 pcbNeeded
?????? EnumPorts(NULL, 2, pBite, 0, &pcbNeeded, &pcReturned);
?????? pBite = new BYTE[pcbNeeded];
?????? // 枚舉端口,能得到端口的具體信息 pBite 以及端口的的個數 pcReturned ?????? EnumPorts(NULL, 2, pBite, pcbNeeded, &pcbNeeded, &pcReturned);
?????? PORT_INFO_2 *pPort;
?????? pPort = (PORT_INFO_2*)pBite;
?????? for ( i = 0; i < pcReturned; i++)
?????? {
????????????? CString str = pPort[i].pPortName;
???? printf("hardwareinfo:%s\n",str);
????????????? // 串口信息的具體確定
????????????? if (str.Left(3) == "COM")
????????????? {??????????????????
???????????????????? strSerialList[m_nSerialPortNum] = str.Left(strlen(str) - 1);
???????????????????? //CString temp = str.Right(strlen(str) - 3);// 下面兩行注釋獲取串口序號用
???????????????????? //m_nSerialPortNo[m_nSerialPortNum] = atoi(temp.Left(strlen(temp) - 1));
????? printf("serialinfo:%s\n",strSerialList[m_nSerialPortNum]);
???????????????????? m_nSerialPortNum++;??????
?????
????????????? }
?????? } 調試輸出信息如下: 可以看出該方法除了串口,還可以枚舉所有的并口和打印機等接口,而且能找到虛擬串口(這些串口有些未使用時,在注冊表和硬件設備管理器中是不能取得的)。但是該方法稍微耗時些,大概需要幾十 ms ,主要問題是該方法有些 usb 串口并不能查到,系統中沒有的串口它都例出來了,所以該方法并不可靠。 4、依次打開串口的方法 該方法就是中規中矩的依次打開串口,看打開是否成功來判斷串口的有無,一般查找一個串口就要 15ms 左右 以上方法個人覺得可取的是第一、二種方法。最可靠的是第二種方法。 與50位技術專家面對面20年技術見證,附贈技術全景圖
總結
以上是生活随笔為你收集整理的在串口通信开发中实现自动查找串口端口的方法的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: vue 过滤器 filters
- 下一篇: android 手机wifi重启,路由器