iterate through multiple serial ports, one after another (not simultaneously)

I have a program that utilizes incoming serial data to do a strcmp with data stored in excel. the string initially comes in looking like this:
Reader(n): 'String'
my code is set up to find the n, and then compare the serial string to the string stored in the Nth column of an excel spreadsheet. A bool value of 1 from this operation will change the Nth panel in a GUI to green, while a bool value of 0 will change the Nth panel to red.
At the moment, my code only iterates from n = 1:2. these are the n values coming in from COM3. I want to use 3 more COM ports, each one carrying n = 3:4, n = 5:6, and n = 7:8. However, I am unsure of how to initialize the ports to be read one after another, no simultaneously. this is my main function:
delete(instrfind('Port', 'COM3')); % removes possibility for 'Port not available' error
tag = serial('COM3'); %initializes the port to be used
fopen(tag); %opens th eport
BOX = char(zeros(2,14)); % matrix to be populated with incoming serial data
TrueValueData = 'C:\RfidChipTrueValues.xlsx';
% location of stored master tags
[~,~,TrueValMat] = xlsread(TrueValueData); % reads our excel file into the proper format
% Creates matrix filled with the correct values
% indexed by box, which is the first row
% all proceeding rows are the master value
for i=1:inf
for n = 1:2
if i>10 % positive reading
readData = fscanf(tag);
if length(readData)>12
BOX(str2double(readData(8)),1:14)= readData(11:24);
if strcmp(TrueValMat{2,n}, BOX(n,:)) %cannot sub-index to CELL types normally, must use this method
set(handles.uipanels(n), 'BackgroundColor', 'g');
else
set(handles.uipanels(n), 'BackgroundColor', 'r');
end
drawnow % allows GUI to update the appearance whenever the loop completes.
if strcmp(TrueValMat{2,1}, BOX(1,:))...
&& strcmp(TrueValMat{2,2}, BOX(2,:)) == 1
set(handles.pushbutton5, 'enable', 'on');
end
end
end
end
end
the GUI at this point works well, with only minor things to be ironed out in the future. the colors change correctly, etc.
This is all for only a single com port. how do I make this work with 3 additional ports?
I know about bytesavailablefcn, but I have no clues how to use it, even after hours spent reading about it, watching videos, etc. obviously I am open to using anything that works, but it will have to really be explained to me.
Thanks so much

 Accepted Answer

portlist = {'COM3', 'COM4', 'COM7', 'COM12'};
nport = length(portlist);
tags = cell{1, nport};
cleanups = cell{1, nport};
for portidx = 1 : nport
delete(instrfind('Port', portlist{portidx})); % removes possibility for 'Port not available' error
tags{portidx} = serial(portlist{portidx}); %initializes the port to be used
fopen(tag); %opens th eport
cleanups{portidx} = onCleanup(@() fclose(portlist{portidx}));
end
BOX = char(zeros(2,14)); % matrix to be populated with incoming serial data
TrueValueData = 'C:\RfidChipTrueValues.xlsx';
% location of stored master tags
[~,~,TrueValMat] = xlsread(TrueValueData); % reads our excel file into the proper format
% Creates matrix filled with the correct values
% indexed by box, which is the first row
% all proceeding rows are the master value
for i=1:inf
for portidx = 1 : nport
nbase = portidx * 2 - 1;
for n = nbase:nbase+1
if i>10 % positive reading
readData = fscanf(tags{portidx});;
if length(readData)>12
BOX(str2double(readData(8)),1:14)= readData(11:24);
if strcmp(TrueValMat{2,n}, BOX(n,:)) %cannot sub-index to CELL types normally, must use this method
set(handles.uipanels(n), 'BackgroundColor', 'g');
else
set(handles.uipanels(n), 'BackgroundColor', 'r');
end
drawnow % allows GUI to update the appearance whenever the loop completes.
if strcmp(TrueValMat{2,1}, BOX(1,:))...
&& strcmp(TrueValMat{2,2}, BOX(2,:)) == 1
set(handles.pushbutton5, 'enable', 'on');
end
end
end
end
end
end
If you want something different to be done for the different ports, then you can test the portidx value.

