MATLAB:在GUI中不使用全局变量退出无限循环

时间:2014-01-14 10:28:32

标签: matlab user-interface infinite-loop

后台:我在GUI中有几个部分来处理不同的任务。在1部分(部分1)我有文本输入和发送按钮。所以一旦我点击发送它就会发送一个数据到我的串口。另一部分(部分2)将从串行端口接收已从其他设备接收的信号。这两个部分都使用两个按钮;一个开始特定部分的工作,一个停止工作。我使用了全局变量和while循环(使用boolean)来退出无限循环,因为我需要连续发送数据或接收数据。

我的问题:问题是当我使用全局变量和上面提到的使用无限循环的方法时,如果我单击part1,则section1将开始迭代。现在,如果我点击part2,那么将停止part1。但我需要同时使用它们,并且它们都会不断发送和接收数据,直到我点击其他按钮退出无限循环。

我的示例代码澄清:

function send_Callback(hObject, eventdata, handles)
  global firstFlag;
  firstFlag = true;
  while firstFlag
  %Required codes
  end

function haltSend_Callback(hObject, eventdata, handles)
  global firstFlag;
  firstFlag = false;

function receive_Callback(hObject, eventdata, handles)
  global secondFlag;
  secondFlag = true;
  while true
  %Required codes
  end

function stopReceive_Callback(hObject, eventdata, handles)
  global secondFlag;
  secondFlag=false;

我试图找到一个引用互联网的解决方案,但大多数解决方案都使用全局变量。如果我能在没有全局变量的情况下工作会更好。但即使我的要求得到满足(根据我的问题)也行不通。

2 个答案:

答案 0 :(得分:2)

全球与否不是这里的问题。

Matlab中的回调都在同一个线程上运行。 因此,当callback1正在运行并触发callback2时,callback2将中断callback1。 callback1将仅在callback2完成后继续。 您只能使用BusyAction属性

稍微修改此过程

http://www.mathworks.de/de/help/matlab/ref/uicontrol_props.html#bqxoija

但这对你的情况没有帮助。 在“适当的”编程语言中,您将有一个并行运行的发送和接收线程。你不能做这个matlab - 除非你是愿意写java代码。

如果你想坚持使用matlab,最接近线程的就是定时器。 这些将替换您的while循环。 例如。如下面的简约示例:

function cbtest()

    try close('cbtest');end
    f = figure('name', 'cbtest');

    % create the timers:
    period = 0.2; % period in seconds, in which the timer shall execute
    sendTimer = timer('TimerFcn', @sendFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);
    recvTimer = timer('TimerFcn', @recvFcn, 'ExecutionMode', 'fixedDelay', 'Period', period, 'TasksToExecute', Inf);

    uicontrol(f, 'position', [10 10 100 25], 'Callback', @(a,b) start(sendTimer), 'string', 'start1');
    uicontrol(f, 'position', [120 10 100 25], 'Callback', @(a,b) stop(sendTimer), 'string', 'stop1');

    uicontrol(f, 'position', [10 50 100 25], 'Callback', @(a,b) start(recvTimer), 'string', 'start2');
    uicontrol(f, 'position', [120 50 100 25], 'Callback', @(a,b) stop(recvTimer), 'string', 'stop2');
end

function sendFcn(hTimer, timerEvt)
    % your send-loop-code
    disp('sending');
end

function recvFcn(hTimer, timerEvt)
    % your receive-loop-code
    disp('receiving');
end

sendFcnrecvFcn此处应包含您在相应的while循环中的代码。 您当然可以根据需要降低period,我选择上述内容进行测试。

答案 1 :(得分:1)

你的问题是你在Callbacks中执行循环。因此,当单击第二个按钮时,第二个回调将开始并无限循环,直到它结束。第一个循环将等待第二个Callback终止,直到它可以恢复。你需要的是一个执行循环的主程序。嵌套回调将确保他们可以访问和更改局部变量,而不会使它们成为全局变量。如果您可以通过编程方式构建GUI,请尝试以下方法:

function main()
  sendFlag = false;
  receiveFlag = false;

  while true
    if sendFlag
      % Your Sending code
    end
    if receiveFlag
      % Your Receiving code
    end
  end

  function send_Callback(~,~,~)
    sendFlag = true;
  end

  % other Callbacks

end

然后在你的按钮的回调中(你可以使用Toggle Buttons),你只需分别设置sendFlag和receiveFlag。

使用GUIDE,您想使用切换按钮。 我并不完全知道GUIDE如何处理OpeningFcn,因此你应该在你的GUI中放置一个“开始”按钮,基本上执行上面的程序并进行一些更改:

function startbutton_Callback(hObject,~,handles)
  while true
    handles = guidata(hObject); % Updates handles structure

    sendFlag = get(handles.sendtoggle, 'Value');
    if sendFlag
      % Your Sending code
    end

    receiveFlag = get(handles.receivetoggle, 'Value');
    if receiveFlag
      % Your Receiving code
    end
  end

此外,创建发送和接收切换按钮并将它们的'Min'设置为0,将'Max'设置为1.这将使它们在0和1之间切换它们的'Value'属性(在上面的循环中读取)你点击它们。在回调中,您可以更改它们显示的内容:

function send_Callback(hObject,~,handles)
  on = get(hObject,'Value');
  if on
    set(hObject, 'String', 'Stop sending');
  else
    set(hObject, 'String', 'Start sending');
  end
  guidata(hObject,handles); % Update GUI data

现在,您的主要功能(单击开始按钮时启动)会运行循环,只检查切换按钮的状态以确定是否发送和接收。