Shop OBEX P1 Docs P2 Docs Learn Events
proj test_tc — Parallax Forums

proj test_tc

I took the Jon time_temp.py code and broke out the time tic stuff. The code below runs without errors. I added some comments, hopefully somebody will fill in some of the blank spots.

Trying to get a better handle on how the show_time() function is running at constant one second. I suppose adding some more code this could become a stop watch, but I digress. If this function keeps running at one second , the next step would be to add code the increase the m(minute) value, and start the s(second) back at zero, so on and so on. Not sure if I am going about this in the correct manner.

Ray

# test_tc.py
from microbit import *
import time

EVENT_MS = 1000  # Runs at 1 second

# Future reference
global h
h=0
global m
m=0
global s
s=0

# starts the tics
t_start = time.ticks_ms() 
runtime = 0

# This the time tics engine
def show_time(rt):
    rt = rt // 1000   # Not sure what this is doing                                  # convert to secs
    h = rt // 3600    #      ''                                   # extract hours
    rt = rt % 3600    #      ''                                    # remove hours
    m = rt // 60      #      ''                                      # extract minutes
    s = rt % 60       #      ''

# Show the time elapsing at the command line
    print("%.2d:%.2d:%.2d   " % (h, m, s))

# Starts the show_time engine
show_time(0)

while True:    # loop

    # Not exactly sure about this
    t_elapsed = time.ticks_ms() - t_start 
    if t_elapsed >= EVENT_MS:
        runtime += EVENT_MS
        show_time(runtime)  # This runs show_time @ 0

        t_start += EVENT_MS  # Time tics


