I'm working on a project that gets some parameters via modbus from a solar charge controller. It's all working well, but I'm wondering how to handle one of the registers that returns two bytes, one for the controller's temperature and one for the battery's temperature.
There's a nodeJS project that that handles it like this:
//0x103 returns two bytes, one for battery and one for controller temp in c
const buf = Buffer.alloc(2)
buf.writeInt16BE(temperatures);
this.battT = buf[0];
this.controlT = buf[1];
(Where "temperatures" are the two bytes).
Any tips on handling that in Arduino-friendly C?
There's a few registers that return data in that format so I'm trying to avoid using my usual duct tape, ha.
How is the temperature value represented in each byte? The format must be described somewhere, usually in the controller manual.
Oops I should have mentioned. The manual describes it like this:
3.7. To read the battery's surface temperature and controller temperature, and the PDU addresses are known to be 0102H and
0103 in sequence
To send: 01 03 0102 0002 6437
To receive: 01 03 02 0020 0028 73E7
Parsing: 0020H indicates the battery's surface temperature is 30 °C, and if the figure turns out to be 800AH, then it
indicates the battery's surface temperature is -10 °C
0028H indicates the controller's temperature is 40 °C, and if the figure turns out to be 800BH, then it indicates the
controller's temperature is -11 °C
Not enough information. Keep looking, or post a link to the manual.
This suggests the temperature is represented by two bytes.
if the figure turns out to be 800AH
Hi,
Can you post a link to where you purchased the charge controller and if possible a link to the instruction manual.
It would have been preferable for you to have continued posting on the other thread as most of your construction info is there.
Tom.... 

I'd already marked it solved, since the gist is done.
Here's the manual:
(That's in the github repo I'm working on for it, but I'm also attaching it.).
ROVER MODBUS.pdf (549.9 KB)
And as integers the two bytes are currently "5657", but it's certainly not ~56 degrees celcius, so I'm guessing it's not as simple as converting to int.
28 in HEX is 40 decimal
0020H indicates the battery's surface temperature is 30 °C
20 in HEX is 32 decimal, not 30
800BH, then it indicates the controller's temperature is -11 °C
B in HEX is 11 decimal. If the high bit "8" means negate, you get -11
I think I made this sound more complicated by mentioning the solar charge controller.
Ultimately I need to convert the cstring "5657" into two bytes (56 and 57). If anyone happens to have any hints for doing so, I'd love to hear it. As it is I'm in the usual hours long riddle that seems to happen whenever I work with cstrings.
You can use strtoul(). It can read in hex or decimal. I am not clear which one you want. However you do need to split the byte strings first.
Ultimately I want to convert it to two decimal values. I have a cstring 5657, which is two bytes (56 and 57). I need to convert that to two decimal values.
You can split it easily with strcpy(). Here is the reference:
https://www.nongnu.org/avr-libc/user-manual/modules.html
For clarification, what does 5657 actually represent? i.e. 56 base 10 and 57 base ten, or 56 base 16 and 57 base 16? Two different numbers, right?
Have I got it right?
I would just make copies of the first two and the second two digits, and convert them using whatever base, to integer variables.
strcpy
strcpy
strtoul
If you want to get data from a solar charge controller, the controller manual is your very best source of information.
So far, you have failed to make clear whatever it is that you are trying to do. Have fun, though.
Thanks, I'm looking at strcpy() now.
The string "5657" is returned by my solar charge controller. It's two bytes, each a different temperature in celcius. The 56 and 57 is each a byte, that I need to convert to integers.
Does this bit of javascript from a nodeJS project give any hints about how they'd be processed in C? This is how they processed the exact same thing I'm working on.
const buf = Buffer.alloc(2)
buf.writeInt16BE(rawData[3]);
this.battT = buf[0];
this.controlT = buf[1];
I don't know JS about javascript.
I've done some Java..
I think forget about that and just focus on C. Why do you need "hints about the numbers"? I thought you described what they are a few posts ago. Look at the AVR library or the libc on the compiler you have if you aren't on that platform. Those are ages old standard C functions. I think I posted the answer to your question.
I've already gotten the data from the charge controller (it's two bytes), I'm just working on converting them to two decimal numbers. I don't think this particular manual is very helpful for this or anything else, but I've already posted the relevant passage and the manual itself. But again I don't think the source of the numbers matters much.
Well if anyone else happens to understand my gibberish, I'm all ears. This is all so blissfully easy using the dreaded String class, but I'm trying to avoid that.
You can do this in 3 short lines. I gave you the link. Sorry, 4 lines. You need to use strtoul twice. Edit - first you have to declare two temporary cstrings as targets for the conversion.
Make two copies using strcpy or strncpy. Use strtoul to convert to your favourite number base.
There are a few other helpful functions and macros in there, take some time and explore it to get a sense of what they're up to.
I'm still banging my head against this wall. I can at least state the problem more succinctly now. See the comments in code below:
// the data arrives from my charge controller like this (for example):
uint16_t temperatures = 5657;
// but I need to break up those two hex numbers into two variables like this:
char temp1_hex[3] = "56";
char temp2_hex[3] = "57";
// from there it's super easy to convert from hex to decimal
byte temp1_byte = strtoul(temp1_hex, NULL, 16);
int temp1 = temp1_byte;
Serial.println(temp1); // prints "86", which is correct (hex 0x56 = decimal 86)
Any tips for converting the uint16_t variable "temperatures" to two chars?
This fails with "invalid conversion from 'uint16_t {aka short unsigned int}' to 'const char*' [-fpermissive]" for reasons I understand, but so far can't get around:
char temp[10];
strcpy (temp, temperatures);
// from there it's super easy to convert from hex to decimal
byte temp1_byte = strtoul(temp1_hex, NULL, 16);
int temp1 = temp1_byte;
What is the point of assigning an unsigned long result to a byte variable, then converting it to an int variable? It is much easier, and correct, to try this instead:
Serial.println(strtoul(temp1_hex, NULL, 16));
This fails with "invalid conversion from 'uint16_t {aka short unsigned int}' to 'const char*'
That is correct, because you are trying to use a C-string function to copy an unsigned integer variable into a C-string (zero terminated character array).
What do you actually want to do?
Probably not. For the right side of that statement, the compiler assumes a two byte decimal integer constant (on AVR based Arduinos).
From the previous posts, the data appear to arrive from the controller in the form of ASCII characters, hexadecimal representation.