PDA

View Full Version : Multiple if then optimization



Mugelpower
- 2nd March 2008, 14:07
Hi Gurus of Picland,

Iīm building a Lambdatester that flattens somewhat out the hard jump in output voltage between lean and rich.

wrote a code that works. Fine, and fast enough because theres hardly need for speed.

Way of simple code for Picdummies like me .

But if an oldschool mechanic like me looks at it even he knows that theres plenty room for codesaving.
You Gurus fall down your chairs laughing and crying at the same time, I know.

'************************************************* ****************
'* Name : Analogbargraph1(16F628A).BAS *
'* Author : M.David *
'* Notice : Copyright (c) 2008 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 28.02.2008 *
'* Version : 1.0 *
'* Notes : needs 12F675 for Lambdatesting device and LCD 1X16 *
'* : input 0.1 - 1.1 Volts in GPIO.0 *
'* : needs ADCserout(12F675).bas *
'************************************************* ****************
'
' DEFINITIONS

@__config _XT_OSC & _WDT_ON & _MCLRE_ON & _LVP_OFF & _CP_OFF
Include "modedefs.bas"
CMCON=%00000111


DEFINE OSC 4
Uin var word
B0 VAR word ' Cnt is a word variable
inputData var word ' variable to receive data into


' START OF MAIN PROGRAM
'
CMCON = 7 ' RA0-RA3 are digital I/O
TRISA = 0 ' PORT A is output
TRISB = 1 ' RB0 is Input others output

main:

Serin PORTB.0,N2400,B0
B0 = 100 * B0
Uin = B0 / 207
gosub bargraph
Pause 5
goto main

bargraph:

if Uin < 10 then LCDOUT $FE,1,"TOO LOW"
if (Uin > 10) and (Uin <= 15 ) then
LCDOUT $FE,1,255
endif

