Timing/Using a Propeller as a stopwatch — Parallax Forums

# Timing/Using a Propeller as a stopwatch

Posts: 97
edited 2013-05-29 20:50
Hello.

I'm moving up from the BASIC Stamp for a project that I'm working on. I'm very new to this type of programming language and I'm looking for some help with getting to learn it.

My project is a stopwatch/timer that is accurate up to 1 microsecond (.000001 sec). This leads to my first question. Is the Propeller capable of doing that (I know the BS2 isn't!!)?

I think I understand what a cog is, but just to make sure I'll explain my plan for this. My stopwatch actually consist of 4 different timers.3 of them start at the same time. So here's how I've layed out my cogs.

Cog 1 - Main (controller). Get's I/O's status and starts/stops the necessary timers.
Cog 2 - Serial Communication. After the time is calculated (I'm not going to be doing any math on the Prop. The computer program will calculate the final time. I just need it to calculate how long - in Prop time - it took for me to press Button A and then Button .
Cog 3 - Timer 1. The main timer. It will have the longest Elapsed Time.
Cog 4 - Timer 2. Starts at the same time as Timer 1, but will end with the shortest Elapsed Time. (Stops separately from Timer 1)
Cog 5 - Timer 3. Starts at the same time as Timer 1, and will have the "middle" Elapsed TIme. (Stops separately from Timer 1)
Cog 6 - Timer 4. Starts at a special time, but will end with Timer 1.

Can the Prop have 4 timers going at the same time and still keep an accurate resolution of 1 microsecond??

I don't see where this code will be very complex, but I could be wrong. All I'm doing is just calculating the ticks it was from the start of a timer to the stop. If I need to account for some overhead, or dividing by 10,000 to get a time in seconds, this will all be done in the program on the computer.

I read somewhere that I should use assembly rather than Spin because it's faster. Is that statement true?

Basically I'm just asking for some help/advice/resources on how to get started on timing in this resolution with the Prop.

If you have any questions, just ask.

Ryan

• Posts: 8,693
edited 2013-04-29 19:17
Hello.

I'm moving up from the BASIC Stamp for a project that I'm working on. I'm very new to this type of programming language and I'm looking for some help with getting to learn it.

My project is a stopwatch/timer that is accurate up to 1 microsecond (.000001 sec). This leads to my first question. Is the Propeller capable of doing that (I know the BS2 isn't!!)?
Yes, the prop can do that.
I think I understand what a cog is, but just to make sure I'll explain my plan for this. My stopwatch actually consist of 4 different timers.3 of them start at the same time. So here's how I've layed out my cogs.

Cog 1 - Main (controller). Get's I/O's status and starts/stops the necessary timers.
Cog 2 - Serial Communication. After the time is calculated (I'm not going to be doing any math on the Prop. The computer program will calculate the final time. I just need it to calculate how long - in Prop time - it took for me to press Button A and then Button .
Cog 3 - Timer 1. The main timer. It will have the longest Elapsed Time.
Cog 4 - Timer 2. Starts at the same time as Timer 1, but will end with the shortest Elapsed Time. (Stops separately from Timer 1)
Cog 5 - Timer 3. Starts at the same time as Timer 1, and will have the "middle" Elapsed TIme. (Stops separately from Timer 1)
Cog 6 - Timer 4. Starts at a special time, but will end with Timer 1.

Can the Prop have 4 timers going at the same time and still keep an accurate resolution of 1 microsecond??
Yes. The timers use the same clock.
I don't see where this code will be very complex, but I could be wrong. All I'm doing is just calculating the ticks it was from the start of a timer to the stop. If I need to account for some overhead, or dividing by 10,000 to get a time in seconds, this will all be done in the program on the computer.
This is fairly simple if the start/stop signals for the timers are clean (no debouncing required) and less than 56 seconds apart. If the elapsed time is more than that it is only a bit more complex. Then you need to take the counter rollover into account.
I read somewhere that I should use assembly rather than Spin because it's faster. Is that statement true?
Yes. Assembly is much faster than spin. Under some circumstances this might be do-able in spin, but may need assembly.
Basically I'm just asking for some help/advice/resources on how to get started on timing in this resolution with the Prop.

If you have any questions, just ask.

Ryan

Will the elapsed time between starting and stopping the timer be more than 56 seconds?

What type of signal will be used to start and stop the counters?
• Posts: 7,706
edited 2013-04-29 19:46
What kind of duration are looking to time? -- longest?
• Posts: 8,122
edited 2013-04-30 04:34
If you are going over 56 seconds, you always have the option of running the propeller at a slower clock.
Running at 10MHz (PLLx2) will allow you almost 8 minutes before you have to worry about roll-over.

Bean
• Posts: 6,566
edited 2013-04-30 08:15
I see from your previous post that you've been working for some time on a 0.4 clay oval racetrack with an infra-red beam breaker. Is that the same as you are asking about here? Anything less than milliseconds is probably pushing the physical limits.

Execution times on the Prop even in Spin are much faster than the BASIC Stamp, and there are commands such as WAITPEQ that would allow the program to synchronize to the bream breaker or to the start signal. The advantage of the Prop there is that it can be timing the one interval at the same time that it is transmitting the previous interval over the serial port.

Another option for timing on the Prop are the COG counters. They can measure pulses down to sub-microsecond resolution, and in the logic modes they can be started/stopped by the levels on a couple of input pins. A spin or pasm program would observe the levels in parallel and capture the intervals to send to your central processor.
• Posts: 97
edited 2013-04-30 13:08
I'm working on another Timing System, but this time for Drag Racing. The times will always be less than 30 seconds. I will be using an infrared beam to start/stop the timers. (Picture a pushbutton though).

I learn better with code, and I haven't seen anything that has really showed me how to do anything.

Can someone give me an example (in Assembly) how to create 3 cogs. 1 for serial port, 1 monitoring the pushbutton output - and starting/stopping the timer, and the last for the timer? (I just want to start off easy. This way I'll learn how to create cogs and time something.. Then I can expand that to more than 1 timer.) I hate asking people to write me code, but I seriously have no clue about this language. Remember. All I really want is clock cycles (I guess). Then I'll send that number to the computer program, which will convert those clock cycles into time. You don't have to worry about accounting for overhead, I'll do that.

- Ryan
• Posts: 687
edited 2013-04-30 14:13
Hi Ryan,
I've not bothered with a serial driver yet.
Haven't had the need.
So this won't be what you may have hoped for.
But it might be useful as an example of a couple of things.
Like How to start other cogs. How to pass information around.

This runs on a QuickStart, so it uses the capacitive touch buttons instead of real switches.
Those take quite a bit of fiddling with to make them work.
Not a problem, but it takes clock cycles.
This button driver is written in Spin, so it takes even more clock cycles.
But it's more understandable for first time coders, I think.

The Touchpad button driver runs in the second cog.

I'm setting a flag in the first cog and watching for it in the third.

Anyway, the main routine:
CON { Flag_Demo.spin }
_CLKMODE=XTAL2
_xinfreq = 5_000_000

VAR
LONG MS001, Buttons, Flag

OBJ button: "QS_Buttons"    ' touchpad driver

OBJ Fwatch: "Flag_Watch"             ' other cog method

PUB ButtonDemo | B          ' local variables
MS001 := CLKFREQ / 1_000  ' define 1 millisec
button.start( @Buttons )  ' send address of Buttons
Fwatch.start(@flag)

Repeat
if Buttons & |< 4       ' button 4 pressed?
Flag := 1           ' set Flag
TurnON(4+16)        ' show the button pressed
WaitMS(10)
TurnOFF(4+16)
else
Flag := 0            ' else clear Flag
If Flag == 1            ' this cog can see Flag directly
TurnON(1+16)        ' LED 1 ON
TurnOFF(6+16)       ' LED 6 Off
else
TurnOFF(1+16)       ' LED 1 OFF
TurnON (6+16)       ' LED 6 ON

PUB WaitMS(W)                ' wait for W milliseconds
W := W*MS001
WaitCNT (W+cnt)

PUB TurnON(pin)
dira[pin] := 1
outa[pin] := 1

PUB TurnOFF(pin)
dira[pin] := 1
outa[pin] := 0

The button driver:
'CON { QS_ButtonScan.spin }
'    { returns buttons packed bitwide is a byte}
VAR
LONG ButtonAdr, ButtonCog, MS001
LONG Stack[ 16 ]                 ' define my stack

if ButtonCog                     ' did the new cog start?
cogstop(ButtonCog-1)           ' OOPS! no cog available
ButtonCog := cognew(ButtonScan, @Stack) + 1
MS001 := clkfreq/1000

PUB ButtonScan | B, B1              ' local variables
dira [0..7] := %11111111          ' all pad pins outputs
outa [0..7] := %11111111          ' all pad pins high
'main loop - scan the buttons
Repeat                            ' loop forever
Repeat B from 0 to 7           ' QS LEDS are pins 0-7
dira [B] := 1                ' make pin an output
dira [B] := 0                ' make pin an input
WaitMS(4)                    ' short delay for some decay
B1 := ina[B]                 ' read the pad
if B1 == 0                   ' 0 here means pressed
BYTE[ButtonAdr] |= |< B   ' set bit if pressed
else
BYTE[ButtonAdr] &= !|< B  ' clear bit if not

PUB WaitMS(W)                       'wait for W milliseconds
W := W * 1000 'MS001
WaitCNT (W+cnt)

And the flag monitor:
CON { Flag_Watch.spin }
VAR
LONG Stack[ 16 ]                 ' define my stack
LONG FlagA, AcogID

PUB start( F )                      ' start this in a new cog
FlagA := F                        ' save location of flag variable
if ACogID
cogstop(ACogID-1)               ' no cog available
ACogID := cognew(Aproc, @Stack) + 1

PUB Aproc
'main loop - scan the buttons
Repeat                            ' loop forever
TurnON(19)                      ' LED 3 show's I'm alive
if  byte[FlagA] ==   1          'if I see a 1
TurnON(16)                   '  show this LED 15
TurnOFF(23)
else                            'if I see a 0
TurnON(23)                   '  show that LED 23
TurnOFF(16)

PUB TurnON(pin)
dira[pin] := 1
outa[pin] := 1

PUB TurnOFF(pin)
dira[pin] := 1
outa[pin] := 0

• Posts: 7,706
edited 2013-04-30 15:47
There are lots of ways to do this -- I've attached a simple demo that may get you started. The timing code is in PASM, though this might work fine in Spin, too (it could be translated). By doing it this way, though, it's a nice, neat object that you can load as many copies of as you like (and have cogs to support). The code is simplified by taking advantage of the internal timers; I'm using positive mode to handle timing while a control pin is high. This allows you to start/stop the timer internally by taking the control pin high/low from your master cog. Or, you can start by taking the control pin high from an external circuit. NOTE that you must put a 3.3K or higher resistor between 3.3v and the control pin as the object drives the control pin high and low.

Again, this is just a start. Brush strokes, if you will. It's up to you to paint the masterpiece. :-)

This is PASM portion of the object. Pretty easy.
dat

org     0

hrtimer                 mov     t1, par                         ' start of parameters
add     t1, #4                          ' skip over timing result
rdlong  t2, t1                          ' read sync pin
mov     syncmask, #1                    ' convert to mask

mov     ctra, POS_DETECT                ' ctra measures high state
or      ctra, t2                        '  of sync pin
mov     frqa, #1

hrmain                  waitpne syncmask, syncmask              ' wait for low on sync
mov     phsa, #0                        ' reset timer

waitpeq syncmask, syncmask              ' wait for high on sync
nop
waitpne syncmask, syncmask              ' wait for low on sync

mov     t1, phsa                        ' copy timing
wrlong  t1, par                         ' report to hub

jmp     #hrmain

' --------------------------------------------------------------------------------------------------

POS_DETECT              long    %01000 << 26                    ' increment phsx on high

syncmask                res     1                               ' mask for control pin

t1                      res     1                               ' work vars
t2                      res     1

fit     496

• Posts: 8,693
edited 2013-04-30 19:56
@ryfitzger227

A little more detail on how the timers will be started and stopped would be of help.

Will there be a signal on one pin to start the timer and a signal on another pin to stop it, or will a pin go high (or low) to start the timer and low (or high) to stop it?

Will the start/stop method be the same for all 4 timers? It sounds like this will be so based on post 1, so two start signals (timers 1, 2, 3) and (timer 4) and three stop signals (timers 1, 4), (timer 2), and (timer 3). Is this correct?

The simplest approach may be to have a PASM program that monitors 2 pins (start and stop), starts a counter when the start signal is true, stops the counter when the stop signal is true, and writes the 32 bit counter value to a hub location. The program could then be loaded into 4 cogs with the pin numbers and hub locations passed as parameters. The main spin program would send the data to the PC.
• Posts: 6,566
edited 2013-04-30 22:58
Can someone give me an example (in Assembly) how to create 3 cogs. 1 for serial port, 1 monitoring the pushbutton output - and starting/stopping the timer, and the last for the timer? (I just want to start off easy. This way I'll learn how to create cogs and time something.. Then I can expand that to more than 1 timer.)

Ryan, you're really biting off quite a lot with that request, as you move up from the BASIC Stamp.

Here is a snippet that starts a serial port at 9600 baud, and then simply spits out the time between two presses of a button. It is all in Spin. Well, not quite. When it starts the serial port object (Parallax Serial Terminal), that in turn does start up another Cog that does the heavy lifting, but you don't have to know the details. In PBASIC, the serial commands are built in, but in Spin, the program has to initialize the serial port. Also in PBASIC, the Pause command is built in, but in Spin, it is a method that is written into your own program code by referring to the Prop's clock frequency and its global counter. You should understand thoroughly how the Pause method works.

The Main program loop goes just as you might write the same thing in PBASIC. It waits for the button on p0 to go low, captures the global counter value, then waits for the button to go up and then down again. At that point it sends the difference between the current value of the counter minus the starting value, out as a decimal ascii number to the serial terminal. Then it waits for the button up again and repeats the whole process. Is all that already completely clear to you? If so, the next step may be to start timers running in parallel in different Cogs. However, I'd echo Kwinn, "A little more detail on how the timers will be started and stopped would be of help."
[FONT=courier new][SIZE=1]CON
_clkmode = xtal1 + pll16x                '
_xinfreq = 5_000_000

OBJ
pst : "Parallax Serial Terminal"

PUB Main : ticks
pst.Start(9600)
Pause(100)

ticks := cnt
repeat
repeat while ina[0]
ticks := cnt
repeat until ina[0]

repeat while ina[0]
pst.dec(cnt - ticks)
pst.newline
repeat until ina[0]

PRI Pause(ms)
waitcnt(clkfreq/1000 * ms + cnt)
[/SIZE][/FONT]

• Posts: 7,706
edited 2013-05-02 07:42
The simplest approach may be to have a PASM program that monitors 2 pins (start and stop), starts a counter when the start signal is true, stops the counter when the stop signal is true, and writes the 32 bit counter value to a hub location.

Super easy. Since you only need one long for the timing result I wrote the pasm such that the start and stop pins are passed in it -- put the start pin in byte0 and the stop pin in byte1; pass the address of your result variable in the cognew() call. Again, easy-peasy.

dat

org     0

tixtimer                rdlong  t1, par                         ' read pins
mov     t2, t1                          ' make copy

and     t1, #\$3F                        ' isolate timer start pin

shr     t2, #8                          ' isolate timer stop pin
and     t2, #\$3F                        ' create mask

mov     t1, #0
report                  wrlong  t1, par                         ' we're ready

runtimer                waitpne startmask, startmask            ' clear control inputs

waitpeq startmask, startmask            ' wait for start
neg     t1, cnt                         ' start timer

waitpeq stopmask, stopmask              ' wait for stop
add     t1, cnt                         ' update ticks

jmp     #report

' --------------------------------------------------------------------------------------------------

startmask               res     1                               ' mask for start input
stopmask                res     1                               ' mask for stop input

t1                      res     1                               ' work vars
t2                      res     1

fit     496

• Posts: 7,706
edited 2013-05-02 07:42
The simplest approach may be to have a PASM program that monitors 2 pins (start and stop), starts a counter when the start signal is true, stops the counter when the stop signal is true, and writes the 32 bit counter value to a hub location.

Super easy. Since you only need one long for the timing result I wrote the pasm such that the start and stop pins are passed in it -- put the start pin in byte0 and the stop pin in byte1; pass the address of your result variable in the cognew() call. Again, easy-peasy.

dat

org     0

tixtimer                rdlong  t1, par                         ' read pins
mov     t2, t1                          ' make copy

and     t1, #\$3F                        ' isolate timer start pin

shr     t2, #8                          ' isolate timer stop pin
and     t2, #\$3F                        ' create mask

mov     t1, #0

report                  wrlong  t1, par

waitpne startmask, startmask            ' clear control inputs

waitpeq startmask, startmask            ' wait for start
neg     t1, cnt                         ' start timer

waitpeq stopmask, stopmask              ' wait for stop
add     t1, cnt                         ' update ticks

jmp     #report

' --------------------------------------------------------------------------------------------------

startmask               res     1                               ' mask for start input
stopmask                res     1                               ' mask for stop input

t1                      res     1                               ' work vars
t2                      res     1

fit     496

• Posts: 97
edited 2013-05-27 17:54
Sorry for taking such a long time to respond back to this thread. I've been busy and had to take a break on this. I have a few questions to add.

First off, before I get too far into PASM - if I use Spin how accurate will the timing be? For example. If I create a timing program in Spin, find out how long it takes for the commands, and add that back to the final time will that overhead be the same EVERY time? Or will it vary? If it does, then I guess I'll use PASM. (I'm assuming you would still have to account for overhead, but that it would have a static overhead when using PASM).

I'm leaning towards using/learning PASM for this project because it seems so simple. I like the idea of the copying and pasting the same program and then passing the pin numbers as paramaters. But you mention that I would use the main program for serial port communication. Is it possible for me to write the main program in Spin and then the rest of the objects in PASM (timing)?

This might seem kinda crazy, but I have no clue. How do you save PASM files? Will they still be .spin?

Honestly, the starting and stopping is fairly complex. It consist of (mainly) 2 Props. Prop 1 for starting/reaction times and controlling the lights that tell the person when to go and getting their reaction time. Prop 2 will be timing that person until he gets to the end of the track (with multiple times at different feet intervals - ex. 60ft, 330ft, and finally 660ft.) I'm going to ignore Prop 1 for now because it's pretty complex. It involves a bunch of different timers starting/stopping at different times. Prop 2 is just (practically) one timer starting and stopping like a stopwatch. Remember Timer 1 (the main, or Elapsed Time, timer)? That timer is what every timer after it (except the last) goes off of by when it's time to start. Prop 1 will do it's timing and when the guy leaves, it will get his reaction time. Well at the same time it will set the base of a transistor that's connected to a pin high. The emitter/collector will be connected to a Pin on Prop 2. This will be the signal that Timer 1 starts by. Therefore, Timer 1, 2, & 3 all start off of that. This will be the only time a transistor is being used. The rest will be started/stopped by an infrared. View the table below for more in depth information.

Starting Line
60 feet
330 feet
MPH Start
MPH/ET End (660 feet)

Started by
Transistor
connected to
Prop 1
Ended
by
infrared
Ended
by
infrared
Started
by
infrared
Ended
by
infrared

Starts Timer 1,
2, & 3
Ends
Timer 2
Ends
Timer 3
Starts Timer
4
Ends Timer 1, 4

If you have anymore questions, just ask. I'm always open for suggestions. Thanks for everything so far!
• Posts: 14,813
edited 2013-05-27 18:28
First off, before I get too far into PASM - if I use Spin how accurate will the timing be? For example. If I create a timing program in Spin, find out how long it takes for the commands, and add that back to the final time will that overhead be the same EVERY time? Or will it vary?

The precision of a WAIT command is the same in Spin and PASM, what PASM allows is faster re-arm, and it could time between edges very close together.

However, if you want to resolve to 1us, but never have edges closer than a few ms, then Spin could be quite ok.
Human Reaction times, and running times, will be > 100ms, and you may need to worry more about the other end of the scale: timer roll-over.
Slowing the Prop down a little from the 80MHz will probably do for that.
• Posts: 4,312
edited 2013-05-28 07:33
... looking for some help with getting to learn it.

My project is a stopwatch/timer that is accurate up to 1 microsecond (.000001 sec).
JonnyMac wrote: »
What kind of duration are looking to time? -- longest?

If you are interested in a solution maybe a little more powerful than spin, and maybe a little easier than PASM:

This is the logging package from propforth. It has microsecond resolution and can comfortably log once per second (counter, date time stamp, and data). It requires no addition hardware besides the SD card for logging (you copuld log to EEprom instead). There is a one time calibration, once the drift setting is input, its nut dead on. If the temperature is stable, there is about 3-4 microsecond variance. It uses double math, and the time stamp won't roll over for just over seven thousand years.

It's seems its fine for day to day logging, as the temperature changes, the clock drifts in then back out again, so over 24 hours, it averages out. If you are going to put it outside for an extended period of time of in varying temperature environment, you can use a temperature compensated crystal, but it hasn't been necessary yet for the testing performed.

The current test is a torture test designed to wear out the SD card, but is has logged 110 gig of data once per second to the same file. The SD has not failed yet even though the head header is constantly being rewritten. To make off loading the data easier, the lgger was changes to create a new file when the Day rolls over, this should never fail the SD.

The logger continues loggin even when the log is accessed or the time is set. If power is lost, the system restarts with default time of 2000, January 1, 12:00 AM; but after you set the correct time (manually) you can easily back fill the correct date stamps.

If you don't use forth, you might be able to use the same method in the language(s) of your choice.
• Posts: 97
edited 2013-05-28 13:51
Thanks for the reply!

Im new to this, so what happens after 56 seconds? Does the timer just stop, or does it become inaccurate? I shouldn't be timing for that long under any circumstance, but in case the stop infrared is missed I want to know what I should do.
• Posts: 14,813
edited 2013-05-28 15:08
Thanks for the reply!

Im new to this, so what happens after 56 seconds? Does the timer just stop, or does it become inaccurate? I shouldn't be timing for that long under any circumstance, but in case the stop infrared is missed I want to know what I should do.

~56 seconds( 2^32/80e6 = 53.6870912) is just the 32 bit number wrap-around, and that is for a 80MHz SysClock.

80MHz gives a 12.5ns LSB, so you may decide to just drop the 80MHz, to move that 53 seconds.
eg 10MHz SysClk gives 32 bits to 428 seconds, and still can edge sense to 100ns.

Or, you could choose to drive a spare Pin as a Counter-Clock, and then you can freely scale to any time you want, but still have a faster CPU processing speed.
The COG counters can be set to tick at that Pin-Rate using POSEDGE or NEGEDGE modes.

Here, 80MHz divided by 80 to a 1us pin-rate, would overflow in 71 minutes, and you could easily change to 10us, or 100us.

If you are serious about the 1us LSB, then you might want to also capture a GPS 1pps signal, and use that as a calibrate reference.
• Posts: 4,312
edited 2013-05-28 18:07
jmg wrote: »
~56 seconds( 2^32/80e6 = 53.6870912) is just the 32 bit number wrap-around, and that is for a 80MHz SysClock.

If you use 64 bit numbers (2^64 / 80e6 ) it rolls over after 7,311 years. The way the counters works, they just operate in the back ground and count time for free, and you can do other stuff with the cogs.

Back to post 6, if you log when the beam was broken, and whether it was at the start or end of the track, you could log not only each race, but the intervals between races, and the interval between race days, for the entire season, and for multiple seasons, all on one SD.

What are you going to use as a display? The prop can also run a VGA display, and a keyboard. And propforth can of course do this, with the logger running on on a separate cog.

(I'm kind of excited about this logger stuff, can you tell?).
• Posts: 97
edited 2013-05-29 15:52
Ryan, you're really biting off quite a lot with that request, as you move up from the BASIC Stamp.

Here is a snippet that starts a serial port at 9600 baud, and then simply spits out the time between two presses of a button. It is all in Spin. Well, not quite. When it starts the serial port object (Parallax Serial Terminal), that in turn does start up another Cog that does the heavy lifting, but you don't have to know the details. In PBASIC, the serial commands are built in, but in Spin, the program has to initialize the serial port. Also in PBASIC, the Pause command is built in, but in Spin, it is a method that is written into your own program code by referring to the Prop's clock frequency and its global counter. You should understand thoroughly how the Pause method works.

The Main program loop goes just as you might write the same thing in PBASIC. It waits for the button on p0 to go low, captures the global counter value, then waits for the button to go up and then down again. At that point it sends the difference between the current value of the counter minus the starting value, out as a decimal ascii number to the serial terminal. Then it waits for the button up again and repeats the whole process. Is all that already completely clear to you? If so, the next step may be to start timers running in parallel in different Cogs. However, I'd echo Kwinn, "A little more detail on how the timers will be started and stopped would be of help."
[FONT=courier new][SIZE=1]CON
_clkmode = xtal1 + pll16x                '
_xinfreq = 5_000_000

OBJ
pst : "Parallax Serial Terminal"

PUB Main : ticks
pst.Start(9600)
Pause(100)

ticks := cnt
repeat
repeat while ina[0]
ticks := cnt
repeat until ina[0]

repeat while ina[0]
pst.dec(cnt - ticks)
pst.newline
repeat until ina[0]

PRI Pause(ms)
waitcnt(clkfreq/1000 * ms + cnt)
[/SIZE][/FONT]

I kinda jumped ahead a little since cavelamb showed me how to create cogs, etc. But this code for the timing I just can't get to work. What am I doing wrong? For testing purposes I'm using a QuickStart board. Are the pushbuttons on it a little different?

Here's the code.

main.spin
CON

_clkmode = xtal1 + pll16x
_xinfreq = 5_000_000

VAR

LONG t1, t2, t3, t4

OBJ pst : "Parallax Serial Terminal"
OBJ timer : "timer"
PUB main

pst.start(9600)
timer.start(@t1, @t2, @t3, @t4)

repeat
pause(250)
pst.str(string(16, "Timer 1: "))
pst.dec(t1)

PUB pause(ms)
waitcnt(clkfreq/1000 * ms + cnt)

timer.spin
VAR

long  stack[10]

PUB start(t1a, t2a, t3a, t4a)

cognew(main(t1a, 0), @stack)

PUB main(tadr, tstart) : ticks

ticks := cnt
repeat
repeat while ina[tstart]
ticks := cnt
repeat until ina[tstart]

LONG[tadr] := cnt - ticks

The Serial Terminal keeps saying "Timer 1: 0".
• Posts: 6,566
edited 2013-05-29 20:50
First advice would be not to jump ahead! Objects are nice, but you should have a good reason for going there. I think here the issue is the buttons themselves and how to read them.

The type of pushbuttons does make a difference. The code I provided as well as quite a bit of the other code here has assumed that the signal is a solid ON or OFF as you would typically get from an industrial electronic timer or control. A mechanical button or the buttons on the quickstart are a different matter. They will bounce and the code will race through its states. You'll need to add code to debounce the buttons to be sure that they are solidly in one state or another, and the debouncing can be done either in line with the timer, or as a separate routine running in its own cog.