creating HEX arrays

I am using an Arduino Mega 2560 as a microcontroller to receive cell voltages from a texas instruments battery monitor (BM). I use HEX messages to communicate between the Arduino and the BM. In my serial monitor, I receive the following message from the BM:

29 AE E0 AF E1 AC E2 ... ... 86 48

29 = message header AEE0 = voltage of cell 1 AFE1 = voltage of cell 2 ACE2 = votlage of cell 3 etc 8648 = checksum

I want to take the response on the serial monitor to produce an array containing (AEE0, AFE1, ACE2...). I can then convert these values to DEC using Arduino's inbuilt conversion function to then calculate the voltages. How would I go about creating this array?

All numbers are binary; hex and decimal are just convenient representations for humans.

Show your code so we can can advise.

All numbers are binary; hex and decimal are just convenient representations for humans.

Hex is a convenient format for humans; but, decimal is a necessary format.

sterretje:
Show your code so we can can advise.

Enclosed in code tags, of course.

code tags1.PNG

Else it may look like this:

code tags.PNG

code tags1.PNG

code tags.PNG

@AWOL - This isn't a question about converting a number between representations (like we always get here), he's starting with pairs of ASCII hex digits, separated by CRLF sequences coming down a serial port; thus, action is required to convert them to numbers.

Take a look at serial input basics thread!

I would probably convert the incoming pairs of characters in HEX to bytes as I got them, and once I got a 27, i'd put the next N bytes (however many the packet length is) into an appropriately sized buffer, then once I got the appropriate number of bytes, check the checksum, and then assign the bytes to their destinations.

GolamMostafa:
Hex is a convenient format for humans; but, decimal is a necessary format.

No, I’m pretty sure the computers get along just fine without decimal :wink:

Hex is a convenient format for humans; but, decimal is a necessary format.

The ancient Romans got along just fine with numbers like XLVII.

he's starting with pairs of ASCII hex digits, separated by CRLF sequences coming down a serial port

Actually, that's not clear. It COULD be that, or it could be "I'm receiving individual binary bytes, and don't know how to combine two of them into a 16bit value" (which is a FAQ as well.) Seeing the existing code would make this more obvious, even if it wasn't very close to achieving the final task...

The ancient Romans got along just fine with numbers like XLVII.

So: Is it the tradition that got changed over the time by its own way or is it the necessity of the time that forced (urged) human to bring change in his own tradition? As a result, XLVII took the form of 47.

Hex is a convenient form to human being in the sense that he can use few numerals to express a multi-bit binary number for academic purposes; whereas, decimal format is a necessity and not a matter of convenience to handle day-to-day affairs.

GolamMostafa: Hex is a convenient format for humans; but, decimal is a necessary format.

Math started out in base 12 in ancient Sumeria. It's the reason we have special names for eleven and twelve instead of them ending in -teen like all the rest after ten. It's the reason there are 12 hours in a day. 12 is a cool number because it has a lot of factors. If you have ten doughnuts you can only share equally with 2 people or 5 people. Any other number of people and it has to be uneven. But with 12 doughnuts you can share equally with 2, 3, 4, or 6 people. That's why doughnuts come in dozens.

Many think it would be a better system

http://www.dozenal.org/

Thank you all for your responses. I am new to programming but I do understand HEX. All I want to do is to go from this list on my Serial monitor:

29 AE E0 AF E1 AC E2 ... ... 86 48

to this list:

mylist = (29, AEE0, AFE1, ACE2, ... , 8648)

how could I create this list?

Is the initial 29 hex or decimal? Why is it eight bit, when all the other values are sixteen?

It is HEX. These are all HEX figures. "29" in this case is a header which represents how many bits of data are included in the message.

I've kind of found what I need to do from this other thread:

https://forum.arduino.cc/index.php?topic=145043.0

Ok I thought I had it… but I’m not quite there yet. Below is my full code so far:

byte vt[]   = {0x94, 0x00, 0x03, 0x1F, 0xFF, 0xFF, 0x00, 0xE7, 0xDD,    // configured so that 13 cell Voltages and 8 AUX temp Voltages are measured
               0x81, 0x00, 0x02, 0x20, 0x28, 0x84};                     // request voltage and aux temp data


bool x = 1;

void setup() {
  // put your setup code here, to run once:
  Serial.begin(9600);           // to the serial monitor
  Serial3.begin(250000);        // to the battery monitor 
 }


void loop() {

    if(x == 1){                               // loop runs once
          Serial3.write(vt, sizeof(vt));      // send message
          for(int i=0; i<45; i++){            // 45 bytes of response from battery monitor (1 header, 26 cell V, 16 aux T, 2 CRC)
            while(Serial3.available()){       // wait for serial port to send data
              int vread = Serial3.read();     // create vread array
              Serial.print(vread, DEC);       // print response as DEC 
              Serial.println();               // print response as DEC
            }
          Serial.parseInt();                  // print response as a list on the Serial Monitor
          x = 0;        
            }
     }
}

I am sending a HEX message to a Serial device and printing the response on the Serial monitor as DEC figures. All good so far. This is the response that comes up instantly on the Serial monitor (all DEC numbers):

41
208
173
193
237
193
226

169
23

Now I need to manipulate these values. What I need to do is ignore 41 (header) and the last two numbers (169, 23), and then I need to create a new list such that:

