array exceeds limits when scanning serial info

I have a code that scans incoming serial information in the form of an alphanumeric tag. The program then looks through an excel sheet to find that tag, and reports the sheet and row the tag appears in:
portlist = {'COM3', 'COM4', 'COM5', 'COM6'}; % , 'COM4', 'COM5', 'COM6'
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}));
cleanups{portidx} = onCleanup(@() fclose('all'));
end
addpath('C:\Users\Administrator\Dropbox (********)\******** Team Folder\Matlab\RFID chip reader\RfidChipData');
filename = 'CorrectedRFIDValues.xlsx';
[~, sheets] = xlsfinfo(filename);
in = char(zeros(1,14));
decision = fscanf(tags{portidx});
in = decision(11:24);
rows_found = [];
sheets_found = {};
for K = 1 : length(sheets)
this_sheet = sheets{K};
[~, ~, raw] = xlsread(filename, this_sheet);
[rowNum, colNum] = find( strcmp(in, raw));
if ~isempty(rowNum)
rows_found = [rows_found; rowNum];
sheets_found = [sheets_found; repmat({this_sheet}, length(rowNum), 1)];
end
end
disp(this_sheet)
disp(rowNum)
later in the code, a number of different ports are utilized for a couple other reasons. for this section, only COM3 is used. I keep getting an index out of bounds error, but I am not sure where it is coming from:
Index exceeds the number of array elements (12).
Error in Manual_auto_update2>Manual_auto_update2_OutputFcn (line 89)
in = decision(11:24);
Error in gui_mainfcn (line 264)
feval(gui_State.gui_OutputFcn, gui_hFigure, [], gui_Handles);
Error in Manual_auto_update2 (line 42)
gui_mainfcn(gui_State, varargin{:});
the information coming in from serial is a line, indicating a scanner number and the tag being scanned.
its looks like this:
Reader 1: 000000020F0D0%
for decision(11:24), i cut out only the tag from the entire line, as that is all I need to find in the excel sheet. I keep getting that error, however, even though I made a zeros matrix to be filled with the incoming tag. I got it to read a single time, which gave me the resulkts I was looking for. but now I have nothing. the entire code is below, which changes the color of a GUI panel based on a string comparison with the incoming serial tags, and the correct ones stored in the excel sheet. there is a number of different tags that work at different times, as well as for a number of different places.

 採用された回答

Guillaume
Guillaume 2020 年 1 月 29 日

0 投票

I'm a bit confused by all the code you've posted. If I understood correctly the problem is with:
in = char(zeros(1,14));
decision = fscanf(tags{portidx});
in = decision(11:24);
For a start, the first line doesn't do anything useful. Whenever you assign something to a non-indexed variable, whatever was in the variable before doesn't matter it's completely wiped out when doing the assigment:
in = something; %doesn't matter what in was before the line. The content is completely replaced
Now, the error is Index exceeds the number of array elements (12), on the line:
in = decision(11:24);
The variable that is being indexed here is not in, it's decision. So the error tells you that the indices 11 to 24 exceed the number of elemens in |decisions. It also tells you tall number of elements is 12. So, the problem is clear, your fscanf only returned 12 characters. You'll have to figure out why. Perhaps it's a problem with your instrument. Looking at the content at what you received may give you a clue. Maybe it's an error code.
When dealing with IO, I would certainly never assume that you get what you wanted without checking that it is actually the case, so changing your code to:
[decision, receivedcount] = fscanf(tags{portidx});
if receivedcount < 24
error('Received less data than expected. Received data was: %s', decision)
end
%now we know we've got at least 24 characters.
%You may still want to check that the characters you receive conform to the pattern you expect. This is left as an exercise to the reader.
in = decision(11:24);
%...

8 件のコメント

