Simulated BinToASCII Problem

technokid

Member
Hello all,

I am working on a project for my dad that finds the speed of a small model train (N Scale or 1:144), scales the speed, finds what the speed would be in real life and displays it on a 3 digit 7 segmented LED display.
I have created two scripts provided below: one that works normally, and one that rounds the speed before displaying it.
My problem is that the script says that the hunds, tens and ones variable all hold a value bigger than 40.
I don't understand how this works and i don't think that the program is working correctly.
It correctly calculates the scaled speed, but there is a problem with the BinToASCII command.
The hunds, tens and ones variables should hold numbers in between 0 and 9.
It seems that calculating those variables are the hardest part of this project (Unbelievably).
Please could anyone tell me where I have gone wrong.

Thanking any help,
Technokid

P.S Sorry. I don't put remarks in my scripts due to many complications finding the right symbol.

Rounded Code:

Code:
symbol hund = b0
symbol tens = b1
symbol ones = b2
symbol speed = b3
dirsc = %01111111

Start:
b4 = 0
b7 = 0
hund = 0
tens = 0
ones = 0
speed = 0
goto MainsA

MainsA:
readadc b.3,b3
if b3 < 75 then goto MainsA
goto SignalFound

SignalFound:
pause 100
b4 = b4 + 1
readadc b.4,b5
if b5 < 75 then goto SignalFound
b4 = b4 / 10
speed = 30/b4
speed = speed * 144
if speed > 999 then goto Verify
bintoascii speed,hund,tens,ones
goto MainsB

MainsB:
high b.5
if hund = 0 then let pinsc = %01111110
endif
if hund = 1 then let pinsc = %00110000
endif
if hund = 2 then let pinsc = %01101101
endif
if hund = 3 then let pinsc = %01111001
endif
if hund = 4 then let pinsc = %00110011
endif
if hund = 5 then let pinsc = %01011101
endif
if hund = 6 then let pinsc = %01011111
endif
if hund = 7 then let pinsc = %01110000
endif
if hund = 8 then let pinsc = %01111111
endif
if hund = 9 then let pinsc = %01111011
endif
pause 15
let pinsc = %00000000
low b.5
high b.6
if tens = 0 then let pinsc = %01111110
endif
if tens = 1 then let pinsc = %00110000
endif
if tens = 2 then let pinsc = %01101101
endif
if tens = 3 then let pinsc = %01111001
endif
if tens = 4 then let pinsc = %00110011
endif
if tens = 5 then let pinsc = %01011101
endif
if tens = 6 then let pinsc = %01011111
endif
if tens = 7 then let pinsc = %01110000
endif
if tens = 8 then let pinsc = %01111111
endif
if tens = 9 then let pinsc = %01111011
endif
pause 15
let pinsc = %00000000
low b.6
high b.7
if ones = 0 then let pinsc = %01111110
endif
if ones = 1 then let pinsc = %00110000
endif
if ones = 2 then let pinsc = %01101101
endif
if ones = 3 then let pinsc = %01111001
endif
if ones = 4 then let pinsc = %00110011
endif
if ones = 5 then let pinsc = %01011101
endif
if ones = 6 then let pinsc = %01011111
endif
if ones = 7 then let pinsc = %01110000
endif
if ones = 8 then let pinsc = %01111111
endif
if ones = 9 then let pinsc = %01111011
endif
pause 20
let pinsc = %00000000
low b.7
b7 = b7 + 1
if b7 < 60 then goto MainsB
goto Start

Verify:
speed = speed + 1 / 2
bintoascii speed,hund,tens,ones
goto MainsB
Normal Code:

Code:
symbol hund = b0
symbol tens = b1
symbol ones = b2
symbol speed = b3
dirsc = %01111111

Start:
b4 = 0
b7 = 0
hund = 0
tens = 0
ones = 0
speed = 0
goto MainsA

MainsA:
readadc b.3,b3
if b3 < 75 then goto MainsA
goto SignalFound

SignalFound:
pause 100
b4 = b4 + 1
readadc b.4,b5
if b5 < 75 then goto SignalFound
b4 = b4 / 10
speed = 30/b4
speed = speed * 144
bintoascii speed,hund,tens,ones
goto MainsB

