How to split a char array?

Hi Everyone!

I am relatively new to programming and was wondering if someone could provide some input.

I'm working on an EMG project where I have 8 channels of data, and each channel is comprised of 24 bits for a total of 216 bits (24-bit * 8 + 24-bit header) which is sent out through SPI.

The 216-bits are encoded into hex and stored into a char myarray[], where the serial output is the following

(Only one active channel at the moment)

The output is the following: [3 bytes header] [3 bytes CH1] [3 bytes CH2] ... [3 Bytes CH8]

I am trying to split each channel into their own char array, but I am not sure what's the best way to proceed?

I'd appreciate any help you could provide, and please let me know if you need more information!

The 216-bits are encoded into hex

What does that mean, and why did you do THAT?

Since the header and channel data are the same size, copying the data from a 1D array to a 2D array would be trivial. The % operator applied to the index of the for loop would tell you which column. The / operator applied to the index of the for loop would tell you the row.

But, there is no real reason to do that. The data for channel n starts at position 3*n in the array (if you number the channels from 1 to 8. The data starts at position 3 * (n+1) if you number the channels from 0 to 7. Just access the three bytes starting from the proper position, for each channel.

Thanks for your reply, I appreciate it!

Your suggestion makes complete sense and I think it's the correct answer, but I'm having issues understanding the syntax (pretty new to arrays) and was wondering if you could provide a quick example.

ericord:
The 216-bits are encoded into hex and stored into a char myarray[], where the serial output is the following
I am trying to split each channel into their own char array, but I am not sure what's the best way to proceed?

Does an 'array element (member)' is represented by 'Natural Binary/Hex' or 'ASCII'.

A channel contains 24-bit (3-byte) data. A byte is of 8-bit long. Is this 8-bit a 'natural binary number' or 'ASCII Code'? The confusion has arisen from the declaration of your 'character type array (char myarray[])' and the phrase 'encoded into hex'. Please, clarify with an 'example data' and then we may help you in taking out the data of a particular channel. For example:

Ch-0 data : 00110001 00111000 00110111 (24-bit, 31 38 37) in ASCII for 1 8 7
Ch-0 data : 00000001 00001000 00000111 (24-bit, 01 08 07) in Binary (aka natural binary) for 1 8 7

The data comes from readSerial command.

Here is the code relating to the 27-byte hex encoded array:

char hexDigits[] = "0123456789ABCDEF";
uint8_t serialBytes[200];
char sampleBuffer[1000];

inline void sendSample(void) { 
  digitalWrite(PIN_CS, LOW);
  register int numSerialBytes = (3 * (maxChannels+1)); //24-bits header plus 24-bits per channel  (3 * 
  numActiveChannels(+1)) This will only display the active channels
  uint8_t returnCode = spiRec(serialBytes, numSerialBytes);
  digitalWrite(PIN_CS, HIGH);
  register unsigned int count = 0;
  encodeHex(sampleBuffer, (char *)serialBytes, numSerialBytes);
  //split(sampleBuffer);


void encodeHex(char* output, char* input, int inputLen) {
  register int count = 0;
  for (register int i=0; i < inputLen; i++) {
    register uint8_t lowNybble = input[i] & 0x0f; //Nyblble = 4 bits
    register uint8_t highNybble = input[i] >> 4;
    output[count++] = hexDigits[highNybble];
    output[count++] = hexDigits[lowNybble];
  }
  output[count] = 0;
}

printing sampleBuffer with one active channel Imgur: The magic of the Internet

The data format for each channel is two's complement and MSB first

@OP

These are my tested codes (brute force codes) which have manipulated 27-bytes data (of 2's complement form) of your array named uint8_t serialBytes[] to find the decimal value of Ch-1.

void setup()
{
  Serial.begin(9600);
  uint8_t serialBytes[] =
  {
    0xC0, 0x00, 0x00,  //header 3-byte
    0xFF, 0x60, 0xAD,   //Ch-1 (arbitray data in 2's complement form)
    0x12, 0x34, 0x56,   //Ch-2
    0x78, 0x9A, 0xAB,   //Ch=3
    0xCD, 0xEF, 0xF0,   //Ch-4
    0x80, 0x83, 0x98,   //Ch-5
    0xCC, 0xBD, 0x1C,   //Ch-6
    0x3B, 0xEF, 0xFE,   //Ch-7
    0x45, 0xDC, 0x57    //Ch-7
  };

  uint32_t myData[8];
  for (int i = 1, j = 0; i <= 8, j < 8; i++, j++)
  {
    myData[j] = ((uint32_t)serialBytes[3 * i] << 16) |
                (uint32_t)(serialBytes[3 * i + 1] << 8) |
                (uint32_t)(serialBytes[3 * i + 2]);
  }

  for(int j=0; j<8; j++)
  {
    Serial.println(myData[j]&0x00FFFFFF, HEX);//FF60AD, 123456, FF9AAB, FFEFF0, FF8398, FFBD1C, ...   
  }
  //decimal value of Ch-1 = myData[0] = (00)FF60AD = -1*2^23+(0x7F60AD) = -8388608 + 8347821 = - 40787
  // .....................................
  for (int i = 23; i >= 0; i--)
  {
    Serial.print((bitRead(myData[0], i)), BIN); //shows: 1111 1111 0110 0000 1010 1101 = FF60AD in 2's comple.
  }
  Serial.println();
  float x1 = -1 * pow(2, 23); //getting: -1*2^23
  Serial.println(x1, 2);  //-8388608.00
  uint32_t x2 = myData[0] & 0x007FFFFF;
  float x3 = (float)x2;
  Serial.println(x3, 2); //+8347821.00 = 7F60AD
  Serial.println((x1 + x3), 2); //-40787.00 = FF60AD (2's complement form)

}

void loop()
{

}

Thank you very much- this is exactly what I was looking for! :slight_smile:

GolamMostafa:
@OP

These are my tested codes (brute force codes) which have manipulated 27-bytes data (of 2's complement form) of your array named uint8_t serialBytes[] to find the decimal value of Ch-1.

void setup()

{
  Serial.begin(9600);
  uint8_t serialBytes[] =
  {
    0xC0, 0x00, 0x00,  //header 3-byte
    0xFF, 0x60, 0xAD,  //Ch-1 (arbitray data in 2's complement form)
    0x12, 0x34, 0x56,  //Ch-2
    0x78, 0x9A, 0xAB,  //Ch=3
    0xCD, 0xEF, 0xF0,  //Ch-4
    0x80, 0x83, 0x98,  //Ch-5
    0xCC, 0xBD, 0x1C,  //Ch-6
    0x3B, 0xEF, 0xFE,  //Ch-7
    0x45, 0xDC, 0x57    //Ch-7
  };

uint32_t myData[8];
  for (int i = 1, j = 0; i <= 8, j < 8; i++, j++)
  {
    myData[j] = ((uint32_t)serialBytes[3 * i] << 16) |
                (uint32_t)(serialBytes[3 * i + 1] << 8) |
                (uint32_t)(serialBytes[3 * i + 2]);
  }

for(int j=0; j<8; j++)
  {
    Serial.println(myData[j]&0x00FFFFFF, HEX);//FF60AD, 123456, FF9AAB, FFEFF0, FF8398, FFBD1C, ... 
  }
  //decimal value of Ch-1 = myData[0] = (00)FF60AD = -12^23+(0x7F60AD) = -8388608 + 8347821 = - 40787
  // .....................................
  for (int i = 23; i >= 0; i--)
  {
    Serial.print((bitRead(myData[0], i)), BIN); //shows: 1111 1111 0110 0000 1010 1101 = FF60AD in 2's comple.
  }
  Serial.println();
  float x1 = -1 * pow(2, 23); //getting: -1
2^23
  Serial.println(x1, 2);  //-8388608.00
  uint32_t x2 = myData[0] & 0x007FFFFF;
  float x3 = (float)x2;
  Serial.println(x3, 2); //+8347821.00 = 7F60AD
  Serial.println((x1 + x3), 2); //-40787.00 = FF60AD (2's complement form)

}

void loop()
{

}

Hi GolamMostafa,

Thank you for your help, this worked perfectly and I was able to convert the decimal values to voltage levels. I'm still new to programming and this has been a new learning curve.

void newBytes () {
  uint32_t myData[8];
  for (int i = 1, j = 0; i <= 8, j < 8; i++, j++)
  {
    myData[j] = ((uint32_t)serialBytes[3 * i] << 16) |
                (uint32_t)(serialBytes[3 * i + 1] << 8) |
                (uint32_t)(serialBytes[3 * i + 2]);
  }

  float x1 = -1 * pow(2, 23); //getting: -1*2^23
  uint32_t x2 = myData[0] & 0x007FFFFF;
  float x3 = (float)x2;


if (x > 8388607){ 
     rawVoltageValue = ((x - 16777216) * 2.4) / (pow(2,23)-1);                                                                
     if (filter_flag == true){
        High_Pass_Filter(rawVoltageValue*1000.0);
      }
      else {
        Serial.println(rawVoltageValue*1000.0, 5); // print voltage with 5 decimal points
      }
  } else {
    rawVoltageValue = (x * 2.4) / (pow(2,23)-1); 
      if (filter_flag == true){
        High_Pass_Filter(rawVoltageValue*1000.0);
      }
      else {
        Serial.println(rawVoltageValue*1000.0, 5); 
      }
  }

 

}

You were the only one who was able to help me, and I was wondering if you could answer one more question.

What would be the best way to store the voltage values for each channel in array?

e.g array[] = {voltagech1, voltagech2, voltagech3, ...}

The reason I need the array is because I need to send the data of all 8 channels to an SD card for post data processing.

Again I truly appreciate your help!

Probably, you are looking for something like:

The Codes:

uint8_t serialBytes[] = //arbitrary data in 2's complement form
{
  0xC0, 0x00, 0x00,  //header 3-byte
  0xFF, 0x60, 0xAD,   //Ch-1  //FF60AD = -40787.00
  0x12, 0x34, 0x56,   //Ch-2  //123456 = 1193046.00
  0x78, 0x9A, 0xAB,   //Ch-3  //789AAB = 7903915.00
  0xCD, 0xEF, 0xF0,   //Ch-4  //CDEFF0 = -3280912.00
  0x80, 0x83, 0x98,   //Ch-5  //808398 = -8354920.00
  0xCC, 0xBD, 0x1C,   //Ch-6  //CCBD1C = -3359460.00
  0x3B, 0xEF, 0xFE,   //Ch-7  //3BEFFE = 3928062.00
  0x45, 0xDC, 0x57    //Ch-7  //45DC57 = 4578391.00
};

float storeVoltage[8];  //save Ch0-Ch7 values as decimal numbers

uint32_t myData[8] = {0};  //save 8-Channel data as bits

void setup()
{
  Serial.begin(9600);
}
void loop()
{
  for (int i = 1, j = 0; i <= 8, j < 8; i++, j++)  //form binary bits
  {
    myData[j] = (uint32_t)(serialBytes[3 * i]) << 16 |
                (uint32_t)(serialBytes[3 * i + 1]) << 8 |
                (uint32_t)(serialBytes[3 * i + 2]);
  }
  Serial.print("Arbitrary Channel Data in 2's Complenet Form:");
  for (int j = 0; j < 8; j++)
  {
    Serial.print((myData[j]& 0x00FFFFFF), HEX); Serial.print("  ");
  }
  Serial.println();
  Serial.println("-------------------------------------------------------");
  findVoltage();  //save above binary bits as decimal values (Ch0-Ch7)
  delay(5000);
  Serial.println("============================================================================");
}

void findVoltage()
{
  for (int i = 0; i < 8; i++)
  {
    bool n = bitRead(myData[i], 23);  //reading bit-27 for 0 (+ve) or 1(-ve)
    float x1 = -n * pow(2, 23); //getting: -1*2^23
    Serial.print("Ch-"); Serial.print(i);
    Serial.print(":Magnitude of MSB: ");
    Serial.print(x1, 2);  //-8388608.00
    Serial.print("\t");
    uint32_t x2 = myData[i] & 0x007FFFFF;
    float x3 = (float)x2;
    // Serial.println(x3, 2); //+8347821.00 = 7F60AD
    storeVoltage[i] = (x1 + x3);
    Serial.print("Final Value of Channel Volatge: ");
    Serial.println(storeVoltage[i], 2);//(x1 + x3), 2); //-40787.00 = FF60AD (2's complement form)
  }
}

GolamMostafa:
Probably, you are looking for something like:

The Codes:

uint8_t serialBytes[] = //arbitrary data in 2's complement form

{
 0xC0, 0x00, 0x00,  //header 3-byte
 0xFF, 0x60, 0xAD,   //Ch-1  //FF60AD = -40787.00
 0x12, 0x34, 0x56,   //Ch-2  //123456 = 1193046.00
 0x78, 0x9A, 0xAB,   //Ch-3  //789AAB = 7903915.00
 0xCD, 0xEF, 0xF0,   //Ch-4  //CDEFF0 = -3280912.00
 0x80, 0x83, 0x98,   //Ch-5  //808398 = -8354920.00
 0xCC, 0xBD, 0x1C,   //Ch-6  //CCBD1C = -3359460.00
 0x3B, 0xEF, 0xFE,   //Ch-7  //3BEFFE = 3928062.00
 0x45, 0xDC, 0x57    //Ch-7  //45DC57 = 4578391.00
};

float storeVoltage[8];  //save Ch0-Ch7 values as decimal numbers

uint32_t myData[8] = {0};  //save 8-Channel data as bits

void setup()
{
 Serial.begin(9600);
}
void loop()
{
 for (int i = 1, j = 0; i <= 8, j < 8; i++, j++)  //form binary bits
 {
   myData[j] = (uint32_t)(serialBytes[3 * i]) << 16 |
               (uint32_t)(serialBytes[3 * i + 1]) << 8 |
               (uint32_t)(serialBytes[3 * i + 2]);
 }
 Serial.print("Arbitrary Channel Data in 2's Complenet Form:");
 for (int j = 0; j < 8; j++)
 {
   Serial.print((myData[j]& 0x00FFFFFF), HEX); Serial.print("  ");
 }
 Serial.println();
 Serial.println("-------------------------------------------------------");
 findVoltage();  //save above binary bits as decimal values (Ch0-Ch7)
 delay(5000);
 Serial.println("============================================================================");
}

void findVoltage()
{
 for (int i = 0; i < 8; i++)
 {
   bool n = bitRead(myData[i], 23);  //reading bit-27 for 0 (+ve) or 1(-ve)
   float x1 = -n * pow(2, 23); //getting: -1*2^23
   Serial.print("Ch-"); Serial.print(i);
   Serial.print(":Magnitude of MSB: ");
   Serial.print(x1, 2);  //-8388608.00
   Serial.print("\t");
   uint32_t x2 = myData[i] & 0x007FFFFF;
   float x3 = (float)x2;
   // Serial.println(x3, 2); //+8347821.00 = 7F60AD
   storeVoltage[i] = (x1 + x3);
   Serial.print("Final Value of Channel Volatge: ");
   Serial.println(storeVoltage[i], 2);//(x1 + x3), 2); //-40787.00 = FF60AD (2's complement form)
 }
}

Thank you so much GolamMostafa, this works perfect!

Your help has taught me a lot, and now I can actually move on from this roadblock.

I wish I could show you my gratitude, you're the best. :slight_smile: