"Left-Shifting" more significant bits in a word?

travis75

New Member
Greetings. I have a serial servo controller that accepts numbers between 500 and 5500 to control the high pulse sent to the servos. I want to use arithmetic to generate words in that range, which won't be a big deal. However, the word that is sent to the servo controller is in the form of two bytes where bit 7 (MSB) of each must be 0. The controller concatenates the 7 bit bytes to get the position word. Since the picaxe's words are 2 8-bit bytes, generating a word bigger than 127 has a chance to make the LSB's msb 1, which kills the controller, i need a way to shift all bits past bit 6 to the "left" one space and make bit 7 a 0.


for example, we have the picaxe generate a 0d5000 (represented in binary):

00010011 10001000

Notice how bit 7 is a 1... this cannot do

what i need is for a 0 to be shoved into bit 7, pushing the displaced bits to the left:

00100111 00001000

...the same number(as seen by the servo controller, as it ignores the msb of each byte)

I could probably bruteforce this, but i am on a Picaxe 18 with only around 50 bytes of prog. space left. If anyone knows of an efficient way of shifting those bits, any help would be greatly appreciated.

Thanks,
travis75
 

BCJKiwi

Senior Member
First thought would be to build a routine based around the info on Manual2 page19 & 21

1. Start with the Leftbyte (on your post) and multiply by 2 to shift it all to the left one bit leaving a zero in the rightmost bit.
2. Test the right byte using using say an AND on the leftmost bit.

If the result contains a number > 0 then you have a 1 in the left most bit.
3. Change this bit to a 0
4. Change the rightmost bit of the leftbyte to a 1

Else leave the LeftByte with the 0 in the rightmost bit.
5. multiply the rightbyte by 2 to shift it to the left one bit.

Not sure myself without testing exactly which functions to use where but its easy to test or one of the gurus in this area will be able to help further.
 

leftyretro

New Member
Greetings. I have a serial servo controller that accepts numbers between 500 and 5500 to control the high pulse sent to the servos. I want to use arithmetic to generate words in that range, which won't be a big deal. However, the word that is sent to the servo controller is in the form of two bytes where bit 7 (MSB) of each must be 0. The controller concatenates the 7 bit bytes to get the position word. Since the picaxe's words are 2 8-bit bytes, generating a word bigger than 127 has a chance to make the LSB's msb 1, which kills the controller, i need a way to shift all bits past bit 6 to the "left" one space and make bit 7 a 0.


for example, we have the picaxe generate a 0d5000 (represented in binary):

00010011 10001000

Notice how bit 7 is a 1... this cannot do

what i need is for a 0 to be shoved into bit 7, pushing the displaced bits to the left:

00100111 00001000

...the same number(as seen by the servo controller, as it ignores the msb of each byte)

I could probably bruteforce this, but i am on a Picaxe 18 with only around 50 bytes of prog. space left. If anyone knows of an efficient way of shifting those bits, any help would be greatly appreciated.

Thanks,
travis75
I think logic functions could be your friend. Doing an AND function between the lower byte value and hex value H80 will tell you if bit seven is a one or a zero. If it's a one you then can multiply the higher byte value by 2 and then add one to that higher byte. It it's a zero you only have to multiply the higher byte value by 2. At least that is how I see it..
Lefty
 

travis75

New Member
Thanks for the fast responses! I'm not too big on bitwise functions like AND, so i'll cut some corners there.

This is my quick pseudo-code subroutine

Code:
'w0 is my servo pos number

shift:
if bit7 == 1{
then
b1 = b1 * 2
b1 = b1 + 1
bit7 = 0
}
return
The old "double and add" trick completely slipped my mind, i was thinking in strings.

Thanks again!
 

BCJKiwi

Senior Member
I figured you would need to multiply both bytes by two as "the MSB must be zero"

Yes, if you have the bytes in bo and b1 then the direct bit test would be simplest.

Logic still basically as I suggested before - should get all that into 50 bytes of code?!?
 

travis75

New Member
I'm working on a test program for all this... For the past 30 minutes or so it was acting erratically, until i remembered that the picaxe does not ignore the msb, therefore my counter loops would get thrown out of scope as the counter variable was being augmented! --I need to get some sleep.

Now i'm using two word vars, one to send to the servo controller, and one to use internally in loops. The whole test program is only ~65 bytes.

Thanks again for your help.
 

womai

Senior Member
untested code (I have no access to a real Picaxe right now):

' assuming that w0 (b1, b0) holds the original number

b1 = b1 * 2 ' shift most significant byte left by 1 bit

if bit7 = 1 then ' carryover from least significant byte (b0)
b1 = b1 + 1
endif

bit7 = 0 ' this bit (MSB of b0) has now been shifted into b1

' b0, b1 now hold the converted number


Wolfgang
 

travis75

New Member
The folowing code is tested, and works, albeit probably rather inefficiently.

Code:
''Simple "slow wipe" test of two servos on a Pololu SSC03A
''Test of "bit shifting" to accommodate SSC's 7-bit byte
''w0 is our servo value, and w2 is the internal counter
loop2:

let w2 = 2500

loop1:

let w0 = w2
gosub shift
serout 0,t2400,($80,$01,$04,0,b1,b0)  ''servo 0
serout 0,t2400,($80,$01,$04,1,b1,b0)  ''servo 1
pause 10
w2 = w2 + 1
if w2 = 3500 then loop2
goto loop1 
 
shift:
b1 = b1 * 2		''move the bits in MSB left one


if bit7 = 1 then
b1 = b1 + 1		''if bit 7 is 1, add it to byte1, then 0 it
bit7 = 0
endif

return
 

womai

Senior Member
As usual Hippy found the most elegant solution...

Travis, you could also combine the two serout statements into one (although I suspect that would only be useful in your test routine, but not in the final application?):

serout 0,t2400,($80,$01,$04,0,b1,b0, $80,$01,$04,1,b1,b0) ' servo 0 & 1
 

westaust55

Moderator
w5 = 5000 ; %00010011 10001000

w5 = w5 * 2 ; %00100111 00010000
b10 = b10/2 ; %00100111 00001000 ==> b10 is low byte of w5

now use value in w5 or b10 and b11
 
Top