以太网温湿度传感器CRC16与CRC32选型及代码实现
发布时间:2026/9/20 5:15:05来源:尧图网络
以太网温湿度传感器这个品类做过的朋友应该都有体会硬件本身不复杂一颗温湿度芯片加一颗带MAC的MCU或者外挂PHY跑个TCP或者UDP把数据丢出去就完事了。但真正到了现场部署尤其是工业环境里多节点、长线缆、电磁干扰大的场景数据传着传着就飘了——温度突然跳变0.5度、湿度偶尔冒出一个负值、设备跑几天之后通信直接卡死。这些问题十有八九不是传感器坏了而是通信链路上的数据完整性没兜住。校验算法就是兜这个底的东西。CRC16和CRC32是嵌入式通信里最常用的两种校验手段但很多人选型的时候基本靠顺手——之前项目用的CRC16这个项目接着用或者听说CRC32更安全直接上CRC32。实际上这两种校验在以太网温湿度传感器这个具体场景下选哪个、怎么用、用在哪一层是有明确工程逻辑的。这篇文章就把我在几个实际项目里踩过的坑、做过的取舍、以及最终跑通的代码实现完整复盘一遍从选型依据到代码落地到现场排错尽量把每个决策背后的为什么讲清楚。1. 以太网温湿度传感器的通信链路到底长什么样1.1 从传感器到上位机的完整数据路径先把这个场景的通信链路拆开看不然后面讨论校验放在哪里就是空中楼阁。一个典型的以太网温湿度传感器系统数据从敏感元件到最终上位机显示大致经过这么几段传感芯片到MCUDHT11、SHT30、SHT31这类芯片通过单总线或I2C把原始温湿度值交给MCU。这一段距离极短通常几厘米干扰有限芯片本身一般自带简单的校验比如DHT11的8位校验和、SHT30的CRC8。MCU内部处理MCU把原始数据换算成实际物理量做线性化、温度补偿然后打包成应用层协议帧。MCU到PHY再到网线如果MCU自带MAC直接通过RMII/MII接口连PHY芯片如果没有就外挂一颗MACPHY合一的芯片比如W5500、ENC28J60。这一段是并行总线或SPI速率不高但时序要求严格。网线传输双绞线可能几米也可能上百米经过交换机、路由器这一段是干扰最严重、最容易出问题的地方。上位机接收解析PC或网关收到以太网帧剥掉各层协议头取出应用层数据校验然后使用。关键点在于以太网本身在数据链路层已经有FCS帧校验序列用的是CRC32。也就是说从MCU的MAC到上位机的MAC这一整段链路硬件层面已经帮你做了一次CRC32校验。那为什么应用层还要再做一次校验这是很多人没想明白的地方也是选型混乱的根源。1.2 以太网FCS能兜住什么、兜不住什么以太网帧尾的FCS字段是32位CRC覆盖范围是从目的MAC地址到数据字段结束的整个帧内容。它的作用是检测帧在传输过程中是否发生了比特错误。如果FCS校验失败网卡硬件直接丢帧上层协议栈根本看不到这个包。听起来很完美对吧但有几个现实问题第一FCS只保护传输段不保护端点内部。数据从传感芯片读到MCU、在MCU内存里搬运、经过SPI或并口送到MAC这些环节出的错FCS管不着。比如I2C读SHT30的时候时序被中断打断读回来一个错值MCU照样把它打包发出去FCS算出来是对的因为FCS只对你发出去的内容负责不对你发出去的内容是否正确负责。第二交换机、路由器在转发时可能重新计算FCS。有些网络设备在存储转发过程中会剥离原FCS再重新生成如果设备内部处理有bug错误可能被洗白。第三应用层协议帧可能跨多个以太网帧。如果你的温湿度数据包比较大或者用了TCP流式传输一个应用层帧可能被拆到多个以太网帧里每个以太网帧的FCS各自独立但应用层数据的完整性需要端到端的校验来保证。第四软件bug和内存越界。MCU程序跑飞了、缓冲区溢出了、DMA搬运地址错了这些产生的错误数据在发送时FCS是正常的但内容是错的。所以结论很明确以太网FCS是必要的但不充分。应用层必须有自己的校验机制。这就是CRC16和CRC32在应用层存在的意义。1.3 应用层校验的插入位置选择应用层校验加在哪里直接影响校验效果和系统开销。常见的做法有三种校验位置覆盖范围优点缺点仅帧头数据应用层有效载荷开销小实现简单不保护帧头中的长度、命令字等字段帧头数据帧尾整个应用层帧保护全面需要先确定帧尾实现稍复杂分段校验每个数据段独立校验可定位错误段开销大协议复杂我在实际项目中用的是第二种从帧起始标志到校验字段之前的所有字节都参与CRC计算校验值放在帧尾。这样帧头里的设备地址、命令字、数据长度、数据内容全部被保护。代价是接收端必须先找到帧起始标志然后按长度字段读出完整帧再对校验字段之前的内容算CRC最后比对。这个方案的好处是任何单比特错误、大部分多比特错误都能被捕获。坏处是如果长度字段本身被干扰错了可能导致读帧长度错误进而校验失败——但这本身也是一种保护因为长度错了校验必然过不了。2. CRC16和CRC32的工程差异不只是位数2.1 检错能力的真实差距很多人以为CRC32就是比CRC16强一倍因为位数多了一倍。实际差距比这个复杂。CRC的检错能力取决于生成多项式的阶数和具体形式。对于随机比特错误一个n位CRC能保证检测出所有长度不超过n的单比特错误和双比特错误能检测出所有奇数个比特错误如果生成多项式包含因子x1能检测出所有长度不超过n的突发错误。具体到常用参数CRC16-CCITT多项式0x102116位能检测所有≤16位的突发错误对17位突发错误的漏检率约2^-15对更长突发错误漏检率约2^-16。在误码率10^-5的链路上对于100字节的帧漏检概率大约在10^-9量级。CRC32以太网多项式0x04C11DB732位能检测所有≤32位的突发错误对更长突发错误漏检率约2^-32。同样条件下漏检概率大约在10^-19量级。看起来CRC32碾压CRC16但要注意这是在随机独立比特错误的假设下。实际工业现场的干扰往往不是随机的而是突发性的、周期性的比如变频器干扰、继电器动作、电机启停。这种情况下两种CRC的实际表现差距可能没有理论值那么大但CRC32仍然有明显优势。2.2 计算开销的实测对比在STM32F10372MHz Cortex-M3上我用查表法实测过两种CRC的计算耗时算法实现方式每字节耗时100字节帧总耗时CRC16-CCITT256项查表约1.2μs约120μsCRC16-CCITT逐位计算约8μs约800μsCRC32256项查表约1.8μs约180μsCRC32逐位计算约15μs约1500μsCRC32STM32硬件CRC约0.1μs约10μs几个关键发现第一查表法比逐位法快6-8倍这是必须用的优化。查表需要256×2512字节CRC16或256×41024字节CRC32的Flash空间对现在的MCU来说完全不是问题。第二CRC16和CRC32的查表法耗时差距只有50%左右不是翻倍。因为主要开销在查表和异或操作位数增加只影响寄存器宽度和表项大小。第三STM32F4/F7/H7系列有硬件CRC外设但注意STM32硬件CRC默认用的是固定多项式CRC32是0x04C11DB7和以太网一致而且它是按字32位计算的不是按字节。如果你的数据长度不是4的倍数需要做填充处理还要注意字节序问题。我在F407上用过硬件CRC速度确实快但配置起来有几个坑后面单独讲。2.3 什么场景下CRC16够用、什么场景必须上CRC32基于上面的分析我给出一个实际选型建议CRC16够用的场景传感器节点数量少10个网络拓扑简单交换机直连线缆长度短30米走线规范远离强干扰源数据更新率低1秒/次偶尔丢一帧不影响业务MCU资源紧张Flash64KBRAM8KB比如STM32F030、STC15系列应用层帧长度短64字节必须上CRC32的场景工业现场有变频器、大功率电机、继电器等干扰源线缆长50米或经过多级交换数据用于闭环控制或安全相关错误数据后果严重应用层帧长128字节或者需要传输配置参数、固件片段MCU有硬件CRC外设计算开销可以忽略我个人的经验是如果MCU是STM32F4以上且有硬件CRC无脑上CRC32因为开销几乎为零检错能力提升明显。如果是F1或更低端MCU看现场环境环境好的用CRC16环境差的还是建议CRC32那点CPU开销换来的是现场少跑几趟。3. 代码实现从查表生成到帧校验的完整链路3.1 CRC16-CCITT查表法的实现细节先给一份可以直接用的CRC16-CCITT代码。多项式用0x1021初始值0xFFFF这是最常用的配置。#include stdint.h // CRC16-CCITT 查表多项式0x1021初始值0xFFFF static const uint16_t crc16_table[256] { 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7, 0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF, // ... 中间省略实际使用时需要完整256项 }; uint16_t crc16_ccitt(const uint8_t *data, uint32_t len) { uint16_t crc 0xFFFF; for (uint32_t i 0; i len; i) { uint8_t idx (uint8_t)((crc 8) ^ data[i]); crc (crc 8) ^ crc16_table[idx]; } return crc; }这段代码有几个容易出错的地方第一查表索引的计算。(crc 8) ^ data[i]这个表达式对于CRC16-CCITT非反射算法是取CRC寄存器的高8位与数据字节异或。如果你用的是反射算法比如CRC16-IBM/Modbus索引计算方式不同表也不同。千万不要混用。第二初始值。0xFFFF和0x0000算出来的结果完全不同。CCITT标准推荐0xFFFF但有些协议用0x0000。你的发送端和接收端必须一致否则永远校验失败。第三结果是否需要异或。有些CRC变体在最后会把结果与0xFFFF异或比如CRC16-IBMCCITT通常不异或。这个也要两端一致。我踩过的坑有一次用了一个网上的CRC16代码发送端算出来和接收端对不上查了半天发现是发送端用了CCITT初始值0xFFFF接收端用了0x0000。这种问题没有捷径就是两端用同一份代码、同一套参数。3.2 CRC32查表法的实现与STM32硬件CRC的坑CRC32的软件实现和CRC16结构一样只是表项变成32位static const uint32_t crc32_table[256] { 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, // ... 完整256项 }; uint32_t crc32_ethernet(const uint8_t *data, uint32_t len) { uint32_t crc 0xFFFFFFFF; for (uint32_t i 0; i len; i) { uint8_t idx (uint8_t)((crc ^ data[i]) 0xFF); crc (crc 8) ^ crc32_table[idx]; } return crc ^ 0xFFFFFFFF; }注意这里用的是反射算法右移索引取低8位这是以太网CRC32的标准形式。初始值0xFFFFFFFF最后结果异或0xFFFFFFFF。这个和以太网FCS用的参数完全一致。现在说STM32硬件CRC的坑。以STM32F407为例硬件CRC外设默认配置多项式0x04C11DB7固定不可改初始值0xFFFFFFFF输入数据按32位字写入输出需要手动异或0xFFFFFFFF问题来了硬件CRC是按字32位计算的不是按字节。如果你的数据长度不是4的倍数怎么办我的做法是在数据末尾填充0x00到4字节对齐然后写入。但要注意填充的0x00会参与计算所以接收端也必须做同样的填充。或者更稳妥的做法是只在数据长度是4的倍数时用硬件CRC否则用软件查表。因为温湿度数据帧通常很短20-40字节软件查表也就几十微秒不值得为了用硬件而引入填充逻辑的复杂性。还有一个坑字节序。STM32是小端模式硬件CRC按字读取时一个32位字内部的字节顺序会影响结果。比如数据是0x01 0x02 0x03 0x04按小端组成字是0x04030201按大端是0x01020304算出来的CRC不同。你需要确认你的协议定义的是哪种字节序然后相应地组织数据。我在F407项目里的实际做法是应用层CRC统一用软件查表法保证跨平台一致性硬件CRC只在需要高速校验大块数据比如固件升级包时使用并且单独封装一个函数明确标注字节序和填充规则。3.3 应用层帧格式设计与校验字段的放置有了CRC函数接下来是帧格式。我用的帧结构如下字段长度说明帧头2字节0xAA 0x55固定设备地址1字节1-2540为广播命令字1字节0x01读温湿度0x02读配置等数据长度1字节后续数据字段的字节数数据N字节温湿度值、配置参数等CRC16/CRC322或4字节从帧头到数据字段结束的校验值帧尾2字节0x0D 0x0A可选校验范围是从帧头开始到数据字段结束不包括CRC字段本身和帧尾。接收端的处理流程在接收缓冲区里搜索帧头0xAA 0x55找到帧头后读取设备地址、命令字、数据长度根据数据长度计算出整帧长度检查缓冲区里是否有足够字节对帧头到数据字段结束的内容计算CRC与接收到的CRC字段比对如果一致处理数据不一致丢弃并记录错误计数这里有个细节如果数据长度字段被干扰错了怎么办比如实际数据长度是4被干扰成200接收端会等待200字节导致帧解析卡死。我的处理方式是设置最大帧长度限制比如数据长度字段超过64就认为是错误帧直接丢弃并重新搜索帧头。同时接收端要有超时机制如果超过一定时间没收到完整帧清空缓冲区重新同步。3.4 发送端和接收端的对称性验证代码写完之后必须做对称性验证。我常用的方法是第一步用PC端工具生成测试向量。找一个在线的CRC计算器注意选择正确的参数CRC16-CCITT多项式0x1021初始值0xFFFF不反射不异或输入几个已知字节序列记下结果。第二步在MCU上跑同样的字节序列用串口打印出计算结果和PC端比对。如果不一致检查参数配置。第三步构造错误帧测试。故意修改帧中某一个字节确认接收端能检测出CRC错误并丢弃。第四步边界测试。测试空数据、1字节数据、最大长度数据确认没有缓冲区溢出或计算错误。我踩过的一个坑在PC端用在线工具算CRC时没注意工具默认用的是反射算法结果和MCU上的非反射算法对不上白白浪费了半天时间。一定要确认在线工具的参数配置和你代码里的一致最好自己用Python写一个小脚本生成测试向量参数完全可控。4. 现场踩坑复盘那些校验通过但数据仍然错误的情况4.1 校验通过但数据错误的第一类原因校验范围不完整这是最常见的问题。校验字段只覆盖了数据字段没有覆盖帧头里的命令字或长度字段。结果就是数据本身没被干扰但命令字被干扰了接收端按错误的命令字去解析数据校验却能通过。比如命令字0x01表示读温湿度0x02表示读配置。如果0x01被干扰成0x02接收端会按配置数据的格式去解析温湿度数据解析出来的值完全不对但CRC校验是通过的因为CRC只校验了数据字段而数据字段确实没变。解决方案校验范围必须覆盖帧头、地址、命令字、长度、数据全部字段。我现在的项目里CRC计算从帧头第一个字节开始到数据字段最后一个字节结束一个都不漏。4.2 校验通过但数据错误的第一类原因字节序不一致这个坑在多平台协作时特别容易踩。MCU是小端PC也是小端看起来没问题。但如果中间经过了某个网关设备网关可能做了字节序转换或者你的协议文档里写的是大端代码实现时忘了转换。具体表现温度值0x1234假设表示46.6度在MCU内存里是34 12发送时如果直接memcpy线上就是34 12。接收端如果按大端解析读成0x3412完全错误。但CRC是对34 12算的校验能通过。解决方案协议里明确规定字节序代码里用统一的转换函数比如htons/ntohs或者自己写的宏发送前转换接收后转换回来。测试时用已知值验证比如发送25.0度确认接收端解析出来也是25.0度。4.3 校验通过但数据错误的第一类原因传感器读取错误但未被发现这是最隐蔽的一类。SHT30通过I2C读取时如果I2C时序被中断打断可能读回一个错误值。SHT30本身有CRC8校验但如果你没启用或者没检查错误值就进入MCU了。然后MCU把它打包、算CRC、发出去接收端校验通过显示一个错误的温湿度值。解决方案传感器层面的校验必须做。SHT30的CRC8、DHT11的校验和都要检查。如果传感器校验失败MCU应该重读而不是把错误值发出去。另外可以在应用层加合理性检查温度范围-40到125度湿度范围0到100%超出范围的值直接标记为无效。4.4 排查链路从现象到根因的完整过程分享一个真实的排查案例。现场反馈某节点温度偶尔跳到85度持续一两秒后恢复。其他节点正常。第一步确认现象。让现场人员记录跳变的时间点、持续时长、是否与某些设备动作相关。发现跳变多发生在整点前后怀疑与某台设备定时启动有关。第二步抓包分析。在交换机上做端口镜像用Wireshark抓包。发现跳变时该节点的数据帧CRC校验是通过的数据字段里的温度值确实是85度。说明不是传输错误是MCU发出来的就是85度。第三步检查MCU端。在MCU代码里加日志记录每次读取SHT30的原始值和CRC8校验结果。发现跳变时SHT30的CRC8校验失败但代码里没有处理直接把错误值用了。第四步根因定位。SHT30的I2C总线和某台设备的控制线走在一起整点时该设备启动产生干扰导致I2C通信错误。SHT30返回了错误数据CRC8校验失败但MCU代码忽略了校验结果。第五步修复。在I2C读取函数里加上CRC8校验失败时重读最多3次3次都失败则标记该次数据无效不更新输出值。同时在应用层加合理性检查温度超过80度直接丢弃。第六步验证。修复后连续运行一周没有再出现跳变。这个案例的教训是CRC校验只能保证传输的内容和发送的内容一致不能保证发送的内容本身是正确的。完整的可靠性设计需要从传感器读取、MCU处理、传输、接收解析每一层都做校验和防护。5. 选型决策的工程化方法用数据而不是感觉做选择5.1 建立误码率与校验强度的量化关系选CRC16还是CRC32不应该拍脑袋而应该基于现场误码率和业务容忍度来算。假设现场误码率是p每比特出错概率帧长是L比特那么一帧中至少有一个比特错误的概率是P(帧错误) ≈ 1 - (1-p)^L ≈ L × p当p很小时对于L800比特100字节p10^-5P(帧错误)≈0.8%。也就是说每125帧就有一帧出错。CRC16的漏检率大约是2^-16≈1.5×10^-5CRC32的漏检率大约是2^-32≈2.3×10^-10。那么每帧的漏检概率CRC160.8% × 1.5×10^-5 ≈ 1.2×10^-7CRC320.8% × 2.3×10^-10 ≈ 1.8×10^-12假设每秒发10帧一天86400秒一天总帧数864000帧CRC16每天漏检约0.1帧大约10天出现一次漏检CRC32大约每6万年出现一次漏检这个计算说明在误码率10^-5的链路上CRC16的漏检率已经低到10天一次对于温湿度监测这种非安全关键应用其实是可以接受的。但如果你的业务要求是一年不能有一次错误数据那CRC16就不够了必须上CRC32。5.2 不同业务场景的选型对照表业务场景数据更新率错误数据后果推荐方案理由楼宇环境监测1次/分钟轻微可人工修正CRC16开销小漏检率足够低农业大棚监测1次/5分钟轻微趋势判断CRC16同上工业车间监测1次/秒中等可能触发报警CRC32干扰大更新快医药仓储监测1次/10秒严重合规要求CRC32应用层确认需要可追溯冷链运输监测1次/30秒严重影响货物CRC32重传环境恶劣这个表是我根据几个实际项目总结的不是绝对标准但可以作为选型起点。核心逻辑是错误数据的后果越严重、现场干扰越大、数据更新越快就越应该用更强的校验。5.3 混合策略CRC16做快速筛选CRC32做最终确认在一些对性能有要求但又不能容忍错误的场景可以用混合策略第一层用CRC16做快速校验。因为CRC16计算快可以第一时间丢弃大部分错误帧。第二层对通过CRC16的帧再用CRC32做二次校验。因为大部分错误帧已经在第一层被丢弃了第二层需要处理的帧数量少总体开销可控。这个策略的代价是帧里要同时放CRC16和CRC32两个字段帧长增加。适合数据字段较长128字节的场景比如带时间戳和历史数据的批量上传。对于温湿度传感器这种短帧场景我一般不建议混合策略因为帧太短两层校验的额外开销占比太高不如直接上CRC32。6. 代码实现中的性能优化与可维护性平衡6.1 查表法的Flash空间与速度权衡前面提到查表法比逐位法快6-8倍但查表需要额外的Flash空间。CRC16需要512字节CRC32需要1024字节。对于Flash只有32KB的MCU比如STM32F030F4这1.5KB可能就很关键。如果Flash实在紧张可以考虑半字节查表16项表每次处理4比特速度介于逐位和全字节查表之间Flash占用小CRC16:32字节CRC32:64字节。动态生成表启动时用逐位算法生成表运行时用查表。这样Flash里只存生成代码不存表数据。代价是启动时间增加生成256项表大约需要几毫秒。只用逐位法如果数据量很小比如每次只校验20字节逐位法的耗时也可以接受20×8160μs不值得为它增加Flash开销。我的选择标准是如果MCU Flash≥64KB直接用全字节查表如果Flash64KB看数据帧长度帧长64字节用半字节查表帧长≤64字节用逐位法。6.2 校验函数的接口设计校验函数看起来简单但接口设计不好会导致调用端容易出错。我推荐的接口形式// 计算CRC返回校验值 uint16_t crc16_calc(const uint8_t *data, uint32_t len); // 校验数据返回0表示通过非0表示失败 int crc16_check(const uint8_t *data, uint32_t len, uint16_t expected); // 在帧尾追加CRC void crc16_append(uint8_t *frame, uint32_t data_len);crc16_check内部调用crc16_calc然后比对。这样调用端只需要记住一个函数减少出错概率。crc16_append用于发送端自动计算并写入帧尾。注意这个函数需要知道帧的总长度和CRC字段的位置接口设计时要考虑清楚。6.3 错误计数与现场诊断校验失败不应该只是默默丢弃而应该记录错误计数方便现场诊断。我在每个节点里维护以下计数器crc_error_countCRC校验失败次数frame_error_count帧格式错误次数帧头不对、长度超限等timeout_count接收超时次数sensor_error_count传感器读取失败次数这些计数器可以通过命令字读取现场人员用调试工具就能看到。如果某个节点的crc_error_count持续增长说明该节点通信链路有问题需要检查线缆、接头、接地。我还会记录最后一次CRC错误的帧内容前32字节方便事后分析。这个功能在排查偶发干扰时特别有用。6.4 代码版本管理与参数固化CRC参数多项式、初始值、异或值、反射方式一旦确定就应该固化在代码里并且用宏定义明确标注#define CRC16_POLY 0x1021 #define CRC16_INIT 0xFFFF #define CRC16_XOROUT 0x0000 #define CRC16_REFLECT 0发送端和接收端引用同一份头文件避免参数不一致。如果项目分多个代码库比如MCU端和PC端把CRC参数和函数放在一个独立的、可共享的文件里两边都引用这个文件。我踩过的坑MCU端和PC端各自维护了一份CRC代码后来MCU端改了初始值PC端忘了改导致现场所有设备通信失败。从那以后我坚持CRC代码只维护一份通过版本控制共享。7. 从实验室到现场环境差异带来的新问题7.1 温度对晶振和时序的影响实验室常温下跑得好好的到了现场夏天机柜内温度可能到60度冬天户外可能到-20度。温度变化会影响晶振频率进而影响SPI、I2C、RMII的时序。具体表现高温下RMII接口的建立/保持时间裕量变小可能导致MAC和PHY之间通信错误。这种错误发生在数据链路层FCS可能检测到也可能检测不到如果错误发生在FCS计算之前。应对措施RMII接口的时钟走线要等长尽量短PHY芯片选工业级-40到85度在极端温度下做长时间通信测试记录错误率。7.2 电源波动对MCU和PHY的影响工业现场的电源质量往往不好大功率设备启停时电压可能跌落或尖峰。MCU和PHY芯片在电源波动时可能工作异常产生错误数据。应对措施电源入口加TVS和滤波电容MCU和PHY的电源分开供电用LDO隔离在电源电压监测中断里如果检测到电压异常暂停通信并复位PHY。7.3 接地环路与共模干扰长线缆连接多个节点时如果各节点接地电位不同会在网线上形成共模干扰严重时导致通信中断。应对措施使用带隔离的PHY或者外接网络隔离变压器网线使用屏蔽双绞线屏蔽层单端接地各节点尽量就近接地避免形成大接地环路。这些环境因素导致的错误CRC校验能检测到一部分但不能完全消除。CRC是最后一道防线不是唯一防线。完整的可靠性设计需要硬件、软件、协议多层配合。8. 写在最后几个让我印象深刻的教训第一个教训来自一个农业大棚项目。当时为了省成本用了CRC16现场有水泵和风机干扰很大。运行一个月后发现历史数据里有几个温度值明显异常比如-10度但当时是夏天。查下来是CRC16漏检了。后来改成CRC32问题消失。省什么都不能省校验尤其是现场环境不可控的时候。第二个教训来自一个楼宇项目。MCU端和PC端用了不同的CRC参数但实验室测试时用的是同一套测试向量没发现问题。现场部署后所有设备通信失败。查了两天才发现是参数不一致。测试向量必须覆盖两端不能只测一端。第三个教训来自一个冷链项目。传感器是SHT30I2C读取时没有检查CRC8结果有一次传感器故障输出固定值MCU一直发这个固定值上位机显示温度恒定不变直到货物出问题才发现。传感器层面的校验和应用层的合理性检查一个都不能少。这些教训归结起来就是一句话通信可靠性是一个系统工程CRC只是其中一环。选对CRC、用对CRC、再配合其他层的防护才能真正做到现场稳定运行。
网站建设高端定制企业官网