8 Comments

its been a bit of a hectic month, I apologize for taking so long to get back to you. I get an error
Invalid syntax for calling function 'cell' on the path. Use a valid syntax or
explicitly initialize 'cell' to make it a variable.
and I am not sure what to do from here.
this is the relevant code that I copied from your answer:
% --- Outputs from this function are returned to the command line.
function varargout = WorkingGUI3_OutputFcn(hObject, eventdata, handles)
%delete(instrfind('Port', 'COM3')); % removes possibility for 'Port not available' error
%tag = serial('COM3'); %initializes the port to be used
%fopen(tag); %opens the port
portlist = {'COM3', 'COM4'}
nport = length(portlist);
tags = cell{1, nport};
cleanups = cell{1, nport};
for portidx = 1 : nport
delete(instrfind('Port', portlist{portidx})); % removes possibility for 'Port not available' error
tags{portidx} = serial(portlist{portidx}); %initializes the port to be used
cleanups{portidx} = onCleanup(@() fclose(portlist{portidx}));
end
BOX = char(zeros(2,14)); % matrix to be populated with incoming serial data
TrueValueData = 'C:\RfidChipTrueValues.xlsx';
% location of stored master tags
[~,~,TrueValMat] = xlsread(TrueValueData); % reads our excel file into the proper format
% Creates matrix filled with the correct values
% indexed by box, which is the first row
% all proceeding rows are the master value
for i=1:inf
pause(0.01)
% for n = 1:2
for portidx = 1 : nport
nbase = portidx * 2 - 1;
for n = nbase:nbase+1
if i>10 % positive reading
% readData = fscanf(tag);
readData = fscanf(tags{portidx});
if length(readData)>12
BOX(str2double(readData(8)),1:14)= readData(11:24);
if strcmp(TrueValMat{2,n}, BOX(n,:)) %cannot sub-index to CELL types normally, must use this method
set(handles.uipanels(n), 'BackgroundColor', 'g');
else
set(handles.uipanels(n), 'BackgroundColor', 'r');
end
drawnow % allows GUI to update the appearance whenever the loop completes.
if strcmp(TrueValMat{2,1}, BOX(1,:))...
&& strcmp(TrueValMat{2,2}, BOX(2,:)) == 1
set(handles.pushbutton5, 'enable', 'on');
end
end
end
end
end
end
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
thanks again for the help
Sorry, should have been
tags = cell(1, nport);
cleanups = cell(1, nport);
Error using fopen
First input must be a file name or a file identifier.
Error in WorkingGUI3>WorkingGUI3_OutputFcn (line 78)
fopen(tags); %opens th eport
Error in gui_mainfcn (line 264)
feval(gui_State.gui_OutputFcn, gui_hFigure, [], gui_Handles);
Error in WorkingGUI3 (line 42)
gui_mainfcn(gui_State, varargin{:});
I corrected the other error as well, here is code now:
% --- Outputs from this function are returned to the command line.
function varargout = WorkingGUI3_OutputFcn(hObject, eventdata, handles)
% delete(instrfind('Port', 'COM3')); % removes possibility for 'Port not available' error
% tag = serial('COM3'); %initializes the port to be used
% fopen(tag); %opens th eport
portlist = {'COM3', 'COM4'};
nport = length(portlist);
tags = cell(1, nport);
cleanups = cell(1, nport);
for portidx = 1 : nport
delete(instrfind('Port', portlist{portidx})); % removes possibility for 'Port not available' error
tags{portidx} = serial(portlist{portidx}); %initializes the port to be used
fopen(tags); %opens th eport
cleanups{portidx} = onCleanup(@() fclose(portlist{portidx}));
end
BOX = char(zeros(2,14)); % matrix to be populated with incoming serial data
TrueValueData = 'C:\Users\Administrator\Dropbox (esberlab)\esberlab Team Folder\Matlab\RFID chip reader\RfidChipData\RfidChipTrueValues.xlsx';
% location of stored master tags
[~,~,TrueValMat] = xlsread(TrueValueData); % reads our excel file into the proper format
% Creates matrix filled with the correct values
% indexed by box, which is the first row
% all proceeding rows are the master value
for i=1:inf
pause(0.01)
% for n = 1:2
for portidx = 1 : nport
nbase = portidx * 2 - 1;
for n = nbase:nbase+1
if i>10 % positive reading
% readData = fscanf(tag);
readData = fscanf(tags{portidx});
if length(readData)>12
BOX(str2double(readData(8)),1:14)= readData(11:24);
if strcmp(TrueValMat{2,n}, BOX(n,:)) %cannot sub-index to CELL types normally, must use this method
set(handles.uipanels(n), 'BackgroundColor', 'g');
else
set(handles.uipanels(n), 'BackgroundColor', 'r');
end
drawnow % allows GUI to update the appearance whenever the loop completes.
if strcmp(TrueValMat{2,1}, BOX(1,:))...
&& strcmp(TrueValMat{2,2}, BOX(2,:)) == 1
set(handles.pushbutton5, 'enable', 'on');
end
end
end
end
end
end
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;
Hello! It has been 2 years, but the code is slowly coming together. I am now working with other people, and I find myself needing to explain certain parts of the code that I did not write. over the years you have been an incredible help to me, so I have one last question for you. what is the purpose of this bit?
portlist = {'COM3', 'COM4'};
nport = length(portlist);
tags = cell(1, nport);
cleanups = cell(1, nport);
for portidx = 1 : nport
delete(instrfind('Port', portlist{portidx})); % removes possibility for 'Port not available' error
tags{portidx} = serial(portlist{portidx}); %initializes the port to be used
fopen(tags); %opens th eport
cleanups{portidx} = onCleanup(@() fclose(portlist{portidx}));
end
would you be able to explain line by line, what is being done here? similarly,
for i=1:inf
pause(0.01)
% for n = 1:2
for portidx = 1 : nport
nbase = portidx * 2 - 1;
for n = nbase:nbase+1
end
I cannot figure out what is being done here. could you explain this as well?
thank you so much for your time, and thank you for all the help you have given me over the years.
I do not explain code "line by line". When someone asks me to explain code "line by line", that means that I have to write a textbook on programming principles, and then a second textbook about programming in MATLAB, as I have to assume that everything about the code is unknown to them.
The first code loops through a fixed set of port names. It checks to see whether the port is already in use, and if so it tells MATLAB to get rid of the existing connection. Then it creates a serial port interface to the port. Finally, it creates an onCleanup object that closes the port when the cleanups variable is destroyed, such as if the user does a clear all or if the user returns from the function that opens the ports without saving the cleanup objects somewhere.
The second code loops forever reading from each port in turn. The first port uses n = 1:2, the second port uses n = 3:4, and so on. So port #K uses n = (2*K-1):(2*K)
I do appreciate the explanation you've given me here, so thank you very much.

