none
How To Make a Timer RRS feed

  • Question

  • Hello Small Basic Community, 

    I am interested in making a timer. I don't want to use the Timer Object. Instead, I want to learn how to make it from scratch and understand the how the code flows to create the illusion of a timer. I particularly want to make a timer using seconds and minutes. I also want the timer to count backwards. User input won't be necessary since it will be used for a video game. To begin this post, I took code from the small basic curriculum (lesson 4.1) to make an attempt in understanding timers. It is only in seconds though. I am currently trying to figure out how to revise to this code to include minutes. Any input will be appreciated. The only part that I don't understand is starting from line " Program.Delay(delaySpeed) " to " EndIf . . . ". It appears that this last block of code measures one second in real time, yet, I don't understand how a program delay of 15 milliseconds is the equivalent of one second. I am aware that it's difficult to exactly calculate one second in real time. All the help will be much appreciated. 

    P.S. I am currently traveling so It will be difficult for me to respond promptly to replies. I will try to respond as quickly as I can. Thank you. 

    sec = 50
    prevSec = 0
    delayspeed = 15
    
    While "True" 
      sec = sec - 0.01
      GraphicsWindow.BrushColor = "Blue"
      GraphicsWindow.FillRectangle(480, 0, 100, 25) 
      GraphicsWindow.BrushColor = "White"
      GraphicsWindow.DrawText(482, 5, "Time:")
      
      If sec >= 10 Then
        GraphicsWindow.DrawText(530, 5,"00:" + Math.Floor(sec)) 
      ElseIf sec > 0 Then 
        GraphicsWindow.DrawText(530, 5,"00:0" + Math.Floor(sec)) 
      EndIf
      
      If sec <= 0 Then 
        GraphicsWindow.DrawText(530, 5,"00:0" + Math.Floor(sec)) 
        Program.End()  
      EndIf  
      
      Program.Delay(delayspeed) '15 milliseconds 
      currentSec = Clock.ElapsedMilliseconds 
      If (currentSec - prevSec) >= 5000 Then               
        prevSec = currentSec 
      EndIf    
    EndWhile


    • Edited by Ezra94 Thursday, August 21, 2014 4:57 AM add more
    Thursday, August 21, 2014 4:54 AM

Answers

  • You are right, this program doesn't count down in seconds.

    Each time the loop is passed, sec is reduced by 0.01, therefore in 100 loops it counts down 1 sec.

    The time taken for 100 steps is at least 100*(15ms) = 1.5 sec and probably longer due to the time to do the actual drawing etc.

    So it takes at lease 75 sec to count down 50 sec?

    This keep better time:
    sec = 50
    time = Clock.ElapsedMilliseconds

    While sec >= 0  
      GraphicsWindow.BrushColor = "Blue"
      GraphicsWindow.FillRectangle(480, 0, 100, 25)
      GraphicsWindow.BrushColor = "White"
      GraphicsWindow.DrawText(482, 5, "Time:")
     
      If sec >= 10 Then
        GraphicsWindow.DrawText(530, 5,"00:" + Math.Floor(sec))
      Else
        GraphicsWindow.DrawText(530, 5,"00:0" + Math.Floor(sec))
      EndIf  
     
      time = time + 1000
      sec = sec-1
      Program.Delay(time - Clock.ElapsedMilliseconds)
    EndWhile

    Program.End()
    The reason this should keep good time is that time is updated by 1000 each pass through the loop, so everything is referenced back to the first time Clock.EllapsedMilliseconds was called and we don't have any errors for the time to do any commands etc.

    • Edited by litdevModerator Thursday, August 21, 2014 7:34 PM
    • Marked as answer by Ezra94 Monday, August 25, 2014 11:16 PM
    Thursday, August 21, 2014 6:51 PM
    Moderator
  • Ezra94,

    For your criteria of counting down minutes and seconds. This works because the subroutine second gets checked many times. When there is a difference between the current second and the next second the counter is decremented. Each time 60 seconds passes the minute down counter is decremented.

    currentsecond=0
    seconddowncounter=60
    minutedowncounter=60
    While "True"
      If currentsecond <> NextSecond Then
        currentsecond = NextSecond
        seconddowncounter=seconddowncounter-1
        TextWindow.WriteLine(seconddowncounter)
        If seconddowncounter=0 then
          TextWindow.WriteLine("1 minute has passed")
          seconddowncounter=60
          minutedowncounter=minutedowncounter-1
          TextWindow.WriteLine(minutedowncounter)
          If minutedowncounter=0 then
            TextWindow.WriteLine("1 hour has passed")
            minutedowncounter=60
          endif
        endif
      endif
      Second()
    EndWhile
    
    Sub Second
      NextSecond=Clock.second
    EndSub 


    JR

    • Marked as answer by Ezra94 Monday, August 25, 2014 11:16 PM
    Thursday, August 21, 2014 7:35 PM
    Answerer

