Code optimization help if you have some spare time :)
I have created a sub and need help trimming it down a bit.
The sub takes a byte and splits it up to show on an LCD. I don't want leading 0's so I had to add more code into it which took up alot of programming space. If you have some spare time, could you help optimize this code a bit please [noparse]:)[/noparse]
Thanks!
The sub takes a byte and splits it up to show on an LCD. I don't want leading 0's so I had to add more code into it which took up alot of programming space. If you have some spare time, could you help optimize this code a bit please [noparse]:)[/noparse]
store:
temp1 = __PARAM1
temp3 = __PARAM2
temp4 = __PARAM3
cmd = __PARAM4
temp5 = 0
digit1:
temp1 = temp1 / 100
temp2 = __REMAINDER
IF temp1 = 0 THEN
temp5 = 0
GOTO digit2
ELSE
temp5 = 1
ENDIF
temp1 = temp1 + "0"
IF temp4 = 2 THEN
PUT line2(temp3), temp1
ELSE
PUT line1(temp3), temp1
ENDIF
INC temp3
digit2:
temp1 = temp2 / 10
temp2 = __REMAINDER
IF temp5 = 0 THEN
IF temp1 = 0 THEN
temp5 = 0
GOTO digit3
ELSE
temp5 = 1
ENDIF
ENDIF
temp1 = temp1 + "0"
IF temp4 = 2 THEN
PUT line2(temp3), temp1
ELSE
PUT line1(temp3), temp1
ENDIF
INC temp3
digit3:
temp1 = temp2 + "0"
IF temp4 = 2 THEN
PUT line2(temp3), temp1
ELSE
PUT line1(temp3), temp1
ENDIF
IF cmd <> 0 THEN
FOR idx = 1 to cmd
INC temp3
IF temp4 = 2 THEN
PUT line2(temp3), "0"
ELSE
PUT line1(temp3), "0"
ENDIF
NEXT
ENDIF
RETURN
Thanks!