Sign in to comment.

More Answers (1)

readers 1 and 2 (both on com3) work perfectly now. however, when a tag is held up to the third reader (on Com4), I get this error:
Index exceeds the number of array elements (2).
Error in WorkingGUI3>WorkingGUI3_OutputFcn (line 103)
set(handles.uipanels(n), 'BackgroundColor', 'r');
Error in gui_mainfcn (line 264)
feval(gui_State.gui_OutputFcn, gui_hFigure, [], gui_Handles);
Error in WorkingGUI3 (line 42)
gui_mainfcn(gui_State, varargin{:});
this is the code I have now:
% --- Outputs from this function are returned to the command line.
function varargout = WorkingGUI3_OutputFcn(hObject, eventdata, handles)
% delete(instrfind('Port', 'COM3')); % removes possibility for 'Port not available' error
% tag = serial('COM3'); %initializes the port to be used
% fopen(tag); %opens th eport
portlist = {'COM3', 'COM4'};
nport = length(portlist);
tags = cell(1, nport);
cleanups = cell(1, nport);
for portidx = 1 : nport
delete(instrfind('Port', portlist{portidx})); % removes possibility for 'Port not available' error
tags{portidx} = serial(portlist{portidx}); %initializes the port to be used
fopen(tags{portidx}); %opens th eport
cleanups{portidx} = onCleanup(@() fclose(portlist{portidx}));
end
BOX = char(zeros(3,14)); % matrix to be populated with incoming serial data
TrueValueData = 'C:\Users\Administrator\Dropbox (esberlab)\esberlab Team Folder\Matlab\RFID chip reader\RfidChipData\RfidChipTrueValues.xlsx';
% location of stored master tags
[~,~,TrueValMat] = xlsread(TrueValueData); % reads our excel file into the proper format
% Creates matrix filled with the correct values
% indexed by box, which is the first row
% all proceeding rows are the master value
for i=1:inf
pause(0.01)
% for n = 1:2
for portidx = 1 : nport
nbase = portidx * 2 - 1;
for n = nbase:nbase+1
if i>10 % positive reading
% readData = fscanf(tag);
readData = fscanf(tags{portidx});
if length(readData)>12
BOX(str2double(readData(8)),1:14)= readData(11:24);
if strcmp(TrueValMat{2,n}, BOX(n,:)) %cannot sub-index to CELL types normally, must use this method
set(handles.uipanels(n), 'BackgroundColor', 'g');
else
set(handles.uipanels(n), 'BackgroundColor', 'r');
end
drawnow % allows GUI to update the appearance whenever the loop completes.
if strcmp(TrueValMat{2,1}, BOX(1,:))...
&& strcmp(TrueValMat{2,2}, BOX(2,:)) == 1
set(handles.pushbutton5, 'enable', 'on');
end
end
end
end
end
end
% varargout cell array for returning output args (see VARARGOUT);
% hObject handle to figure
% eventdata reserved - to be defined in a future version of MATLAB
% handles structure with handles and user data (see GUIDATA)
% Get default command line output from handles structure
varargout{1} = handles.output;

