У меня есть код:
#define AMB_LSB 0.0625
void Ambient::read()
{
uint32_t raw;
float filtered;
uint8_t bytes = 2;
uint8_t buf[bytes];
if(i2c_smbus_read_i2c_block_data(i2c_bus_address, A_TEMP_REG, bytes, buf) < 0)
printf("AMB Block Read Failed\n");
uint32_t va = buf[0];
uint32_t vb = buf[1];
uint32_t result = ((va<<8)+vb);
// 12-bit code
raw = result >> 4;
filtered = filter.execfilter( raw );
temperature = filtered * AMB_LSB; << CALCULATION
printf("AMB buffers %d %d -> result %d -> raw %d -> filtered %d -> amb C %f\n",va, vb, result, raw, filtered, temperature);
}
Это код для чтения информации с MCP9800 через i2c. Извините за включение, но, возможно, это как-то связано с этим.
Функция работает хорошо около дюжины циклов, пока внезапно не начнет иметь неправильные значения. Но с некоторыми странными отклонениями.
1. Если РАСЧЕТ следующий
temperature = filtered * AMB_LSB;
Я получаю этот вывод:
temperature = ((float) filtered * (float) AMB_LSB);
ЗА РАБОТОЙ
AMB buffers 28 240 -> result 7408 -> raw 463 -> filtered 463 -> amb C 28.937500
AMB buffers 28 240 -> result 7408 -> raw 463 -> filtered 463 -> amb C 28.937500
AMB buffers 28 240 -> result 7408 -> raw 463 -> filtered 1024 -> amb C 64.000000
провал
AMB buffers 29 0 -> result 7424 -> raw 464 -> filtered -**2147483648** -> amb C -134217728.000000
AMB buffers 29 0 -> result 7424 -> raw 464 -> filtered **2147483647** -> amb C 134217728.000000
AMB buffers 29 0 -> result 7424 -> raw 464 -> filtered -**2147483648** -> amb C -134217728.000000
Поэтому, как только он начинает давать сбой, я вижу, что вывод отфильтрованного значения неверен.
2. Если РАСЧЕТ:
temperature = raw * AMB_LSB;
Так что отфильтрованный вообще не используется, вывод такой:
ЗА РАБОТОЙ
AMB buffers 29 48 -> result 7472 -> raw 467 -> filtered 0 -> amb C 29.187500
AMB buffers 29 48 -> result 7472 -> raw 467 -> filtered 2147483647 -> amb C 29.187500
AMB buffers 29 64 -> result 7488 -> raw 468 -> filtered 468 -> amb C 29.250000
провал
AMB buffers **255 130** -> result **65410** -> raw **4088** -> filtered 2147483647 -> amb C 255.500000
AMB buffers **255 130** -> result **65410** -> raw **4088** -> filtered -2147483648 -> amb C 255.500000
AMB buffers **255 130** -> result **65410** -> raw **4088** -> filtered 2147483647 -> amb C 255.500000
Смотрите отмеченные звездочкой цифры для вывода, который является неправильным. По какой-то причине, когда вы не используете отфильтрованные значения, остальные цифры тоже начинают становиться неправильными! Всю дорогу до байтов я снял чип i2c.
Итак, сначала я вижу, что, возможно, фильтр не работает правильно. Но его удаление также делает неправильное необработанное значение необработанным. Все, что execFilter () делает, это некоторое усреднение, чтобы предотвратить большие случайные изменения.
Кроме того, я также создал скрипт через CLI, который использовал i2cget, и он был очень постоянным в своих возвращаемых значениях. Там не было сбоев или неожиданных значений.
Почему это происходит?
Похоже, аппаратная проблема. Многие из ваших значений 0x7FFFFFFF, например линия SDA управляется нагрузочным резистором. Это произошло бы, если бы шум на линии SDA вызвал ложное условие остановки I2C — устройство немедленно включило бы его выход, и вы получили бы только высокие биты для остальной части передачи.
На линиях SCL и SDA предлагаются фильтры низких частот RC для замедления фронтов и блокировки высокочастотного шума, что помогает предотвратить такие ошибки связи.
Проверьте возвращаемое значение из i2c_smbus_read_i2c_block_data()
звоните, а не только будь то отрицательный или нет.
Бьюсь об заклад, он возвращает 0 или 1, когда вы получаете неудачные переводы. Помните, что фактическая функция зависит от адаптера; Я бы никогда не предположил, что он полностью преуспеет, если не вернет ошибку, поскольку задокументировано, что вместо этого возвращается число байтов.
Это привело к повреждению памяти из другого класса в моем приложении.