convert int to char and concatenate

I am reading the following digital inputs on my mega2560:

int task0 = 19;                // Task Sensors  
int task1 = 20;
int task2 = 21;
int task3 = 22;
int task4 = 23;
int task5 = 24;

Using the digital read function, I will get either a 1 or 0 for each variable.

What I would like is to get a single char array that contains all 6 of these values. So, basically I want to be able to convert these 6 inputs to char's and then concatenate them into a single value. All of this will happen each time I read the inputs.

So I want to end up with, for example, a char variable that looks like this: "100101"... or any combination that the inputs could produce.

I have Google'd all day long and found nothing for C or Arduino, so I finally decided I should burden you all by asking here.

Thanks in advance for the help!

Wade

What you probably really want is to just convert the individual values directly to bits in a variable.
You should read up on bit manipulation.
Here is some tutorial type information to get you started:
http://www.arduino.cc/playground/Code/BitMath

and here is a link to some Arduino bit manipulation functions:
http://www.arduino.cc/en/Reference/Bit

which might make it easier, since it hides the actual shifting, masking, ORing and ANDing.
<< >> | and &

— bill

bperrybap:
What you probably really want is to just convert the individual values directly to bits in a variable.
You should read up on bit manipulation.
Here is some tutorial type information to get you started:
http://www.arduino.cc/playground/Code/BitMath

and here is a link to some Arduino bit manipulation functions:
http://www.arduino.cc/en/Reference/Bit

which might make it easier, since it hides the actual shifting, masking, ORing and ANDing.
<< >> | and &

— bill

Thanks for the reply. I’m thinking that may be more complex than I need. This is why: The circuit providing the 6 inputs to the micro can only return 9 possible combinations of 0s and 1s (10001100, 10101100, etc). So all I care about is comparing what I have to a table with these 9 values stored in it. Then when I know which of the 9 I currently have, I can make a decision.

So my final product will be storing all 9 combinations in a char array, then using a for loop and strcmp, I will check to see which of the 9 values match my current value.

That said, if I could somehow get these 6 inputs into a single string, it seems like the rest would be easy. The micro doesn’t have to know it is a binary number at all, it just has to see how string matches up with the choices in the table I build.

Thanks for the reply. I'm thinking that may be more complex than I need. This is why: The circuit providing the 6 inputs to the micro can only return 9 possible combinations of 0s and 1s (10001100, 10101100, etc). So all I care about is comparing what I have to a table with these 9 values stored in it. Then when I know which of the 9 I currently have, I can make a decision.

I'm not sure how you get more than 6 one and zero characters from 6 inputs. Do you have 6 inputs or more than 6 inputs? Typo?

That said, if I could somehow get these 6 inputs into a single string, it seems like the rest would be easy. The micro doesn't have to know it is a binary number at all, it just has to see how string matches up with the choices in the table I build.

Messing with strings seems like a lot of extra work to perform this task. Why mess with using the digitalRead() values to create a character string from them only to then have to compare the character string to other character strings, when you could use the digitalRead() values to set bits in a variable and then look directly at the variable and do things based on the value of that variable?

Using bit math, the 6 inputs you have can create a single variable which can be an int or a uint8_t

i.e. the bit math operations will create a single variable that contains a value. Based on your 6 inputs that variable could have a theoretical value between 0 and 63.

So if you have only 9 possible combinations of your 6 inputs (vs the theoretical 64 combinations), then you will end up with only 9 different values for that variable vs all 64.

While using bit math may seem too complex at first, it really is quite simple and IMHO, seems like the way to go for this task as it can reduce everything to code that deals with a single integer variable. Then a small case statement can be used to process the 9 different values of the variable.

vs having to generate a string of characters in a buffer and then having to compare that buffer against an array of strings.

In other words, if I understand you needs correctly, I believe that using bit math will be smaller code that is easier to work with than using character strings. i.e. it is easier to set a bit in a variable than to concatenate characters in to a string buffer. and it is easier to compare an integer variable against values using something like a case statement than to compare strings using a table lookup into an array of strings.

--- bill

Ok so here is a an example of using bit math.
It assumes that all the sensors are numbered contiguously and demonstrates
how to create the combined sensor value using bit math and then some examples of how
you can go back and look at the combined sensor value to do things.

— bill

void setup()
{
}

