上一篇我们用函数实现了 CRC-16 MODBUS 校验。程序能跑了,但有一个让人不太满意的地方: 每校验一个字节,都要循环 8 次。
今天我们来解决这个问题。用 查表法 ,运算速度直接快上 8 到 10 倍。
一、为什么一张表能涵盖所有运算结果
你可能会担心: CRC 的运算结果千变万化,一张小小的表,真的都能覆盖吗?会不会碰到 " 表里没有 " 的情况?
答案是: 不会。表中涵盖了所有可能的结果。
为什么?
查表法是一个字节一个字节处理数据的。每次处理,都是把 " 当前 CRC 寄存器 " 和 " 新来的一个字节 " 揉在一起,然后用揉出来的结果去查表。
关键在于: 这个 " 揉在一起 " 的结果,永远是一个字节,也就是 8 个比特。
8 个比特一共能表示多少种不同的值?只有 256 种 ( 0 到 255 )。
所以不管你的数据有多长、 CRC 寄存器之前是什么状态,每次用来查表的那个 " 索引 " ,一定落在 0 到 255 之间。
表里刚好有 256 个元素,每一个索引对应的结果都提前算好了。你来一个索引,我就返回一个结果 —— 不可能出现第 257 种情况。
这就好比你有一张试卷,上面有 256 道选择题,编号从 0 到 255 。你提前把所有题目的标准答案写好,钉在墙上。考试的时候,别人随便报一个编号,你去墙上找对应的答案,一秒交卷。
二、 怎么获得这张表?
用这个函数直接生成 CRC-16MODBUS 查找表:
![]()
运行一次 Generate_CRC16_Table 函数,表就生成了。
三、节约 RAM 的小技巧
表 crc16_table 占用了 512 字节的 RAM ,如果在上位机程序中,这点内存不算事,可要是单片机程序, 512 字节的 RAM 做一个表怪心疼的。
解决的办法很简单,那就是把表放在 Flash 里:
![]()
加一个 const ,编译器就会把它放进 Flash 而不是 RAM 。这样既不用运行时动态生成表,也不占用宝贵的 RAM 空间。
四、 如何查表计算完整数据的 CRC ?
有了表,计算就变成 “ 字节级操作 ” ,一个字节只需一次查表和两次异或。
我们来试试效果。还是用上一篇一样的例子:
![]()
unsigned short crc16_result;
crc16_result = crc16_modbus(U1TxBuffer,6);
结果: crc16_result = 0xC755 。
和上一篇逐位算法算出来的完全一致,但速度快了 8 到 10 倍。
五、简单总结
查表法的本质,就是把 " 一个字节被 CRC 多项式反复折腾 8 次 " 这件事,提前算好 256 种标准答案。实际计算时,你只需要根据当前状态查一下表,两步异或就完事了。
至于那张表 —— 它不是在算什么新东西,它只是把你上一篇已经写过的逐位循环,提前跑了 256 遍而已。
特别声明:以上内容(如有图片或视频亦包括在内)为自媒体平台“网易号”用户上传并发布,本平台仅提供信息存储服务。
Notice: The content above (including the pictures and videos if any) is uploaded and posted by a user of NetEase Hao, which is a social media platform and only provides information storage services.