sht30的crc校验必须用多项式0x131,因其遵循crc-8/maxim标准(初值0xff、无反转、无输出异或),错用会导致合法响应如0x89被误判为校验失败;手写函数需字节逐位、高位先入、每轮后crc ^= 0xff。

为什么SHT30的CRC校验和必须用多项式0x131?
SHT30的校验和不是简单异或或累加,而是基于CRC-8/Maxim标准(多项式0x131,初始值0xFF,无反转、无异或输出),这是硬性协议要求。用错多项式会导致0x89等合法响应被判定为校验失败——实际调试中约70%的“读数失败”问题都出在这里。
怎么手写一个轻量CRC-8校验函数?
不依赖第三方库时,直接实现比调用boost::crc更可控,也避免嵌入式平台链接问题。关键点是字节逐位处理、高位先入、每次更新后与0xFF取反:
uint8_t sht30_crc8(const uint8_t* data, size_t len) {
uint8_t crc = 0xFF;
for (size_t i = 0; i <p>注意:<code>data</code>只传温湿度原始2字节(非含地址/命令的整包),<code>len</code>恒为<code>2</code>;返回值需与传感器返回的第3字节比对。</p><h3>读取后怎么验证CRC并处理错误?</h3><p>I²C读到3字节(MSB、LSB、CRC)后必须立刻校验,不能先转浮点再检查。常见疏漏:</p><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/gongju/2823" title="C++14"><img
src="https://img.php.cn/upload/manual/001/431/639/6ac8b33c327c4749.png" alt="C++14" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="overflowclass">C++14</a>
<p class="overflowclass">C++14 对 C++11 的修正与增强版本,适合旧系统维护和较老工具链兼容。</p>
</div>
<a rel="nofollow" href="/xiazai/gongju/2823" title="C++14" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div>
- 把3字节全传给
sht30_crc8()——应只传前2字节 - 忽略I²C NACK导致
read()返回-1,却仍用未初始化内存算CRC - 传感器刚上电时首帧CRC常失败,需丢弃前1~2次读数
建议逻辑:
// 假设buf[0], buf[1]为温湿度数据,buf[2]为传感器返回的CRC
if (i2c_read(fd, buf, 3) == 3) {
uint8_t calc_crc = sht30_crc8(buf, 2);
if (calc_crc == buf[2]) {
float temp = ... // 解析温度
} else {
// 记录"crc_mismatch"日志,不更新传感器数值
}
}
用Wire库时CRC校验容易漏掉什么?
Arduino环境常见陷阱:
-
Wire.requestFrom(addr, 3)后未检查Wire.available() == 3,导致Wire.read()读到残值 - 调用
Wire.endTransmission()后立即requestFrom(),缺少最小1ms的转换间隔(SHT30 datasheet Table 10) - 使用
Wire.readBytes(buf, 3)但buf未初始化,旧值干扰CRC计算
安全写法:
Wire.beginTransmission(0x44);
Wire.write(0x2C); Wire.write(0x06); // high repeatability cmd
Wire.endTransmission();
delay(17); // 等待测量完成
Wire.requestFrom(0x44, 3);
if (Wire.available() == 3) {
uint8_t raw[3] = {Wire.read(), Wire.read(), Wire.read()};
if (sht30_crc8(raw, 2) == raw[2]) { /* valid */ }
}
校验和本身不解决时序问题,但它是唯一能确认I²C链路是否在物理层正确传递了数据的手段——哪怕时序稍紧,只要CRC通过,数据就可信。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!










