Matlab探尋(三):自動識別串口設備並獲取其串口號(serial && friendly name)

   Matlab編寫的串口調試助手網上有很多,有些比較好用的可以從這裏下載[Matlab串口助手]。但是這些串口調試助手每次都需要手動設置串口號,然後才能打開設備,調試可以用,但是交互體驗不好。所以我最後實現的是讓Matlab自動識別串口設備及其對應的串口號。

常見識別設備串口號的方法

   開始之前我們先來看看其他人主要是怎麼識別串口設備的。

  a.任務管理器

   大家最常用的方法,每次都手動打開任務管理器,看看這個設備連接到了哪個串口上!例如我的一個串口設備CH340連接到了COM4上。

  b.遍歷可用串口

   Matlab可以使用指令返回所有可用串口

Ports = instrhwinfo('serial');  %%查找所有可用串口

   該語句可以返回所有可用串口,結果如下圖。然後Matlab後臺編寫程序和這些可用串口一個個握手,直到找到目標串口設備。這樣不光效率低下,而且有時候對於沒有握手信號的串口設備也不太可行。

自動識別設備串口號

   可是我既不想每次都手動打開任務管理器,也不想暴力遍歷所有串口,那麼怎麼辦呢?所以我想既然任務管理器裏面有設備的名字,這裏寫圖片描述,而且Matlab那麼強大,能不能去識別這個設備名字呢?答案是肯定的。
   查了很多資料,最終寫出了這個函數。該函數利用dos命令,在兩個地方掃描Windows註冊表,並將活動的COM端口與註冊的“friendly name”和“service”關聯起來。該函數返回一個N×2單元陣列,其中N是活動COM端口的數量。每行的第一列是串口設備的“friendly name”,第二列是它的COM號。如果沒有找到具有“friendly name”的設備,則設備是空的。

function devices = IdentifySerialComs()

devices = [];

Skey = 'HKEY_LOCAL_MACHINE\HARDWARE\DEVICEMAP\SERIALCOMM';
[~, list] = dos(['REG QUERY ' Skey]);
if ischar(list) && strcmp('ERROR',list(1:5))  %% strcmp 兩個字符串相同返回1
    disp('Error: EnumSerialComs - No SERIALCOMM registry entry')
    return;
end
list = strread(list,'%s','delimiter',' '); %#ok<FPARK> requires strread()
coms = 0;
for i = 1:numel(list)  %%numel 返回元素個數
    if strcmp(list{i}(1:3),'COM')
        if ~iscell(coms)
            coms = list(i);
        else
            coms{end+1} = list{i}; %#ok<AGROW> Loop size is always small
        end
    end
end
out = 0;
outK = 0;
for j=1:2
    switch j
        case 1
            key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\USB\';
        case 2
            key = 'HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\FTDIBUS\';
    end
    [~, vals] = dos(['REG QUERY ' key ' /s /f "FriendlyName" /t "REG_SZ"']);
    if ischar(vals) && strcmp('ERROR',vals(1:5))
        disp('Error: EnumSerialComs - No Enumerated USB registry entry')
        return;
    end
    vals = textscan(vals,'%s','delimiter','\t');
    vals = cat(1,vals{:});
    for i = 1:numel(vals)
        if strcmp(vals{i}(1:min(12,end)),'FriendlyName')
            if ~iscell(out)
                out = vals(i);
            else
                out{end+1} = vals{i}; %#ok<AGROW> Loop size is always small
            end
            if ~iscell(outK)
                outK = vals(i-1);
            else
                outK{end+1} = vals{i-1}; %#ok<AGROW> Loop size is always small
            end
        end
    end
end

i_dev=1;Sservices=[];
for i = 1:numel(coms)
    match = strfind(out,[coms{i},')']);
    ind = 0;
    for j = 1:numel(match)
        if ~isempty(match{j})
            ind = j;
            [~, sers] = dos(['REG QUERY "' outK{ind} '" /f "Service" /t "REG_SZ"']);
            sers = textscan(sers,'%s','delimiter','\t');
            sers = cat(1,sers{:});
            if (numel(sers)>1)
                sers=strread(sers{2},'%s','delimiter',' ');
                Sservices{i_dev} = sers{3};
                i_dev=i_dev+1;
            end
        end
    end
end
Sservices=unique(Sservices);

i_dev=1;
for ss=1:numel(Sservices)
    key = ['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\' Sservices{ss} '\Enum'];
    [~, vals] = dos(['REG QUERY ' key ' /f "Count"']);
    if ischar(vals) && strcmp('ERROR',vals(1:5))
        %         disp('Error: EnumSerialComs - No Enumerated services USB registry entry')
        %         return
    end
    vals = textscan(vals,'%s','delimiter','\t');
    vals = cat(1,vals{:});

    if (numel(vals)>1)
        vals=strread(vals{2},'%s','delimiter',' ');
        Count=hex2dec(vals{3}(3:end));
        if Count>0
            [~, vals] = dos(['REG QUERY ' key]);
            vals = textscan(vals,'%s','delimiter','\t');
            vals = cat(1,vals{:});
            out=0;
            j=0;
            for i = 1:numel(vals)
                Enums=strread(vals{i},'%s','delimiter',' ');
                try nums=hex2dec(Enums{1});
                catch
                    nums=-1;
                end
                if(nums==j)
                    out=['HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Enum\' Enums{3}];
                    [~, listC] = dos(['REG QUERY "' out '" /s /f "PortName" /t "REG_SZ"']);
                    listC = textscan(listC,'%s','delimiter','\t');
                    listC = cat(1,listC{:});
                    if (numel(listC)>1)
                        listC=strread(listC{2},'%s','delimiter',' ');
                        for i = 1:numel(coms)
                            if strcmp(listC{3},coms{i})
                                [~, NameF] = dos(['REG QUERY "' out '" /s /f "FriendlyName" /t "REG_SZ"']);
                                NameF = textscan(NameF,'%s','delimiter','\t');
                                NameF = cat(1,NameF{:});
                                com = str2double(coms{i}(4:end));
                                if com > 9
                                    length = 8;
                                else
                                    length = 7;
                                end
                                devices{i_dev,1} = NameF{2}(27:end-length); %#ok<AGROW>
                                devices{i_dev,2} = com; %#ok<AGROW> Loop size is always small
                                i_dev=i_dev+1;
                            end
                        end
                    end
                    j=j+1;
                end
            end
        end
    end
end

end

   運行之後可以看到返回的結果,整個過程僅耗時0.1s,如下圖。第一列是串口設備的“friendly name”即設備名(”USB-SERIAL CH340”),第二列是它的COM號(COM4)。源碼可以從這裏下載[Matlab自動識別串口設備及其串口號]


   之後,把該函數加到自己的程序中,識別對應的設備名就可以獲取其串口號了。Well done!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章