Pymodbus: как мне прочитать отдельные биты этого входного регистра?

У меня есть проект солнечной энергии и монитор в реальном времени, который использует контроллер заряда EpSolar Tracer и Raspberry Pi для считывания энергетических данных через MODBUS.

Я легко читаю входные регистры, когда они простые целые числа, например:

# 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)

... но у меня проблемы с пониманием того, как я читаю входной регистр, в котором каждый из отдельных битов обозначает что-то свое. В частности, я хочу прочитать регистр "статуса зарядки", который содержит 12 различных частей информации -

Посмотреть изображение

Когда я читаю этот регистр (0x3201), все, что я получаю, это число 7. Как бы я прочитал каждый из 12 различных фрагментов данных в этом регистре? Я думал, что, возможно, 7 - десятичное представление 0000000000000111 - но я не думаю, что это может быть правильно.

Любая помощь в этом будет оценена!

Matt

1 ответ

Вы на правильном пути. И эти биты легко достать. Вот как:

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

Верхняя строка - это позиция бита, а нижняя строка - это значение 7... допустим, вас интересует бит 2, третий справа. Давайте сделаем немного маски для этого, взяв 1 и сдвинув его n раз, где n это битовая позиция. Итак, мы хотим сдвинуть его 2 раза:

int mask = (1 << 2);

Это даст:

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

Теперь все, что мы делаем, чтобы определить, установлен ли второй бит, это AND значение и маска

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

Итак, в 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

Теперь иногда вы хотите извлечь более одного бита. Вот пример того, как извлечь двухбитную комбинацию. Сначала давайте оговорим, что два бита 11 это значение 3 (один 1 и один 2). Итак, теперь мы собираемся сделать аналогичный процесс, чтобы извлечь два бита из одного и того же значения (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

Теперь мы маскируем с 3 вместо 1:

int mask = (3 << 2);

Это даст:

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

Теперь все, что мы делаем, чтобы определить, установлен ли второй бит, это AND значение и маска

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

Но в документации может быть что-то вроде битов:3-2 это "статус х". ценности -

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

Итак, теперь мы должны взять наше окончательное значение, 0100 из ANDприведите приведенный выше результат и сдвиньте его на два вправо, чтобы получить следующие возможные значения:

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

Так как результатом является 01, десятичное 1, шестнадцатеричное 1, то результат b сверху.

РЕДАКТИРОВАТЬ:

Теперь окончательные расчеты в python:

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

Тот же результат, биты 3-2 равны 1, что означает (на основе вашей таблицы данных), что результат диагностики:

бит 0: "работает", бит 1: "ошибка", бит 3-2: "поплавок"

Другие вопросы по тегам