Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

MATLAB change repeating timer period

Tags:

timer

matlab

Is it possible to change the Period of a repeating timer (in TimerFcn)?

Intuitively, when programming for Windows, I would handle WM_TIMER messages and use SetTimer to edit the period of a timer, but a similar approach doesn't seem to work in MATLAB, because the timer needs to be restarted in order to change the Period property. This messes up execution, which can be best described as changing the period to near-zero. No errors are produced.

Here's some example code that's used to create a task array: each task item consists of something to do and a delay. The array is basically walked by a timer, which should change its Period based on the current task delay.

function obj = Scheduler(~)
    obj.scheduletimer = timer(...
        'TimerFcn',@obj.OnTimer,...
        'BusyMode','queue',...
        'TasksToExecute',length(obj.tasklist),...
        'ExecutionMode','fixedRate');
end
function OnTimer(obj,source,event)
    obj.Start(); // Executed task, schedule next
end
function Start(obj)

    // Stop timer if needed
    if(strcmp(obj.scheduletimer.Running,'on'))
        stop(obj.scheduletimer);
    end;

    // Set new period and resume
    if(~isempty(obj.tasklist))
        obj.scheduletimer.Period = obj.tasklist(1).something;
        start(obj.scheduletimer);
    end;
end

When I don't mess with the timer in OnTimer, everything obviously works fine, but I'd like to change the Period each iteration.

Edit: I've tried to implement the pingpong solution suggested by Pursuit, but it's still not working. Note that the switching timers idea does work, but periods still don't seem to be applied.

function obj = Scheduler(~)
    obj.timer1 = timer(...
        'TimerFcn',@obj.OnTimer);
     obj.timer2 = timer(...
        'TimerFcn',@obj.OnTimer);
end
function OnTimer(obj,source,event)
    obj.Start(); // Executed task, schedule next
end
function Start(obj)
    if(strcmp(obj.timer1.Running,'on'))
        obj.timer2.Period = obj.tasklist{1}{2};
        start(obj.timer2);
    else
        obj.timer1.Period = obj.tasklist{1}{2};
        start(obj.timer1);
    end;
end

Ugh.

like image 988
Orwell Avatar asked Apr 15 '26 22:04

Orwell


1 Answers

Use two timers, (e.g. timerNamePing and timerNamePong). At the end of the action for each timer setup the next timer to execute once in single shot mode with some delay.

This avoids the need to constantly tear down and create new timers, and avoids the error which occurs when you try and edit a timer which is currently executing.

Here is a working example to demonstrate:

function setupPingPong

timerPing = timer;
timerPong = timer;

timerPing.TimerFcn = @(~,~)pingPongActivity(true,  timerPing, timerPong);
timerPing.Name = 'PingTimer';

timerPong.TimerFcn = @(~,~)pingPongActivity(false, timerPing, timerPong);
timerPong.Name = 'PongTimer';

timerPing.StartDelay = 0;
start(timerPing);

function pingPongActivity(isPing, timerPing, timerPong)
    if isPing
        disp(['PING (' datestr(now,'yyyy-mm-dd HH:MM:SS.FFF') ')'])
    else
        disp(['PONG (' datestr(now,'yyyy-mm-dd HH:MM:SS.FFF') ')'])
    end
    delayTime = ceil(rand*10);
    display(['    delaying '  num2str(delayTime) ' sec.'])
    if isPing
        nextTimer = timerPong;
    else
        nextTimer = timerPing;
    end
    set(nextTimer,'StartDelay', delayTime);
    start(nextTimer);

Once this is going, to stop the madness, I use:

t = timerfind; stop(t); delete(t)
like image 84
Pursuit Avatar answered Apr 21 '26 09:04

Pursuit



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!