// assuming all sensors are numerically contiguous
const int sensorbase = 19;
const int numsensors = 6;


void dummyfunc(void);

void loop ()
{
uint8_t sensorvalue = 0; // initially zero out value, this is very important.

	// read all the sensors and build up a combined sensorvalue
	for(uint8_t sensor = 0; sensor < numsensors; sensor++)
	{
		if(digitalRead(sensorbase + sensor) == HIGH)
		{
			bitSet(sensorvalue, sensor); // high sensor values are 1 bits in the variable
		}
	}

	// process the sensor inputs

	switch(sensorvalue)
	{
		case 0:	// do something for this value
			dummyfunc();
			break;

		case bit(0): // do something if sensor 0 is HIGH
			dummyfunc();
			break;

		case 2 ... 4: // do something for values 2,3, and 4
			dummyfunc();
			break;

		case B110001: // can also use binary, base sensor is on right
			dummyfunc();
			break;

		case 5:
		case 6: // do the same thing for values 5 and 6
			dummyfunc();
			break;

		default: // catch the "invalid" values
			dummyfunc();

	}

	if(bitRead(sensorvalue, bit(0)) == 0) // check if sensor 0 is LOW
		dummyfunc();

	if(bitRead(sensorvalue, bit(0)) == 1) // check if sensor 0 is HIGH
		dummyfunc();
			
	if(bitRead(sensorvalue, bit(3)) == 0) // check if sensor 3 is LOW
		dummyfunc();
}

void dummyfunc(void)
{
}

You can pack all 6 sensors in 1 byte easily.

1) zero the storage byte 2) for each sensor 2a> multiply the storage byte x 2 which is the same thing as a left shift and might use 1 cycle. 2b> read the sensor 2c> add the 0 or 1 to the storage byte

Put your 9 combinations into a char array.

switch (storage byte) { case combination[0] : etc etc etc

You will use less than 20% as much SRAM, use -far- less code and run at least 6x faster.

Where's the hard part?

GoForSmoke: 2c> add the 0 or 1 to the storage byte

Technically, you only have to add in 1 if the digitalRead() returns HIGH. :)

(The initial zero takes care of all the LOWs)

Where's the hard part?

I think the hard part is that bit math can seem difficult or complex, particularly for those that haven't been exposed to much of it. For those of us that have been doing embedded coding for decades it is second nature and quite simple.

--- bill

right that is the hard part… I could have written out what you did (a list of things that needed to happen), but I don’t know how to actually implement it.

What I have here works in my C compiler (not sure about in real life on the Arduino). It basically uses an sprintf to put all 6 of the int values into a char. Then it compares the char with all of the ones stored in the table. When it finds the one that matches, it returns the number of the item from the table, and uses that number to select a case in the switch statement. From what I gather from you guys, it will take up a lot more memory and be slower though. What do you think? I tried to comment very well so it should be easy to follow…

//  BlockLogic.c
//  Created by Wade Sweatt on 11/1/11.
//

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Lookup table
const char* lookup_table[] = { 
    "010000",
    "010010",
    "100011",
    "101111",
    "010011",
    "100111",
    "000111"
};

int main (int argc, const char * argv[])
{
    
    // task sensor inputs
    int task0 = 1;
    int task1 = 0;
    int task2 = 0;
    int task3 = 1;
    int task4 = 1;
    int task5 = 1;
    
    // holds block turn information
    // for the switch case statement
    int found;
    
    // holds array of task sensor inputs
    // and converts to a string
    char valuename[255];
    sprintf(valuename,"%d%d%d%d%d%d",task0, task1, task2,task3,task4,task5);
    printf("Current sensor value is: %s\n", valuename);
    
    for (int i=0; i<7; i++) {
        
        if ( strcmp(valuename, lookup_table[i]) == 0){
            found = i;
            printf("strings were equal at: %d\n", i);
        }
        else {
            printf("strings were not equal at: %d\n", i);
        }
    }
    
    // Based on int stored in found, select a case
    //
    // TODO: replace printf with Arduino state change
    //
    switch ( found )
    {
        case 0:
            printf("turn right!\n");
            break;
        case 1:
            printf("turn right!\n");
            break;
        case 2:
            printf("turn right!\n");
            break;
        case 3:
            printf("turn right!\n");
            break;
        case 4:
            printf("turn left!\n");
            break;
        case 5:
            printf("turn left!\n");
            break;
        case 6:
            printf("No Signal..\n");
            break;
    }
    return 0;
}

