Variable declaration using a truncated variable??

Okay. I know that title sounds a little scary, but I named it as best as I could.

I am trying to figure out the code to make Arduino declare a certain variable equal to another one that has been truncated (‘chopped’). for example:

``````int x = 3254
int xA = (first two digits of x (54 in this case))
int xB = (second two digits of x (32 in this case))
``````

I am in the process of transforming some PBASIC code (for BASIC Stamps) into Arduino code. I need this segment:

``````ldrive          VAR    drive.BYTE1
rdrive          VAR    drive.BYTE0
``````

…to be made into Arduino code. This part (‘ldrive VAR drive.BYTE1’ is saying “let ‘ldrive’ be byte register 1 of ‘drive’”). And this one (‘rdrive VAR drive.BYTE0’ is saying “let ‘rdrive’ be byte register 0 of ‘drive’”). So basically, ‘drive’ contains the information for ‘ldrive’ and ‘rdrive’, but just clumped up. HOW do I write the code for the Arduino to do the same thing that this PBASIC code is doing?? I really really really am itching to find this one out; I really need help with this one; ADMINS: Please help! I could not find anywhere on the Arduino site under ‘Reference’ how to do this!!!.

You seem to be asking for two different things here. Assuming you want to obtain the values of the two bytes in an integer, you can do:

int value = something;
char highByte = something >> 8;
char lowByte = something & 0xFF;

Note that this is not the same thing as saying

int value = 1234;
char highByte = 12;
char lowByte = 34;

but it would be the same as

int value = 0x1234;
char highByte = 0x12;
char lowByte = 0x34;

Note that this isn’t an Arduino thing, it’s a C thing. Moreover, it’s basically just a math thing. If you understand mathematically what digits in a number mean and how bases work, you should be able to do this sort of thing in any programming language using standard operators.

• Ben

You could use a union to duplicate the drive.BYTE0 construct, but I can’t for the life of me see why an obfuscation tool like that remapping would be useful.

If you must use that sort of construct, you could simulate it with a preprocessor macro, e.g.

``````#define xA (x >> 8)
``````

why not simply use the appropriate syntax, like `( x & 0xff)` for the low order byte of x?

Note that Ben’s example initializes those variables to the approriate value, but is not a “live” mapping, which is what it seems you are after.
-j

Ok. Thanks for the help guys.

I can see what you are getting at; but this is a little more advanced for me, so maybe by giving you the full code in which the ‘drive’, ‘ldrive’ and ‘rdrive’ variables are manipulated, you can better see what the prpose of what I am trying to do is. Then maybe you can explain it a little further for me so I can replicate the PBASIC code into Arduino code…? Here’s the PBASIC code I’m trying to code into Arduino syntax:

``````avdo:

LOOKUP i,[rr, rl, drive],tmp
drive = tmp
i = 0                                         'clear history

avdone:

RETURN

wander:                                          ' randomly wander around
IF wDur > 0 THEN wDone1
RANDOM seed                                    ' random direction
i = seed & %111                                ' mask off for 0-7 only
LOOKUP i,[fd,tl,fd,fd,fd,fd,tr,fd],wDir        'chose direction
seed = seed + i
wDur = (seed & %111111) + 20                   ' mask for 64 choices of duration

wDone1:
wDur = wDur - 1                                'decrement wander counter
drive = wDir                                   'get direction
RETURN                                         'completed

act:                                             ' moves servo motors
aDur = SACT                              ' times through this one
PULSOUT LEFT,ldrive * 10
PULSOUT RIGHT,rdrive * 10

RETURN
``````

I took that code from Justin R. Ratliff’s site, so credit for the design goes to him. I thought it looked like an excellent way to randomize my robot’s movements, so I decided to use it (under appropriate copyright terms, of course). I do understand this code to some extent; if you all do feel free to explain it to me because I am eventually going to need to ‘translate’ it into Arduino code. What I CAN see (among other things, of course; I understand enough of this code to see what it does) is that ‘ldrive’ and ‘rdrive’ are simply two separate parts of ‘drive’ (‘drive’ stores information on pulse width durations for the left and right servos).

