String byte to byte conversion

Hi guys, I'm working on ESP32 output extension with 74HC575 Shift Registers.

const int dataPin = 34;   // DS pin 34
const int latchPin = 35;  // ST_CP pin 35
const int clockPin = 36;  // SH_CP pin 36

String Out_Str_0 = "1", Out_Str_1 = "1", Out_Str_2 = "1", Out_Str_3 = "1", Out_Str_4 = "1", Out_Str_5 = "1", Out_Str_6 = "1", Out_Str_7 = "1",
       Out_Str_8 = "1", Out_Str_9 = "1", Out_Str_10 = "1", Out_Str_11 = "1", Out_Str_12 = "1", Out_Str_13 = "1", Out_Str_14 = "1", Out_Str_15 = "1";

String Final_Out_Str;
byte Final_Out_Byte;
byte Test_Byte = 0b1111111111111111;

void setup() {
  Serial.begin(115200);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
}


void loop() {
  Out_Str_0 = "0";  Out_Str_1 = "0";
  Final_Out_Str = "";
  Final_Out_Str = "0b" + Out_Str_0 + Out_Str_1 + Out_Str_2 + Out_Str_3 + Out_Str_4 + Out_Str_5 + Out_Str_6 + Out_Str_7 + Out_Str_8 + Out_Str_9 + Out_Str_10 + Out_Str_11 + Out_Str_12 + Out_Str_13 + Out_Str_14 + Out_Str_15;
  Serial.println(Final_Out_Str);

  //  Final_Out_Byte = Final_Out_Str;
  //  shiftWrite(Final_Out_Str, BIN);
}


void shiftWrite(unsigned int desiredPins) {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, highByte(desiredPins));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(desiredPins));
  digitalWrite(latchPin, HIGH);
}

I'm getting the printed output as

23:33:54.983 -> 0b0011111111111111
23:33:54.983 -> 0b0011111111111111
23:33:54.983 -> 0b0011111111111111

Which is a byte formated string that I want to convert into byte and wite as shiftWrite(Final_Out_Byte);

I tried my best reading over forums but couldn't get the idea.
Please suggest me how to convert this into byte.

Checking arduino/refrence and string, byte, bits.... might contain useful stuff.

Actually there is a reason to plan for string.
I'm using the below code for writing an individual pin to LOW and setting all other pin HIGH so that I can control any one of the pin at a time. but if I want to control any combination of pins to set LOW, its a tedious process as obviously useless to have combinations of 2^16.

so my plan is to set each pin in global variable and as per the use case, assign and concat the value and latch into the register.

Also checked arduino/refrence - no blink.

const int dataPin = 34;   // DS pin 34
const int latchPin = 35;  // ST_CP pin 35
const int clockPin = 36;  // SH_CP pin 36
byte bb = 0b1111111111111111;

unsigned int data[16] = {
  0b1111111111111110,
  0b1111111111111101,
  0b1111111111111011,
  0b1111111111110111,
  0b1111111111101111,
  0b1111111111011111,
  0b1111111110111111,
  0b1111111101111111,
  0b1111111011111111,
  0b1111110111111111,
  0b1111101111111111,
  0b1111011111111111,
  0b1110111111111111,
  0b1101111111111111,
  0b1011111111111111,
  0b0111111111111111
};

void setup() {
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
}


void loop() {
  manyOnAtATime();  // Scroll down the line
}


void shiftWrite(unsigned int desiredPins) {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, highByte(desiredPins));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(desiredPins));
  digitalWrite(latchPin, HIGH);
}

void shiftWriteAllOff() {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(0b1111111111111111));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(0b1111111111111111));
  digitalWrite(latchPin, HIGH);
}

void shiftWriteAllOn() {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, highByte(0b0000000000000000));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(0b0000000000000000));
  digitalWrite(latchPin, HIGH);
}

void manyOnAtATime() {
  int delayTime = 50;
  for (int i = 0; i < 16; i++) {
    shiftWrite(data[i]);  // turn LEDs on
    delay(delayTime);      // pause to slow down the sequence
  }
  //shiftWrite1(bb);
  shiftWriteAllOff();
  delay(1000);
  shiftWriteAllOn();
  delay(1000);
  shiftWriteAllOff();
  delay(1000);
}

