2

I have a solar power project and real-time monitor which uses an EpSolar Tracer charge controller, and a Raspberry Pi to read the energy data via MODBUS.

I'm reading the input registers easily when they are simple integers, like this -

# Request the range of registers that hold the solar/battery realtime data (3100 - 3105)
result = client.read_input_registers(0x3100,6,unit=1)

# Solar voltage is register 3100, divide by 100
sV = float(result.registers[0] / 100.0)

..but I'm having trouble understanding how I read an input register in which each of the individual bits stand for something different. In particular, I want to read a 'charging status' register which holds 12 different pieces of information -

See image

When I read this register (0x3201) all I get back is the number 7. How would I go about reading each of the 12 different pieces of data in this register? I thought perhaps 7 is the decimal representation of 0000000000000111 - but I don't think this can be right.

Any help on this would be appreciated!

Matt

Martin Tournoij
  • 26,737
  • 24
  • 105
  • 146
Matt Hubbert
  • 21
  • 1
  • 2

1 Answers1

1

You're on the right track. And it's easy to get those bits out. Here's how:

16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
                                           1  1  1

The top line is the bit position and the bottom line is the value 7...let's say you're interest in bit 2, the third from the right. Let's make a bit mask for that bit by taking a 1 and shifting it over n times, where n is the bit position. So we want to shift it 2 times:

int mask = (1 << 2);

This will yield:

16 15 14 13 12 11 10 09 09 07 06 05 04 03 02 01 00
                                           1  0  0

Now all we do to determine if bit two is set is to AND the value and the mask

16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
                                           1  1  1   value
                                           1  0  0   mask
--------------------------------------------------
                                           1  0  0   ANDed result

So, in C:

int value = 7;  // or any 16-bit value
int mask = (1 << 2);  // == 4

if ((value & (1 << 2)) == mask)
    // bit is set
else
    // bit is not set

Now, sometimes you want to extract more than one bit. Here's an example of how to extract a two-bit combination. First let's stipulate that two bits 11 is the value 3 (one 1 and one 2). So now w're going to do a similar process to extract two bits from the same value (7).

16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  1

Now we mask with a 3 instead of a 1:

int mask = (3 << 2);

This will yield:

16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
 0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  0  0

Now all we do to determine if bit two is set is to AND the value and the mask

16 15 14 13 12 11 10 09 08 07 06 05 04 03 02 01 00
 0  0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  1   value
 0  0  0  0  0  0  0  0  0  0  0  0  0  1  1  0  0   mask
--------------------------------------------------
                                        0  1  0  0   ANDed result

But the documentation might say something like bits:3-2 is "status x." values -

00 - a
01 - b
02 - c
03 - d

So now we have to take our final value, 0100 from the ANDed result above, and shift it two to the right to get these possible values:

result = (old_result >> 2);
0100 >> 2 == 01 

Since the result is 01, decimal 1, hexadecimal 1, then the result is b from above.

EDIT:

Now the final calculations in python:

>>> value = 0x0007
>>> mask = (3 << 2)
>>> result = value & mask
>>> print (result)
4
>>> shifted_result = result >> 2
>>> print (shifted_result)
1

Same result, bits 3-2 are equal to 1, which means (based on your datasheet) that the diagnostic result is:

bit 0: "running" bit 1: "fault" bit 3-2: "float"

TomServo
  • 7,248
  • 5
  • 30
  • 47
  • Thanks for your quick response. The only reason I thought I was mistaken is because this result would suggest that there is a fault with the charger. (D1: 0 Normal, 1 Fault.) but I'm quite certain there's no fault with it, its working fine! However, apart from that the other values seem correct. (That it's running, and currently in float charge mode). – Matt Hubbert Jun 25 '17 at 12:18
  • @MattHubbert If this helps, an upvote and "Accept" would help others find this answer as well, thanks. Your questions is titled well enough that the question, and hopefully my answer, are both general enough that others could benefit. – JLH 11 mins ago – TomServo Jun 25 '17 at 12:32
  • Thanks. I'm still not sure how I convert that decimal. Converting 7 into binary might give me 111, but the actual data I'm trying to read is hexadecimal. Converting decimal to hexadecimal gives me the same number, 7. Furthermore, the information in the image provided above says that the values in some of the bits range from 00/01/02/03 - not just 0 or 1. Still confused I'm afraid! – Matt Hubbert Jun 25 '17 at 12:41
  • Ah yes, which of the two bit-combinations are you interested in? I'll cook up a solution for you. – TomServo Jun 25 '17 at 12:44
  • I'm mostly interested in D3-2: Charging status. 00 No charging, 01 Float, 02 Boost, 03 Equalization. – Matt Hubbert Jun 25 '17 at 12:50
  • @MattHubbert Looking at your picture now -- which I missed before -- I can see the bit patterns now. A value of 7 means D3-2 says it's in float mode, D1 = 1 says there's a fault, D0 =1 means it's on standby. It is reporting fault mode ,so that is unexpected if it's floating and on standby. But that's what the value says. – TomServo Jun 25 '17 at 13:08
  • @MattHubbert What's weird is the fault bit D1 is set, but no other of the higher bits are set, which ostensibly show the various kinds of faults.. That I cannot explain. – TomServo Jun 25 '17 at 13:11
  • 1
    Note that I've come across many datasheets that have typos and other issues (documentation says a bit(s) are in one place but I've proven out that the reality was different), so if you're getting weird results (unexpected fault bit set for instance), try to look around for updated versions of the document, or whether others have experienced similar findings. I'm not saying that's the case here, but I see the same result (lowest three bits are set, indicating a fault while charge status is floating and in running status). – stevieb Jun 25 '17 at 13:40
  • @MattHubbert Would it help you if I were to amend my answer to by in python? I used C because that's my main "bit twiddling" language. ;) – TomServo Jun 25 '17 at 13:55
  • @MattHubbert Added python example to end of my answer. – TomServo Jun 25 '17 at 14:04