Shop OBEX P1 Docs P2 Docs Learn Events
Accurate measurment of long time intervals — Parallax Forums

Accurate measurment of long time intervals

DylanBDylanB Posts: 24
edited 2006-03-15 18:41 in BASIC Stamp
Hi,

We are designing a fraction collector (automated collection of effluent from soil columns) which is based around a BS2 and serial stepper motor controller. A simple outline of how the device is supposed to work is as follows:

1. init motor controller

main:
2. poll for user input (4 buttons)
3. display contents of timing variables (time between cycling a collection vessel) on serial LCD

4. if the user has pushed the 'start' key, start counting out time intervals specified in the program, and optionally modified by buttons.
5. check elapsed time, and rotate fraction collector carriage a single step.

goto main

The main problem is that while counting out time (with PAUSE or SLEEP) the BS2 can't really do anything else, and we would want to constantly be polling for user input on some buttons, and updating the LCD.

I have taken a look at the "pocket watch b" module, and wonder if polling this device in every loop of the main subroutine might work for couting out long time intervals (10mins to 2 hours)...?

Note that the single motor controller will be used to address 3 stepper motors, thus three timing variables will be used to decide when it is time to rotate the fraction collector carriage.

Any thoughts or ideas would be appreciated!

Cheers,

Dylan
«1

Comments

  • Jon WilliamsJon Williams Posts: 6,491
    edited 2006-02-08 16:34
    Use an RTC chip with the project; this will be useful for real-time and for durations (you'll to time-based math). The DS1302 is easy to connect to the BS2 and we have plenty of code examples for it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Jon Williams
    Applications Engineer, Parallax
  • Vern GranerVern Graner Posts: 337
    edited 2006-02-08 18:00
    DylanB said...
    The main problem is that while counting out time (with PAUSE or SLEEP) the BS2 can't really do anything else, and we would want to constantly be polling for user input on some buttons, and updating the LCD.
    Don't know if this will be helpful, but I've used the Pocket Watch B and have set an "alarm time" on the unit. Then, you can make a "DO WHILE" loop contingent on the state of the alarm pin, when that pin state changes you know that the pre-set time has elapsed.

    Another method I've seen used is to "roll your own" pause command by creating a subroutine and then placing the polled item in a loop. So instead of placing a "pause 100" command in the middle of your program, set a variable and call a loop with the sensor check and a pause together. Here's some pseudo-code to (poorly) demonstrate what I'm getting at:

    cntI    VAR Byte     ' Counter
    DELAY   VAR Byte     ' number of miliseconds to wait
    MOTOR   PIN 1        ' Pin where motor is connected
    SENSOR  PIN 2        ' pin where sensor is connected
    
    'Main Code
    :AGAIN
      HIGH MOTOR
      DELAY=100
      GOSUB WorkingPause
      GOTO AGAIN
    
    'Subroutine for a "Working" pause
    WorkingPause:
     FOR cntI=1 TO DELAY
      IF SENSOR=1 THEN RETURN
      PAUSE 1
     NEXT
    LOW MOTOR
    RETURN
    
    


    The idea is to make the sensing or "work" portion of the code "interleaved" with the pause statement so instead of a "Pause 100" use a "pause 1 and Check Sensor" in a 100 count loop and call the loop instead using a "pause" command.... Not really elegant, but it can avoid having the stamp "sleeping" when it could be doing work... smile.gif

    Vern

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Vern Graner CNE/CNA/SSE    | "If the network is down, then you're
    Senior Systems Engineer    | obviously incompetent so why are we
    Texas Information Services | paying you? Of course,if the network
    http://www.txis.com        | is up, then we obviously don't need
    Austin Office 512 328-8947 | you, so why are we paying you?" ©VLG
    
    

    Post Edited (Vern) : 2/8/2006 6:07:41 PM GMT
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-08 18:10
    Attached is an example of waiting for 15 minutes using a DS1302.· The test runs within a loop which could easily be doing other tasks while waiting.· Once 15 minutes has elapsed the program ends, but could just as easily do something else.· The code starts by resetting the minutes and seconds to 00:00 and counting up.· The minutes/seconds could be reset at the end of any interval.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-09 03:13
    Thanks you to everyone who responded to my question- it looks like the RTC will do the trick. Now to complicate matters.

    This device will be running 3 motors (fraction collector carriages) simultaneously. The time interval in between "steps" in each of the motor assemblies will often be different. For example the delta-time (dt) for the three motors might look something like the following:

    motor  dt
        1       5 minutes
        2       8 minutes
        3      20 minutes
    
    



    Ideally, we need to trust that the accuracy of the dt for each motor is about +- 1 second for time intervals < a couple of minutes.

    My initial plan on how to accomplish this goes something like this

    dt1 = 5 minutes
    dt2 = 8 minutes
    dt3 = 20 minutes
    
    
    start_clock()
    
    loop:
       poll_keys()
       update_lcd()
       dt = check_dt_from_start()
    
       if(dt >= dt1)
         advance_motor_1
       if(dt >= dt2)
         advance_motor_2
       if(dt >= dt3)
         advance_motor_3
    
    goto loop
    
    



    ...and use some method of either reseting the clock at a certain point, or using the MOD operator to get an integral number of times that a motor_increment time interval has elapsed.

    I am worried that it will be hard to maintain an accurate tracking of real time and the time at which commands are run by the basic stamp--- but given the speed of the BS2, should I be?

    Thanks again,

    Dylan
  • Kevin WoodKevin Wood Posts: 1,266
    edited 2006-02-09 04:01
    You could always use a seperate DS1302 for each motor. I think this would be easier to keep track of the timing, since you could reset each clock after the motor advances, and wouldn't have to get code-happy with the timing math. Just keep polling the inputs and clocks as needed.

    Also, because of the timing intervals, you might want to stagger the initial motor starts by a minute or so. Otherwise, I think worst case scenario would be all three motors conflicting every 40 minutes or so.
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-09 04:56
    I think one DS1302 will work fine just as I implemented the sample source...I am just not clear on the exact order of events.· It's easy enough to compare multiple variables and switch inputs on/off based on that data.· If you can describe in more detail what you're trying to do, I may be able to quickly modify that routine to do it as it stands (one DS1302).· For example:

    Motor 1 comes on after 5 minutes, then Motor 2 comes on after 8 minutes, Motor 3 comes on after 20 minutes.· If there is a shut down time for each, it too can easily be implemented.· Some time ago I built a Digital Thermostat with multiple schedules for events.· It wasn't limited like the ones you buy at Wal-Mart.· You could input several on/off times for each event on different days.· This applies here as well.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-09 07:19
    Thanks for the quick reply Chris.

    Here is a little bit more info on the project. We have 3 stepper motors, each attached to a circular test tube rack. A single test tube is positioned under a soil column, and effluent is collected in the test tube. Based on the nature of the soil, and thus the rate of effluent discharge, the test tube rack under the soil column must be advanced 1 test tube every time interval. this time interval can be specified in the program sent to the BS2 (based on some initial guesses), and then later adjusted up or down with some buttons connected to the BS2. Since the three soils are not quite the same, the time interval between advancing the test tube rack for each setup may be different.

    Therefore, once the device has been started, motor1 will need to be advaced every dt1 interval, motor 2 will need to be advanced every dt2 intervatl, and motor 3 will need to be advanced every dt3 interval.

    a simplified flowchart might look like this:

    1. init motor controller
    
    dt1 = 10minutes
    dt2 = 15minutes
    dt3 = 30minutes
    
    main loop:
    2. update an LCD 
    3. poll buttons for adjustments to time intervals
    4. when start button is pressed, start timer and enter running loop
    
    running loop:
    5. poll for adjustements to dt values
    6. update LCD 
    
    check elapsed time
    
    if elapsed time since last activation of motor1 >= dt1
       advance motor 1
    if elapsed time since last activation of motor1 >= dt2
       advance motor 2
    if elapsed time since last activation of motor3 >= dt3
       advance motor 3
    
    goto running loop
    
    
    



    advancing the motors is accomplished by sending some serial data to a motor controller, which addresses each motor.

    My thoughts on using a single clock: it would be more elegant if we can do it this way, but i am worried about losing precision due to integer math on time durations- but maybe this is not an issue. It sounds like the smallest time interval that we need is 1 minute.

    thanks again,

    Dylan
  • DylanBDylanB Posts: 24
    edited 2006-02-09 07:23
    Also- the BS2 is only sending a motor "advance" command to the motor controller -- i.e. tell the motor to move to position 2000 at speed x at acceleration y -- the motor controller then figures out the hard stuff, and turns off the motor when it has reached position 2000

    dyan
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-09 15:27
    Dylan,

    ·· Because you are only using minutes you should be able to use a single DS1302.· You could even further simplify the whole thing by converting ALL time (hrs, mins, secs) to just minutes.· There are 1440 minutes in a single day and the code to handle a roll-over is easy although in your application I'm not sure it would apply.·

    ·· Now, for simplicity, if you DO want to use three DS1302 chips you can share the clock/data lines so that three DS1302 chips will take up 5 I/O pins.· You can use the same constants for clock and data simplifying the control of the chip.· This would be very easy to implement.·

    ·· This also makes more sense if you need to be able to adjust your interval on the fly, so to speak.· Each DS1302 has RAM which is backed-up with the time when using a backup battery.· You could store interval values on there and retrieve them at startup.· When they're changed you could update the value on the chip.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-13 01:34
    Chris,

    Thank you for the helpful hints. We ordered 3 DS1302 units + crystals. The sample code for interfacing to a single RTC seems like it will be a good starting point. Which inputs/outputs can be shared between all three RTC units? Is there any sample code for this floating around somewhere perhaps... ?

    Thanks!

    Dylan
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-13 04:43
    Dylan,

    ·· As in my previous post you can share the clock and data lines.· Each chip will need it's own chip select (RST) line so you're looking at using 5 I/O lines total in DS1302s.· Once you have the chips, get one working and I will show you an example of using more than one.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-26 00:09
    Chris,

    Your code and hints have been most helpful!

    We were successful in implementing the 3 independent DS1302 chips, using only 5 I/O lines as you suggested.

    Now we have a new bug to squash... When the three clocks are started at the same time... well almost the same time with a FOR loop:

    FOR idx = 0 TO 2
        mins(idx) = $00
        secs(idx) = $00
        GOSUB Set_Time
    NEXT
    
    Set_Time:                               ' DS1302 Burst Write
        HIGH rtc(idx)                           ' Select DS1302
        SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]WrBurst]
        SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]secs(idx), mins(idx), hrs(idx),date, month, day, year, 0]
        LOW rtc(idx)                            ' Deselect DS1302
    RETURN
    
    



    ... the clocks appear to stay in sync:

    'get the time by updating our time variables
    GOSUB Get_Time
    
    'update the clock display on the LCD
    SEROUT LCD_serial_pin,LCD_serial_setup,[noparse][[/noparse]254,71,1,1, " ", HEX2 mins(0), ":", HEX2 secs(0), " ", HEX2 mins(1), ":", HEX2 secs(1), " " , HEX2 mins(2), ":", HEX2 secs(2), " "]
    
    Get_Time:
        FOR idx = 0 TO 2                               ' DS1302 Burst Read
            HIGH rtc(idx)                           ' Select DS1302
            SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]RdBurst]
            SHIFTIN DataIO, Clock, LSBPRE, [noparse][[/noparse]secs(idx), mins(idx), hrs(idx), date, month, day, year]
            LOW rtc(idx)                            ' Deselect DS1302
        NEXT
    RETURN    
    
    
    



    ...however, we are resetting individual clock units when a specific delta-time has elapsed

    
    'reset clock 2
    idx=2
    mins(idx) = $00
    secs(idx) = $00
    GOSUB Set_Time
    
    Set_Time:                               ' DS1302 Burst Write
        HIGH rtc(idx)                           ' Select DS1302
        SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]WrBurst]
        SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]secs(idx), mins(idx), hrs(idx),date, month, day, year, 0]
        LOW rtc(idx)                            ' Deselect DS1302
    RETURN
    
    




    I have noticed that each time i reset a clock, it loses a small amount of time relative to other clocks that are still running. - possibly due to the fact that resetting a clack takes a small amount of time.

    i am wondering if there is perhaps a more efficient way of accomplishing this task, i.e. some math that can be done to determine if a delta-time unit has elapsed, without having to reset the clock units.

    attached is a complete listing of the program

    Thanks!

    Dylan
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-26 02:18
    Dylan,

    ·· How is it that you mean the clock is out of sync with the others?· If you could better explain that I would know what I am looking for.· Also, understanding your need to read 3 clocks at the same time I might recommend forgoing a little code space and actually directly SHIFTOUT/SHIFTIN the data in that routine instead of using a FOR...NEXT loop.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-26 02:55
    Chris,

    Starting all clocks at 00:00.

    if i reset:
    clock 0 every 15 sec
    clock 1 every 30 sec
    clock 2 every 45 sec

    ...then clock 0 will lag behind clock 1 which will lag behind clock 2.

    i.e. near 15 seconds this is what the clocks should read
    00:14 00:14 00:14
    00:00 00:00 00:30

    and they do.

    i.e. near 30 seconds this is what the clocks should read
    00:14 00:29 00:29
    00:00 00:00 00:30

    and they do.

    i.e. near 45 seconds this is what the clocks should read
    00:14 00:14 00:44
    00:00 00:15 00:00

    and they almost do: clock 0 appears to increment _just after_ clock 1 and 2

    i.e. near 60 seconds this is what the clocks should read
    00:14 00:29 00:14
    00:00 00:00 00:15

    and they almost do: clock 0 appears to increment _slightly after_ clock 1 and 2

    i.e. after 75 seconds this is what the clocks should read
    00:14 00:14 00:29
    00:00 00:15 00:30

    and they almost do: clock 0 appears to increment _slightly after_ clock 1 and 2

    i.e. after 90 seconds this is what the clocks should read
    00:14 00:29 00:44
    00:00 00:00 00:00

    and they almost do: clock 0 appears to increment _slightly after_ clock 1 and 2

    .... and so on. the longer i let it run, the more "behind" clock 0 and then clock 1 become relative to clock 2 .

    in summary, after a total time duration of 100 minutes = 6000 seconds, the clocks have been reset:
    clock 0: 400 times
    clock 1: 200 times
    clock 2: 133 times

    seems that every clock reset operation makes each one of these three clocks slightly slower than an outside time source, porportional to the number of reset operations.
    I wonder if there is some way to compensate for this...

    As far as savinf some space goes. How exactly would I implement a single SHIFTIN operation such that it read in data from each clock ?

    Thanks!

    Dylan
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-26 03:16
    Dylan,

    ·· Do you have a measurement of how far off they are and at what interval?· If so, instead of loading them with $00 each time you could maybe load seconds with $01 or something to compensate for lost time.· I wonder if the problem could be when the other operations are happening before you reset the clock.

    ·· Okay, I see one thing that could slow it down a little...When the clock reaches its trip point you should be resetting it immediately, but instead you gosub to the mx routine and SEROUT and DEBUG first.· That will cost a little time.· Remember, the clock will keep going once reset so you can do that other stuff right afterward.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2006-02-26 20:38
    Yes, resetting these clocks does rezero the internal counter for fractions of seconds.

    I agree with the earlier posts about using only one single clock chip. Then you read the time and convert to a sequential time of the proper granularity. For exmple minutes of day from 0 to1439:
    minOfDay = hours.nib1 * 10 + hours.nib0 * 6 + minutes.nib1 * 10 + minutes.nib0

    Then the different event timings are a matter of period and phase:
    motor1flag = minOfDay +1440 + phase1 // period1 max 1 ' = 0 when it is time to advance motor 1, =1 otherwise
    motor2flag = minOfDay +1440 + phase2 // period2 max 1 ' = 0 when it is time to advance motor 1, = 1 otherwise
    etc.

    1440 is added to the minute of day so that it will work properly over the midnight boundary. The phase is a number from 0 to (period-1), to allow for the start times to be offset from an integer multiple of the period with respect to real time.

    The granularity could be taken down to 5 seconds and stil fit in one word variable.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • DylanBDylanB Posts: 24
    edited 2006-02-27 20:05
    Tracy,

    Thank you for the tips. Programming in the PBASIC environment is still a bit new to me- especially after spending most of my time using scripting languages like AWK and PHP.

    I don't quite follow the logic of how your example code would work.

    For example, my delta-time value for motor 1 (dt_1) is equal to 10 minutes. I would like to run a subroutine every dt_1 minutes.

    Looking at your example:
     minOfDay = hours.nib1 * 10 + hours.nib0 * 6 + minutes.nib1 * 10 + minutes.nib0
     motor1flag = minOfDay +1440 + phase1 // period1 max 1 ' = 0 when it is time to advance motor 1, =1 otherwise
    
    



    It looks like I would implement this such that:
    'turn on device
    ' set the time to 00:00:00 with 
    gosub init_rtc
    
    'setup some dt values
    
    dt_1 = 10  'minutes
    dt_2 = 12  'minutes
    dt_3 = 15  'minutes
    
    'main loop
    
    main:
    'get the minute of the day - since last reset
    minOfDay = hours.nib1 * 10 + hours.nib0 * 6 + minutes.nib1 * 10 + minutes.nib0
    
    'set a flag for motor 1 based on my preset dt value
    motor1flag = minOfDay +1440 + phase1 // period1 max 1 
    motor2flag = minOfDay +1440 + phase2 // period2 max 1 
    motor3flag = minOfDay +1440 + phase3 // period3 max 1 
    
    'based on each motor flag do stuff
    gosub do_stuff
    
    goto main
    
    
    



    However, I am not quite sure what the variables: phase1 and period1 "mean" ....

    As for the granularity of this project, I think that a single minute would be good enough- as long as it is consistant.

    Thanks!
  • DylanBDylanB Posts: 24
    edited 2006-02-27 20:06
    Just for the record, this forum has been a great help to this project! I will post some pictures of the _nearly_ complete setup later this afternoon.

    Dylan
  • DylanBDylanB Posts: 24
    edited 2006-02-27 21:01
    here is a link to some pictures to describe the device that this thread was started for:
    http://169.237.35.250/~dylan/fraction_collector/

    Cheers,
  • Tracy AllenTracy Allen Posts: 6,658
    edited 2006-02-27 22:41
    Hi Dyan,

    Nice project!

    For the math, the first thing need to know is the "//" operator. In Stampese, that means, "remainder after division". In my example, period1 is equivalent to your dt_1, that is, how often you want the motor to turn on.

    in this code

    motor1flag = minOfDay // 10 MAX 1
    motor2flag = minOfDay // 12 MAX 1
    motor3flag = minOfDay // 15 MAX 1
    



    the three independent flags will equal zero once every 10, 12 and 15 minutes respectively, and 1 at all other times. That is because minOfDay // period is the remainder of the divisions, e.g.,
    29 // 15 = 14
    30 // 15 = 0
    31 // 15 = 1
    32 // 15 = 2

    The MAX operator restricts the value to either zero or 1.

    The actions as written occur exactly matched with clock time. That is, with 10 minutes it would happen on the hour, 10 minutes after the hour, and so on, and with 12 minutes, it would also be on the hour, 12 minutes after the hour and so on. That might be what you want.

    However, if you want an arbitrary origin for starting each interval, then you need phase1, phase2, phase3. Say you want to start a 10 minute interval for motor 1 at 7 minutes after the hour of 2am. The value of minOfDay at that time is 127, and the remainder when divided by 10 is 7. Set phase1 equal to that value. Subsequently, the motor1flag will equal zero at 137, 147, 157,...
    motor1flag = minOfDay + 7 // 10
    which you would use with variables instead of constants for 7 and 10. The phase1=7 is the starting phase with respect to the 10 minute cycle.

    If you restrict your time intervals to numbers that evenly divide 1440 minutes, then that is all you need. You don't even have to add the extra 1440 I showed in my example. Those numbers that divide evenly into 1440 are,
    1,2,3,4,5,6,8,10,12,15,18,20,24,30,32,45,60,... and others.

    If you need to use numbers like 13 that do not divide evenly into 1440, then the system will have to do an extra bit of calculation as the clock rolls back at midnight. It is a simple operation to adjust the phase with respect to clock time. Otherwise you would have a glitch at midnight and a motor would run too short or to long. Let me know if you need help with code to do that.

    The advantage of this approach is that you can use a single RTC, and you let it run, without the subsecond error of resetting it.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Tracy Allen
    www.emesystems.com
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-27 23:57
    Dylan,

    ·· However you solve this minor issue, once it is done you should definately post it in the Projects Section with a few of the pictures.· You've done some nice work there and I see the StampCI Board in the mix as well.· =)

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-28 00:49
    Tracy,

    thanks for the great explanation -- I am starting to get a handle on your examples now.

    After talking with the person who is actually going to be using this system, it sounds like she would like to have control over the starting time, and dt values for each of the motors independently: i.e. setup motor 1 and start it .... a little later setup motor 2 and then start it . In this way the absolute starting time of any one motor will most likely not be the same for the other 2. However, i have three RTC units in place, so perhaps a slight modification to your example might do the trick:

    'for any given motor
    'wait for motor to be activated via button press
     'then
        'wait for start command
          'then
            'set timer 1 to 00:00:00 and proceed incrementing motor 1
            
            'this might have to be adjusted to account for total run times of > 24 hours        
            motor1flag = minOfDay +1440 + phase1 // period1 max 1 
    
    
    
    



    I will start a new thread for the couple questions I have regarding that aspect of the project.

    A couple notes:
    an RTC will be started from 00:00:00 when a motor is "enabled" . We will need to be able to set the dt value for this motor in arbitrary amounts of minutes, probably in the range of 1-300 minutes . At the maxmum dt of 300 minutes * 30 test tubes, this would be 6.25 days. While I doubt that we would actually run a single sample for that long, i think that building in support for total time durations of >24 hours would be a good idea (just in case). might need some pointers on this aspect.

    Thanks,

    Dylan
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-28 01:47
    Dylan,

    ·· A tip on working with the days of the week...The defauly value is 0, but the valid days are 1 through 7.· Obviously the other values are literal, but the days thing had me confused for a while when I first started using this chip.· I guess the main question is, does the unit always work in full minutes or is there a time when you will want to go for xx minutes and xx seconds?

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-28 02:45
    Chris,

    I imagine that this device will only operate in increments of minutes-- i.e. we need second-leve precision, but only minute-level time step intervals.

    thanks,

    Dylan
  • DylanBDylanB Posts: 24
    edited 2006-02-28 03:17
    Chris, about the DS1302 : is it required that the time values be specified in HEX ? any pointers on this?

    thanks,

    Dylan
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-28 05:05
    Dylan,

    ·· The reason you use HEX is because the values are in BCD within the DS1302.· That means there are 2 digits packed into a single byte.· When you specify a 2 digit decimal value it will often not equal the BCD value.· HEX formatting is as close as you're going to get as long as each digit doesn't exceed 9.· For example, $99 is the largest BCD value while $FF is the largest HEX value, otherwise the packed format is similar.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-28 05:08
    Chris and Tracy:

    ok, i have done some more work-- and it almost works!

    here is a code snippet
      DO
        'get 4 button's status
        GOSUB Get_Buttons
    
        'get the time by updating our time variables
        GOSUB Get_Time
    
        'get the number of minutes since start from each clock
        minOfDay(0) = hrs.NIB1(0) * 10 + hrs.NIB0(0) * 6 + mins.NIB1(0) * 10 + mins.NIB0(0)
        minOfDay(1) = hrs.NIB1(1) * 10 + hrs.NIB0(1) * 6 + mins.NIB1(1) * 10 + mins.NIB0(1)
        minOfDay(2) = hrs.NIB1(2) * 10 + hrs.NIB0(2) * 6 + mins.NIB1(2) * 10 + mins.NIB0(2)
        
        'should we increment any motor ?
        motor_flag(0) = minOfDay(0) + 1440 + 0 // dt(0) MAX 1 ' = 0 when it is time to advance motor 1, =1 otherwise
        motor_flag(1) = minOfDay(1) + 1440 + 0 // dt(1) MAX 1 ' = 0 when it is time to advance motor 1, =1 otherwise
        motor_flag(2) = minOfDay(2) + 1440 + 0 // dt(2) MAX 1 ' = 0 when it is time to advance motor 1, =1 otherwise
    
        'update the clock display on the LCD
         SEROUT LCD_serial_pin,LCD_serial_setup,[noparse][[/noparse]254,71,1,1, "[noparse][[/noparse]m", DEC motor_select, "][noparse][[/noparse]", BIN1 motor_enable(motor_select),"]  ", DEC tube_num(0), "  ", DEC tube_num(1), "  ", DEC tube_num(2)]
        
       [b] 'NOT QUITE RIGHT.... each of the motor increment expressions evaluates to TRUE about 5 times per loop![/b]
        'check: motor enabled? motor flag = 0?  seconds = 00? 0th minOfDay != 0?  
        IF motor_enable(0) = 1 AND motor_flag(0) = 0 AND secs(0) = $00 AND  minOfDay(0) <> 0 THEN GOSUB m0
        IF motor_enable(1) = 1 AND motor_flag(1) = 0 AND secs(1) = $00 AND  minOfDay(1) <> 0 THEN GOSUB m1
        IF motor_enable(2) = 1 AND motor_flag(2) = 0 AND secs(2) = $00 AND  minOfDay(2) <> 0 THEN GOSUB m2
    
        'update the LCD
        GOSUB Update_LCD
    
      LOOP
    
    m0:
      motor_flag(0) = 1                                               [b] ' we are incrementing motor 0, now leave it alone for the rest of this minute![/b]
      idx=0                                                                  'we are working with motor 0
      tube_num(idx) = tube_num(idx) + 1                      'increment test tube index
      SEROUT motor_ctl_rx,84,[noparse][[/noparse]"1b0="]                         'reset internal counter to 0
      SEROUT motor_ctl_rx,84,[noparse][[/noparse]"1b500p1000r1919g"]     'move motor to position 1919, 500steps/sec/sec accel, 1000 steps/sec velocity
    RETURN
    
    Get_Time:
      FOR idx = 0 TO 2                               ' DS1302 Burst Read
        HIGH rtc(idx)                           ' Select DS1302
        SHIFTOUT DataIO, Clock, LSBFIRST, [noparse][[/noparse]RdBurst]
       ' SHIFTIN DataIO, Clock, LSBPRE, [noparse][[/noparse]secs(idx), mins(idx), hrs(idx), date, month, day, year]
        SHIFTIN DataIO, Clock, LSBPRE, [noparse][[/noparse]secs(idx), mins(idx), hrs(idx)]
        LOW rtc(idx)                            ' Deselect DS1302
      NEXT
    RETURN
    
    Get_Buttons:
      Btns = %1111                                  ' enable all four inputs
      FOR BtnIdx = 1 TO 5
        Btns = Btns & ~BtnBus                       ' test inputs
        'PAUSE 5                                     ' delay between tests
      NEXT
    
      'check for a mode switch  (switch 0)
      IF Btns.BIT0 = 1 THEN
        motor_select = motor_select + 1 // 3      ' update motor_select    constrain  to 0-2
        GOSUB Update_LCD
      ENDIF
    
     'check for an increase in dt (switch 1)
      IF Btns.BIT1 = 1 THEN
       dt(motor_select) = dt(motor_select) + 1
       GOSUB Update_LCD
      ENDIF
    
     'check for a decrease in dt (switch 2)
      IF Btns.BIT2 = 1 THEN
       dt(motor_select) = dt(motor_select) - 1
       GOSUB Update_LCD
      ENDIF
    
     'check for motor enable/disable  (switch 3)
      IF Btns.BIT3 = 1 THEN
        motor_enable(motor_select) = motor_enable(motor_select) + 1 // 2  'constrain to 0-1
        GOSUB Update_LCD
        'start the clock for this motor
        idx = motor_select
        GOSUB Set_Time
    
      ENDIF
    
    RETURN
    
    
    




    however, the part of the loop which checks to see if we should increment a motor evaluates to TRUE about 5 times per loop in which motorflag = 0 .... i think that this is due to the fact that this loop is running about 5 times per second -- thus there are 5 loops where the follwoing expression is TRUE:
    motor_enable(0) = 1 AND motor_flag(0) = 0 AND secs(0) = $00 AND  minOfDay(0) <> 0
    
    



    Any thoughts on how to only run the motor advance routines *once* per TRUE evaluation of the about code?

    Thanks -- we are almost there...

    Dylan
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-28 05:19
    Dylan,

    ·· It's easier to deal with code as an attachment...That way it can be loaded into the editor and viewed properly.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
  • DylanBDylanB Posts: 24
    edited 2006-02-28 05:27
    Got it, here is the code!
  • Chris SavageChris Savage Parallax Engineering Posts: 14,406
    edited 2006-02-28 05:37
    Wow!· Your code has changed much and has a LOT of commented code.· Can you give a brief explanation of what you're doing and I will see what I can find?· I understood what was happening before but now it's not so clear.

    ▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
    Chris Savage
    Parallax Tech Support
    csavage@parallax.com
Sign In or Register to comment.