Concatenating Integer variables

Hi,

I have the following variables all declared as integers:

intNo1, intNo2, intNo3, intNo4, intNo5, intNo6, intNo7, intNo8

Each variable stores a single digit, being either 0 or 1.

I would like to concatenate the values in the above variables and store them in just one variable. For example:

intNo1 = 0
intNo2 = 1
intNo3 = 0
intNo4 = 0
intNo5 = 1
intNo6 = 1
intNo7 = 0
intNo8 = 1

intConcat = 01001101

I think this is easier to do with strings rather than integers, but for the life of me I don't know how to go about this.

Any help appreciated.
Thanks

Think of it in normal decimal numbers first. That way you can count on your fingers. Then turn it into binary later.

If you have a 1 and a 1 and you want to show this as 11, what is that number? It's eleven isn't it? Eleven is ten plus one. Ten is 1 times ten and one is just 1.

  intConcat= 10*intNo2 + intNo1

So in binary it's two. 1 times 2, 1 times 4 and so on. But I like to make the compiler do that work for me. In binary, two is 10. Notice the similarity to the decimal above?

Turning that into code...

  intConcat = 0b100*intNo3 + 0b10*intNo2 + intNo1;

Of course the input integers can only be 0 or 1, so you must add a check above this line to make sure every single one can only take one of those two values. One clever trick to do this is the not-not operation. Put a "!!" in front of each value so that the integer gets converted to a boolean, inverted, inverted back again and then the boolean is converted to an integer with the values 0 or 1.

  intConcat = 0b100*!!intNo3 + 0b10*!!intNo2 + !!intNo1;

Another option would be to use bitWrite().

Using the ternary operator.

The ternary conditional operator checks the boolean value of the first expression and, depending on the resulting value, evaluates and returns either the second if true or the third expression if false.

int intConcat = intNo1 ?  1 : 0
              | intNo2 ?  2 : 0
              | intNo3 ?  4 : 0
              | intNo4 ?  8 : 0
              | intNo5 ? 16 : 0
              | intNo6 ? 32 : 0
              | intNo7 ? 64 : 0
              | intNo8 ?128 : 0;

I think this should work but I didnt try it. I'll let you fill in between the ...

newVariable=(intNo1<<7) | (intNo2<<6)| (inNo3<<5 )| ... | intNo8<<0);

Meh. They may "look" clever, but I have my doubts whether ternary operators or "standard conversion routines" like the one involving multiply will end up being any smaller or quicker than the "obvious"

result = 0;
if (intNo1)
  result += 0b10000000;
if (intNo2)
  result += 0b01000000;
if (intNo3)
  result += 0b00100000;
if (intNo4)
  result += 0b00010000;
  :

(the "ternary operator" example should produce nearly identical code; It implements nearly exactly the same logic. But telling a beginner to go off and use one of the more obscure language features seems cruel...)

If your integers were in a nice array instead of separate variables, this could be put into a short loop...

Although the solutions offered are all worthwhile I can't help feeling that the original data may not need to be in the form presented in the first place.

With the variables having a numeric suffix the possible use of an array to hold them looks likely or they could perhaps be put directly into the bits of a byte. We know nothing of why the data needs to be transformed from one format to another but if it is merely for the purpose of printing it then is there a need to transform it in the first place I wonder ?

@Jim_cliff
Where does the data come from and why do you need to transform it ?

Thanks for the replies all, but I haven't managed to concatenate the numbers using any of the code above.

Basically, this is my situation. I have a rotary encoder with the following outputs (all LVTTL on / off):

Bit1
Bit2
Bit3
Bit4
Strobe

The encoder is in ONE of 8 positions and depending on its current position, it outputs a combination of the above. Eg. Position 2 would equal high / low on the following:

Bit1 = 0
Bit2 = 1
Bit3 = 0
Bit4 = 0
Strobe = 1

The encoder is attached to a motor and gearbox in which I'd like to control the position. For example if I wanted to move to position 8 I'd have the variables set at the following values:

RequiredBit1 = 0
RequiredBit2 = 0
RequiredBit3 = 0
RequiredBit4 = 1
RequiredStrobe = 1

I'm then using the following while statement:

while(Bit1 != RequiredBit1 && Bit2 != RequiredBit2 && Bit3 != RequiredBit3 && Bit4 != RequiredBit4 && Strobe != RequiredStrobe) {
SetBit(motordrivepin); 
	printf("running");
	CurEncoderValues();
   }
   
printf("done");
ClearBit(motordrivepin);
}

The problem is with the while statement. I was expecting the motor to kick in, winding the shaft round slowly until position 8 was met (basically until the 5 conditions all equal TRUE). Instead the code jumps over the while and prints done every time.

