[uquote="Влад56",url="/forum/viewtopic.php?p=4667818#p4667818"]Вы не могли бы просто пояснить что есть полином Х8+Х2+Х1+1. Везде поясняется так, что при записи нового адреса следует сложить десятичные значение адреса слейва, команду, мл.байт и старший байт соответственно.[/uquote]Начну с того, что в интернете есть
онлайн-калькулятор для вычисления этого кода. Я только что ввёл туда пример из PDFa по записи в EEPROM: b42207c8, указав Content Type = HEX и получил ответ Hex Result = 48. В ПДФе приведено тоже 48, так что всё сходится.
А вообще циклический контрольный код отличается от простой контрольной суммы тем, что вычисления делаются несколько раз в цикле, но со сдвигами. В выражении Х8+Х2+Х1+1 пропущены знаки возведения в степень. Вместе с ними должно быть x^8 + x^2 + x^1 + 1. Опять же, считать это всё вручную не надо. Для обсуждаемого датчика подходит вот такая подпрограммка (я её не сам написал, а нашёл в интернете да адаптировал для этого датчика, выкинув из неё всё лишнее):
Спойлер
Код: Выделить всё
/*
* Name : CRC-8
* Poly : 0x07 x^8 + x^2 + x^1 + 1
* Init : 0x00
* Revert: false
* XorOut: 0x00
* Check : 0xF7 ("123456789")
* MaxLen: 15 байт(127 бит) - обнаружение одинарных,
* двойных, тройных и всех нечётных ошибок
*/
unsigned char crc8(unsigned char *pcBlock, unsigned int len) {
#define poly 0x07 // порождающий многочлен
#define init 0x00 // начальное значение
unsigned char crc = init;
while (len--) { crc ^= *pcBlock++;
for (unsigned int i = 0; i < 8; i++) crc = crc & 0x80 ? (crc << 1) ^ poly : crc << 1;
}
return crc;
}
Там, собственно, после выкидывания осталось всего 5 строчек, не считая пары дефайнов, но в алгоритмах CRC есть две фишки: это начальное значение CRC и значение порождающего многочлена. Для этого датчика начальное значение CRC должно быть равно нулю, а порождающий многочлен — 7. Где я это вычитал, уже не помню, а вот так прямо щас в ПДФе этих данных не нашёл. Может, просто подобрал их в своё время в ходе экспериментов. И не надо самому вычислять никаких сумм: надо лишь в вызывающей программе объявить массив подходящей длины (для измерения температуры достаточно 5 элементов, для изменения адреса может хватить и 4, но я сделал для себя 6 во избежание выхода за границы массива) да скормить подпрограмме CRC8 этот массив и его длину. Когда я измеряю температуру, то там всё делаю по книжке:
Спойлер
Код: Выделить всё
#define ADDR_TS 0x5A // Address for SMBus temperature sensor
#define size_of_cmd 1
#define size_of_data 3
int short temp; // температура
uint8_t read_tr[1]={0x07}; // команда чтения температуры объекта
uint8_t buf_crc[6]={ADDR_TS<<1, 0, (ADDR_TS<<1)+1, 0, 0, 0}, buf_t[3];
smbus_res_t result;
SMBus.write(ADDR_TS, read_tr, size_of_cmd, no_stop_bit);
result = SMBus.read(ADDR_TS, buf_t, size_of_data, with_stop_bit);
temp = ((buf_t[1] << 8) + buf_t[0]) / 5 - 2731;
buf_crc[1] = read_tr[0];
buf_crc[3] = buf_t[0];
buf_crc[4] = buf_t[1];
crc = crc8(buf_crc, 5);
Заметьте, что я читаю с шины SMBus в массив buf_t, а затем вручную переношу два байта в массив buf_crc. На ассемблере я бы сразу читал в buf_crc и не делал бы промежуточного массива. Но в С я слаб, поэтому мне проще сделать промежуточный массив. Если я правильно понял книжку, то для смены адреса надо сделать наоборот, сначала заполнить четырьмя нужными значениями массив buf_crc, затем вычислить CRC8, после чего записать этот пакет в датчик. То есть должно получиться что-то вроде этого:
Код: Выделить всё
uint8_t write_tr[3]={0x2E,0x5B,0}; // команда смены адреса
//buf_crc[0] = ADDR_TS<<1; // адрес можно не формировать каждый раз, но после смены придётся
buf_crc[1] = write_tr[0]; // здесь будет команда записи нового адреса, возможно это 0x2E
buf_crc[2] = write_tr[1]; // младший байт команды
buf_crc[3] = write_tr[2]; // старший байт команды
buf_crc[4] = crc8(buf_crc, 4); // PEC
SMBus.write(ADDR_TS, write_tr, 4, no_stop_bit); // а может и 3...
Но я не проверял, поэтому гарантии дать не могу. И там ещё указано, что прежде чем писать что-то в EEPROM, надо сначала стереть старое значение, записав в эту ячейку ноль, так что эту процедуру надо сначала выполнить с нулём, потом подождать 5-10 мс, потом выполнить сию процедуру уже с нужным значением, снова подождать 5-10 мс, после чего уже можно будет считать записанное значение, чтобы убедиться, что оно действительно записалось.
Ну и я не привожу текстов библиотеки SMBus, поскольку у меня процессор не Атмега, так что они будут не очень полезны. Просто надо понимать, что обе функции (как Read, так и Write) посылают адрес, указанный первым аргументом, затем Write посылает, а Read принимает массив, указанный вторым аргументом, длина которого указана третьим аргументом. Четвёртым аргументом указано наличие или отсутствие заключительного стоп-бита. В принципе, функция записи заливает весь пакет в датчик на одном дыхании, так что её можно было бы заставить просто заливать массив buf_crc без использования промежуточного массива write_tr. Но изначально это была библиотека I2C, она была написана (не мной) именно так, и я не стал её сильно переделывать. Работает — и ладно!
В моем случае 5А (90),2Е (46)-адрес регистра где шинный адрес храниться, то что будем записывать(к примеру новый адрес 0х5В (91). Это 227 в сумме.
Нет. Там циклическая сумма, её надо считать той подпрограммой CRC8. И если честно, то я пока не уверен, сколько байт надо записывать при смене адреса: один или два. Ведь в описалове про команду 0x2E сказано "LSByte only". Может статься, эта команда будет трёхбайтовой 5A2E5B, и тогда PEC будет 5D, пятая строчка незаспойлеренного кода будет лишней, а шестая превратится в buf_crc[3] = crc8(buf_crc, 3);, ну и в седьмой будет тройка вместо четвёрки. Но что-то я плохо понимаю смысл написанного в ПДФе на 18-й странице:
для того, чтобы обеспечить доступ к любому устройству или назначить адресс слейву перед подключением его в систему, связь надо начать с нулевым адресом, за которым подать нулевой R/W бит. Когда мастер подаёт эту команду, MLX90614 всегда отвечает, игнорируя свою внутреннюю информацию. Может статься, что правильная команда будет начинаться с нулевого адреса 002E5B, и тогда PEC будет FE, но это всё надо проверять на реальном датчике.
При попытке чтения дефолтного адреса на шине, датчик шлет мне контрольную сумму 190. Могу я 191 ему отослать, чтобы он адрес поменял на следующий по списку?
Нет. При смене адреса на единицу CRC8 съедет на несколько единиц. Это не контрольная сумма.