Here’s the variable declarations and constants at the beginning of the program used for this code:

``````' **Servo Routines**

SACT            CON    5                                ' times through act routine
drive           VAR    Word                             ' wheel command combo
ldrive          VAR    drive.BYTE1                      ' left wheel command
rdrive          VAR    drive.BYTE0                      ' right wheel command
aDur            VAR    Byte                             ' duration of pulse left

' **Servo Drive Commands**

fd      CON    \$6432                            ' forward (left = 100 ((16*6)+4), right = 50 ((16*3)+2))
rv      CON    \$3264                            ' reverse (left = 50 ((16*3)+2), right = 100 ((16*6)+4))
st      CON    \$4b4b                            ' STOP (left = 75 ((16*4)+11), right = 75 ((16*4)+11))
tr      CON    \$644b                            ' turn right (left = 100 ((16*6)+4), right = 75 ((16*4)+11))
tl      CON    \$4b32                            ' turn left (left = 75 ((16*4)+11), right = 50 ((16*3)+2))
rr      CON    \$6464                            ' rotate right (left = 100 ((16*6)+4), right = 100 ((16*6)+4))
rl      CON    \$3232                            ' rotate left (left = 50 ((16*3)+2), right = 50 ((16*3)+2))
``````

I wrote in all that crazy math to help myself understand how the values work. When all is said and done, I want to be able to understand how this works-inside and out-so I can manipulate it to my liking. Let’s just address the var.BYTE1, var.BYTE2, etc. topic for now. Thanks for the help so far.

Like the others said (and I will repeat)

``````int drive;
byte ldrive, rdrive;
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
``````

I don’t think the cast is necessary but I’m not a programmer.

Thanks Stephen. Can you explain briefly how that code segment works? I’d like to know to fulfill my sense of curiosity.

Hmmm. I’m having some problems. The code I made isn’t working >:(

Here it is:

``````boolean irDetectLeft;
boolean irDetectCenter;
boolean irDetectRight;
byte pulseCount;
int distance;
int oldDistance;
int counter;
int micVal;
int cdsVal;
int irLval;
int irCval;
int irRval;

int i;
int tmp;
int seed;

int wDir;
byte wDur;

int LeftPin = 10;
int RightPin = 9;
int PiezoPin = 11;
int PingPin = 5;
int PingServoPin = 6;
int irLPin = 2;            // Analog 0
int irCPin = 1;            // Analog 1
int irRPin = 0;            // Analog 2

#define BAUD 9600
#define SACT 5
#define fd   0x6432                            // forward (left = 100 ((16*6)+4), right = 50 ((16*3)+2))
#define rv   0x3264                             // reverse (left = 50 ((16*3)+2), right = 100 ((16*6)+4))
#define st   0x4b4b                            // STOP (left = 75 ((16*4)+11), right = 75 ((16*4)+11))
#define tr   0x644b                            // turn right (left = 100 ((16*6)+4), right = 75 ((16*4)+11))
#define tl   0x4b32                            // turn left (left = 75 ((16*4)+11), right = 50 ((16*3)+2))
#define rr   0x6464                            // rotate right (left = 100 ((16*6)+4), right = 100 ((16*6)+4))
#define rl   0x3232                            // rotate left (left = 50 ((16*3)+2), right = 50 ((16*3)+2))
int drive;
byte ldrive, rdrive;

void setup() {
Serial.begin(9600);
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
pinMode(PiezoPin, OUTPUT);
pinMode(LeftPin, OUTPUT);
pinMode(RightPin, OUTPUT);
pinMode(irLPin, INPUT);
pinMode(irCPin, INPUT);
pinMode(irRPin, INPUT);
for(i = 0; i < 500; i++) {
digitalWrite(PiezoPin, HIGH);
delayMicroseconds(1000);
digitalWrite(PiezoPin, LOW);
delayMicroseconds(1000);
}
i = 0;
}

void loop()
{
wander();
act();
//Serial.print("Val: ");
//Serial.println(irCval);
//delay(200);
}
void avdo() {
switch(i) {
case 0:
tmp = rr;
case 1:
tmp = rl;
case 2:
tmp = drive;
}
drive = tmp;
i = 0;
}
void avdone() {
return;
}
void wander() {
if(wDir > 0) {
wDone1();
}
seed = random(seed);
i = seed & B11;
switch(i) {
case 0:
wDir = fd;
case 1:
wDir = tl;
case 2:
wDir = fd;
case 3:
wDir = fd;
case 4:
wDir = fd;
case 5:
wDir = fd;
case 6:
wDir = tr;
case 7:
wDir = fd;
}
seed = seed + i;
wDur = (seed & B111111) + 20;
}
void wDone1() {
wDur = wDur - 1;
drive = wDir;
return;
}
void act() {
}
digitalWrite(LeftPin, HIGH);
delayMicroseconds(ldrive * 10);
digitalWrite(LeftPin, LOW);
delay(20);
digitalWrite(RightPin, HIGH);
delayMicroseconds(rdrive * 10);
digitalWrite(RightPin, LOW);
delay(20);
}
}
return;
}
``````