MainsB:
high b.5
if hund = 0 then let pinsc = %01111110
endif
if hund = 1 then let pinsc = %00110000
endif
if hund = 2 then let pinsc = %01101101
endif
if hund = 3 then let pinsc = %01111001
endif
if hund = 4 then let pinsc = %00110011
endif
if hund = 5 then let pinsc = %01011101
endif
if hund = 6 then let pinsc = %01011111
endif
if hund = 7 then let pinsc = %01110000
endif
if hund = 8 then let pinsc = %01111111
endif
if hund = 9 then let pinsc = %01111011
endif
pause 15
let pinsc = %00000000
low b.5
high b.6
if tens = 0 then let pinsc = %01111110
endif
if tens = 1 then let pinsc = %00110000
endif
if tens = 2 then let pinsc = %01101101
endif
if tens = 3 then let pinsc = %01111001
endif
if tens = 4 then let pinsc = %00110011
endif
if tens = 5 then let pinsc = %01011101
endif
if tens = 6 then let pinsc = %01011111
endif
if tens = 7 then let pinsc = %01110000
endif
if tens = 8 then let pinsc = %01111111
endif
if tens = 9 then let pinsc = %01111011
endif
pause 15
let pinsc = %00000000
low b.6
high b.7
if ones = 0 then let pinsc = %01111110
endif
if ones = 1 then let pinsc = %00110000
endif
if ones = 2 then let pinsc = %01101101
endif
if ones = 3 then let pinsc = %01111001
endif
if ones = 4 then let pinsc = %00110011
endif
if ones = 5 then let pinsc = %01011101
endif
if ones = 6 then let pinsc = %01011111
endif
if ones = 7 then let pinsc = %01110000
endif
if ones = 8 then let pinsc = %01111111
endif
if ones = 9 then let pinsc = %01111011
endif
pause 20
let pinsc = %00000000
low b.7
b7 = b7 + 1
if b7 < 60 then goto MainsB
goto Start
 
Last edited:

Technical

Technical Support
Staff member
PICAXE>Wizards>ASCII menu and you will see the correct ASCII code for the character '0' is indeed 48.
So if you want to change any ASCII character from '0' to '9' into a number 0 you must subtract 48.
 

Goeytex

Senior Member
There are quite a few problems with your code besides the lack of commenting. Here is a glaring one.

Code:
speed = speed * 144
if speed > 999 then goto Verify
The speed variable is assigned as a byte (b3). A byte has a max value of 255. Yet you are multiplying speed (b3) by 144 which means any value of b3 > 1 will cause an overflow. IS this what you want to do? Speed can NEVER be > 255 since it is a byte.

Before going further I suggest you look over the code and make sure that your variables are appropriate for the values that they are expected to hold.
 

westaust55

Moderator
While not the cause of your current problem, the fact that you have many lines of
iF...THEN commands (repeated three times for 100s, 10s and 1s) suggests that you did not look at the code examples given to you in the previous thread:
http://www.picaxeforum.co.uk/showthread.php?26845-Controling-The-7-Segment-LED-Display
Have a look at the LOOKUP command which taking the values in your IF...THEN statements can convert your value 0 to 9 into a 7-seg display value and greatly reduce the number of program lines.

You say that the posted code correctly calculates the speed.
How? Where? Maybe on paper but as Goeytex indicates above your values exceed the capability of a byte variable so you may/will need to use a word variable to hold values up to 65535.
Are you trying to work with decimal parts - keep in mind PICAXE math is integer only.

Sorry I do not accept the comment that there are no comments included because of "complications" ????
If you include some details on the calculation such as spacing of the two IR sensors and basis of the math behind the calculation in the program folks here can help you to formulate a calculation that will work.
 

technokid

Member
I have corrected the speed scale, speed overflow error and generally fixed the script.
I have included the "comments" in this script.
I have used IR sensors 30cm apart (12 inches).
Here is the improved script:

Code:
symbol hund = b0		'Set up variables
symbol tens = b1
symbol ones = b2
symbol speed = w13
dirsc = %01111111		'Sets up outputs for display

Start:
b4 = 0			'Sets variables to 0
b7 = 0
hund = 0
tens = 0
ones = 0
speed = 0
goto MainsA

MainsA:
readadc b.3,b3		'Check if ir one detected
if b3 < 75 then goto MainsA
goto SignalFound

SignalFound:
pause 100
b4 = b4 + 1			'Check how long until ir detected
readadc b.4,b5		'Check if ir two detected
if b5 < 75 then goto SignalFound
b4 = b4 / 10		'Scale b4 to seconds
speed = 30 / b4		'Scale down speed
speed = speed * 7
bintoascii speed,hund,tens,ones
hund = hund - 48
tens = tens - 48
ones = ones - 48
goto MainsB