Comments
temp1 = temp2 / 10
You will find a LOT of code is generated for division. In fact, if you are using division, multiplication or modulo anywhere in your application, wrap 'em into a subroutine and you will find huge amounts of code space freed up, e.g.
' Use -- result = MATH_DIV word|byte, word|byte ' when mixing word and byte, the WORD comes first... ' tmpW1 and 2 are word vars FUNC MATH_DIV IF __PARAMCNT = 2 THEN tmpW1 = __PARAM1 tmpW2 = __PARAM2 ELSEIF __PARAMCNT = 3 THEN tmpW1 = __WPARAM12 tmpW2 = __PARAM3 ELSE tmpW1 = __WPARAM12 tmpW2 = __WPARAM34 ENDIF tmpW1 = tmpW1 / tmpW2 RETURN tmpW1 ENDFUNC▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
result = MATH_DIV 255, 100
rrem = __PARAM2
But....now my display is putting strange characters in place of what used to be numbers if I did it the old fashion way. The reason I need to get this working is because I cannot fit anything else on the chip and I need more room. There are only 2 divide functions through the entire code but any little bit will help.
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
Post Edited (Zoot) : 2/22/2009 5:57:35 PM GMT
In any case, __REMAINDER is available in both 1.51.x and 2.x of SX/B -- I just don't recall which param is actually assigned, SO DON'T USE __PARAMx, use __REMAINDER as this will keep your code compatible down the road.
Oh, and until I refreshed myself I forgot about __WREMAINDER (which will have an automatically assigned _LSB and _MSB). But I don't think you need that here as you have byte division going on?
To wit:
Even if you have it wrapped in a sub/func, it will be fine, as long as you save/use the __REMAINDER immediately upon return from the sub/func (because subsequent SX/B intructions may clobber that param variable).
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
FUNC MATH_DIV IF __PARAMCNT < 4 THEN __PARAM4 = 0 IF __PARAMCNT < 3 THEN __PARAM3 = __PARAM2 __PARAM2 = 0 ENDIF ENDIF \CLC \RR __PARAM4 \RR __PARAM3 tmpW1 = tmpW1 + __WPARAM34 tmpW1 = tmpW1 / tmpW2 RETURN tmpW1 ENDFUNC▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
Will this code work with numbers higher than 99? I would also need to leave out leading 0's so I guess this would be a simple IF statement. The way my function is designed, it splits the Byte down, number by number, removes leading 0's, then it stores the individual numbers into an array. Later in the code, the Array is sent to another sub to display on the LCD. Would storing hex in place of the array mess it up?
Here is an example of how it works now :
PUT Line1, "This is Line 1 "
PUT Line2, "Var : "
MyVar = 220
store MyVar, 6, 2, 1
UPDATE_L1
UPDATE_L2
The LCD would then show :
This is Line 1
Var : 2200
SX/B 2.0 has a new feature called STR that will do the "splitting" of numbers for you.
And no, it only does two digits, but just call it twice. Second, if you are dumping conversion to LCD, I see no reason to "store" the values; just convert on the fly and dump them and move on. Array code will consume a lot of space quickly. Here is a simple, pseudo-codish version of using above to send a 4 digit HEX "value" to LCD....
So, what about decimal numbers? Well, divide and dump as you go.
If you want to suppress leading zeros, you can parse that as you get each byte and decide what to do (move the cursor over a postion, etc). You can also rewrite LCD_HEX2 do to one character at a time and automatically advance the display char position (which is what I would prob. do, but it depends on what kind of stuff you might send). You also don't need to do a read; you can just use the "add to zero" method....
▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔
When the going gets weird, the weird turn pro. -- HST
1uffakind.com/robots/povBitMapBuilder.php
1uffakind.com/robots/resistorLadder.php
What you'll find is that it uses the new STR instruction which you can use and simply copy characters from the nStr() array to your line array. Note that the 100s digit (or a space) ends up in nStr(0), the 10s (or space) in nStr(1), and the 1s in nStr(2). If you want to print without the spaces you'll have the test the value and advance the index into the nStr() array to skip past the spaces.
Post Edited (JonnyMac) : 2/24/2009 4:26:06 AM GMT
Am I using the wrong editor? I have version 3.2.92h Beta
-- C:\Program Files\Parallax Inc\SX-Key v3.2.3\Compilers\SXB
Here is some that are used for EEprom access :
PUT_EE: IF __PARAMCNT = 3 THEN ' write one byte tmpW1 = __WPARAM12 temp1 = __PARAM3 i2cMulti = 0 ELSE tmpW1 = __WPARAM12 temp1 = __PARAM3 temp2 = __PARAM4 i2cMulti = 1 ENDIF I2C_START I2C_OUT SlaveWr ' send slave ID I2C_OUT tmpW1_MSB ' send address, high byte I2C_OUT tmpW1_LSB ' send address, low byte I2C_OUT temp1 ' send data byte IF i2cMulti = 1 THEN I2C_OUT temp2 ' send second data byte ENDIF I2C_STOP ' finish DO ' let write cycle finish I2C_START I2C_OUT SlaveWr LOOP UNTIL ackNak = Ack RETURN FUNC Div temp1 = __PARAM1 temp2 = __PARAM2 temp1 = temp1 / temp2 temp2 = __REMAINDER RETURN temp1, temp2 ENDFUNC FUNC PUT_DIGIT temp1 = __PARAM1 ' copy value LOOKUP temp1, $3F,$06,$5B,$4F,$66,$5E,$79, temp1 RETURN temp1 ENDFUNC FUNC GET_EE tmpW1 = __WPARAM12 I2C_START I2C_OUT SlaveWr ' send slave ID I2C_OUT tmpW1_MSB ' send address, high byte I2C_OUT tmpW1_LSB ' send address, low byte I2C_START I2C_OUT SlaveRd temp1 = I2C_IN Nak I2C_STOP RETURN temp1 ENDFUNC SUB I2C_START I2CSTART SDA ENDSUB SUB I2C_STOP I2CSTOP SDA ENDSUB SUB I2C_OUT I2CSEND SDA, __PARAM1, ackNak ENDSUB FUNC I2C_IN ackNak = __PARAM1.0 I2CRECV SDA, __PARAM1, ackNak ENDFUNC FUNC RX_BYTE SERIN RX, Baud, temp1 RETURN temp1 ENDFUNC FUNC load_eprom eeAddr = __PARAM1 eeIn = GET_EE eeAddr wait 50 RETURN eeIn ENDFUNCeeAddr will never be higher than 255 and the value to be stored will never be higher than 255. I have tried to convert it to use Bytes, but once completed, no values are ever returned or saved [noparse]:([/noparse]
' Use: I2C_START ' -- generates I2C start condition on SDA/SCL pins SUB I2C_START I2CSTART SDA ENDSUB ' ------------------------------------------------------------------------- ' Use: I2C_STOP ' -- generates I2C stop condition on SDA/SCL pins SUB I2C_STOP I2CSTOP SDA ENDSUB ' ------------------------------------------------------------------------- ' Use: { ackResult = } I2C_OUT byteVal ' -- writes "byteVal" to SDA pin ' -- affects global var "ackNak" ' -- may be used like a subroutine FUNC I2C_OUT I2CSEND SDA, __PARAM1, ackNak __PARAM1 = ackNak ENDFUNC ' ------------------------------------------------------------------------- ' Use: byteVal = I2C_IN AckBit ' -- reads "byteVal" from SDA pin FUNC I2C_IN ackNak = __PARAM1.0 I2CRECV SDA, __PARAM1, ackNak ENDFUNC ' ------------------------------------------------------------------------- ' Use: WRITE_EE address, value ' -- "address" is a word (compiler promoted if necessary) ' -- "value" is a byte SUB WRITE_EE wrAddr VAR tmpW1 wrValue VAR tmpB1 IF __PARAMCNT = 2 THEN wrAddr = __PARAM1 wrValue = __PARAM2 ELSE wrAddr = __WPARAM12 wrValue = __PARAM3 ENDIF I2C_START I2C_OUT SlaveWr I2C_OUT wrAddr_MSB ' send address, high byte I2C_OUT wrAddr_LSB ' send address, low byte I2C_OUT wrValue ' send data byte I2C_STOP ' finish '{$IFDEF EEWAIT} DO ' let write cycle finish I2C_START I2C_OUT SlaveWr LOOP UNTIL ackNak = Ack '{$ENDIF} ENDSUB ' ------------------------------------------------------------------------- ' Use: value = READ_EE address ' -- reads "value" from EEPROM location "address" FUNC READ_EE rdAddr VAR tmpW1 rdResult VAR tmpB1 IF __PARAMCNT = 1 THEN rdAddr = __PARAM1 ELSE rdAddr = __WPARAM12 ENDIF I2C_START I2C_OUT SlaveWr I2C_OUT rdAddr_MSB ' send address, high byte I2C_OUT rdAddr_LSB ' send address, low byte I2C_START ' restart for read I2C_OUT SlaveRd rdResult = I2C_IN Nak I2C_STOP RETURN rdResult ENDFUNC' Use: WRITE_EE address, value ' -- "address" is a byte ' -- "value" is a byte SUB WRITE_EE wrAddr VAR tmpB1 wrValue VAR tmpB2 wrAddr = __PARAM1 wrValue = __PARAM2 I2C_START I2C_OUT SlaveWr I2C_OUT $00 I2C_OUT wrAddr I2C_OUT wrValue I2C_STOP '{$IFDEF EEWAIT} DO I2C_START I2C_OUT SlaveWr LOOP UNTIL ackNak = Ack '{$ENDIF} ENDSUB ' ------------------------------------------------------------------------- ' Use: value = READ_EE address ' -- reads "value" from EEPROM location "address" ' -- "address" is a byte FUNC READ_EE rdAddr VAR tmpB1 rdResult VAR tmpB2 rdAddr = __PARAM1 I2C_START I2C_OUT SlaveWr I2C_OUT $00 I2C_OUT rdAddr I2C_START I2C_OUT SlaveRd rdResult = I2C_IN Nak I2C_STOP RETURN rdResult ENDFUNCYou never did say what resolution you need and how often you need it. The ISR code I posted was, essentially, a background version of the COUNT command (by using the ISR we could send and receive serial at the same time).
You might try this to get RPM in units of 100:
The downside is that this holds the program for 0.6 seconds and this might be a problem.
It would be really helpful if you would post your program -- doing this piecemeal is really difficult. What the heck, you're asking for free consulting, anyway, you might as well go all the way and end up with a better product to sell.