5 Comments

In the code presented, we do not see any evidence that you have created as many uipanels listed in handles.uipanels as there are ports in portlist . You appear to have only one entry in handles.uipanels .
You appear to be using GUIDE. If you have multiple objects in your figure that all have the same Tag value 'uipanels' then GUIDE would automatically store all of their handles in handles.uipanels (but in some undetermined order.) If you are creating the uipanels at run-time you need to store their handles in handles.uipanels yourself.
thank you very much, I figured it out. i had an array up above that lsited all uipanels, i forgot to insert uipanel3.
the last thing is that the end of my code enables a pushbutton. this is what I used to have the enable it:
if strcmp(TrueValMat{2,1}, BOX(1,:))...
&& strcmp(TrueValMat{2,2}, BOX(2,:)) == 1
set(handles.pushbutton5, 'enable', 'on');
end
and that worked great. however, when doing this:
if strcmp(TrueValMat{2,1}, BOX(1,:))...
&& strcmp(TrueValMat{2,2}, BOX(2,:))
&& strcmp(TrueValMat{3,1}, BOX(3, :)) == 1
set(handles.pushbutton5, 'enable', 'on');
end
I get this error:
Invalid use of operator.
I figured it out, I forgot to include the ...
thanks ofr all the help, everything works great
Note that you do not need the "== 1" part.
if strcmp(TrueValMat{2,1}, BOX(1,:)) ...
&& strcmp(TrueValMat{2,2}, BOX(2,:)) ...
&& strcmp(TrueValMat{3,1}, BOX(3, :))
set(handles.pushbutton5, 'enable', 'on');
end

Sign in to comment.

Products

Release

R2019b

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!