MainsB:
high b.5			'Display digit hunds data
if hund = 0 then let pinsc = %01111110
endif
if hund = 1 then let pinsc = %00110000
endif
if hund = 2 then let pinsc = %01101101
endif
if hund = 3 then let pinsc = %01111001
endif
if hund = 4 then let pinsc = %00110011
endif
if hund = 5 then let pinsc = %01011101
endif
if hund = 6 then let pinsc = %01011111
endif
if hund = 7 then let pinsc = %01110000
endif
if hund = 8 then let pinsc = %01111111
endif
if hund = 9 then let pinsc = %01111011
endif
pause 15
let pinsc = %00000000	'Clear display
low b.5
high b.6			'Display digit tens data
if tens = 0 then let pinsc = %01111110
endif
if tens = 1 then let pinsc = %00110000
endif
if tens = 2 then let pinsc = %01101101
endif
if tens = 3 then let pinsc = %01111001
endif
if tens = 4 then let pinsc = %00110011
endif
if tens = 5 then let pinsc = %01011101
endif
if tens = 6 then let pinsc = %01011111
endif
if tens = 7 then let pinsc = %01110000
endif
if tens = 8 then let pinsc = %01111111
endif
if tens = 9 then let pinsc = %01111011
endif
pause 15
let pinsc = %00000000	'Clear display
low b.6
high b.7			'Display digit ones data
if ones = 0 then let pinsc = %01111110
endif
if ones = 1 then let pinsc = %00110000
endif
if ones = 2 then let pinsc = %01101101
endif
if ones = 3 then let pinsc = %01111001
endif
if ones = 4 then let pinsc = %00110011
endif
if ones = 5 then let pinsc = %01011101
endif
if ones = 6 then let pinsc = %01011111
endif
if ones = 7 then let pinsc = %01110000
endif
if ones = 8 then let pinsc = %01111111
endif
if ones = 9 then let pinsc = %01111011
endif
pause 20
let pinsc = %00000000	'Clear display
low b.7
b7 = b7 + 1			'Display data for three seconds
if b7 < 60 then goto MainsB
goto Start
Thanks for all your help,
Technokid.

P.S I use a lot simple commands and being newish to this, the most complex command I have ever used is the serin and serout commands.
I do not intend to get into complex programming as I like to take one look at a script and know how it works.
Thanks anyways.
 

westaust55

Moderator
Okay, lets look at your code and try to clear up the problems as I see them.

While your calculations may work on paper or in Excel you are losing a lot of accuracy and likely getting wrong results as you are thinking in decimal/part numbers and not whole/integer numbers.
PICAXE math only works in whole / integer numbers

Code:
SignalFound:
pause 100
b4 = b4 + 1			'Check how long until ir detected
readadc b.4,b5		'Check if ir two detected
if b5 < 75 then goto SignalFound
b4 = b4 / 10		'Scale b4 to seconds
speed = 30 / b4		'Scale down speed
speed = speed * 7
bintoascii speed,hund,tens,ones
hund = hund - 48
tens = tens - 48
ones = ones - 48
goto MainsB
Lets say it took just under a second to pass between the two IR detectors.
at 0.9 seconds the READACD detects a high state (> 75) and b4 contain the value 9.

now the line:
b4 = b4 / 10 'Scale b4 to seconds
the result is
0 = 9 / 10 ; not 0.9 but only the integer part ==> 0

instead of the lines:
Code:
if b5 < 75 then goto SignalFound
b4 = b4 / 10		'Scale b4 to seconds
speed = 30 / b4		'Scale down speed
speed = speed * 7
marginally better:
Code:
if b5 < 75 then goto SignalFound
speed = 3 / b4		'Scale down speed = the same as 30/(b4/10)
speed = speed * 7
but still we have b4 = 9 and by PICAXE math 3 / 9 = 0 and not 0.33 as we only have the integer/whole part
so the next improvement is:
Code:
if b5 < 75 then goto SignalFound
speed = 21 / b4		'Scale down speed = the same as 7 * 30/(b4/10)
now for durations up to 2 seconds that will give a speed value other than zero but it is still very coarse.
if you want greater resolution then consider
Code:
if b5 < 75 then goto SignalFound
speed = 210 / b4		'Scale down speed = the same as 7 * 30/(b4/10)
now the value for speed is 10 time the value you calculated on paper
if it takes 5 seconds to travel the 30 cm then
b4 = 50 and speed = 210 / 50 ==> 4 (not 4.2 with PICAXE math) that equates to 0.4 km so you have still lost around 200 to 300 metres
so as a final pass try:
Code:
if b5 < 75 then goto SignalFound
speed = 2100 / b4
now you have a value of 42 which is somewhat more useful. 21000 / b4 could be better still if the train might really creep along.

Hopefully that will give you an idea on how to improve the resolution of the calculations.
 
Last edited:

westaust55

Moderator
Now let us consider the actual calculations.

Your 300 mm (30 cm) distance in N scale (1:144) equates to 300 * 144 / 1000 = 43.2 metres

So if my maths is correct then the calculation would be:
43.2 * 3600 / 1000 / duration (in tenths of second) / 10 (to convert to seconds)
where:
. 3600 = seconds in an hour
. 1000 = metres in a kilometre

Which can be simplified to 1555.2 / duration ; where duration = the value in variable b4.
Or for the PICAXE:
Speed = 1555 / b4

Then if it takes 5 seconds to traverse the 300 mm the speed is 1555 / 50 ==> 31 kph (actual is 31.1 but with integer math we lose a little accuracy),
and if it takes 2 seconds to traverse the 300 mm the speed is 1555 / 20 ==> 77 kph (actual is 77.76 but with integer math we lose a little accuracy).
 
Top