MATLAB串口连接太慢 [英] MATLAB serial port connection is too slow

查看:753
本文介绍了MATLAB串口连接太慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个检测器,当我打开它时,它会以很高的速率吐出两个数字.我一直在使用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.BytesAvailablepause实际上花费的时间比您预期的要多得多-前者是因为它调出了操作系统,后者是因为暂停的时间可能比您根据时间片指定的时间长得多.

进行此更改会带来一个新问题: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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