Introduction
Although, this discussion is set in the framework of a timer for a Pinewood Derby competition, it is applicable to a general class of problems where it is desired to know the ordering of events and when each event occurred.
Each February, the fathers of Cub Scouts compete in a competition. I say that with tongue in cheek. It's billed as a Cub competition, but my experience is its often a father competition or "my father is better than your father" type thing. When I was a Cub Master many years ago, we used human judges, but there was always a helpful someone who brought a Polaroid. In case their child was "wronged", they could produce a "photo finish".
For the past several years, in December and January, I have received a number of requests for electronics to do the timing and I always think back to pulling that racetrack out of our basement and I get tired, and can't imagine folks wiring up photocell arrangements, crystal oscillators, timer circuits and LED displays.
But, they do, and the problem is interesting in that it is simply stated; display the order of a sequence of events and the time that each event occurred, and yet it tends to defy a simple solution with a minimum of components.
The BasicX with its on-board timer capability may provide a simple solution.
Detailed Discussion
In the program PineWood.Bas, an input GO is brought low to start the race. This input may be derived from whatever actually starts the race, or an output from the BasicX might be used to start the cars when the GO button is depressed.
I have assumed four lanes and that when a car passes the finish line, some optical circuitry provides a momentary logic zero to the BasicX on the lower four bits of PortA.
The BasicX continually reads the lanes and if there is a change involving a lane (or lanes) which has not finished, the time is fetched and the lane (or lanes) are identified and the "place" and time are stored in array elements associated that lanes (or lanes).
On timeout which I have set to 10.0 seconds or when all cars have finished, the results are displayed. This might be a PC or serial LCD (or huge VFD). If a finish was not detected in a lane, question marks are displayed.
Note that in a single fetch of the status of the lanes, there may be multiple finishes. If so, all cars are assigned the same place.
In this routine, no amazinging output was provided when a car crosses the finish line. However, one might output NotFinished on PortC to turn on a lane indicator when a car finishes.
A question arises as to whether a car might be missed. That is, the car manages to completely cross the finish line between samples by the BasicX. Yes. If the maximum execution time from taking one sample to taking the next is greater than the time the signal from a lane is low, the event will be missed. A solution might be to set a latch (to 0) when a car crosses the finish.
Please note that my intent in developing this routine was simply to tinker and it was tested using push button switches. It seems practical for Pinewood Derbies, but I may be wrong.
' PineWood.Bas
'
' See text.
'
' copyright, Peter H. Anderson, Baltimore, MD, Oct, '99
Sub Main()
Dim Lane as Integer ' Lanes 1 through 4
Dim NewLanes as Byte ' current state of the four lanes
Dim OldLanes as Byte ' previous state of the four lanes
Dim Change as Byte ' difference of New and OldLanes
Dim FinishDetected as Boolean ' used as a flag
Dim NotFinished as Byte ' those lanes that have not finished
Dim NewChange as Byte ' Change and not finished
Dim Tm as Single ' current time
Dim TimeOut as Single ' time to wait until race finished
Dim Place as Byte ' first, second, etc
Dim PlaceLane(1 to 4) as Byte ' place and time associated
Dim PlaceTime(1 to 4) as Single ' with each lane
Dim space as String *1
Dim question_mark as String *1
Dim NotGo as Byte
space = " "
question_mark = "?"
Call OpenSerialPort(2, 9600)
TimeOut = 10.0
NotFinished = &H0f ' a one in a bit position indicates lane has
' not finished
OldLanes = &H0f
Place = 1 ' first place
Do ' loop until GO button pressed
Register.DDRA = &H00
Register.PORTA = &Hff
NotGo = Register.PinA AND bx00010000
Loop Until (NotGo = 0)
Call PutTime (0, 0, 0.0) ' initialize on board clock
Do
Register.DDRA = &H00 ' PortA all inputs
Register.PORTA = &Hff ' with Pull up resistor
NewLanes = Register.PINA AND &H0F ' lower four bits
' Call PutB(NewLanes)
' Call NewLine()
Change = (OldLanes XOR NewLanes) AND &H0f
' a logic one in bit positions where there is a new change
NewChange = (Change AND NotFinished) AND &H0f
' a logic one where was a change and not finished
OldLanes = NewLanes
FinishDetected = FALSE
If (NewChange <> 0) then
' Call PutStr(question_mark)
Tm = Timer() ' fetch the time
For Lane = 1 To 4
If (GetByteBit(NewChange, CByte(Lane-1)) = 1) then
' if finished
NotFinished = PutByteBit(NotFinished, CByte(Lane-1), 0)
' save that it finished
PlaceLane(Lane) = Place
PlaceTime(Lane) = Tm
FinishDetected = TRUE
End If
Next
End If
If (FinishDetected) then
FinishDetected = FALSE
Place = Place+1
End If
Tm = Timer()
' Call PutB(NotFinished)
' Call PutStr(space)
' Call PutS(Tm)
' Call NewLine()
' loop until timeout or all cars have finished
Loop Until ((Tm > 10.0) OR (NotFinished = 0)) ' race over
' now report the results
For Lane = 1 to 4 ' for each lane
Call PutI(Lane)
Call PutStr(space)
If (GetByteBit(NotFinished, CByte(Lane - 1)) = 1) then
' didn't finish
Call PutStr(question_mark)
Call PutStr(space)
Call PutStr(question_mark)
Call NewLine()
Else
Call PutB(PlaceLane(Lane))
Call PutStr(space)
Call PutS(PlaceTime(Lane))
Call NewLine()
End If
Next
End Sub
Function PutByteBit(ByVal v as Byte, ByVal pos as Byte, _
ByVal state as Byte) as Byte
' sample usage
' x = PutByteBit(x, 3, 0) ' make bit 3 a zero
Dim N as Byte, Mask as Byte
Mask = bx00000001
For N = 1 To Pos
Mask = Mask * 2
Next
If (state = 1) then
v = v OR Mask
Else
v = v AND (Mask XOR &Hff)
End If
PutByteBit = v
End Function
Function GetByteBit(ByVal v as Byte, ByVal pos as Byte) as Byte
' sample usage
' y = GetByteBit(x, 3) ' get the value of bit 3
Dim N as Byte, Mask as Byte, RetVal as Byte
Mask = bx00000001
For N = 1 To Pos
Mask = Mask * 2
Next
v = v AND Mask
If (v <>0) Then
RetVal = 1
Else
RetVal = 0
End If
GetByteBit = RetVal
End Function