Туговат на понимание работы с байтовыми операциями, прошу помочь

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Доброе время всем! Купил температурный датчик DS18B20. Скачал библиотечку, запустил тестовую прогу, получаю с датчика температуру, все ок. Но хочу разобратся как это все работает. Скачал даташит на него, читаю и пытаюсь сопоставить сс тем что в коде примера прописано, понимаю, что не хватает знаний С+...

Вот кусочек кода который хочу разобрать:

int16_t raw = (data[1] << 8) | data[0];
byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;  
    else if (cfg == 0x20) raw = raw & ~3;
raw = (raw & 0xFFF0) + 12 - data[6];

Как понять эту операцию "cfg=(data[4] & 0x60)", вот эту "raw = raw & ~7"

В массиве data находится значение к примеру (01 D6 01 4B 46 7F FF C 10 E9)

Здесь: data[1] << 8) | data[0] я понял только первую часть, это значение D6 (1101 0110) смещаем влево на 8 бит, т.е получаем такую штуку наверное (1101 0110 0000 0000), а вот что происходит в этой части

"| data[0]"  не понимаю...

И еще здесь

raw = (raw & 0xFFF0) + 12 - data[6];
(raw & 0xFFF0) - какая операция? 

+12  - прибавляем 12 в hex системе?

arduinec
Offline
Зарегистрирован: 01.09.2015

Побитовые операции (и другие) можно посмотреть здесь:
http://atmel.ucoz.ru/publ/spravochnik_po_jazyku/1-1-0-1

+12 в десятичном виде, в шестнадцатиричном виде будет +0x12

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Почитал, пробую пройти самостоятельно алгоритм и где-то туплю.. Вот что получилось у меня

Полный код:

 int16_t raw = (data[1] << 8) | data[0];
  if (type_s) {
    raw = raw << 3; 
    if (data[7] == 0x10) {
        raw = (raw & 0xFFF0) + 12 - data[6];
    }
  } else {
    byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;  
    else if (cfg == 0x20) raw = raw & ~3;
    else if (cfg == 0x40) raw = raw & ~1; 
   }

В массиве data = 01 08 02 4B 46 7F FF 0C 10 98

Высчитываю эту строку

raw = (data[1] << 8) | data[0];

Получаем data[1]=08(h) = 1000(b), добавляем 8 бит справа, получаем 1000 0000 0000(b), это 800(h) или 2048(dec)

Иду дальше - type_s =0, тогда

byte cfg = (data[4] & 0x60);

Data[4]=46(h) = 01000110(b), число 60(h) = 01100000(b), умножаем побитово, получаем 01000000(b) =40 (h)

Иду дальше

raw = raw & ~1;

Вот тут загвоздка... ~1 это значит инверсия 1, т.е равно 0, вроде так? тогда не понимаю команду "800(h) & ~1", по сути умножить на 0??? Вот тут я и завис ))) поясните как решается эта строка плиз )

P.S. знаю что в raw должен остаться резульат 208(h)

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Как показал опыт, похоже расшифровка значения температуры только в этой строке:

raw = (data[1] << 8) | data[0];

Осталось правильно ее понять )) при том что Data[1]=08(h), а Data[0]=01(h) число должно получится 208(h)

8(h) = 1000(b)

1(h) = 0001(b)

208(h) = 0010 0000 1000(b)

где тут логика ))

Дописал код:

celsius1 = (data[1] << 8);

Serial.print(celsius1);  получаю 512(dec), 200(h), 1000000000(b), вот тут я полностью потерялся... ведь функция <<8 должна добавить 8 нулей к значению 1000(b) ? а тут 6 нолей получается.. какой-то не польный байт даж... что я пропустил?

Жееесть какая!!! В data[1] хранится 1h, а в Data[0] хранится 8h!!! (выявил тем же print() )... тогда получается что 1(h) << 8  добавляет к 1 - 8 нулей,  100000000(b), и сравнивает с числом 1000(b)...

0001 0000 0000

0000 0000 1000

---------------------

0001 0000 1000 =108(h) а где еще 100(h)? ))

arduinec
Offline
Зарегистрирован: 01.09.2015

При data[1]=08(h) и data[0]=01(h) операция raw = (data[1] << 8) | data[0] даёт 0801(h) или 0x0801.

Русскоязычное описание датчика DS18B20 здесь:
http://masterkit.ru/zip/ds18b20-rus.pdf