if (Uin > 15) and (Uin <= 19 ) then
LCDOUT $FE,1,255,255
endif
if (Uin > 19) and (Uin <= 24 ) then
LCDOUT $FE,1,255,255,255
endif
if (Uin > 24) and (Uin <= 29 ) then
LCDOUT $FE,1,255,255,255,255
endif
if (Uin > 29) and (Uin <= 34 ) then
LCDOUT $FE,1,255,255,255,255,255
endif
if (Uin > 34) and (Uin <= 43 ) then
LCDOUT $FE,1,255,255,255,255,255,255
endif
if (Uin > 43) and (Uin <= 53 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255
endif
if (Uin > 53) and (Uin <= 62 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255
endif
if (Uin > 62) and (Uin <= 72 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255
endif
if (Uin > 72) and (Uin <= 81 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255, 255
endif
if (Uin > 81) and (Uin <= 86 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255, 255,255
endif
if (Uin > 86) and (Uin <= 91 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255, 255,255,255
endif
if (Uin > 91) and (Uin <= 96 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255, 255,255,255,255
endif
if (Uin > 96) and (Uin <= 100 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255, 255,255,255,255,255
endif
if (Uin > 100) and(Uin <= 105 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255, 255,255,255,255,255,255
endif
if (Uin > 105) and(Uin <= 110 ) then
LCDOUT $FE,1,255,255,255,255,255,255,255,255,$FE,$C0,255, 255,255,255,255,255,255,255
endif
if Uin > 110 then
LCDOUT $FE,$C0,"TOO RICH"
endif

return

END ' End of program

on the other hand it works and shows how good and fast the combination of pics and PBP works.

Any Ideas? maybe case select or lookdown or whatever?

sincerely

Mugel

Acetronics2
- 2nd March 2008, 15:39
Hi,

The Obvious Command is ... SELECT CASE

Note here you check Twice your values ... a better test arrangement looks like :



IF Value < 19
....
ENDIF

IF Value < 24
....
ENDIF

IF Value < 29
....
ENDIF




also can be used ...




IF Value < 10 THEN LCDOUT $FE, 1, "TOO LOW"

LOOKDOWN2 Value , < ,[ 10,15,19,24,29, ....], NbPatterns

LCDOUT $FE, 1, REP 255\ NbPatterns


Which is ... Somewhat shorter ( from the listing point of view ...)

Alain

duncan303
- 2nd March 2008, 15:47
hi Mugel,

I don't know where all the gurus are today, but in thier absence I glanced at your post and thought you might like to take a look at the >select case< command. As all your conditions are sequentially discrete then this might be worth considering.

The trouble with long lists of if..thens are that once the condition is met (let say at the begginning of the list) then the program continues to chunder through all the remaining if...thens, whereas select case will exit at >end case< once the condition is met. Be careful though if your conditions are not discrete ,then you will have to arrange the cases in order of preference.

As to code space, I cannot remember but you could quickly swap the code over and see which is smaller.


Duncan

tenaja
- 2nd March 2008, 18:14
The trouble with long lists of if..thens are that once the condition is met (let say at the beginning of the list) then the program continues to chunder through all the remaining if...thens, whereas select case will exit at >end case< once the condition is met. Be careful though if your conditions are not discrete ,then you will have to arrange the cases in order of preference.

Duncan
The way around this is to nest them, and put the largest value at the top. For instance, instead of this...

if a < 5 then...
endif...
if a < 10 then...
endif...

You do this for nesting:
if a < 10 then
if a < 5 then
code here...
else
code here...
endif
endif

or this for simple and fast testing:
if a < 10 then
code here...
goto SkipTests
endif
if a < 5
code here...
endif

SkipTests:

Using this method skips all of the IF's if the most extreme condition isn't true. All of this depends upon the assumption that the value of "a" isn't changed within any of the conditional statements.

Archangel
- 2nd March 2008, 20:24
Hi Mugelpower,
Have you tried Darrel's Bargraph routine?
http://www.picbasic.co.uk/forum/showthread.php?t=2359

duncan303
- 3rd March 2008, 00:10
The way around this is to nest them, and put the largest value at the top.


I am curious if this would compile with the list that Mugel has created, some 20 nested if…then...Else’s on a 16F device?

Duncan

tenaja
- 3rd March 2008, 00:25
It should. I believe it just uses goto's, no stack use.

Mugelpower
- 3rd March 2008, 07:06
yes the 20 if then work, no problem. Assembling took maybe 3 times longer then those blinky codes and it uses nearly 3/5 of the code space in my 16F628..but works flawlessly.

to Joe:

oh man I tried to use DTs bargraph routines but only got the error "coulndīt open bargraph.bas" or something. Copied it in a "dozen" directories around the main PBP main and my project directories...didnīt work, always the same error.
But I uses DTs instant interrupt blinky program and that worked....so I donīt know a bone about how to work around "include" problems.

On the other my bargraph is quite crude with its big bars....but a fine bargraph isnīt an option here...way to hard to see while driving the car or bike, you need only sort of lean/rich tendencies and the lambda sensor it VERY jumpy around the stochiometric area.

8 leds would do but I did it mainly because of 3 reasons:

1.: I COULD do it.......with a little help of my friends....greetings to you all!
2.: One of my employees is sort of colour blind and wanted something to recocnize
without colours.
3.: we do a lot around sportscars engines and we test drive them mainly when the sun shines and a LED bargraph is hard to read while driving 100km/h in corners and the sun shining all over....

Yeah......Iīm telling junk. Here in Germany the sunīs just a rumour you know, seen last time in june 2007 or so....

sayzer
- 3rd March 2008, 08:12
Here it is
982 words


<font color="#008000">@__config _XT_OSC &amp; _WDT_ON &amp; _MCLRE_ON &amp; _LVP_OFF &amp; _CP_OFF

</font><font color="#000080"><b>INCLUDE </b></font><font color="#008000"><b>&quot;modedefs.bas&quot;
</b></font><font color="#000080"><b>DEFINE </b></font>OSC <font color="#FF0000"><b>4
</b></font>Uin <font color="#000080"><b>VAR WORD
</b></font>B0 <font color="#000080"><b>VAR WORD </b><i>' Cnt is a word variable
</i></font>InputData <font color="#000080"><b>VAR WORD </b><i>' variable to receive data into
</i></font>RepNo <font color="#000080"><b>VAR BYTE

</b><i>' START OF MAIN PROGRAM
'
</i></font>CMCON = <font color="#FF0000"><b>7 </b></font><font color="#000080"><i>' RA0-RA3 are digital I/O
</i></font>TRISA = <font color="#FF0000"><b>0 </b></font><font color="#000080"><i>' PORT A is output
</i></font>TRISB = <font color="#FF0000"><b>1 </b></font><font color="#000080"><i>' RB0 is Input others output

</i></font>Main:

<font color="#000080"><b>SERIN </b></font>PORTB.<font color="#FF0000"><b>0</b></font>,N2400,B0
B0 = <font color="#FF0000"><b>100 </b></font>* B0
Uin = B0 / <font color="#FF0000"><b>207
</b></font><font color="#000080"><b>GOSUB </b></font>Bargraph
<font color="#000080"><b>PAUSE </b></font><font color="#FF0000"><b>5

</b></font><font color="#000080"><b>GOTO </b></font>Main

Bargraph:

<font color="#000080"><b>LCDOUT </b></font><font color="#FF0000"><b>$fe</b></font>,<font color="#FF0000"><b>1 </b></font><font color="#000080"><i>'Valid for all cases.

</i><b>SELECT CASE </b></font>Uin

<font color="#000080"><b>CASE IS </b></font>&lt; <font color="#FF0000"><b>10
</b></font><font color="#000080"><b>LCDOUT </b></font><font color="#008000"><b>&quot;TOO LOW&quot;
</b></font><font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>10 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>15
</b></font>RepNo = <font color="#FF0000"><b>1
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>15 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>19
</b></font>RepNo = <font color="#FF0000"><b>2
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>19 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>24
</b></font>RepNo = <font color="#FF0000"><b>3
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>24 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>29
</b></font>RepNo = <font color="#FF0000"><b>4
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>29 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>34
</b></font>RepNo = <font color="#FF0000"><b>5
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>34 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>43
</b></font>RepNo = <font color="#FF0000"><b>6
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>43 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>53
</b></font>RepNo = <font color="#FF0000"><b>7
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>53 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>62
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>62 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>72
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>1
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>72 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>81
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>2
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>81 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>86
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>3
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>86 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>91
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>4
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>91 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>96
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>5
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>96 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>100
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>6
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>100 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>105
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>7
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE IS </b></font>&gt; <font color="#FF0000"><b>105 </b></font><font color="#000080"><b>AND IS </b></font>&lt;= <font color="#FF0000"><b>110
</b></font>RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD
<font color="#000080"><b>GOSUB </b></font>LCD2
RepNo = <font color="#FF0000"><b>8
</b></font><font color="#000080"><b>GOSUB </b></font>RepLCD

<font color="#000080"><b>CASE ELSE
LCDOUT </b></font><font color="#FF0000"><b>$FE</b></font>,<font color="#FF0000"><b>$C0</b></font>,<font color="#008000"><b>&quot;TOO RICH&quot;
</b></font><font color="#000080"><b>END SELECT

RETURN

</b></font>RepLCD:
<font color="#000080"><b>WHILE </b></font>RepNo &gt; <font color="#FF0000"><b>0
</b></font><font color="#000080"><b>LCDOUT </b></font><font color="#FF0000"><b>255
</b></font>RepNo = RepNo - <font color="#FF0000"><b>1
</b></font><font color="#000080"><b>WEND
</b></font><font color="#000080"><b>RETURN

</b></font>LCD2:
<font color="#000080"><b>LCDOUT </b></font><font color="#FF0000"><b>$FE</b></font>,<font color="#FF0000"><b>$C0
</b></font><font color="#000080"><b>RETURN

</b></font>


Btw:
Select case produces 100 words more!
So, if you go with your IF..THENs, it will be approx. 882 words, but select case provides a clean look.

Acetronics2
- 3rd March 2008, 08:46
Another way




'************************************************* ****************
'* Name : Analogbargraph1(16F628A).BAS *
'* Author : M.David *
'* Notice : Copyright (c) 2008 [select VIEW...EDITOR OPTIONS] *
'* : All Rights Reserved *
'* Date : 28.02.2008 *
'* Version : 1.0 *
'* Notes : needs 12F675 for Lambdatesting device and LCD 1X16 *
'* : input 0.1 - 1.1 Volts in GPIO.0 *
'* : needs ADCserout(12F675).bas *
' 569 Lines
'************************************************* ****************
'
' DEFINITIONS

@ __config _XT_OSC & _WDT_ON & _MCLRE_ON & _LVP_OFF & _CP_OFF
Include "modedefs.bas"
'CMCON=%00000111


DEFINE OSC 4

NbPatterns var Byte
Uin var word
B0 VAR word ' Cnt is a word variable
inputData var word ' variable to receive data into


' START OF MAIN PROGRAM
'
CMCON = 7 ' RA0-RA3 are digital I/O
TRISA = 0 ' PORT A is output
TRISB = 1 ' RB0 is Input others output

main:

Serin PORTB.0,N2400,B0
B0 = 100 * B0
Uin = B0 / 207

bargraph:

IF Uin < 10 THEN LCDOUT $FE,1,"TOO LOW" : GOTO Show

IF Uin > 110 THEN LCDOUT $FE,1,"TOO HIGH" : GOTO Show


LOOKDOWN2 Uin , < [ 11,16,20,25,30,35,44,54,63], NbPatterns

LCDOUT $FE, 1, REP 255\ NbPatterns

IF Uin > 62 THEN

LOOKDOWN2 Uin , < [ 63,73,82,87,92,97,101,106,111], NbPatterns

LCDOUT $FE, 1, REP 255\ 8

LCDOUT $FE, $C0, REP 255\ NbPatterns

ENDIF

Show:

Pause 5
goto main


END ' End of program






569 Words ...




Alain

Mugelpower
- 3rd March 2008, 09:18
Hey Girls & Guys,

seems I poked into a bees nest.... I will try those codes in the evening (10 hrs from now).

Youre really helpful.

How about a code for extern interrupt that triggers a 1 ms high port after a delay found in a lookdown/case/if then row list? from 3 to 600 Hz of course......to get a constant phase shift between trigger and output.....

Its oughta be real fast!! 20MHz 16F628A preferred
"On interrupt" gets 180° phase shift (maximum limit) at 200 Hz.....

I dunno how to integrate a variable delay into DTs instant interrupts....

Acetronics2
- 3rd March 2008, 09:30
How about a code for extern interrupt that triggers a 1 ms high port after a delay found in a lookdown/case/if then row list? from 3 to 600 Hz of course......to get a constant phase shift between trigger and output.....

....

Could you explain that better ???

You're asking for a PBP written electronic ignition here ...

don't you think you abuse ... just a little bit !!!

Have an eye here ... : http://a110.free.fr/SPIP172a110/article.php3?id_article=23

Ok, assembler ... but kit or scratch realizable, and the forum offers a Huge help ...

Alain

PS: I'm working on a full PBP version ... but Assembler interrupts can't be avoided !!!

Mugelpower
- 3rd March 2008, 11:21
Hi Acetronics,

yeah, in Principle thats that. BUT: thats french (ARGL-GARG!!) and I donīt understand 2% of it.
And: I have to modify the code it myself fromtime to time which could only be done if Iīm knowing quite a lot about the code. Man, thats a BIG FISH to swallow for an oldschool mechanic. Learning programming, trying to avoid asm, learning that asm couldnīt be avoided...... ARGL-GARG !

Acetronics2
- 3rd March 2008, 12:25
Hi,

Generally speaking ...

Using PbP do not "protect" you from learning assembler ...it's a real "plus" to see the ASM result of your programming ...
and overall understand what's really happening, and how ...

Now about Ignition ... it's simple: you have an asm program to use with MPLAB , and a " Table generator " program ( in QBasic or, more recently EXCEL), just to load your timing values.
So, there are special knowledge of assembler needed ...

For French ... aha ... just think I spent a year in Berlin ( Yr 1990 ), and had to dig out my German school knowledge ... Euuuuhhhh, I'm also an old Mechanics ( and Thermics ) guy ...

Just Follow the scheme and components list ... you'll have done 90% of the work. ... on the Forum, we ALSO Compute tables for ... how to tell it ??? .... E.T.s ?

You also have this link ... in English :

http://www.transmic.net/index.htm

But ... not so good as ours ... yeah !!!

Alain

PS for Sayzer ...: I found a Turkish > French / French > Turkish free dictionnary on the Web; I do Hope you appreciate the effort ( LoL ...)

Mugelpower
- 3rd March 2008, 13:52
Hi Acetronics,

youve been to Germany? thats been a dark time I guess.....haha.

I already Knew the CDI transmic link but they have only the .hex file GRRRR....!

I found this too:

http://www.angelfire.com/ia/lfb/Pgbosch.html

but thats way more code and unneccessary extra sparks.

and by the way.....isnīt it more fun to get to the finish by ourselfs?

Acetronics2
- 3rd March 2008, 14:16
We'll have to close this Ignition thread ... Because HS ...

a last one ...

http://denis.tauvel.free.fr/index.htm

<< youve been to Germany? thats been a dark time I guess.....haha. >>

no,no ... was a wonderful year ... indeed !!! Berliners are really smart people !


Alain

skimask
- 3rd March 2008, 14:56
@ __config _XT_OSC & _WDT_ON & _MCLRE_ON & _LVP_OFF & _CP_OFF
Include "modedefs.bas"
nbpatterns var byte:uin var word:cmcon=7:trisa=0:trisb=1
main: serin portb.0,n2400,uin:uin=(uin*100)/207:lcdout $fe,1,"TOO ":if uin<10 then lcdout "LOW":goto show
IF Uin > 110 THEN LCDOUT "HIGH": GOTO Show
lookdown2 uin,<[11,16,20,25,30,35,44,54,63],nbpatterns:lcdout $fe,1,rep 255\nbpatterns
if uin > 62 then
lookdown2 uin,<[ 63,73,82,87,92,97,101,106,111], NbPatterns
lcdout $fe,1,rep 255\ 8,$fe, $c0, rep 255\ nbpatterns
ENDIF
Show: Pause 5:goto main
END ' End of program


13 LINES! :D

Mugelpower
- 3rd March 2008, 15:37
Hi Skimask,

yeah will try that too, never worked around the lookdown commands...will see how it works


sincerely

Mugel

Acetronics2
- 3rd March 2008, 15:43
13 LINES! :D


Hi, Ski

That's way too hard for my old eyes !!! Lol ...

at second look ... I've seen that somewhere before, but Where ??? ...

Alain

skimask
- 3rd March 2008, 15:49
Hi, Ski
That's way too hard for my old eyes !!! Lol ...
at second look ... I've seen that somewhere before, but Where ??? ...
Alain

Might even be a few words shorter on code!
Or at least a few colons longer. :)

sayzer
- 3rd March 2008, 15:56
13 lines is not the case ;

But, it is only 2 words smaller then Alain's.

Come on Ski, saved 2 words only ???

:)
-----------------

skimask
- 3rd March 2008, 15:59
13 lines is not the case ;
But, it is only 2 words smaller then Alain's.
Come on Ski, saved 2 words only ???
:)
-----------------

It's monday! What'd you expect?
Wait 'till DT comes online...
Figure maybe down to...what...25 words total? :D

Mugelpower
- 3rd March 2008, 18:41
Welcome dear ladies and gentlemen to todays code shrinking contest!

Now I testet all 3 programms and have to tell the outcome:

1.: Dear Mr. Sayzer, theres a small bug in your code, it shows only "Too High" or "Too Low"

2.: Dear Mr. Acetronic: Excellent work, runs flawlessly.

3.: Dear Mr. skimask: Full OK also !

Applause to all three contestants.

Besides: tons (ok kilos) of learning opportunities for me.

Thanks you Gurus!

Mugel

skimask
- 3rd March 2008, 19:31
CASE IS >19 AND IS <= 24
Does the AND in the CASE IS actually work?
I thought the CASE could only take one parameter to work on...

Darrel Taylor
- 4th March 2008, 05:51
It's monday! What'd you expect?
Wait 'till DT comes online...
Figure maybe down to...what...25 words total? :D

Thanks for the vote of confidence ski.

But sadly, all I could muster was a slim 335 words


<font color="#000000"><b>CMCON </b>= <font color="#800000"><b>7 </b></font><font color="#0000FF"><b><i>' Disable Comparators

</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUG_BAUD </b><font color="#800000"><b>2400 </b></font><font color="#0000FF"><b><i>'Debug baud rate
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUGIN_REG PORTB </b><font color="#0000FF"><b><i>'Debugin pin port
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUGIN_BIT </b><font color="#800000"><b>0 </b></font><font color="#0000FF"><b><i>'Debugin pin bit
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUGIN_MODE </b><font color="#800000"><b>1 </b></font><font color="#0000FF"><b><i>'Debugin mode: 0 = True, 1 = Inverted

</i></b></font><b>Uin </b><font color="#008000"><b>VAR WORD
</b></font><b>B0 </b><font color="#008000"><b>VAR BYTE
</b></font><b>BarCount </b><font color="#008000"><b>VAR BYTE
</b></font><b>BarValue </b><font color="#008000"><b>VAR WORD
</b></font><b>MsgAddr </b><font color="#008000"><b>VAR WORD
</b></font><b>Carry </b><font color="#008000"><b>VAR </b></font><b>STATUS</b>.<font color="#800000"><b>0 </b></font><font color="#0000FF"><b><i>; Hardware carry flag

</i></b></font><font color="#008000"><b>GOTO </b></font><b>Main </b><font color="#0000FF"><b><i>; Jump over data
;================================================= ============================
</i></b></font><b>BarSteps</b>: <b>POKECODE </b><font color="#800000"><b>10</b></font>,<font color="#800000"><b>15</b></font>,<font color="#800000"><b>19</b></font>,<font color="#800000"><b>24</b></font>,<font color="#800000"><b>29</b></font>,<font color="#800000"><b>34</b></font>,<font color="#800000"><b>43</b></font>,<font color="#800000"><b>53</b></font>,<font color="#800000"><b>62</b></font>,<font color="#800000"><b>72</b></font>,<font color="#800000"><b>81</b></font>,<font color="#800000"><b>86</b></font>,<font color="#800000"><b>91</b></font>,<font color="#800000"><b>96</b></font>,<font color="#800000"><b>100</b></font>,<font color="#800000"><b>105
</b></font><b>_BarSteps </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; create a PBP constant that points to the Table

</i></b></font><b>TooLow</b>: <b>POKECODE </b><font color="#800000"><b>$FE</b></font>,<font color="#800000"><b>1</b></font>,<font color="#FF0000">&quot;TOO LOW &quot;</font>,<font color="#800000"><b>0
</b></font><b>_TooLow </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; PBP constant pointing to the &quot;Too Low &quot; string

</i></b></font><b>TooRich</b>: <b>POKECODE </b><font color="#800000"><b>$FE</b></font>,<font color="#800000"><b>$C0</b></font>,<font color="#FF0000">&quot;TOO RICH&quot;</font>,<font color="#800000"><b>0
</b></font><b>_TooRich </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; PBP constant pointing to the &quot;Too Rich&quot; string

</i></b></font><b>FlashSize </b><font color="#008000"><b>CON </b></font><b>EXT
</b><font color="#008000"><b>ASM
</b></font><font color="#000080">ifdef BSR
FlashSize = 2 </font><font color="#0000FF"><b><i>; 18F has byte addressing (2)
</i></b></font><font color="#000080">else
FlashSize = 1 </font><font color="#0000FF"><b><i>; 12F/16F has words (1)
</i></b></font><font color="#000080">endif
</font><font color="#008000"><b>ENDASM

</b></font><b>MidChar </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; MidChar is the border between
</i></b></font><font color="#000080">@MidChar = 8 * FlashSize </font><font color="#0000FF"><b><i>; 8 char segments of the 1x16 LCD being used

;================================================= ============================
</i></b></font><b>Main</b>:
<font color="#008000"><b>DEBUGIN </b></font>[<b>Uin</b>.<b>LowByte</b>] <font color="#0000FF"><b><i>; Serial Input
</i></b></font><b>Uin </b>= <b>Uin </b>*/ <font color="#800000"><b>124 </b></font><font color="#0000FF"><b><i>; same as (* 100 / 207)
</i></b></font><font color="#008000"><b>LCDOUT </b></font><font color="#800000"><b>$FE</b></font>, <font color="#800000"><b>2 </b></font><font color="#0000FF"><b><i>; LCD Home Cursor

</i></b></font><font color="#008000"><b>FOR </b></font><b>BarCount </b>= <font color="#800000"><b>0 </b></font><font color="#008000"><b>TO </b></font>(<font color="#800000"><b>15 </b></font>* <b>FlashSize</b>) <font color="#008000"><b>STEP </b></font><b>FlashSize
</b><font color="#008000"><b>IF </b></font>(<b>BarCount </b>= <b>MidChar</b>) <font color="#008000"><b>THEN LCDOUT </b></font><font color="#800000"><b>$FE</b></font>,<font color="#800000"><b>$C0 </b></font><font color="#0000FF"><b><i>; Second half of 1x16 LCD
</i></b></font><b>PEEKCODE </b>(<b>_BarSteps</b>+<b>BarCount</b>),<b>BarValue </b><font color="#0000FF"><b><i>; Get BarValue from Table
</i></b></font><b>R0</b>.<b>LowByte </b>= <b>Uin</b>.<b>LowByte </b>- <b>BarValue
</b><font color="#008000"><b>IF </b></font><b>Carry </b><font color="#008000"><b>THEN </b></font><font color="#0000FF"><b><i>; Uin &gt;= BarValue
</i></b></font><font color="#008000"><b>LCDOUT </b></font><font color="#800000"><b>255 </b></font><font color="#0000FF"><b><i>; show a Full char
</i></b></font><font color="#008000"><b>ELSE </b></font><font color="#0000FF"><b><i>; Uin &lt; BarValue
</i></b></font><font color="#008000"><b>LCDOUT </b></font><font color="#FF0000">&quot; &quot; </font><font color="#0000FF"><b><i>; show a blank
</i></b></font><font color="#008000"><b>ENDIF
NEXT </b></font><b>BarCount

R0</b>.<b>LowByte </b>= <b>Uin</b>.<b>LowByte </b>- <font color="#800000"><b>10 </b></font><font color="#0000FF"><b><i>; if Uin &lt; 10
</i></b></font><font color="#008000"><b>IF </b></font>!<b>Carry </b><font color="#008000"><b>THEN </b></font><b>MsgAddr </b>= <b>_TooLow </b>: <font color="#008000"><b>GOSUB </b></font><b>ShowMsg

R0</b>.<b>LowByte </b>= <b>Uin</b>.<b>LowByte </b>+ <font color="#800000"><b>145 </b></font><font color="#0000FF"><b><i>; if Uin &gt; 110
</i></b></font><font color="#008000"><b>IF </b></font><b>Carry </b><font color="#008000"><b>THEN </b></font><b>MsgAddr </b>= <b>_TooRich </b>: <font color="#008000"><b>GOSUB </b></font><b>ShowMsg
</b><font color="#008000"><b>GOTO </b></font><b>Main

</b><font color="#0000FF"><b><i>;================================================= ============================
</i></b></font><b>ShowMsg</b>:
<b>PEEKCODE MsgAddr</b>, <b>B0
</b><font color="#008000"><b>IF </b></font><b>B0 </b>= <font color="#800000"><b>0 </b></font><font color="#008000"><b>THEN RETURN
LCDOUT </b></font><b>B0
MsgAddr </b>= <b>MsgAddr </b>+ <b>FlashSize
</b><font color="#008000"><b>GOTO </b></font><b>ShowMsg
</b>

cheers,

Mugelpower
- 4th March 2008, 08:01
Hi Darrel,

looks impressive to me like a motorcycle to a small boy.....

Whats this command:

Uin = Uin */ 124 ; same as (* 100 / 207)

|
|
|
the above means two mathematic orders in one? something like shifting bits?

there would be a small mistake but thats totally acceptable because the bargraph is that crude which is really fine enough.

will test that of course although there should be no need.....

regards

Mugel

Darrel Taylor
- 4th March 2008, 12:38
The */ operator first multiplies the 2 values (Uin * 124).
Then it discards the low byte, and returns the rest.
So effectively, it divides the result by 256, without having to do the divide part.

100 / 207 = 0.48309178
124 / 256 = 0.484375 ; not exact, but pretty close

You're correct that there are small differences between the 2 formulas, but the error is less than +/- 1. And, you will never see a difference with the resolution of a 16 block bargraph.

And, there probably is a need to test it.
I was using a 16F877 with a 4x20 LCD. Could have missed something for your 16F628A and 1x16 LCD.
<br>

Acetronics2
- 4th March 2008, 12:55
Hi, Darrel

Could you tell us for LCD Initialization at powerup ...If Uin first value is > 10 ... I do not see any ???

you just suppose exhaust is air filled ???

Alain

Darrel Taylor
- 4th March 2008, 13:06
I'm not sure what you mean Alain.

If the first value is > 10, it will just draw the bargraph like normal.
It doesn't do anything until a serial byte is received.
<br>

Acetronics2
- 4th March 2008, 14:32
I'm not sure what you mean Alain.

If the first value is > 10, it will just draw the bargraph like normal.
It doesn't do anything until a serial byte is received.
<br>

Hi,Darrel

What I ment is you initialize the LCD ... ONLY if the value is < 10 ... ( when writing TOO LOW )

What if you stop the engine and start it again ??? ... first value will be > 10 , due to the exhaust gases still in the exhaust tubing ... and I do not see any LCDOUT $FE,1 in this figure.

Alain

skimask
- 4th March 2008, 14:52
What if you stop the engine and start it again ??? ... first value will be > 10 , due to the exhaust gases still in the exhaust tubing ... and I do not see any LCDOUT $FE,1 in this figure.
Alain

Exhaust gases might still be in the tubing, but I wonder how quickly the sensor will cool off and not make a decent output. In my experience, those things cool off fairly quick. But then again, the 3/4 wire ones heat up pretty fast too...

Mugelpower
- 4th March 2008, 15:32
Hi Guys,

now thats stuff Iīm into ! Those lambda probes are reacting pretty fast when hot, about the whole scale from too lean to too rich in half a second . Reliable results will be in after about half a minute with a cold engine starting when using 4 wire probes, 2 minutes or more with one wire probes and those one wire probes without heating are useless for idle control, heats too low. You can see lots of hidden stuff like choke or accelerator pump work or fuel cutoff when stepping off the gas. Funny to watch but most times absolut neccessary for the first setup.

Darrel Taylor
- 4th March 2008, 21:30
What I ment is you initialize the LCD ... ONLY if the value is < 10 ... ( when writing TOO LOW )

What if you stop the engine and start it again ??? ... first value will be > 10 , due to the exhaust gases still in the exhaust tubing ... and I do not see any LCDOUT $FE,1 in this figure.

Oh, you mean the "Clear Screen".
Since it writes to all 16 characters on each pass, I used "Home Cursor" ($FE,2) instead of "Clear Screen" ($FE,1) to prevent blinking of the display during updates.

Or, if you're referring to the Power-On initialization that gets rid of the black blocks and makes the LCD work in the first place .... Mugel didn't have any specific initialization sequences in his original program and reported it to be working. So I assumed his display didn't need it.

The first character sent to the LCD will cause PBP to initialize the display (if it hasn't already). It doesn't have to be $FE,1.
<br>

paul borgmeier
- 5th March 2008, 08:03
A Different Approach (317 Words ... without most of Darrel's amazing methods, which means there is room for more codesavings)


;@__config _XT_OSC & _WDT_ON & _MCLRE_ON & _LVP_OFF & _CP_OFF
CMCON=%00000111
DEFINE DEBUG_BAUD 2400 'Debug baud rate
DEFINE DEBUGIN_REG PORTB 'Debugin pin port
DEFINE DEBUGIN_BIT 0 'Debugin pin bit
DEFINE DEBUGIN_MODE 1 'Debugin mode: 0 = True, 1 = Inverted

;DEFINE OSC 4

xB0 var byte ; SERIAL IN IS A BYTE SO MAKE IT A BYTE
;inputData var word ' variable to receive data into

' START OF MAIN PROGRAM
'
CMCON = 7 ' RA0-RA3 are digital I/O
TRISA = 0 ' PORT A is output
TRISB = 1 ' RB0 is Input others output

MAIN:

DEBUGin [xB0]

;B0 = 100 * B0 ; why do these two lines? B0 is already a Byte so work with Bytes
;Uin = B0 / 207 ;

LCDOUT $FE, 1

If xB0 < 21 then
LCDOUT "TOO LOW"
GOTO OUT
ENDIF

IF xB0 < 34 then BARGRAPH1
IF xB0 < 42 then BARGRAPH2
IF xB0 < 52 then BARGRAPH3
IF xB0 < 63 then BARGRAPH4
IF xB0 < 73 then BARGRAPH5
IF xB0 < 92 then BARGRAPH6
IF xB0 < 112 then BARGRAPH7
IF xB0 < 131 then BARGRAPH8

LCDOUt $FE, $C0

IF xB0 < 152 then BARGRAPH9
IF xB0 < 170 then BARGRAPH10
IF xB0 < 181 then BARGRAPH11
IF xB0 < 191 then BARGRAPH12
IF xB0 < 201 then BARGRAPH13
IF xB0 < 210 then BARGRAPH14
IF xB0 < 220 then BARGRAPH15
IF xB0 < 230 then BARGRAPH16

LCDOUT $FE,$C0,"TOO RICH"

goto OUT

BARGRAPH16:
gosub p255
BARGRAPH15:
gosub p255
BARGRAPH14:
gosub p255
BARGRAPH13:
gosub p255
BARGRAPH12:
gosub p255
BARGRAPH11:
gosub p255
BARGRAPH10:
gosub p255
BARGRAPH9:
gosub p255

LCDOUT $FE, $80 ; line 1

BARGRAPH8:
gosub p255
BARGRAPH7:
gosub p255
BARGRAPH6:
gosub p255
BARGRAPH5:
gosub p255
BARGRAPH4:
gosub p255
BARGRAPH3:
gosub p255
BARGRAPH2:
gosub p255
BARGRAPH1:
gosub p255

OUT:
Pause 5
goto MAIN

p255:
lcdout 255
return


END ' End of program


untested

Darrel Taylor
- 5th March 2008, 11:56
Good one Paul.

Completely different way, and saved 18 words.

And you're right. The multiplication uses a lot of code space.
So I thought I'd remove it from my last version too and see what happened.

268 words :)
<font color="#000000"><b>CMCON </b>= <font color="#800000"><b>7 </b></font><font color="#0000FF"><b><i>' Disable Comparators

</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUG_BAUD </b><font color="#800000"><b>2400 </b></font><font color="#0000FF"><b><i>'Debug baud rate
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUGIN_REG PORTB </b><font color="#0000FF"><b><i>'Debugin pin port
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUGIN_BIT </b><font color="#800000"><b>0 </b></font><font color="#0000FF"><b><i>'Debugin pin bit
</i></b></font><font color="#008000"><b>DEFINE </b></font><b>DEBUGIN_MODE </b><font color="#800000"><b>1 </b></font><font color="#0000FF"><b><i>'Debugin mode: 0 = True, 1 = Inverted

</i></b></font><b>Uin </b><font color="#008000"><b>VAR BYTE
</b></font><b>B0 </b><font color="#008000"><b>VAR BYTE
</b></font><b>BarCount </b><font color="#008000"><b>VAR BYTE
</b></font><b>BarValue </b><font color="#008000"><b>VAR WORD
</b></font><b>MsgAddr </b><font color="#008000"><b>VAR WORD
</b></font><b>Carry </b><font color="#008000"><b>VAR </b></font><b>STATUS</b>.<font color="#800000"><b>0 </b></font><font color="#0000FF"><b><i>; Hardware carry flag

</i></b></font><font color="#008000"><b>GOTO </b></font><b>Main </b><font color="#0000FF"><b><i>; Jump over data
;================================================= ============================
</i></b></font><b>BarSteps</b>: <b>POKECODE </b><font color="#800000"><b>22</b></font>,<font color="#800000"><b>33</b></font>,<font color="#800000"><b>41</b></font>,<font color="#800000"><b>51</b></font>,<font color="#800000"><b>62</b></font>,<font color="#800000"><b>72</b></font>,<font color="#800000"><b>91</b></font>,<font color="#800000"><b>111</b></font>,<font color="#800000"><b>130</b></font>,<font color="#800000"><b>151</b></font>,<font color="#800000"><b>169</b></font>,<font color="#800000"><b>180</b></font>,<font color="#800000"><b>190</b></font>,<font color="#800000"><b>200</b></font>,<font color="#800000"><b>209</b></font>,<font color="#800000"><b>219
</b></font><b>_BarSteps </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; create a PBP constant that points to the Table

</i></b></font><b>TooLow</b>: <b>POKECODE </b><font color="#800000"><b>$FE</b></font>,<font color="#800000"><b>1</b></font>,<font color="#FF0000">&quot;TOO LOW &quot;</font>,<font color="#800000"><b>0
</b></font><b>_TooLow </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; PBP constant pointing to the &quot;Too Low &quot; string

</i></b></font><b>TooRich</b>: <b>POKECODE </b><font color="#800000"><b>$FE</b></font>,<font color="#800000"><b>$C0</b></font>,<font color="#FF0000">&quot;TOO RICH&quot;</font>,<font color="#800000"><b>0
</b></font><b>_TooRich </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; PBP constant pointing to the &quot;Too Rich&quot; string

</i></b></font><b>FlashSize </b><font color="#008000"><b>CON </b></font><b>EXT
</b><font color="#008000"><b>ASM
</b></font><font color="#000080">ifdef BSR
FlashSize = 2 </font><font color="#0000FF"><b><i>; 18F has byte addressing (2)
</i></b></font><font color="#000080">else
FlashSize = 1 </font><font color="#0000FF"><b><i>; 12F/16F has words (1)
</i></b></font><font color="#000080">endif
</font><font color="#008000"><b>ENDASM

</b></font><b>MidChar </b><font color="#008000"><b>CON </b></font><b>EXT </b><font color="#0000FF"><b><i>; MidChar is the border between
</i></b></font><font color="#000080">@MidChar = 8 * FlashSize </font><font color="#0000FF"><b><i>; 8 char segments of the 1x16 LCD being used

</i></b></font><b>CountLength </b><font color="#008000"><b>CON </b></font><b>EXT
</b><font color="#000080">@CountLength = 15 * FlashSize

</font><font color="#0000FF"><b><i>;================================================= ============================
</i></b></font><b>Main</b>:
<font color="#008000"><b>DEBUGIN </b></font>[<b>Uin</b>] <font color="#0000FF"><b><i>; Serial Input
</i></b></font><font color="#008000"><b>LCDOUT </b></font><font color="#800000"><b>$FE</b></font>, <font color="#800000"><b>2 </b></font><font color="#0000FF"><b><i>; LCD Home Cursor

</i></b></font><font color="#008000"><b>FOR </b></font><b>BarCount </b>= <font color="#800000"><b>0 </b></font><font color="#008000"><b>TO </b></font><b>CountLength </b><font color="#008000"><b>STEP </b></font><b>FlashSize
</b><font color="#008000"><b>IF </b></font>(<b>BarCount </b>= <b>MidChar</b>) <font color="#008000"><b>THEN LCDOUT </b></font><font color="#800000"><b>$FE</b></font>,<font color="#800000"><b>$C0 </b></font><font color="#0000FF"><b><i>; Second half of 1x8 LCD
</i></b></font><b>PEEKCODE </b>(<b>_BarSteps</b>+<b>BarCount</b>),<b>BarValue </b><font color="#0000FF"><b><i>; Get BarValue from Table
</i></b></font><b>R0</b>.<b>LowByte </b>= <b>Uin </b>- <b>BarValue
</b><font color="#008000"><b>IF </b></font><b>Carry </b><font color="#008000"><b>THEN </b></font><font color="#0000FF"><b><i>; Uin &gt; BarValue
</i></b></font><font color="#008000"><b>LCDOUT </b></font><font color="#800000"><b>255 </b></font><font color="#0000FF"><b><i>; show a Full char
</i></b></font><font color="#008000"><b>ELSE </b></font><font color="#0000FF"><b><i>; Uin &lt;= BarValue
</i></b></font><font color="#008000"><b>LCDOUT </b></font><font color="#FF0000">&quot; &quot; </font><font color="#0000FF"><b><i>; show a blank
</i></b></font><font color="#008000"><b>ENDIF
NEXT </b></font><b>BarCount

R0</b>.<b>LowByte </b>= <b>Uin </b>- <font color="#800000"><b>22 </b></font><font color="#0000FF"><b><i>; if Uin &lt; 22
</i></b></font><font color="#008000"><b>IF </b></font>!<b>Carry </b><font color="#008000"><b>THEN </b></font><b>MsgAddr </b>= <b>_TooLow </b>: <font color="#008000"><b>GOSUB </b></font><b>ShowMsg

R0</b>.<b>LowByte </b>= <b>Uin </b>+ <font color="#800000"><b>29 </b></font><font color="#0000FF"><b><i>; if Uin &gt; 227
</i></b></font><font color="#008000"><b>IF </b></font><b>Carry </b><font color="#008000"><b>THEN </b></font><b>MsgAddr </b>= <b>_TooRich </b>: <font color="#008000"><b>GOSUB </b></font><b>ShowMsg
</b><font color="#008000"><b>GOTO </b></font><b>Main

</b><font color="#0000FF"><b><i>;================================================= ============================
</i></b></font><b>ShowMsg</b>:
<b>PEEKCODE MsgAddr</b>, <b>B0
</b><font color="#008000"><b>IF </b></font><b>B0 </b>= <font color="#800000"><b>0 </b></font><font color="#008000"><b>THEN RETURN
LCDOUT </b></font><b>B0
MsgAddr </b>= <b>MsgAddr </b>+ <b>FlashSize
</b><font color="#008000"><b>GOTO </b></font><b>ShowMsg
</b><font color="#008000"><b>RETURN
</b></font>

sayzer
- 5th March 2008, 12:15
Good one Paul.

Completely different way, and saved 18 words.

And you're right. The multiplication uses a lot of code space.
So I thought I'd remove it from my last version too and see what happened.
...

"TOO " is used twice. This could be arranged to save a few words more.

:>)