In fact, I'm referring below link to understand shift binary and registers.
If I'm not wrong, BIT SHIFT is used to move/offset the already registered or stored binary values with countable left or right.
It's not suitable in my case becasue, my usecase is random and just want to make sure the way I use these register output ports as similar to onboard MC's output ports.
like writing any of the pin high or low shouldnot affect someother pins.

https://docs.arduino.cc/learn/programming/bit-math/

And I want to kindly mention that I'm not forcely intended to use Strings.
any suggestions are thankfully welcomed.

I like your idea of the line below. does it not affect the next/prev digits of the registry?
Can you please share any reference link for the below line to go though and understand it?

outByte |= (1<<5); // to set the 5th bit

All common architectures today use octets for a byte. Eight bits. What numeric value does Test_Byte have there?

You are right. It should be a byte of 8 bits. but the code and the method i use, spilts multibytes and writes the respective pins as byte packages while I cascaded 2-8bit shift register chips together.
No issues there in byte of 16 digit bits (2 bytes) wrote and validated in hardware aswel works cool.

Thanks for the code,
It populates a random byte and got the below output seems like shifting / appending but not sure how to use it :sweat_smile:

01:22:35.280 -> 212
01:22:35.280 -> 11010100
01:22:35.280 -> 212
01:22:35.280 -> 11010100
01:22:35.280 -> 424
01:22:35.280 -> 110101000
01:22:35.280 -> 848
01:22:35.280 -> 1101010000
01:22:35.280 -> 1696
01:22:35.280 -> 11010100000
01:22:35.280 -> 3392
01:22:35.280 -> 110101000000
01:22:35.280 -> 6784
01:22:35.280 -> 1101010000000
01:22:35.280 -> 13568
01:22:35.280 -> 11010100000000
01:22:35.280 -> 27136
01:22:35.280 -> 110101000000000

You are right. It should be a byte of 8 bits. but the code and the method i use, spilts multibytes and writes the respective pins as byte packages while I cascaded 2-8bit shift register chips together.
No issues there in byte of 16 digit bits (2 bytes) wrote and validated in hardware aswel works cool.

you are right it can't take 16 digits at once.
I have posted it in both of my code in post #1 & post#3 Please refer the below lines.

  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, highByte(desiredPins));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(desiredPins));
  digitalWrite(latchPin, HIGH);

Here it takes the MSB 8 bits and writes down in chip-A then second set of 8 digits in chip-B

Below are my references: simple difference is I use ESP32 GPIOS instead of Arduino Ports.

Why don't you use the SPI pins of the Uno.
And use SPI.transfer16(value); where value is the 16-bit int.
No joining of the two bytes, and faster.
Leo..

Don't quite understand the issue??

Helped someone here remove delays out of led animations that are driven by 2 shift registers..
2 Shift registers Uno
Maybe it helps..

good luck.. ~q

You seem to be confused about the difference between a number and a text representation of that number and I do not think that it was explained in the above posts (maybe I missed it).

byte outVal = 0b1010010101 is an instruction for the compiler to create a variable that can hold a number that is 1 byte in size.
String outVal = "0b10100101" is an instruction to the compiler to create a text representation of the number in memory and it will take 8 (plus 1, omitting the String (capital S) overhead) bytes in memory.

There can be valid reasons why you want to use a text representation; e.g. the Serial Monitor sends ASCII characters so you collect that as text and next convert it to a number to send it to a shift register.

Thanks a lot @Delta_G for the beautiful catch of sending DECIMAL value (eg, 65535) to the shift register instead of binary (eg, 0b1111111111111111).
It worked great. and the problem perfectly resolved. Let me explain how I approached with your idea step by step. So in future it will be helpful for others aswel.

shiftWrite(0b0011111001111100); // Old Method - Binary
shiftWrite(15996); // New Method - Decimal

Both the lines resulted in same result.
Got a beautiful Arduino-Number-Converter library by CarlOhlsson

//Example Conversion
#include <Convert.h>
Convert convert;

void setup() {
  Serial.begin(115200);
  String bin = "11011001000000101000"; // Random
  Serial.print("binary converted to decimal: ");
  Serial.println(convert.binaryToDecimal(bin));
}
void loop() {}

// printed result:
// binary converted to decimal: 888872

Finally I have updated my code at post #1 to the below.

#include <Convert.h>
Convert convert;