avram alter
avram alter 2020 年 1 月 29 日
編集済み: avram alter 2020 年 1 月 29 日
thanks for that. the code returns the error as:
Error using Manual_auto_update2>Manual_auto_update2_OutputFcn (line 90)
Received less data than expected. Received data was: Reader 8:
the issue is that it is looking for the info off of COM6, not COM3 as I want. do you know why that is?
once I scan something with reader 8, it works without a problem
a lot of the code I posted was for some background. I wasn't sure how in depth I should go.
another issue is that I immediately get the error, if a tag is not currently held up. How can I get it to loop until something shows up?
Guillaume
Guillaume 2020 年 1 月 29 日
it is looking for the info off of COM6, not COM3 as I want. do you know why that is?
It is most likely a bug earlier in your code.
How can I get it to loop until something shows up?
I'm not very familiar with the serial object of the instrument control toolbox. Nowadays, you have serialport in base matlab. There are typically two ways of doing this.
1) Check the BytesAvailable property (or whatever the equivalent is in the toolbox) in a while loop. Easy, but you can't do anything else while waiting for the data.
2) Use the BytesAvailableFcn callback (or whatever the equivalent is in the toolbox) together with the BytesAvailableFcnCount property to get your callback called whenever there is enough data. It means you can do other stuff while waiting but asynchronous IO is slightly more difficult to program.
avram alter
avram alter 2020 年 1 月 29 日
it seems that
fscanf(tags{portidx})
is defaulting to the nport value ie, the final value in portlist, COM6. I want to switch it to
fscanf(portlist(1).port
but I get the
Invalid file identifier. Use fopen to generate a valid file identifier
error. And I cant use debugging to find the file identifier, because in debugging mode
whos
doesn't work. if I leave debugging mode, all my variable names are removed from workspace. do you know of a way to generate a valid file identifier for portlist(1).port?
Walter Roberson
Walter Roberson 2020 年 1 月 30 日
For a start, the first line doesn't do anything useful.
Unless, that is, the code is inside a MATLAB Function Block for Simulink use, in which case you need to initialize most variables to the proper size and datatype before using the variable as the output of a function call.
Guillaume
Guillaume 2020 年 1 月 30 日
@Walter, I don't think we're in a simulink context here.
@avram, fscanf doesn't default to anything, so if tags(portidx} is the serial port object attached to COM6 when it shouldn't, there's a bug earlier in your code.
With regards to 'invalid file identifier'. The fscanf function is a bit overloaded. It's primary role is to read data from files. For that it needs a valid file identifier as its first argument. Then there's the fscanf overload for serial objects. To call that overload, the first argument must be a serial object, otherwise you end up called the standard file fscanf. So if you get 'invalid file identifier' when using fscanf(portlist(1).port) it means that portlist(1).port is not a serial object at all. Perhaps, it's just []. Again, if it's supposed to be a serial object, you've got a bug.
avram alter
avram alter 2020 年 1 月 30 日
編集済み: avram alter 2020 年 1 月 30 日
I've chnaged my approach a bit. instead of using fcsanf, I using read(). this is what my code looks like:
portlist = {'COM3', 'COM4', 'COM5', 'COM6'};
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('all'));
end
addpath('C:\Users\Administrator\Dropbox (********)\******** Team Folder\Matlab\RFID chip reader\RfidChipData');
filename = 'CorrectedRFIDValues.xlsx';
[~, sheets] = xlsfinfo(filename);
delete(instrfind());
x = 24;
decision = read(serialport('COM3', str2double('9600')), double(x), 'char');
in = decision(11:24);
rows_found = [];
sheets_found = {};
for K = 1 : length(sheets)
this_sheet = sheets{K};
[~, ~, raw] = xlsread(filename, this_sheet);
[rowNum, colNum] = find( strcmp(in, raw));
if ~isempty(rowNum)
rows_found = [rows_found; rowNum];
sheets_found = [sheets_found; repmat({this_sheet}, length(rowNum), 1)];
end
end
when I scan my tag in with the arduino serial monitor, I get exactly what I expect:
Reader 1: 000000020F0D0%
Reader 2:
Reader 1: 000000020F0D0%
Reader 2:
Reader 1: 000000020F0D0%
Reader 2:
Reader 1: 000000020F0D0%
Reader 2:
this what I expect, as the I am reading that code off of reader 1. the prblem is, when I run the above code, decision (which should be 'Reader 1: 000000020F0D0%)' is
Reader 1: Reader 2:
I am not sure why my code is completely skipping over the tag.
Is there away to make read() ignore anything after a newline?
Guillaume
Guillaume 2020 年 1 月 31 日
I think you'll need to attach your code. I assume you're not using exactly what you've posted above as it can't possibly work.
There's a number of oddities in what you've posted. Most of them are probably unrelated to your problem, but still:
  • You're storing a cleanup function for each port you open in a cell array. However, for each port the cleanup function does the same thing: closing all the ports. So, you don't really need to do it per port. You may has well have just:
%after the loop opening the ports:
cleanup = onCleanup(@() fclose('all'));
  • In any case, all that business of opening ports is completely wasted, since you have a delete(instrfind) before you actually use them. You then only reopen COM3 with serialport (the recommend function nowadays)
  • Why do you have str2double('9600') when 9600 would be simpler?
  • Why do you have double(x) when (the badly named) x is already double?
  • Your serialport call is syntactically invalid, after the baudrate all inputs must be specified as name-value pairs. I'm not sure what x is supposed to be, maybe the 'Timeout' and there's no property of serialport that accepts 'char'
  • read(serialport(..)) is very iffy. You open the serial port but don't save its handle, just pass it to read. and never close the port. So if you try to do the same again, the serialport call will fail since you still have an open port for which you no longer have the handle.
avram alter
avram alter 2020 年 1 月 31 日
to answer a bunch of your questions, I was basically ignoring a large chunk of the code to deal with a single thing at once. that why I used delete(instrfind()), before I actually do anything. Ill try to go through your points one at a time:
portlist = {'COM3', 'COM4', 'COM5', 'COM6'};
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('all'));
end
addpath('C:\Users\Administrator\Dropbox (********)\******** Team Folder\Matlab\RFID chip reader\RfidChipData');
filename = 'CorrectedRFIDValues.xlsx';
[~, sheets] = xlsfinfo(filename);
delete(instrfind());
Decidingport = serialport('COM3', 9600)
decision = read(Decidingport, 24, 'char');
in = decision(11:24);
rows_found = [];
sheets_found = {};
for K = 1 : length(sheets)
this_sheet = sheets{K};
[~, ~, raw] = xlsread(filename, this_sheet);
[rowNum, colNum] = find( strcmp(in, raw));
if ~isempty(rowNum)
rows_found = [rows_found; rowNum];
sheets_found = [sheets_found; repmat({this_sheet}, length(rowNum), 1)];
end
end
I fixed your earlier points (the problematic naming and variable types was written very quickly, without looking over it).
the syntax for read() is
read(device, count, precision)
device being the serial port, count being the number of values to be read, and precision is the type of data.
here, I used serialport() as device. serialport is
serialport(port, baudrate)
with the port being COM3 and the baudrate being 9600. I dont want to have to open the serial port again, as that brings back your first point of delete(instrfind()). however, I don't know how to properly use fscanf to correctly point it at COM3. I still ge the same problem as above, however, and I am unsure of what is going wrong.

サインインしてコメントする。

その他の回答 (0 件)

カテゴリ

製品

リリース

R2019b

質問済み:

2020 年 1 月 29 日

コメント済み:

2020 年 1 月 31 日

Community Treasure Hunt

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

Start Hunting!

Translated by