bperrybap:

GoForSmoke: 2c> add the 0 or 1 to the storage byte

Technically, you only have to add in 1 if the digitalRead() returns HIGH. :)

(The initial zero takes care of all the LOWs)

True but my way the only instruction is to add regardless of value. I think that should take 1 cycle. Otherwise I would have to perform a compare (if) to see whether I should add before adding or not.

Where's the hard part?

I think the hard part is that bit math can seem difficult or complex, particularly for those that haven't been exposed to much of it. For those of us that have been doing embedded coding for decades it is second nature and quite simple.

--- bill

I didn't start mucking with MCUs until after 2000, but I've pack bits since 1980 and before that I packed digits. The Atmega328 is more computer than I got to use prior to 1985. I packed digits on TI programmable calculators from 77 to 80 because when you have only 10 to 100 memory registers, you pack digits!

Really, how hard can learning binary be? All you need to do is stop translating to decimal for a while.

In binary which only has 0 and 1; 1 + 1 = 10. 10 + 1 = 11. 11 + 1 = 100. Binary 10 is decimal 2. Binary 100 is decimal 4. Binary 111 is decimal 4 + 2 + 1. In binary, to multiply by decimal 2 you add a zero because decimal 2 is binary 10. In binary or decimal, 10 x 10 = 100. The only difference is what 100 means in either system.

Decimal works by powers of 10 and uses 10 digits while binary works by powers of 2 and uses only 2 digits. Binary is far, far simpler than decimal.

It's not some kind of arcane, esoteric, need a degree or priest's robe. It's not secret anointed knowledge. It's an hour or so at most to learn and understand unless you're either self-complicated, stubborn or 'specially challenged'.

Every byte can store 8 x 2 possible state bits; true/false, up/down, left/right, etc,... flags that would otherwise take 8 bytes as characters and 16 bytes as integers. 1 bit can store 1 of 2 states. 2 bits can store 1 of 4. 8 bits can store 1 of 256 states. And the big hairy thing about signed integers is that the high bit means positive if 0 or negative if 1.

Maybe 32k of flash, 1k eeprom and 4k of SRAM only lets people learn sloppy, wasteful habits. In that case isn't it time that Micro$oft moved in and took over?

In binary, to multiply by decimal 2 you add a zero

!

@OP:

const char* lookup_table[] = { 
    "010000",  // 16
    "010010",  // 18  (16 + 2)
    "100011",  // 35  (32 + 2 + 1)
    "101111",  // 47  (32 + 8 + 4 + 2 + 1)
    "010011",  // 19  (16 + 2 + 1)
    "100111",  // 39  (32 + 4 + 2 + 1)
    "000111"   //  7   (4 + 2 +1)
};

Do the binary coding "trick", substitute the numbers in the comments for the case selectors, and you're done. No strings or lookup required.

Sure, your basic method should work with some changes. You can even keep the oversize string buffer until your code needs to do a good bit more. But why not trim it down a bit anyway?

On the Arduino you will be making one sensor read at a time. And from your 1st post I see you will be reading 6 different sensors:
int task0 = 19; // Task Sensors
int task1 = 20;
int task2 = 21;
int task3 = 22;
int task4 = 23;
int task5 = 24;

And maybe you will be doing that more than once but let’s say 1 or more times?

So you have a flow of

  • read the sensors
  • match the pattern
  • print the results

You might set up each step in a function and have your main loop call each in turn. That will help if you need to expand or change things as you go.

You might want to store your reads in a string. I might suggest that you use a 7 byte character array. That’s 1 character for each sensor read and a string terminating 0 as the last char.

So up top you might set up a global variable to save having the space allocated and de-allocated over and over:

char valuename[7];

And each sensor has a pin number, might as well set them up as global constants with easy to change count:
const byte sensors = 6;
const byte sensorPin[sensors] = { 19, 20, 21, 22, 23, 24 };

And as your last globals you have your lookup table:
// Lookup table
const byte lookups = 7;
const char* lookup_table[lookups] = {
“010000”,
“010010”,
“100011”,
“101111”,
“010011”,
“100111”,
“000111”
};