const int dataPin = 34;   // DS pin 34
const int latchPin = 35;  // ST_CP pin 35
const int clockPin = 36;  // SH_CP pin 36

// initialization
String Pin_0 = "1", Pin_1 = "1", Pin_2 = "1", Pin_3 = "1", Pin_4 = "1", Pin_5 = "1", Pin_6 = "1", Pin_7 = "1",
       Pin_8 = "1", Pin_9 = "1", Pin_10 = "1", Pin_11 = "1", Pin_12 = "1", Pin_13 = "1", Pin_14 = "1", Pin_15 = "1";

String Final_Str;
int Final_Int;
int delayx = 500;

void setup() {
  Serial.begin(115200);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
}

void loop() {

Pin_All_On(); delay(delayx);
Pin_All_Off(); delay(delayx);

//  /*
  Pin_0 = "0" ;   Refresh_Pins();  delay(delayx);
  Pin_6 = "0" ;   Refresh_Pins();  delay(delayx);
  Pin_9 = "0" ;   Refresh_Pins();  delay(delayx);
  Pin_14 = "0" ;   Refresh_Pins();  delay(delayx);
  Pin_0 = "1" ;   Refresh_Pins();  delay(delayx);
  Pin_6 = "1" ;   Refresh_Pins();  delay(delayx);
  Pin_9 = "1" ;   Refresh_Pins();  delay(delayx);
  Pin_14 = "1" ;   Refresh_Pins();  delay(delayx);
//  */
  
}

void shiftWrite(unsigned int desiredPins) {
  digitalWrite(latchPin, LOW);
  shiftOut(dataPin, clockPin, MSBFIRST, highByte(desiredPins));
  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(desiredPins));
  digitalWrite(latchPin, HIGH);
}

void Refresh_Pins(){
    Final_Str = Pin_0 + Pin_1 + Pin_2 + Pin_3 + Pin_4 + Pin_5 + Pin_6 + Pin_7 + Pin_8 + Pin_9 + Pin_10 + Pin_11 + Pin_12 + Pin_13 + Pin_14 + Pin_15;
    Final_Int = convert.binaryToDecimal(Final_Str);
    shiftWrite(Final_Int); Serial.println(Final_Int);
}

void Pin_All_Off() { shiftWrite(65535); Serial.println("All_Pins-Off"); }

void Pin_All_On() { shiftWrite(0); Serial.println("All_Pins-On"); }

Now I can easily control any of the pin states independently & almost similar to calling direct onboard MC-Output ports (validated with hardware aswel).

Thank you all for your suggestions. Will keep your inputs and below discussions in mind & try if they needed.

@murugesh_rcpilot your problem is so,ved, but remains somewhat klunky.

You may enjoy learning how to de-klunk it using bit manipulation, to which you were directed unsuccessfully in post #2.

I'll look for a competent tutorial, but for now on this page

look at the section labeled Bits and Bytes...

You will be able to directly set, clear and test the bits in a 16 bit integer, whilst referring to them by number 0 to including 15.

The functions documented there will let you do those things without needing to learn how it is done at the level of simple C/C++ expressions, which you will probably want/need to learn about in the future, near or distant.

There will be no need for the obtuse intermediate representation of the pin states which is current a String.

I can't through the tiny window, but it looks like you can entirely jettison the use of Strings in your code, which is always a Good Idea.

a7

2 Likes

Sure! thanks for the link pal.
Will go through them once I completed my current project.

I surmise your ultimate target is to try to receive a string from serial, containing 1 and 0 values as characters in that string, and that you've separated out this part as a first, or second, step. Bravo for the "divide and conquer" approach, it's a valid learning tool.
However. Parsing a string of 16 values, such as "0100 0100 1011 0000" isn't usually done by explicitly comparing each character in the string to "0" or "1". Rather, it's best to

  • receive your 16 character string(NOT String), but a character buffer of ASCII chars.
  • optionally, but wisely, verifying it is 16 long and only contains 0 and 1 values,
  • processing the string in a loop, setting/clearing each output appropriately.

Other approaches might include

  • receive a single character which uniquely identifies which bit, and what to set it to"
  • receive a command character, then a bit number, something like N13 to set bit 13 on, F13 to turn it off
  • Receive a command character that toggles a designated bit, something like T13, which would invert whatever bit 13 is set to