Comments

  • JonnyMacJonnyMac Posts: 9,157
    edited 2024-01-02 01:07

    Not sure what this is doing

    The run time (rt) is in milliseconds. Dividing by 1000 converts that down to seconds. There 3600 seconds in one hour -- dividing rt (seconds) by 3600 gives hours. The modulus opeator (%s) gives us the remaining seconds. Dividing those by 60 returns minutes; taking the modulus of 60 are the final seconds.

    Note: Since h, m, and s are only used in the show_time() function they do not need to be declared as globals -- in fact, what you have now are two sets of variables with the same names. Python is different this way. If you really need a global variable you and need to modify it in a function, you need to specify that you're accessing the global, not a local. This is a function from a cosplay controller I wrote for a friend (@Harukofett on IG). The variable called state_timer is global I need to modify it in some functions.

    def do_flash1():
        """Alternate pixel between specified level and OFF."""
        global state_tmr
    
        state_tmr += 1
        if (state_tmr >= 200):                             # 200 x 10ms = 2s
            state_tmr = 0
    
        if (state_tmr < 100):                              # on 1s
            update_outs(brightness)
        else:                                              # off 1s
            update_outs(0)
    

    Not exactly sure about this
    t_elapsed = time.ticks_ms() - t_start

    t_elapsed is the time elapsed since the last marker. The marker is called t_start. Think of time.ticks_ms() as right now.

    Think of it this way: You mix up a batch of 5-minute epoxy and look at your watch. The time is 4:55 (we'll call this t_start). A while later you look at your watch again and it's 4:58. 4:58 (now) minus 4:55 (t_start) is three minutes, so you know you have a couple more minutes to work. Once five or more minutes have elapsed you have to mix a new batch and reset the start time.

    Since we don't have any delays between events, we can simply add the event duration to the initial t_start to update it.

    Once this technique sinks in it will seem very easy and you can create what looks like a multi-tasking system (that said, you have to make sure your tasks don't take a lot of time).

  • JonnyMacJonnyMac Posts: 9,157

    I have no idea why the first line of the quoted text is so large. @Wuerfel_21?

  • @JonnyMac said:
    I have no idea why the first line of the quoted text is so large. @Wuerfel_21?

    Because you're quoting code outside a codeblock and markdown turns # Something into <h1>Something</h1>

  • JonnyMacJonnyMac Posts: 9,157

    Thanks

  • Do note that control characters can always be bypassed using a backslash

    # Something

  • RsadeikaRsadeika Posts: 3,837

    Thanks Jon. "...and you can create what looks like a multi-tasking system..." I am going to try to separate and run the tics , temperature as separate items. That should give me an indication as to whether this concept is sinking in. Have to get my old brain working a little bit faster and better.

    Ray

  • RsadeikaRsadeika Posts: 3,837

    This my first attempt at running two tasks. It runs without errors, but the temp part values that are shown gets corrupted. Not sure how to slow the showing of the temp values down, it seems to run very quickly. Their must be a better way to do this, I am sure.

    Ray

    from microbit import *
    import time
    #
    EVENT_MS = 1000  # Runs at 1 second
    
    # starts the tics
    t_start = time.ticks_ms() 
    tic_runtime = 0
    temp_runtime = 0
    
    # Future reference
    global hh
    hh=0
    global mmm
    mm=0
    global ss
    ss=0
    
    def show_time(rt):
        global mm
        global hh
    
        rt = rt // 1000   # Not sure what this is doing                                  # convert to secs
        h = rt // 3600    #      ''                                   # extract hours
        rt = rt % 3600    #      ''                                    # remove hours
        m = rt // 60      #      ''                                      # extract minutes
        s = rt % 60       #      ''
    
        if s == 60:
           mm = m + 1
        if m >= 59:
            hh = h + 1
    # Show the time elapsing at the command line
        print("%.2d:%.2d:%.2d   " % (hh, mm, s))
    
    def show_temp(tt):
        temp = (temperature() * 9 / 5 + 32.0)-4.5
        temp_string=str(round(temp,1))+"F"
        display.show(temp_string,delay=450,wait=False)
    
    # Starts the show_time engine
    show_time(0)
    show_temp(0)
    
    while True:    # loop
        #show_temp()
        # Not exactly sure about this
        t_elapsed = time.ticks_ms() - t_start 
        if t_elapsed >= EVENT_MS:
            tic_runtime += EVENT_MS        
            show_time(tic_runtime)  # This runs show_time @ 0              
            t_start += EVENT_MS  # Time tics
    
        if t_elapsed >= EVENT_MS:     
            tic_runtime += EVENT_MS 
            show_temp(temp_runtime)  # This runs show_temp
            t_start += EVENT_MS  # Time tics
    
    
    
  • JonnyMacJonnyMac Posts: 9,157
    edited 2024-01-02 17:16

    You're trying to handle two different events from the same task timer variable. Even if they run at the same rate, you should have a separate timer variable for each task.

    I think this does what you want. Note that even though the display.show() function runs in the background, if you call it before it's finished it will restart.

    Update: I made it a little fancier by alternating between F and C.

    from microbit import *
    import time
    
    RTC_MS = 1000                                          # update rtc every 1s
    TMP_MS = 5000                                          # display temp every 5s
    
    t_rtc = time.ticks_ms()
    t_tmp = time.ticks_ms()
    
    rtcsecs = 0
    tmpmode = 0
    
    
    def show_time(s):
      h = s // 3600
      s = s % 3600
      m = s // 60
      s = s % 60
    
      print("%.2d:%.2d:%.2d" % (h, m, s))
    
    
    def show_tempf():
        global tmpmode
    
        tmpmode += 1
        if tmpmode % 2:
            ts = str(round(temperature() * 9 / 5 + 32.0)) + "F "
        else:
            ts = str(round(temperature())) + "C "
        display.show(ts, delay=500, wait=False)
    
    
    show_time(0)
    show_tempf()
    
    while True:
        now = time.ticks_ms()
    
        if now - t_rtc >= RTC_MS:
            rtcsecs += 1
            show_time(rtcsecs)
            t_rtc = now
    
        if now - t_tmp >= TMP_MS:
            show_tempf()
            t_tmp = now
    
  • RsadeikaRsadeika Posts: 3,837

    Thanks Jon. Now, I think I am starting to catch on. I wonder how many tasks can be run this way before the system starts to bog down. Is their a microbit command that shows how much memory is being used on the microbit. Now I will try to add the start/stop of tasks, then add the listdir and system commands. Still not sure how I will handle the delete file command.

    Ray

  • JonnyMacJonnyMac Posts: 9,157
    edited 2024-01-02 18:54

    I wonder how many tasks can be run this way before the system starts to bog down.

    It will depend on how many tasks are running and how long they take. For my friend's cosplay controller I tried to use a 5ms time base but looking at a free output on a 'scope I found there was a lot of wobble (because some tasks states took a little too long). I bumped it up to 10ms (which is easier to deal with mentally, anyway) and all was fine. In her case the project is monitoring, debouncing, and auto-repeating three buttons (I created a simple class for that) and running the current state of the program which can be LED on, LED flashing (two different modes), or fading the LED on and off (which is why my time base needs to be short).

    Micropython has a timer class built in, but I'm not sure how it's implemented on the micro:bit. This is why I still favor Spin1 and Spin2 above all other embedded languages: nothing is hidden "under the hood." That said, I can't run Spin on an RP2040 which is what my friend wants to use in her cosplays. Python (which mechanically inspired Spin) is closest.

  • RsadeikaRsadeika Posts: 3,837

    This is my latest attempt. Almost everything works. I added an ontime, offtime and showtime commands. What I am trying to do is start the time with ontime, in the background, and then use showtime to show the current time. For some reason I cannot get this to work correctly. I got the temp to work fine.

    Ray

    # mc_mb_test.py
    #
    from microbit import *
    import time, sys, os
    from time import sleep
    
    RTC_MS = 1000                                          # update rtc every 1s
    TMP_MS = 5000
    
    t_rtc = time.ticks_ms()
    t_tmp = time.ticks_ms()
    
    rtcsecs = 0
    tmpmode = 0
    
    tics = 0
    temp = 0
    
    
    uart.init(115200)
    
    def menu():
        print("       System Menu")
        print("quit - End the program.")
        print("dir - System directory.")
        print("system - System information.")
        print("ontemp - Show the temperature.")
        print("offtemp - Turn off the temperature.")
        print("delfile - Delete a file, to be developed.")
    
    def listDir():
        x=os.listdir()
        print(x)
        uart.write("\n>>>")
    
    def uname():
        y=os.uname()
        print(y)
        uart.write("\n>>>")
    
    def del_file():
        print("Code to be developed")
        uart.write("\n>>>")
    
    def show_time(s):
        global h
        global m
        #global s
        h = s // 3600
        s = s % 3600
        m = s // 60
        s = s % 60
    
      #print("%.2d:%.2d:%.2d" % (h, m, s))
    
    def showtime():
        global h
        global m
        global s
        print("%.2d:%.2d:%.2d" % (h, m, s)) 
    
    def show_tempf():
        global tmpmode
    
        tmpmode += 1
        if tmpmode % 2:
            ts = str(round(temperature() * 9 / 5 + 32.0)-4.5) + "F "
    
        else:
            ts = str(round(temperature())) + "C "
    
        display.show(ts, delay=700, wait=False)
    
    
    
    uart.write("Type help for system menu.\n>>>")
    menu()
    uart.write("\n>>>")
    
    
    while True:
        inbuff=""
        if uart.any():
            inbuff=uart.read().strip().decode()
            if inbuff == "quit":
                print("sys_dir program has ended.")
                sys.exit()
    
            elif inbuff == "help":
                menu()
            elif inbuff == "dir":
                listDir()
            elif inbuff == "system":
                uname()
            elif inbuff == "ontemp":
                temp=1
                uart.write("\n>>>")
            elif inbuff == "offtemp":
                temp=0
                uart.write("\n>>>")
            elif inbuff == "delfile":
                del_file()
            elif inbuff == "ontime":
                tics=1
                uart.write("\n>>>")
            elif inbuff == "offtime":
                tics=0
                uart.write("\n>>>")
            elif inbuff == "showtime":
                showtime()
                uart.write("\n>>>")
            else:
                uart.write("not an option")
                uart.write("\n>>>")    
    
    
        now = time.ticks_ms()
        # Not implemented yet, not sure what I will do.
        #if tics == 1:
        if tics == 1 and now - t_rtc >= RTC_MS:
            rtcsecs += 1
            show_time(rtcsecs)
            t_rtc = now
        if tics == 0 and now - t_rtc >= RTC_MS:
            display.clear()
    
        # This works, not sure it it can be improved.
        if temp == 1 and now - t_tmp >= TMP_MS:
            show_tempf()
            t_tmp = now
        if temp == 0 and now - t_tmp >= TMP_MS :
            display.clear()
    
        sleep(0.5)
    
    
  • the os Module contains 3 file functions "listdir()", "remove(filename)" and "size(filename)". If the file does not exist an OSError will occur.

    link: https://microbit-micropython.readthedocs.io/en/v1.0.1/os.html

    Remove will delete the file "filename"

    def del_file(filename):
        try:
            os.remove(filename)
            uart.write("\n>>>")
        except:
            print("something went wrong")
    
    del_file("my.csv")
    

    There is a small app called MicroFS that copies a file from the device or writes a local file to the microbit, I'm not sure if it will be of use to you or just muddy the waters. If you don't think you need it at this time make sure to keep a bookmark for later it's a neat little utility.

    link: https://microfs.readthedocs.io/en/latest/_modules/microfs.html

  • RsadeikaRsadeika Posts: 3,837

    Thanks Unsoundcode. I have the readthedocs pdf, at some point I will print out a paper copy. I am old school, stuff like that I like to read a paper copy.

    For the tasking stuff how do I no that the task has actually stopped (quit). I know for the offtemp, the task stops showing, so theoretically the task has quit. Now, when I get the ontime to work, that will be running in the background all the time. When I select offtime, how do I stop(quit) the task.

    When I get the bugs worked out for the softRTC, I will start looking into the logging task, that should be interesting.

    Ray

Sign In or Register to comment.