MATLAB串口连接太慢 [英] MATLAB serial port connection is too slow
问题描述
我有一个检测器,当我打开它时,它会以很高的速率吐出两个数字.我一直在使用HyperTerminal捕获数据,它似乎能够跟上设备的速度.
我想使过程自动化并完全通过Matlab来控制设备,但是发现不到一半的数据传递给Matlab. Matlab在此方面的速度是否存在任何已知问题?
这就是我用来读取数据的内容:
s = serial('COM1', 'BaudRate', 115200, 'DataBits', 8, 'Terminator','CR/LF', 'InputBufferSize', 1024);
T1 = 1; % Initial T1, T2 values
T2 = 10000;
timer = 300;
% Inputs to serial device: T1, T2, runtime (seconds)
fprintf(s, sprintf('%d %d %d\r', T1, T2, timer));
tdata = zeros(1e5,2,'uint16');
data = fopen(sprintf('%s.txt',date_and_trial),'w');
tic;
while toc <= timer
% Read data into an array, and write to file.
if s.BytesAvailable >= 13
line = fgets(s);
if length(line) == 13
a = sscanf(line, '%u %u');
if length(a) == 2
tdata(i,1) = a(1);
tdata(i,2) = a(2);
fprintf(data, sprintf('%d %d\r', tdata(i,1), tdata(i,2)));
i++;
end
end
else
pause(0.01);
end
end
disp(toc);
fclose(s);
fclose(data);
fprintf('Finished!\r');
我一直在考虑条件条件可能会减慢它的速度,但是它们似乎对于保持所需的'%i%i \ n'格式也很有必要.也许有某种方法可以读取所有数据并在完成后对其进行处理?
由于在串行端口打开调用中传递了'Terminator', 'CR/LF'
,因此可以替换
if s.BytesAvailable >= 13
line = fgets(s);
if length(line) == 13
和line = fscanf(s);
. fscanf
将等待终止符,并返回整行(假设线路上没有错误).您也可以删除else pause
部分.这些更改将使循环运行得足够快,以跟上串行数据的速度.我猜想s.BytesAvailable
和pause
实际上花费的时间比您预期的要多得多-前者是因为它调出了操作系统,后者是因为暂停的时间可能比您根据时间片指定的时间长得多.>
进行此更改会带来一个新问题:fscanf
将阻止等待终止符,这意味着如果设备在您的toc >= timer
条件变为真之前停止发送,程序将挂起.因此,您应该确保在serial
调用中设置合理的超时时间.
您可以在循环的主体中进行两次较小的加速:tdata(i,:) = a';
将以一杆的速度填充该行,而fprintf(data, '%s\r', line);
将跳过printf
.因此,将它们放在一起:
s = serial('COM1', 'BaudRate', 115200, 'DataBits', 8, 'Terminator','CR/LF', 'InputBufferSize', 1024, 'Timeout', 3);
T1 = 1; % Initial T1, T2 values
T2 = 10000;
timer = 300;
% Inputs to serial device: T1, T2, runtime (seconds)
fprintf(s, sprintf('%d %d %d\r', T1, T2, timer));
tdata = zeros(1e5,2,'uint16');
data = fopen(sprintf('%s.txt',date_and_trial),'wt');
tic;
while toc <= timer
% Read data into an array, and write to file.
line = fscanf(s); %# waits for CR/LF terminator
a = sscanf(line, '%u %u');
if length(a) == 2
tdata(i,:) = a'; %# ' assumes sscanf returned a column vector
fprintf(data, '%s\r', line);
i++;
end
end
disp(toc);
fclose(data);
fclose(s);
fprintf('Finished!\r');
I've got a detector that spits out two numbers at a high rate when I turn it on. I've been capturing my data using HyperTerminal, which seems to be able to keep up with the device.
I wanted to automate the process and control the device entirely through Matlab, but discovered that less than half of the data gets through to Matlab. Are there any known issues with Matlab's speed in this area?
Here's what I'm using to read in data:
s = serial('COM1', 'BaudRate', 115200, 'DataBits', 8, 'Terminator','CR/LF', 'InputBufferSize', 1024);
T1 = 1; % Initial T1, T2 values
T2 = 10000;
timer = 300;
% Inputs to serial device: T1, T2, runtime (seconds)
fprintf(s, sprintf('%d %d %d\r', T1, T2, timer));
tdata = zeros(1e5,2,'uint16');
data = fopen(sprintf('%s.txt',date_and_trial),'w');
tic;
while toc <= timer
% Read data into an array, and write to file.
if s.BytesAvailable >= 13
line = fgets(s);
if length(line) == 13
a = sscanf(line, '%u %u');
if length(a) == 2
tdata(i,1) = a(1);
tdata(i,2) = a(2);
fprintf(data, sprintf('%d %d\r', tdata(i,1), tdata(i,2)));
i++;
end
end
else
pause(0.01);
end
end
disp(toc);
fclose(s);
fclose(data);
fprintf('Finished!\r');
I've been thinking that the conditionals might be slowing it down, but they also seem to be necessary to keep things in the '%i %i\n' format that I need. Maybe there's some way to read in all the data and process it after completion?
Since you pass 'Terminator', 'CR/LF'
in the serial port open call, you can replace
if s.BytesAvailable >= 13
line = fgets(s);
if length(line) == 13
with line = fscanf(s);
. fscanf
will wait for the terminator, and return a whole line (assuming there aren't errors on the wire). You can also remove the else pause
part. These changes should make the loop run fast enough to keep up with the serial data. I would guess that s.BytesAvailable
and pause
actually take much more time than you'd expect - the former because it calls out to the OS and the latter because the pause could go much longer than you specify depending on timeslicing.
Making this change introduces a new problem though: fscanf
will block waiting for the terminator, meaning if the device stops sending before your toc >= timer
condition becomes true, the program will hang. So you should make sure to set a sensible timeout in the serial
call.
You can make two minor speedups in the body of the loop: tdata(i,:) = a';
will fill the row in one shot, and fprintf(data, '%s\r', line);
will skip printf
. So putting it all together:
s = serial('COM1', 'BaudRate', 115200, 'DataBits', 8, 'Terminator','CR/LF', 'InputBufferSize', 1024, 'Timeout', 3);
T1 = 1; % Initial T1, T2 values
T2 = 10000;
timer = 300;
% Inputs to serial device: T1, T2, runtime (seconds)
fprintf(s, sprintf('%d %d %d\r', T1, T2, timer));
tdata = zeros(1e5,2,'uint16');
data = fopen(sprintf('%s.txt',date_and_trial),'wt');
tic;
while toc <= timer
% Read data into an array, and write to file.
line = fscanf(s); %# waits for CR/LF terminator
a = sscanf(line, '%u %u');
if length(a) == 2
tdata(i,:) = a'; %# ' assumes sscanf returned a column vector
fprintf(data, '%s\r', line);
i++;
end
end
disp(toc);
fclose(data);
fclose(s);
fprintf('Finished!\r');
这篇关于MATLAB串口连接太慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!