As you can see, there are many possibilities. It's possible you've clearly defined what it is you want to do, but I missed it; if not, consider the above to be a set of concepts to start from.
Please note, NONE of these mentions the least possibility of any form of "String" usage. Most of it can be done with a few switch() cases, only one requires even a char[] buffer.

For fun, I modified your code to avoid String, or string, completely. I had to comment out the library and it's references, but the Serial Output shows I'm exercising the word as per your comments. It works in Wokwi, using a Mega as the target:
Shifty
Beyond that, tell us what you're really after.

//#include <Convert.h>  //just commented out to avoid the missing library call
//Convert convert;      //just commented out to avoid the missing library call

const int dataPin = 34;   // DS pin 34
const int latchPin = 35;  // ST_CP pin 35
const int clockPin = 36;  // SH_CP pin 36
const uint16_t ALL_ONE = 0b1111111111111111;
const uint16_t ALL_ZERO = 0b0000000000000000;
uint16_t dataword;

//String Final_Str;
//int Final_Int;

int delayx = 500;

void setup() {
  Serial.begin(115200);
  pinMode(dataPin, OUTPUT);
  pinMode(clockPin, OUTPUT);
  pinMode(latchPin, OUTPUT);
}

void loop() {
//dataword always contains what you last wrote to the outputs
  shiftWrite(dataword = ALL_ZERO); delay(delayx);
  shiftWrite(dataword = ALL_ONE); delay(delayx);

  shiftWrite(dataword ^= 0b0000000000000001);  delay(delayx); //flips bit 0
  shiftWrite(dataword ^= 0b0000000001000000);  delay(delayx); //flips bit 6
  shiftWrite(dataword ^= 0b0000001000000000);  delay(delayx); //flips bit 9
  shiftWrite(dataword ^= 0b0100000000000000);  delay(delayx); //flips bit 14
  shiftWrite(dataword ^= 0b0000000000000001);  delay(delayx); //flips bit 0
  shiftWrite(dataword ^= 0b0000000001000000);  delay(delayx); //flips bit 6
  shiftWrite(dataword ^= 0b0000001000000000);  delay(delayx); //flips bit 9
  shiftWrite(dataword ^= 0b0100000000000000);  delay(delayx); //flips bit 14
}

void shiftWrite(uint16_t desiredPins) {
  Serial.println(desiredPins, BIN);    //put the printout HERE, always shows what we're about to write to the outputs
  digitalWrite(latchPin, LOW);
//  shiftOut(dataPin, clockPin, MSBFIRST, highByte(desiredPins));  //just commented out to avoid the missing library call
//  shiftOut(dataPin, clockPin, MSBFIRST, lowByte(desiredPins));   //just commented out to avoid the missing library call
  digitalWrite(latchPin, HIGH);
}

Glad you made a code pal. thats interesting. however, I like to stick with string for now as its easy during random call instead of playing with binary flipps, I can mindlessly assign writes.
ofcourse I will learn your ideas and use it when require.

I'm after industrial automation currently working on a flatness measuring machine
and I'm out of GPIO's to operate cylinders and read sensors.
Tried I2C extendors like MCP23017, PCF8574, PCF8575 causes reliability issues over time & SPI like MCP23S17 - has no supporting lib for ESP32.

So switching to conventional method of I/O extensions through registers like
74HC575 for Output Extension
74HC165 for Input Extension

Best of luck!
I say that, because "industrial automation" and 'wiring your own digital stuff' are pretty much incompatible, if you want it to work right, unless you have a very significant amount of hardware design experience.
In this thread, and your previous one about (something about unreliable MCP23017), you've shown an unwillingness to expose the details of your hardware to scrutiny. Hence, I sincerely doubt you'll get anywhere useful with the approach you're taking, so I'm wishing you "Best of luck!" - because that'll be what you most need.

1 Like

I'm happy that @camsysca saved me the trouble.

I can only speak for myself… it feels like we see you walking 23 miles to the beach and passing by a train station, a bus stop, a taxi stand and a bicycle rental shop.

That is to say you may want to put off progress on your project for just the short time it would take to learn up on the things you've been shown, then you'll zip past where you would have been had you not, smugly in your taxi at 80 km/h laughing at that other guy wearing out his shoes and sweating a pig.

There is room for creativity even for ppl new to coding; sometimes getting clever ends up being a liability.

a7

2 Likes