Some part of the code must be wrong; it only sends pulses to the servo connected to pin 9. Something must be wrong with either the code structure or the bitwise math (all that ‘ldrive.BIT1’ and ‘drive >> 8’, etc.). What’s wrong?

That code should do EXACTLY the same thing as this BASIC Stamp II code:

``````' {\$STAMP BS2e}
' {\$PBASIC 2.5}

' -----[ Variables/Constants ]--------------------------------------------------------------------------------------------

i                 VAR   Byte                    ' loop counter, whatever
tmp               VAR   Word                    ' temporary holder
seed              VAR   Word                    ' random number seed

' these are for the servo routines

LEFT    CON    13                               ' left wheel port
RIGHT   CON    12                               ' right wheel port
SACT    CON    5                                ' times through act routine
drive   VAR    Word                             ' wheel command combo
ldrive  VAR    drive.BYTE1                      ' left wheel command
rdrive  VAR    drive.BYTE0                      ' right wheel command
aDur    VAR    Byte                             ' duration of pulse left

' servo drive commands

fd      CON    \$6432                            ' forward (left = 100 ((16*6)+4), right = 50 ((16*3)+2))
rv      CON    \$3264                            ' reverse (left = 50 ((16*3)+2), right = 100 ((16*6)+4))
st      CON    \$4b4b                            ' STOP (left = 75 ((16*4)+11), right = 75 ((16*4)+11))
tr      CON    \$644b                            ' turn right (left = 100 ((16*6)+4), right = 75 ((16*4)+11))
tl      CON    \$4b32                            ' turn left (left = 75 ((16*4)+11), right = 50 ((16*3)+2))
rr      CON    \$6464                            ' rotate right (left = 100 ((16*6)+4), right = 100 ((16*6)+4))
rl      CON    \$3232                            ' rotate left (left = 50 ((16*3)+2), right = 50 ((16*3)+2))

' wander values

wDir    VAR    Word 'wander value
wDur    VAR    Byte 'wander duration

Main:                                       ' The program starts here

GOSUB wander
GOSUB act

GOTO Main

avdo:

LOOKUP i,[rr, rl, drive],tmp
drive = tmp
i = 0                                         'clear history

avdone:

RETURN

wander:                                          ' randomly wander around
IF wDur > 0 THEN wDone1
RANDOM seed                                    ' random direction
i = seed & %111                                ' mask off for 0-7 only
LOOKUP i,[fd,tl,fd,fd,fd,fd,tr,fd],wDir        'chose direction
seed = seed + i
wDur = (seed & %111111) + 20                   ' mask for 64 choices of duration

wDone1:
wDur = wDur - 1                                'decrement wander counter
drive = wDir                                   'get direction
RETURN                                         'completed

act:                                             ' moves servo motors
aDur = SACT                              ' times through this one
PULSOUT LEFT,ldrive * 10
PULSOUT RIGHT,rdrive * 10

RETURN
``````

UPDATE:

I realized something: pin 8 does not do PWM. So I changed the ‘LeftPin’ value to ‘6’. I also noticed some other bugs that I fixed. Here’s the updated code:

``````boolean irDetectLeft;
boolean irDetectCenter;
boolean irDetectRight;
byte pulseCount;
int distance;
int oldDistance;
int counter;
int micVal;
int cdsVal;
int irLval;
int irCval;
int irRval;

int i;
int tmp;
int seed;

int wDir;
byte wDur;

int LeftPin = 6;
int RightPin = 9;
int PiezoPin = 11;
int PingPin = 5;
int PingServoPin = 6;
int irLPin = 2;            // Analog 0
int irCPin = 1;            // Analog 1
int irRPin = 0;            // Analog 2

#define BAUD 9600
#define SACT 5
#define fd   0x6432                            // forward (left = 100 ((16*6)+4), right = 50 ((16*3)+2))
#define rv   0x3264                             // reverse (left = 50 ((16*3)+2), right = 100 ((16*6)+4))
#define st   0x4b4b                            // STOP (left = 75 ((16*4)+11), right = 75 ((16*4)+11))
#define tr   0x644b                            // turn right (left = 100 ((16*6)+4), right = 75 ((16*4)+11))
#define tl   0x4b32                            // turn left (left = 75 ((16*4)+11), right = 50 ((16*3)+2))
#define rr   0x6464                            // rotate right (left = 100 ((16*6)+4), right = 100 ((16*6)+4))
#define rl   0x3232                            // rotate left (left = 50 ((16*3)+2), right = 50 ((16*3)+2))
int drive;
byte ldrive, rdrive;

void setup() {
Serial.begin(9600);
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
pinMode(PiezoPin, OUTPUT);
pinMode(LeftPin, OUTPUT);
pinMode(RightPin, OUTPUT);
pinMode(PingServoPin, OUTPUT);
pinMode(irLPin, INPUT);
pinMode(irCPin, INPUT);
pinMode(irRPin, INPUT);
for(i = 0; i < 500; i++) {
digitalWrite(PiezoPin, HIGH);
delayMicroseconds(1000);
digitalWrite(PiezoPin, LOW);
delayMicroseconds(1000);
}
i = 0;
}

void loop()
{
wander();
act();
//Serial.print("Val: ");
//Serial.println(irCval);
//delay(200);
}
void avdo() {
switch(i) {
case 0:
tmp = rr;
case 1:
tmp = rl;
case 2:
tmp = drive;
}
drive = tmp;
i = 0;
}
void avdone() {
return;
}
void wander() {
if(wDir > 0) {
wDone1();
}
seed = random(seed);
i = seed & B111;
switch(i) {
case 0:
wDir = fd;
case 1:
wDir = tl;
case 2:
wDir = fd;
case 3:
wDir = fd;
case 4:
wDir = fd;
case 5:
wDir = fd;
case 6:
wDir = tr;
case 7:
wDir = fd;
}
seed = seed + i;
wDur = (seed & B111111) + 20;
}
void wDone1() {
wDur = wDur - 1;
drive = wDir;
return;
}
void act() {
}
digitalWrite(LeftPin, HIGH);
delayMicroseconds(ldrive * 10);
digitalWrite(LeftPin, LOW);
delay(20);
digitalWrite(RightPin, HIGH);
delayMicroseconds(rdrive * 10);
digitalWrite(RightPin, LOW);
delay(20);
}
}
return;
}
``````

BUT- I’m still having problems with it; the servos just continuously rotate in opposite directions, never changing course like they should. They should also be spinning in the SAME direction (and switching the pins for the servos does not fix that; I tried), making minute changes to add random movement. Help!

Simplify your code. Get it working right for the simplest case you can think of and build up from there.

• Ben

`ldrive` and `rdrive` will never change values. They will be initialized to whatever garbage is in the low and high bytes of `drive` when `setup()` runs, and will never change throughout program execution.

You must execute `ldrive = (byte)(drive >>8);  rdrive = (byte)(drive & 0xff);` after assigning a new value to `drive`, every time `drive` is changed.

-j

Oh. Darn; I did mean to post that after I realized that; I DID figure that out a while ago. Here’s the new code, but it is still having the same problem