arduinec
Offline
Зарегистрирован: 01.09.2015

Dr_grizzly пишет:

Вот кусочек кода который хочу разобрать:

int16_t raw = (data[1] << 8) | data[0];
byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;  
    else if (cfg == 0x20) raw = raw & ~3;
raw = (raw & 0xFFF0) + 12 - data[6];

Как понять эту операцию "cfg=(data[4] & 0x60)", вот эту "raw = raw & ~7"

В массиве data находится значение к примеру (01 D6 01 4B 46 7F FF C 10 E9)

raw = (data[1] << 8) | data[0] = 0xD601
cfg = (data[4] & 0x60) = 0x40
raw = raw & ~7 = raw & 0xFFF8 = 0xD600

Nosferatu
Offline
Зарегистрирован: 04.11.2012

Я такие расчёты на калькуляторе делаю. http://www.hexelon.com/kalkulator/index_en.php

arduinec
Offline
Зарегистрирован: 01.09.2015

Такие расчеты и в уме просто делаются, и на windows'ком калькуляторе можно сделать. Главное понимать!

Nosferatu
Offline
Зарегистрирован: 04.11.2012

Можно делать в уме, и на windows'ком калькуляторе, но придется заново  рассчитывать при внесении изменений.

Предпочитаю калькуляторы  которые поддерживают Ctrl+C  и Ctrl+V, это экономит время.

Jeka_M
Jeka_M аватар
Offline
Зарегистрирован: 06.07.2014

Nosferatu пишет:

Предпочитаю калькуляторы  которые поддерживают Ctrl+C  и Ctrl+V, это экономит время.

Windows'кий калькулятор поддерживает Ctrl+C и Ctrl+V, а также работает с разными системами счисления и позволяет переводить числа из одной системы в другую.

Nosferatu
Offline
Зарегистрирован: 04.11.2012

Да, проверил сейчас, поддерживает. Но неполноценно. Можно копировать и вставлять только последнее число. А заменять числа в начале расчёта никак.

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Да калькулятором то я и считаю, но нужно понимать что происходит, т.к. этот калькулятор нужно вписать в код программы)))

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

arduinec пишет:

Dr_grizzly пишет:

Вот кусочек кода который хочу разобрать:

int16_t raw = (data[1] << 8) | data[0];
byte cfg = (data[4] & 0x60);
    if (cfg == 0x00) raw = raw & ~7;  
    else if (cfg == 0x20) raw = raw & ~3;
raw = (raw & 0xFFF0) + 12 - data[6];

Как понять эту операцию "cfg=(data[4] & 0x60)", вот эту "raw = raw & ~7"

В массиве data находится значение к примеру (01 D6 01 4B 46 7F FF C 10 E9)

raw = (data[1] << 8) | data[0] = 0xD601
cfg = (data[4] & 0x60) = 0x40
raw = raw & ~7 = raw & 0xFFF8 = 0xD600

Я так понял что это на калькуляторе посчитано? как первую строку получили?

raw = (data[1] << 8) | data[0] = 0xD601 ? При том, что в Data[0]=8h а в Data[1] = 1h

 

arduinec
Offline
Зарегистрирован: 01.09.2015

Dr_grizzly пишет:

arduinec пишет:

Dr_grizzly пишет:

В массиве data находится значение к примеру (01 D6 01 4B 46 7F FF C 10 E9)

raw = (data[1] << 8) | data[0] = 0xD601

Я так понял что это на калькуляторе посчитано? как первую строку получили?

raw = (data[1] << 8) | data[0] = 0xD601 ? При том, что в Data[0]=8h а в Data[1] = 1h

Слабо свои собственные записи прочитать?
В массиве data находится значение к примеру (01 D6 ...

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

Теперь понял )) но это не верное, результат вычислений дает совсем другой ответ... он явно не соединяет эти два байта... при (01 08..) - получается 208(h) в этой строке... там еще какая-то операция, типа побитовое умножение.. но когда я его делаю на бумаге, у меня между разярядами не хватает одного нуля... не пойму от куда он берется в этом алгоритме..

Dr_grizzly
Dr_grizzly аватар
Offline
Зарегистрирован: 07.12.2015

прикол опять нашел ) Если представить число 01D6 то это 470(dec), что является верным.. 470/16=29,37 градуса цельсия... тогда не понимаю, что происходит с байтам data = (01 08 ... ).... здесь не выходит 32.50 градуса... 208(h)=520(dec)/16 = 32.50