CRC в Si7021

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

Читаю данные из HTU21D(F) Старший байт, Младший байт, СRС. При пересчете CRC выявляется несовпадение суммы. 

В прямую считывал с логического анализатора данные, брал из ДШ, ничего совпадает.

К примеру 0x683A, CRC=0x7C, по ДШ. В реальности

Bout[0]=104; Bout[1]=58;Bout[3]=OneWire::crc8(Bout,2);

 Serial.print("CRC2 =  ");Serial.println(Bout[3], DEC); CRC2 =  236! Должно быть  124!  Полином далассовский... Целый день думаю, чего лыжи не едут. Сталкивался кто нибудь с этим?

 

b707
Онлайн
Зарегистрирован: 26.05.2017

А почему Bout[3] если длина данных 2 байта?

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

В Bout[3] записывается CRC предыдущих двух байт.

Pyotr
Offline
Зарегистрирован: 12.03.2014

Пример из интернетов - чтение влажности, температуры и расчет CRC8 для датчика si7021

/* Measurement of relative humidity and temperature using Si7021 */
#include <Wire.h>
#define ADDRESS_SI7021 0x40
#define MEASURE_RH_HOLD 0xE5
#define READ_T_FROM_PRE_RH_MEASUREMENT 0xE0
byte buffer[] = {0, 0, 0};
byte crcHumi;
word outHumi = 0;
int outTemp = 0;
unsigned long a, b;

void setup(){
  Wire.begin();
  //TWBR = 12;//400 kHz
  Serial.begin(9600);
}

void loop(){
  //perform a RH measurement and read back the RH value
  a = micros();
  Wire.beginTransmission(ADDRESS_SI7021);
  Wire.write(MEASURE_RH_HOLD);
  Wire.endTransmission();
  Wire.requestFrom(ADDRESS_SI7021, 3);
  if(Wire.available() >= 3){
    buffer[0] = Wire.read(); //high byte
    buffer[1] = Wire.read(); //low byte
    buffer[2] = Wire.read(); //crc
  }
  outHumi = (buffer[0]<<8) | buffer[1];
  crcHumi = CRC8(outHumi, buffer[2]);
  
  outHumi = word(12500Ul *outHumi /65536 - 600);//целое в сотых %
  
  //read temperature from previous RH measurement
  Wire.beginTransmission(ADDRESS_SI7021);
  Wire.write(READ_T_FROM_PRE_RH_MEASUREMENT);
  Wire.endTransmission();
  Wire.requestFrom(ADDRESS_SI7021, 2);
  if(Wire.available() >= 2){
    buffer[0] = Wire.read(); //high byte
    buffer[1] = Wire.read(); //low byte; no crc
  }
  outTemp = (buffer[0]<<8) | buffer[1];
  outTemp = int(17572L *outTemp /65536 - 4685);//целое в сотых *С
  
  //valueHumi = 125.0*outHumi/65536 - 6;//float
  //valueTemp = 175.72*outTemp/65536 - 46.85;//float
  b = micros();
 
  Serial.print(float(outHumi) /100); Serial.print(" \%RH\t"); 
  Serial.print(float(outTemp) /100); Serial.println(" C");
  Serial.print(buffer[2]);Serial.print(" CRC "); Serial.println(buffer[2],BIN);
  Serial.print(crcHumi); Serial.print(" crc ");Serial.println(crcHumi, BIN);
  Serial.println();
//  if (crcHumi == 0 && outHumi != 0 && outTemp != 0){
//    Serial.println("CRC checked.");
//    Serial.println(b-a);//19 msec
//  }
//  else{
//    Serial.println("Error!");
//  }
  delay(1000);
}
//==HTU21D Humidity Sensor Library By: Nathan Seidle SparkFun Electronics
byte CRC8(uint16_t message_from_sensor, uint8_t check_value_from_sensor){
  uint32_t remainder = (uint32_t)message_from_sensor << 8; 
  //Pad with 8 bits because we have to add in the check value
  remainder |= check_value_from_sensor; //Add on the check value
  uint32_t divsor = (uint32_t)0x988000;
  for (int i = 0 ; i < 16 ; i++){ //Operate on only 16 positions of max 24. 
  //The remaining 8 are our remainder and should be zero when we're done.
    if( remainder & (uint32_t)1<<(23 - i) ) //Check if there is a one in the left position
      remainder ^= divsor;
      divsor >>= 1; //Rotate the divsor max 16 times so that we have 8 bits left of a remainder
    }
  return (byte)remainder;
}

 

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

Спасибо! Как раз такой скетч искал! Сейчас посмотрим, что там в третьем байте пересылается.

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

Проверил - суммы совпадают, значит, ошибка в моей программе на АСМе. Спасибо!

 

b707
Онлайн
Зарегистрирован: 26.05.2017

CotDaVinchi пишет:

В Bout[3] записывается CRC предыдущих двух байт.

третий байт массива - это Bout[2], а не Bout[3]

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

Ага! Рассеянность... Сути несовпадения сумм это не меняет. Запустил прогу - CRC высчитанное и полученное не совпадают. Совпало только в одном месте, именно в него и уткнулся на радостях. CRC считал другой библиотекой.

  Serial.print(buffer[0]);Serial.print(" B0 "); Serial.println(buffer[0],BIN);
  Serial.print(buffer[1]);Serial.print(" B1 "); Serial.println(buffer[1],BIN);
  Serial.print(buffer[2]);Serial.print(" B2 "); Serial.println(buffer[2],BIN);
      crcTST=OneWire::crc8(buffer,2);//  расчет контрольной суммы 
  Serial.print(crcTST);Serial.print(" B21 "); Serial.println(crcTST,BIN);
 
148 B0 10010100
238 B1 11101110
16 B2 10000
14 B21 1110
 
Видимо начать надо заново и с железа. 
Кстати, что это за команда Е0?  В ДШ идут команды Е3,Е5,Е6. 
 
Pyotr
Offline
Зарегистрирован: 12.03.2014

команда 0xE0  считывает температуру, при которой производилось последнее измерение влажности

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

Понятно.

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

Железо -ОК! Может CRC считается как то по другому? Примеры из ДШ тоже не совпадают.

Где читать об остальных командах, не представленных в ДШ?

Все таки косяк в проге на АСМ. 

sadman41
Offline
Зарегистрирован: 19.10.2016

На вход подаётся массив, выловленный из Wire (3 байта) Возвращаемый результат равен нулю при корректном CRC.

#define SHIFTED_DIVISOR 0x988000UL 

static uint8_t calcSHT2xCRC(uint8_t* _src) {

  uint32_t remainder = ((uint32_t) _src[0x00] << 16) | ((uint16_t) _src[0x01] << 8) | _src[0x02]);

  uint32_t divisor = (uint32_t) SHIFTED_DIVISOR;

  for (uint8_t i = 0x00 ; 0x10 > i ; i++) {
    if (remainder & ((uint32_t) 0x01 << (0x17 - i))) { remainder ^= divisor; }
    divisor >>= 1; 
  }

  //Serial.print("CRC: "); Serial.println((uint8_t) remainder);
  return (uint8_t) remainder;
}

 

 

CotDaVinchi
Offline
Зарегистрирован: 12.05.2016

Спасибо! Я тоже исследовал, где накосячил. Пишу на АСМе, поэтому Си, немного не в тему, но подход - тот же! необходимо суммировать все ТРИ байта. Буду переделывать. Проверял вручную 100110001 и XOR. На определенных шагах вычислений получался 0.