Running a timer inside another timer

2 views (last 30 days)
Chloe Soriano
Chloe Soriano on 11 Jan 2023
Answered: Adam Danz on 14 Jan 2023
Hello, so I need to run a timer inside another timer, and I need to keep the properties of each timer specific to THAT timer. I was able to get it to run the inside timer once, but it never repeated once it went to the outside timer. Seems like there is an issue with the outside timer. May I please have some assistance with this by any ideas on how to go about it? Thank you.
  6 Comments
Adam Danz
Adam Danz on 12 Jan 2023
Edited: Adam Danz on 12 Jan 2023
This isn't a minimal working example. If you could provide a watered down version with the bare minimum components that we could copy-paste-run, that would expedite the troubleshooting process.
Where are you starting these timers? I see thier start functions but I don't see thier start commands.
Chloe Soriano
Chloe Soriano on 13 Jan 2023
@Adam Danz Here is the the version where I could simplify as much as I could. It is a GUI, so the last 150 lines of code is just the setup.
classdef workingdepriv < matlab.apps.AppBase
% Properties that correspond to app components
properties (Access = public)
UIFigure matlab.ui.Figure
WaitTimeinBetweenEachRoundDropDown matlab.ui.control.DropDown
WaitTimeinBetweenEachRoundDropDownLabel matlab.ui.control.Label
NumberofDeprivationRoundsDropDown matlab.ui.control.DropDown
NumberofDeprivationRoundsDropDownLabel matlab.ui.control.Label
LengthofexperimentinhoursDropDown matlab.ui.control.DropDown
LengthofexperimentinhoursDropDownLabel matlab.ui.control.Label
STOPButton matlab.ui.control.Button
STARTButton matlab.ui.control.Button
end
properties (Access = public)
deprivTimer = timer; % defining the timer variable, this controls deprivation
length; % length of experiment in hours
dayTimer = timer; % defining timer to run for x number of days
numDeprivRounds; % tasks to execute for dayTimer
waitTime; % period for dayTimer
numExecutions; % tasks to execute for deprivTimer
end
% Callbacks that handle component events
methods (Access = private)
% Code that executes after component creation
function startupFcn(app)
% deprivTimer: controls when the deprivation motor performs a deprivation
app.deprivTimer.UserData = [45, randi([0, 2.25 * 60], 1)];
app.deprivTimer.Period = 180;
app.deprivTimer.ExecutionMode = 'fixedRate';
app.deprivTimer.StartFcn = @SNAPstep;
app.deprivTimer.TimerFcn = @SNAPstep;
app.deprivTimer.StopFcn = @SNAPstep;
app.deprivTimer.ErrorFcn = @SNAPstep;
function SNAPstep(mTimer,event)
event_type = event.Type;
switch event_type
case 'StartFcn'
disp([event_type ' deprivTimer executed ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
case 'TimerFcn'
disp([event_type ' deprivTimer executed ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
pause(app.deprivTimer.UserData(2)) % pauses for the specified random interval until the deprivation movement should start
disp(['Deprive executed ',datestr(clock,'dd-mmm-yyyy HH:MM:SS.FFF')]);
pause(mTimer.UserData(1)) % pauses the function until the deprivator is finished cycling
app.deprivTimer.UserData(2) = randi([0, 2.25 * 60] , 1); %sets a new random interval within the 3 minute window for the next deprivation
case 'StopFcn'
disp([event.Type ' deprivTimer executed ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
stop(mTimer)
case 'ErrorFcn'
disp([event.Type,datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
end
end
% dayTimer: controls when all of the events associated with deprivTimer occurs
app.dayTimer.StartFcn = @CHATstep;
app.dayTimer.TimerFcn = @CHATstep;
app.dayTimer.StopFcn = @CHATstep;
app.dayTimer.ExecutionMode = 'fixedRate';
function CHATstep (cTimer, event)
event_type = event.Type;
switch event_type
case 'StartFcn'
disp([event_type ' dayTimer started ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
case 'TimerFcn'
disp([event.Type ' dayTimer executed ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
start(app.deprivTimer);
case 'StopFcn'
disp([event.Type ' dayTimer Fcn complete ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
stop(cTimer);
end
end
end
% Value changed function: LengthofexperimentinhoursDropDown
function LengthofexperimentinhoursDropDownValueChanged2(app, event)
app.LengthofexperimentinhoursDropDown.Value;
% converting the drop down into the correct format for app.TasksToExecute
app.length = str2double(app.LengthofexperimentinhoursDropDown.Value)
execute = (app.length * 60) / 3
% the variable execute is sometimes read as a negative number, loop is to make sure
% execute is always positive
if execute < 0
app.numExecutions = -execute;
else
app.numExecutions = execute;
end
app.deprivTimer.TasksToExecute = app.numExecutions
end
% Value changed function: NumberofDeprivationRoundsDropDown
function NumberofDeprivationRoundsDropDownValueChanged(app, event)
app.NumberofDeprivationRoundsDropDown.Value;
app.numDeprivRounds = str2double(app.NumberofDeprivationRoundsDropDown.Value)
app.dayTimer.TasksToExecute = app.numDeprivRounds
end
% Value changed function: WaitTimeinBetweenEachRoundDropDown
function WaitTimeinBetweenEachRoundDropDownValueChanged(app, event)
app.WaitTimeinBetweenEachRoundDropDown.Value;
app.waitTime = str2double(app.WaitTimeinBetweenEachRoundDropDown.Value)
app.dayTimer.Period = app.waitTime * 3600 % selected number of hrs converted to sec
end
% Button pushed function: STARTButton
function STARTButtonPushed(app, event)
% prevents user from pushing START if it was pushed already
set(app.STARTButton, 'Enable', 'off');
% starting dayTimer
start(app.dayTimer);
% how to get deprivTimer to start within dayTimer? all of the events of deprivTimer need to
% repeat
% to keep record of when deprivTimer and dayTimer occur
disp(app.deprivTimer);
disp(app.dayTimer);
end
% Button pushed function: STOPButton
function STOPButtonPushed(app, event)
stop(app.deprivTimer);
stop(app.dayTimer);
set(app.STOPButton, 'Enable', 'on');
% loop means that if STOP is pushed, START will turn on
if strcmpi(app.STARTButton.Enable,'off')
set(app.STARTButton, 'Enable', 'on');
end
end
end
% Component initialization
methods (Access = private)
% Create UIFigure and components
function createComponents(app)
% Create UIFigure and hide until all components are created
app.UIFigure = uifigure('Visible', 'off');
app.UIFigure.Position = [100 100 640 480];
app.UIFigure.Name = 'MATLAB App';
% Create STARTButton
app.STARTButton = uibutton(app.UIFigure, 'push');
app.STARTButton.ButtonPushedFcn = createCallbackFcn(app, @STARTButtonPushed, true);
app.STARTButton.BackgroundColor = [0 1 0];
app.STARTButton.FontSize = 20;
app.STARTButton.Position = [112 96 146 66];
app.STARTButton.Text = 'START';
% Create STOPButton
app.STOPButton = uibutton(app.UIFigure, 'push');
app.STOPButton.ButtonPushedFcn = createCallbackFcn(app, @STOPButtonPushed, true);
app.STOPButton.BackgroundColor = [1 0 0];
app.STOPButton.FontSize = 20;
app.STOPButton.Position = [393 96 139 66];
app.STOPButton.Text = 'STOP';
% Create LengthofexperimentinhoursDropDownLabel
app.LengthofexperimentinhoursDropDownLabel = uilabel(app.UIFigure);
app.LengthofexperimentinhoursDropDownLabel.HorizontalAlignment = 'right';
app.LengthofexperimentinhoursDropDownLabel.FontSize = 17;
app.LengthofexperimentinhoursDropDownLabel.Position = [66 320 293 24];
app.LengthofexperimentinhoursDropDownLabel.Text = 'Length of experiment (in hours):';
% Create LengthofexperimentinhoursDropDown
app.LengthofexperimentinhoursDropDown = uidropdown(app.UIFigure);
app.LengthofexperimentinhoursDropDown.Items = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24'};
app.LengthofexperimentinhoursDropDown.ValueChangedFcn = createCallbackFcn(app, @LengthofexperimentinhoursDropDownValueChanged2, true);
app.LengthofexperimentinhoursDropDown.FontSize = 17;
app.LengthofexperimentinhoursDropDown.Position = [374 322 100 22];
app.LengthofexperimentinhoursDropDown.Value = '1';
% Create NumberofDeprivationRoundsDropDownLabel
app.NumberofDeprivationRoundsDropDownLabel = uilabel(app.UIFigure);
app.NumberofDeprivationRoundsDropDownLabel.HorizontalAlignment = 'right';
app.NumberofDeprivationRoundsDropDownLabel.FontSize = 17;
app.NumberofDeprivationRoundsDropDownLabel.Position = [66 261 293 26];
app.NumberofDeprivationRoundsDropDownLabel.Text = 'Number of Deprivation Rounds:';
% Create NumberofDeprivationRoundsDropDown
app.NumberofDeprivationRoundsDropDown = uidropdown(app.UIFigure);
app.NumberofDeprivationRoundsDropDown.Items = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10'};
app.NumberofDeprivationRoundsDropDown.ValueChangedFcn = createCallbackFcn(app, @NumberofDeprivationRoundsDropDownValueChanged, true);
app.NumberofDeprivationRoundsDropDown.FontSize = 17;
app.NumberofDeprivationRoundsDropDown.Position = [374 265 100 22];
app.NumberofDeprivationRoundsDropDown.Value = '1';
% Create WaitTimeinBetweenEachRoundDropDownLabel
app.WaitTimeinBetweenEachRoundDropDownLabel = uilabel(app.UIFigure);
app.WaitTimeinBetweenEachRoundDropDownLabel.HorizontalAlignment = 'right';
app.WaitTimeinBetweenEachRoundDropDownLabel.FontSize = 17;
app.WaitTimeinBetweenEachRoundDropDownLabel.Position = [66 207 293 26];
app.WaitTimeinBetweenEachRoundDropDownLabel.Text = 'Wait Time in Between Each Round:';
% Create WaitTimeinBetweenEachRoundDropDown
app.WaitTimeinBetweenEachRoundDropDown = uidropdown(app.UIFigure);
app.WaitTimeinBetweenEachRoundDropDown.Items = {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', '11', '12', '13', '14', '15', '16', '17', '18', '19', '20', '21', '22', '23', '24'};
app.WaitTimeinBetweenEachRoundDropDown.ValueChangedFcn = createCallbackFcn(app, @WaitTimeinBetweenEachRoundDropDownValueChanged, true);
app.WaitTimeinBetweenEachRoundDropDown.FontSize = 17;
app.WaitTimeinBetweenEachRoundDropDown.Position = [374 211 100 22];
app.WaitTimeinBetweenEachRoundDropDown.Value = '1';
% Show the figure after all components are created
app.UIFigure.Visible = 'on';
end
end
% App creation and deletion
methods (Access = public)
% Construct app
function app = workingdepriv
% Create UIFigure and components
createComponents(app)
% Register the app with App Designer
registerApp(app, app.UIFigure)
% Execute the startup function
runStartupFcn(app, @startupFcn)
if nargout == 0
clear app
end
end
% Code that executes before app deletion
function delete(app)
% Delete UIFigure when app is deleted
delete(app.UIFigure)
end
end

Sign in to comment.

Answers (1)

Adam Danz
Adam Danz on 14 Jan 2023
The problem seems to be that the line that starts deprivTimer uses "app.deprivTimer" but "app" is not one of the input arguments in that function.
function CHATstep (cTimer, event) %<---------- "app" is not an input
event_type = event.Type;
switch event_type
case 'StartFcn'
disp([event_type ' dayTimer started ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
case 'TimerFcn'
disp([event.Type ' dayTimer executed ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
start(app.deprivTimer); % <--------------- HERE
case 'StopFcn'
disp([event.Type ' dayTimer Fcn complete ',datestr(event.Data.time,'dd-mmm-yyyy HH:MM:SS.FFF')]);
stop(cTimer);
end
end
To fix that, you need to include the app object in the function definitions. Here are examples you can apply to your file.
app.dayTimer.StartFcn = @(timer,event)CHATstep(app,timer,event);
app.dayTimer.TimerFcn = @(timer,event)CHATstep(app,timer,event);
app.dayTimer.StopFcn = @(timer,event)CHATstep(app,timer,event);
function CHATstep (app,cTimer, event) % <-- add app input
...
start(app.deprivTimer); % <--- now this will work
...
end
However there are some other puzzles here. First it appears that there is much time between events. This line below suggests several minutes. The other section below shows that you're pausing for potentially long periods. Make sure you reduces these to short periods of time when testing and developing.
app.dayTimer.Period = app.waitTime * 3600
case 'TimerFcn'
pause(app.deprivTimer.UserData(2)) % pauses for the specified random interval until the deprivation movement should start
pause(mTimer.UserData(1)) % pauses the function until the deprivator is finished cycling
Lastly, as mentioned in the documentation for timer, timers like these should not be used for precise control of temporal events. So if your program requires precise timing control (sub-second), be aware that of these limitations.

Categories

Find more on Develop Apps Using App Designer in Help Center and File Exchange

Products


Release

R2022b

Community Treasure Hunt

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

Start Hunting!