Exploring the issue further I believe the logical && operator is causing 'short-circuiting'. Basically if condition1 = False then the remaining 4 conditions are not evaluated. Even by using the bitwise & so all conditions are evaluated I'm still having the same problem. I expect in the above while statement ALL conditions have to be TRUE between the & for the code to execute? This would never be the case until the required position is met as a result of turning through all positions between 2 and 8 for example.

Anyway, that leads me to this concatenation post. I thought if I concatenate all 5 variable values into one variable I wouldn't have this issue. For example:

intCurrentConcat = 01001 //position 2
intRequiredConcat = 00011 //position 8

while(intCurrentConcat != intRequiredConcat) {
SetBit(motordrivepin); 
	printf("running");
	CurEncoderValues();
   }
   
printf("done");
ClearBit(motordrivepin);
}

I hope this helps you understand my requirements and issue a little better. All I need is basically to put 5 integer variables (always either 0 or 1) into a single integer variable.

Could I concatenate the integers as a string and then convert the result back to a single int?

Thanks,

Please post your code.

Jim_cliff:
Exploring the issue further I believe the logical && operator is causing 'short-circuiting'. Basically if condition1 = False then the remaining 4 conditions are not evaluated.

You have the logic wrong. To check for inequality you want to see if ANY bit does not match. By using AND instead of OR you are getting 'true' only when EVERY bit does not match. Change && to ||.

It seems to me that you are complicating things.

From your description the encoder has 4 outputs so let's label them from 0 to 3. If you read the state of each output and set the equivalent bit of a byte variable and test the value of the byte variable, then in the case of your 2 examples you would be in position 2 when the byte value was 2 and in position 8 when the byte value was 8.

However, 2 examples is not much to go on. What does the strobe pin do ?

Jim_cliff; this should change your view completely: Arduino Playground - BitMath

4 bits can be 16 values from 0 to 15. What are the -possible- encoder return values that there are only 8?

The harder they come, the harder they fall, one and all. --- Jimmy Cliff

Is your encoder one of these?
http://www.bbn.com.tw/pdf/EA40T-U.pdf

I see that even though they have 4 bits of output (16 possible combinations) they come in 8 and 12 position models.

Thanks for the valuable replies all. GoForSmoke that link you shared is interesting and critical to what I'm doing.

The datasheet for the encoder I'm using is attached. Yes it's old, and it is 24vdc. All of its outputs I've brought down to LVTTL using voltage dividers for interfacing. Bit5 is not used for the 8 position version. Strobe is essentially a qualifier for every position, so if its HIGH we are actually in ONE of the eight positions. Parity check is not needed, and was never actually wired up on the old controller.

The truth table for the 8 positions is also attached.

johnwasser:
You have the logic wrong. To check for inequality you want to see if ANY bit does not match. By using AND instead of OR you are getting 'true' only when EVERY bit does not match. Change && to ||.

Thanks John, that makes sense, I'll try changing to OR tomorrow and post the results.

Encoder.pdf (548 KB)

EncPos.png

Is there chance that your encoder 24V is the maximum rated voltage? Have you tried it with 5V?

Jim, 4 bits can be used to make 0 to 15 and the understanding of bits can let you work with 4 bits as 1 number/

However the encoder bits tell you the physical state of the encoder switches that have a pattern within those 4 bits.

Where those things intersect is your answer, is why I ask what the possible encoder states are, as bits the intersection shows itself.

The computer itself runs on bits, each wire HIGH or LOW. A byte of memory is an array of 8 bits. The low bit is worth 0 or 1, the next higher bit is 0 or 2 and each doubles in value until the top bit that is 0 or 128. With decimal numbering each higher digit is 10 times more, with binary it is 2 times more but you only need 1 finger to count a binary digit, it is up or down only.

With 10 fingers you can count from 0 to 1023. My early teachers would say we needed to take our shoes and socks off to count to 20, even te ones that showed us binary which I thought was a bit dense.

Words at the bottom of the pdf translate as - absolute encoder.

@OP

Did you read and understand reply #10 ?

UKHeliBob, yes and I did read and understand your reply, and I appreciate you taking the time to help. As primitive as the coding in my program is I couldn't see a reason why it wouldn't work the way it was.

I changed my While loop conditions to OR as suggested by JohnWasser. Problem solved. The setup works perfectly.

Once again, thanks all.
Jim

Arduino gives you bit commands

From the Arduino Reference Page. These are links to pages on each function.
Bits and Bytes

bit()
bitClear()
bitRead()
bitSet()
bitWrite()
highByte()
lowByte()

My problem with what you are doing is that I don't like to see people torture themselves so badly to learn so little, to miss so much.

Those 4 encoder bits, you can read them all on a single port in one cycle, mask them in the next and put that through a switch-case statement to do the appropriate thing fast enough to not miss a click -- when you're ready.