In your setup you will need to set those sensor pins as inputs and set your com channel to your PC:
for (byte i = 0; i < sensors; i++) {
pinMode(sensorPin*,INPUT);*
}
Serial.begin(9600); // 9600 unless you want different
In your sensor reading function you use a loop to read the sensor values into a local byte variable and write the result into the valuename char array:
void read_sensors() {
byte sensorRead;
for (byte i = 0; i < sensors; i++ ) {
_ sensorRead = digitalRead(sensorPin*);_
_ if (sensorRead == LOW) valuename = ‘0’;
else valuename = ‘1’;
}
}*_

in your match the pattern function you will be comparing valuename to lookup_table strings until you have a match. You want this function to return the number of the pattern matched:

byte match_pattern() {
byte mp = -1; // when the pattern is matched, the match number goes here
byte i = 0; // index through the lookup tables
byte j; // index through the char array strings
byte k; // a flag set if any char of valuename does not match the current lookup_table char
while ((i < lookups) && (mp < 0)) {
* j = 0;*
* k = 1;*
* while (( j < sensors) && k) { // because why load string.h to do one string compare at next to or no savings?*
* if (valuename[j] != lookup_table[j]) k = 0;
_ else j++;
}
if (k) mp = i;
}
return mp;
}
And that leaves the print results function, besides the main function, void loop()
void print_result( byte found) {
switch ( found )
{
case 0:
Serial.println(“turn right!”);
break;
case 1:
Serial.println(“turn right!”);
break;
case 2:
Serial.println(“turn right!”);
break;
case 3:
Serial.println(“turn right!”);
break;
case 4:
Serial.println(“turn left!”);
break;
case 5:
Serial.println(“turn left!”);
break;
case 6:
Serial.println(“No Signal…”);
break;
}
}
I’ll leave void loop(), debugging and any changes up to you. But perhaps this will give you some direction.
Here’s a link to the Arduino Language Reference:
http://arduino.cc/en/Reference/HomePage
> The Arduino language is based on C/C++. It links against AVR Libc and allows the use of any of its functions; see its user manual for details.*

And here’s a link to that:
avr-libc: AVR Libc_

AWOL:

In binary, to multiply by decimal 2 you add a zero

!

Are you saying NOT?

binary:
1
doubled = 10
double that = 100
double that = 1000

if I take storage into consideration then yeah it goes horribly wrong at the sign bit or on overflow

I was just trying to show how to shift bits left without using <<

Yes, I’m saying not.
You’re CONCATENATING a zero, not adding.

I was just trying to show how to shift bits left without using <<

…and failing.

Sorry I didn't use the precise terms!

Concatenating to me is adding characters and that wasn't what I was trying to show at all.

Some people say in decimal that 123 x 10 is 123 with a zero added, as in 1230. Binary does work the same way.

110 binary is decimal 6. 1100 binary is decimal 12. That's 6 x 2 = 12.

If I code the following:

void setup() { Serial.begin(9600);

int n = 7; Serial.println(n,BIN); n *= 2; Serial.println(n,BIN); }

void loop(){ }

You now on My Serial Monitor it prints out 111 1110

Maybe some day I'll find the PC words to describe that.

Some people say in decimal that 123 x 10 is 123 with a zero added

But that’s confusing - 123 with zero added is 123.
(I almost wrote “123 with zero added is 123!”, but some pedants may have taken that as factorial 123, which is something like 1.2 x 10205)

I see. Yes I explained it wrong. I did not mean + 0 even though I used the words zero added. I hope that with the examples provided that he is/was able to get past my confusing explanation.

I'd really like to see him convert the string based parts to numeric and for sure the multiply by two and add the read state (as 0 or 1) 'trick' should work just fine for consecutive reads but maybe he should learn to use the shift commands.

but maybe he should learn to use the shift commands.

Or the bitWrite macros provided

GoForSmoke:
Sure, your basic method should work with some changes. You can even keep the oversize string buffer until your code needs to do a good bit more. But why not trim it down a bit anyway?

On the Arduino you will be making one sensor read at a time. And from your 1st post I see you will be reading 6 different sensors:
int task0 = 19; // Task Sensors
int task1 = 20;
int task2 = 21;
int task3 = 22;
int task4 = 23;
int task5 = 24;

And maybe you will be doing that more than once but let’s say 1 or more times?

So you have a flow of

  • read the sensors
  • match the pattern
  • print the results