``````boolean irDetectLeft;
boolean irDetectCenter;
boolean irDetectRight;
byte pulseCount;
int distance;
int oldDistance;
int counter;
int micVal;
int cdsVal;
int irLval;
int irCval;
int irRval;

int i;
int tmp;
int seed;

int wDir;
byte wDur;

int LeftPin = 6;
int RightPin = 9;
int PiezoPin = 11;
int PingPin = 5;
int PingServoPin = 6;
int irLPin = 2;            // Analog 0
int irCPin = 1;            // Analog 1
int irRPin = 0;            // Analog 2

#define BAUD 9600
#define SACT 5
#define fd   0x6432                            // forward (left = 100 ((16*6)+4), right = 50 ((16*3)+2))
#define rv   0x3264                             // reverse (left = 50 ((16*3)+2), right = 100 ((16*6)+4))
#define st   0x4b4b                            // STOP (left = 75 ((16*4)+11), right = 75 ((16*4)+11))
#define tr   0x644b                            // turn right (left = 100 ((16*6)+4), right = 75 ((16*4)+11))
#define tl   0x4b32                            // turn left (left = 75 ((16*4)+11), right = 50 ((16*3)+2))
#define rr   0x6464                            // rotate right (left = 100 ((16*6)+4), right = 100 ((16*6)+4))
#define rl   0x3232                            // rotate left (left = 50 ((16*3)+2), right = 50 ((16*3)+2))
int drive;
byte ldrive, rdrive;

void setup() {
Serial.begin(9600);
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
pinMode(PiezoPin, OUTPUT);
pinMode(LeftPin, OUTPUT);
pinMode(RightPin, OUTPUT);
pinMode(PingServoPin, OUTPUT);
pinMode(irLPin, INPUT);
pinMode(irCPin, INPUT);
pinMode(irRPin, INPUT);
for(i = 0; i < 500; i++) {
digitalWrite(PiezoPin, HIGH);
delayMicroseconds(1000);
digitalWrite(PiezoPin, LOW);
delayMicroseconds(1000);
}
i = 0;
}

void loop()
{
wander();
act();
//Serial.print("Val: ");
//Serial.println(irCval);
//delay(200);
}
void avdo() {
switch(i) {
case 0:
tmp = rr;
break;
case 1:
tmp = rl;
break;
case 2:
tmp = drive;
break;
}
drive = tmp;
i = 0;
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
}
void avdone() {
return;
}
void wander() {
if(wDir > 0) {
wDone1();
}
seed = random(seed);
i = seed & B111;
switch(i) {
case 0:
wDir = fd;
break;
case 1:
wDir = tl;
break;
case 2:
wDir = fd;
break;
case 3:
wDir = fd;
break;
case 4:
wDir = fd;
break;
case 5:
wDir = fd;
break;
case 6:
wDir = tr;
break;
case 7:
wDir = fd;
break;
}
seed = seed + i;
wDur = (seed & B111111) + 20;
}
void wDone1() {
wDur = wDur - 1;
drive = wDir;
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
return;
}
void act() {
}
//ldrive = (byte)(drive >>8);
//rdrive = (byte)(drive & 0xff);
digitalWrite(LeftPin, HIGH);
delayMicroseconds(ldrive * 10);
digitalWrite(LeftPin, LOW);
digitalWrite(RightPin, HIGH);
delayMicroseconds(rdrive * 10);
digitalWrite(RightPin, LOW);
delay(20);
}
}
return;
}
``````

Aha! I found a problem: the timing (the pulse width for the servos) is very different from the BS2 to the Arduino. In PBASIC,

``````PULSOUT 13, 750
``````

Is the same as

``````digitalWrite(RightPin, HIGH);
delayMicroseconds(1490);
digitalWrite(RightPin, LOW);
``````

I had to tweak and do trial-and-error to find the butter zone for the pulse width to make the servos stop. I’m not sure what time scale the format is for the ‘PULSOUT, (pin), (pwm val)’ as compared to the ‘delayMicroseconds(pwm val)’ for the arduino, but I came out in the end with a scale that is 1.9866666666666666666666666666667x the BS2 pwm value, so I used that. NOW the wheels are getting the correct PWM value, but there’s one remaining problem: The random movement code isn’t working; they just continuously rotate forwards. What is left that’s wrong? Here’s the new code:

``````boolean irDetectLeft;
boolean irDetectCenter;
boolean irDetectRight;
byte pulseCount;
int distance;
int oldDistance;
int counter;
int micVal;
int cdsVal;
int irLval;
int irCval;
int irRval;

int i;
int tmp;
int seed;

int wDir;
byte wDur;

int LeftPin = 6;
int RightPin = 9;
int PiezoPin = 11;
int PingPin = 5;
int PingServoPin = 6;
int irLPin = 2;            // Analog 0
int irCPin = 1;            // Analog 1
int irRPin = 0;            // Analog 2

#define BAUD 9600
#define SACT 5
#define fd   0x6432                            // forward (left = 100 ((16*6)+4), right = 50 ((16*3)+2))
#define rv   0x3264                             // reverse (left = 50 ((16*3)+2), right = 100 ((16*6)+4))
#define st   0x4b4b                            // STOP (left = 75 ((16*4)+11), right = 75 ((16*4)+11))
#define tr   0x644b                            // turn right (left = 100 ((16*6)+4), right = 75 ((16*4)+11))
#define tl   0x4b32                            // turn left (left = 75 ((16*4)+11), right = 50 ((16*3)+2))
#define rr   0x6464                            // rotate right (left = 100 ((16*6)+4), right = 100 ((16*6)+4))
#define rl   0x3232                            // rotate left (left = 50 ((16*3)+2), right = 50 ((16*3)+2))
int drive;
byte ldrive, rdrive;
float scale;

void setup() {
Serial.begin(9600);
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
scale = (float)20 - 0.013333333333333333333333333333;
pinMode(PiezoPin, OUTPUT);
pinMode(LeftPin, OUTPUT);
pinMode(RightPin, OUTPUT);
pinMode(PingServoPin, OUTPUT);
pinMode(irLPin, INPUT);
pinMode(irCPin, INPUT);
pinMode(irRPin, INPUT);
for(i = 0; i < 500; i++) {
digitalWrite(PiezoPin, HIGH);
delayMicroseconds(1000);
digitalWrite(PiezoPin, LOW);
delayMicroseconds(1000);
}
i = 0;
}

void loop()
{
wander();
act();
//digitalWrite(LeftPin, HIGH);
//delayMicroseconds(1490);
//digitalWrite(LeftPin, LOW);
//digitalWrite(RightPin, HIGH);
//delayMicroseconds(1490);
//digitalWrite(RightPin, LOW);
//delay(20);
//Serial.print("Val: ");
//Serial.println(irCval);
//delay(200);
}
void avdo() {
switch(i) {
case 0:
tmp = rr;
break;
case 1:
tmp = rl;
break;
case 2:
tmp = drive;
break;
}
drive = tmp;
i = 0;
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
}
void avdone() {
return;
}
void wander() {
if(wDir > 0) {
wDone1();
}
seed = random(seed);
i = seed & B111;
switch(i) {
case 0:
wDir = fd;
break;
case 1:
wDir = tl;
break;
case 2:
wDir = fd;
break;
case 3:
wDir = fd;
break;
case 4:
wDir = fd;
break;
case 5:
wDir = fd;
break;
case 6:
wDir = tr;
break;
case 7:
wDir = fd;
break;
}
seed = seed + i;
wDur = (seed & B111111) + 20;
}
void wDone1() {
wDur = wDur - 1;
drive = wDir;
ldrive = (byte)(drive >>8);
rdrive = (byte)(drive & 0xff);
return;
}
void act() {
}
//ldrive = (byte)(drive >>8);
//rdrive = (byte)(drive & 0xff);
digitalWrite(LeftPin, HIGH);
delayMicroseconds((float)ldrive * scale);
digitalWrite(LeftPin, LOW);
digitalWrite(RightPin, HIGH);
delayMicroseconds((float)rdrive * scale);
digitalWrite(RightPin, LOW);
delay(20);
}