208256 + 173
193
256 + 237
193*256 + 226

Therefore my new list would like this:

41
53421
49645
49634

169
23

How would I create this new list?

byte high = Serial.read();
byte low = Serial.read();

int together = high <<8 + low;

mk14g09:
Below is my full code so far:

Finally :wink:

A first step would be to read the data into a byte array of sufficient length instead of printing.

byte response[45];

The below code will basically do the same as your current code; just a slightly different approach so it does not block during receive.

byte vt[]   = {0x94, 0x00, 0x03, 0x1F, 0xFF, 0xFF, 0x00, 0xE7, 0xDD,    // configured so that 13 cell Voltages and 8 AUX temp Voltages are measured
               0x81, 0x00, 0x02, 0x20, 0x28, 0x84
              };                     // request voltage and aux temp data

const byte replySize = 45;
byte replyBuffer[replySize];

bool x = 1;

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);           // to the serial monitor
  Serial3.begin(250000);        // to the battery monitor
}


void loop()
{
  static byte replyIndex = 0;
  if (x == 1)
  {
    Serial3.write(vt, sizeof(vt));      // send message
    x = 0;
  }
  else
  {
    if (Serial3.available() > 0 && replyIndex < replySize - 1)
    {
      replyBuffer[replyIndex++] = Serial3.read();
    }
  }

  if (replyIndex == replySize)
  {
    // do something with the data
    for (int cnt = 0; cnt < replySize; cnt++)
    {
      Serial.println(replyBuffer[cnt], DEC);
    }
    // reset replyIndex
    replyIndex = 0;
    // indicate ready to initiate next reading
    x = 0;
  }
}

Do you need to create a new list or can you work on the data that you received? The below works directly on the received data.

Next you can replace the “do something” by what you need.

Based on Delta_G’s approach above

  if (replyIndex == 45)
  {
    // first integer
    unsigned int voltage1 = (replyBuffer[1] << 8) + replyBuffer[2];
    Serial.println(voltage1);

    // second integer etc
    ...
    ...


    // reset replyIndex
    replyIndex = 0;
    // indicate ready to initiate next reading
    x = 0;
  }

Instead of using a variable called x, I would use a name that reflects what it does; e.g. transmitReady. As you’re using a bool, it’s a lot clearer to use true and false instead of 0 and 1. If you need to do more with the data, you might want to consider the use of a struct to store all data instead of e.g. voltage1, voltage2 etc. That will combine all data into one variable and you can access the individual elements.

Delta_G and Sterretje, thank you so much. I’m getting what I need now. Sterretje, I had to modify your code slightly for it to work:

byte vt[]   = {0x94, 0x00, 0x03, 0x1F, 0xFF, 0xFF, 0x00, 0xE7, 0xDD,    // configured so that 13 cell Voltages and 8 AUX temp Voltages are measured
               0x81, 0x00, 0x02, 0x20, 0x28, 0x84
              };                     // request voltage and aux temp data

const byte replySize = 45;
byte replyBuffer[replySize];

bool x = 1;

void setup()
{
  // put your setup code here, to run once:
  Serial.begin(9600);           // to the serial monitor
  Serial3.begin(250000);        // to the battery monitor
}


void loop()
{

/////////////////////////////////PART 1 
  
  static byte replyIndex = 0;
  if (x == 1)
  {
    Serial3.write(vt, sizeof(vt));      // send message
    x = 0;
  }
  else
  {
    while(Serial3.available() && replyIndex < replySize - 1)
    {
      replyBuffer[replyIndex++] = Serial3.read();
    }
  }

/////////////////////////////////PART 2 
    
     // do something with the data
    //{
      if(Serial3.available())
      {
        // Cell 1
        unsigned int voltage1 = (replyBuffer[1] << 8) + replyBuffer[2];
        Serial.println(voltage1);
        
        // Cell 2      
        unsigned int voltage2 = (replyBuffer[3] << 8) + replyBuffer[4];
        Serial.println(voltage2);
        

        // Cell 3 etc
      }

    Serial.parseInt();
      
    // reset replyIndex
    replyIndex = 0;
    // indicate ready to initiate next reading
    x = 0;
}

I now have two final things to do:

Do you need to create a new list or can you work on the data that you received?

I can work with the data I have received. However, I would like to do a further calculation. For example:

 unsigned int voltage1 = (replyBuffer[1] << 8) + replyBuffer[2];

this gives me 53325. All good so far. But I want to do this:

float Vref = 1.25; //mV

int bin = 16384;  //2^14

float ratio = Vref/bin;

float voltage1 = ((replyBuffer[1] << 8) + replyBuffer[2])*ratio;

The fraction 1.25/(2^14) converts the value further into a voltage, which should read 53325*1.25/2^14 = 4.07 V. However my code is not working. I could use >> 14 for the /2^14 part but how would multiply by 1.25?

Secondly, I need to be able to sum all the values in this new list to get me an overall pack voltage. And it’s not as simple as this:

 // Cell 1 + Cell 2
        unsigned int voltage12 = voltage1 + voltage2;

Any advice on either issue would be much appreciated. Thank you for all your advice so far!

Why do you still need a parseInt?

Why do you still need a parseInt?

I couldn’t understand why, but nothing comes up on the Serial monitor without it.