You might set up each step in a function and have your main loop call each in turn. That will help if you need to expand or change things as you go.

You might want to store your reads in a string. I might suggest that you use a 7 byte character array. That’s 1 character for each sensor read and a string terminating 0 as the last char.

So up top you might set up a global variable to save having the space allocated and de-allocated over and over:

char valuename[7];

And each sensor has a pin number, might as well set them up as global constants with easy to change count:
const byte sensors = 6;
const byte sensorPin[sensors] = { 19, 20, 21, 22, 23, 24 };

And as your last globals you have your lookup table:
// Lookup table
const byte lookups = 7;
const char* lookup_table[lookups] = {
“010000”,
“010010”,
“100011”,
“101111”,
“010011”,
“100111”,
“000111”
};

In your setup you will need to set those sensor pins as inputs and set your com channel to your PC:
for (byte i = 0; i < sensors; i++) {
pinMode(sensorPin*,INPUT);*
}
Serial.begin(9600); // 9600 unless you want different
In your sensor reading function you use a loop to read the sensor values into a local byte variable and write the result into the valuename char array:
void read_sensors() {
byte sensorRead;
for (byte i = 0; i < sensors; i++ ) {
_ sensorRead = digitalRead(sensorPin*);_
_ if (sensorRead == LOW) valuename = ‘0’;
else valuename = ‘1’;
}
}*_

in your match the pattern function you will be comparing valuename to lookup_table strings until you have a match. You want this function to return the number of the pattern matched:

byte match_pattern() {
byte mp = -1; // when the pattern is matched, the match number goes here
byte i = 0; // index through the lookup tables
byte j; // index through the char array strings
byte k; // a flag set if any char of valuename does not match the current lookup_table char
while ((i < lookups) && (mp < 0)) {
* j = 0;*
* k = 1;*
* while (( j < sensors) && k) { // because why load string.h to do one string compare at next to or no savings?*
* if (valuename[j] != lookup_table[j]) k = 0;
_ else j++;
}
if (k) mp = i;
}
return mp;
}
And that leaves the print results function, besides the main function, void loop()
void print_result( byte found) {
switch ( found )
{
case 0:
Serial.println(“turn right!”);
break;
case 1:
Serial.println(“turn right!”);
break;
case 2:
Serial.println(“turn right!”);
break;
case 3:
Serial.println(“turn right!”);
break;
case 4:
Serial.println(“turn left!”);
break;
case 5:
Serial.println(“turn left!”);
break;
case 6:
Serial.println(“No Signal…”);
break;
}
}
I’ll leave void loop(), debugging and any changes up to you. But perhaps this will give you some direction.
Here’s a link to the Arduino Language Reference:
http://arduino.cc/en/Reference/HomePage
> The Arduino language is based on C/C++. It links against AVR Libc and allows the use of any of its functions; see its user manual for details.
And here’s a link to that:
avr-libc: AVR Libc
[/quote]*

Ok thanks so much for the help. Do you think that my method will not work? Or are you just saying that this is another way that it can be done. I noticed your method leaves out the need for string.h, which could be good. Thanks again!
Wade_

No-one is saying your method will not work, just that it is over-complicated.

AWOL: No-one is saying your method will not work, just that it is over-complicated.

And very resource intensive as well. For example, the xxprintf() code will consume close to 2k of FLASH. That is quite bit of code considering some lower end microcontrollers only have that much. The AVR is a harvard architecture ( http://en.wikipedia.org/wiki/Harvard_architecture ). It isn't a more traditional single flat address space architecture like CISC CPUs use like the xx86 processor found in all the PCs where once the operating starts everything is stored in RAM. The C language wasn't designed for a Harvard architecture, and it really creates some challenges for the compiler. Because of that compilers like gcc will copy all initialized data variables to RAM so that they can be accessed transparently and still be modified like the C language requires. What that means is that when using gcc on the AVR, every byte of initialized data that you have also eats up a byte of RAM. RAM is a very precious resource on these small microcontrollers so learning techniques that can reduce these types of resource needs can be a very beneficial tool in ones knowledge toolkit as in more complex larger projects it can potentially mean the difference between designing something that can work with a given microcontroller or ending up with something that must be redesigned to live within the real world constraints of the microcontroller.

So it isn't that the string concatenation and comparison technique won't work, it is that there are other techniques available that are less complicated and will be much less resource intensive.

--- bill