All replies

  • You are right, this program doesn't count down in seconds.

    Each time the loop is passed, sec is reduced by 0.01, therefore in 100 loops it counts down 1 sec.

    The time taken for 100 steps is at least 100*(15ms) = 1.5 sec and probably longer due to the time to do the actual drawing etc.

    So it takes at lease 75 sec to count down 50 sec?

    This keep better time:
    sec = 50
    time = Clock.ElapsedMilliseconds

    While sec >= 0  
      GraphicsWindow.BrushColor = "Blue"
      GraphicsWindow.FillRectangle(480, 0, 100, 25)
      GraphicsWindow.BrushColor = "White"
      GraphicsWindow.DrawText(482, 5, "Time:")
     
      If sec >= 10 Then
        GraphicsWindow.DrawText(530, 5,"00:" + Math.Floor(sec))
      Else
        GraphicsWindow.DrawText(530, 5,"00:0" + Math.Floor(sec))
      EndIf  
     
      time = time + 1000
      sec = sec-1
      Program.Delay(time - Clock.ElapsedMilliseconds)
    EndWhile

    Program.End()
    The reason this should keep good time is that time is updated by 1000 each pass through the loop, so everything is referenced back to the first time Clock.EllapsedMilliseconds was called and we don't have any errors for the time to do any commands etc.

    • Edited by litdevModerator Thursday, August 21, 2014 7:34 PM
    • Marked as answer by Ezra94 Monday, August 25, 2014 11:16 PM
    Thursday, August 21, 2014 6:51 PM
    Moderator
  • Ezra94,

    For your criteria of counting down minutes and seconds. This works because the subroutine second gets checked many times. When there is a difference between the current second and the next second the counter is decremented. Each time 60 seconds passes the minute down counter is decremented.

    currentsecond=0
    seconddowncounter=60
    minutedowncounter=60
    While "True"
      If currentsecond <> NextSecond Then
        currentsecond = NextSecond
        seconddowncounter=seconddowncounter-1
        TextWindow.WriteLine(seconddowncounter)
        If seconddowncounter=0 then
          TextWindow.WriteLine("1 minute has passed")
          seconddowncounter=60
          minutedowncounter=minutedowncounter-1
          TextWindow.WriteLine(minutedowncounter)
          If minutedowncounter=0 then
            TextWindow.WriteLine("1 hour has passed")
            minutedowncounter=60
          endif
        endif
      endif
      Second()
    EndWhile
    
    Sub Second
      NextSecond=Clock.second
    EndSub 


    JR

    • Marked as answer by Ezra94 Monday, August 25, 2014 11:16 PM
    Thursday, August 21, 2014 7:35 PM
    Answerer
  • Thank you for the code. Do you know why it's 75 secs and not the intended 50 secs? I derived this sample from a small game called "Hit the Right Shape" from curriculum 4.1. There were several shapes constantly moving and the player had to touch them. This leads my question: Does a game loop or even a program that has graphics and excessive information affect the nature and accuracy of a timer (or the program as a whole?)? If so, is there a pattern design that handles timers and graphics smoothly?

    As for timers in general, is program.Delay(1000) the key to making an accurate timer since 1000 milliseconds is equal to one second? How does Clock.ElapsedMilliseconds work exactly? I used TextWindow.WriteLine to find its value and got a long decimal. I'm not sure how this is related to Program.Delay(1000) (one second) exactly.

    Friday, August 22, 2014 2:55 PM
  • Thank you for the blue print. I'm going to make a graphics version of this. From what I read, you made the program keep track of the computer's clock then recorded one minute when 60 seconds passed. Is that correct?
    Friday, August 22, 2014 3:02 PM
  • it is 75 seconds because each time through the loop there is a delay of 15ms, but the time is recorded as 0.01 sec (10 ms), so for 50 sec recorded time (5000 times through the loop, since 50 = 0.01*5000), the actual delayed time is 75 seconds (0.015*5000).

    The accuracy of the Timer object is not affected by time spent in the program doing calculations or graphics etc.

    Both the version I and jricestk showed will also be accurate regardless of the time spent in the program.

    However if you do a delay of 1000ms you will get a delay of 1 sec + any time spend doing other things in your program loop.

    Friday, August 22, 2014 5:57 PM
    Moderator