APM32F072实现CRC16-MODBUS
本帖最后由 heyanmei 于 2025-7-1 19:41 编辑# APM32F072实现CRC16-MODBUS
## CRC基本原理
### 什么是CRC
* [ ] 循环冗余校验(英语:Cyclic redundancy check,简称CRC),由W.Wesley Peterson于1961年首次提出的一种纠错码理论。
* [ ] CRC是一种数据纠错方法,主要应用于数据通信或者数据存储的场合,用来检测或校验数据传输或者数据存储后可能出现的错误,特别是擅长检测由传输通道中的噪声引起的常见错误
### 多项式的概念
* [ ] 在CRC校验中,多项式其实就是收发双方约定好的一个二进制数,当然要成为这个二进制数是要有一些要求的。
* [ ] 对任意的二进制数都可以构造一个与其对应的二进制系数多项式。比如:二进制10011b,这个二进制数对应的多项式公式就是:
P(x)= x^4+x+1
### 成为多项式要满足的条件
* [ ] 最高位和最低位都必须是1
* [ ] 当数据在传输过程中出错时,CRC的校验码不应该是0(也就是要有余数)
* [ ] 该多项式要有最大的错误检测能力
## 模2运算
### 模2运算的概念
* [ ] 模2运算,是一种二进制运算,是二进制编码理论中的运算基础。这种运算和我们以前学的四则运算的规则不同,模2运算不考虑进位、借位这些规则,它有着一套新的运算规则。
* [ ] 模2运算也有加减乘除法
### 模2运算加减法规则
* [ ] 加法规则:1+1=0 0+0=0 1+0=1 0+1=1
* [ ] 减法规则:0−0=0 1−1=0 0−1=1 1−0=1
* [ ] 加法不考虑进位,减法不考虑进位
模2加减法运算运算结果都是一样的,他和C语言的异或运算有着一样的规则。
!(data/attachment/forum/202506/30/111529p441r1vvarn3jiqa.png "image.png")
### 模2运算乘除法规则
* [ ] 乘法规则:0×0=0 0×1=0 1×0=0 1×1=1
* [ ] 除法规则:0÷1=0 1÷1=1
* [ ] 模2的乘除法运算,与普通的运算有着类似的演算规则。但是在乘法时乘积相加,除法时余数和除数相减,就需要按照模2加减法规则运算。
* [ ] 除法:当被除数位数大于除数时,商1,不够则商为0。然后被除数的位数补下来,如果最终余数小于除数时,那么除法终止运算。
!(data/attachment/forum/202506/30/111518pzrk6ys567yk686r.png "image.png")
## CRC校验
### CRC校验的检测过程
在计算过程中,我们首先要知道二进制多项式,这个多项式其实就是除数,而待校验的数据就是被除数,最终进行模2除法运算得到的余数,就是CRC校验码。
1. 先约定好收发双方选择的CRC多项式,这个多项式其实就是计算过程中的除数。
2. 在待校验的数据(可看作是发送方的数据)后面加上n个0,这个n是多少取决于你所选择的多项式。比如你选择的多项式是:P(x)=x^4+x+1。那么CRC检验码的位宽就是4,也就是说你要补4个0
3. 对待校验数据进行模2除法运算,得出的余数就是CRC校验值。
4. 然后把CRC检验码添加到待检验数据的末尾。
5. 接收方,把接收到的数据,也进行模2除法的计算过程,如果余数为0,那么接收正确,如果不为0,那么数据在传输过程中出错。
### CRC校验码计算演示过程
* [ ] 下面以多项式:P(x)=x^4+x+1为例,该多项式对应的二进制数就是:10011,进行计算演示。
* [ ] 原始数据假设是:1100110
!(data/attachment/forum/202506/30/111500xfbbsz3g9a39ahas.png "image.png")
### 常见的CRC多项式
CRC应用中的多项式不用我们自己去设计。前人经过研究,已经积累了各种应用场合的多项式了,不同的场合有不同的多项式,以便实现最大的纠错能力。下表列出了一小部分常用CRC的多项式表示:
!(data/attachment/forum/202507/01/194100ydafwoxwcqialjql.png "image.png")
## APM32F072的CRC函数库
| 函数名 | 描述 |
| ---------------------------- | ------------------------------------- |
| CRC_Reset | 将CRC外设寄存器重置为其默认复位值 |
| CRC_ResetDATA | 复位CRC数据寄存器 |
| CRC_SetPolynomialSize | 设置CRC多项式的大小 |
| CRC_SetPolynomialValue | 设置CRC多项式系数 |
| CRC_SelectReverseInputData | 选择要对输入数据执行的反向操作 |
| CRC_EnableReverseOutputData| 对输出数据进行反向操作 |
| CRC_DisableReverseOutputData | 禁止对输出数据进行反向操作 |
| CRC_WriteInitRegister | 写CRC初始化值 |
| CRC_CalculateCRC | 计算给定数据字的32位CRC(32位) |
| CRC_CalculateCRC8bits | 计算给定数据字的32位CRC(8位) |
| CRC_CalculateCRC16bits | 计算给定数据字的32位CRC(16位) |
| CRC_CalculateBlockCRC | 计算给定数据字缓冲区的32位CRC(32位) |
| CRC_ReadCRC | 返回当前的CRC值 |
| CRC_WriteIDRegister | 在独立数据寄存器中存储8位数据 |
| CRC_ReadIDRegister | 读独立数据寄存器中的8位数据 |
## APM32F072的CRC
APM32F072的CRC相比于APM32F103的CRC拥有更强的灵活性,可以配置输入数据是否翻转、输出数据是否翻转、CRC的初始值可配置、CRC多项式值可配置、多项式的大小可配置,因此APM32F072的CRC自由度相当高,不单纯只局限于CRC32-以太网;下面演示一下使用APM32F072实现CRC16-MODBUS
### CRC16-MODBUS的配置
```
void CRC16_MODBUS_Init(void)
{
/* 开启CRC时钟 */
RCM_EnableAHBPeriphClock(RCM_AHB_PERIPH_CRC);
/* CRC复位 */
CRC_Reset();
/* 设置CRC多项式的大小为16 */
CRC_SetPolynomialSize(CRC_POLYNOMIAL_SIZE_16);
/* 设置CRC多项式系数为8005 */
CRC_SetPolynomialValue(0x8005);
/* 对输出数据进行反向操作 */
CRC_EnableReverseOutputData();
/* 选择要对输入数据执行的反向操作 */
CRC_SelectReverseInputData(CRC_REVERSE_INPUT_DATA_16B);
/* 配置CRC初始值 */
CRC_WriteInitRegister(0xFFFF);
}
```
因为函数库里面实现数组的CRC运算是32位的,16位的需要我们自己编写一下函数
```
uint16_t CRC16_CalculateBlockCRC(uint16_t pBuffer[], uint32_t bufferLength)
{
uint32_t index = 0;
for (index = 0; index < bufferLength; index++)
{
CRC_CalculateCRC16bits(pBuffer);
}
return (CRC->DATA);
}
```
### CRC16-MODBUS演示和验证
demo验证和CRC在线网站计算的CRC16-MODBUS值一致,说明CRC16-MODBUS验证OK
!(data/attachment/forum/202506/30/113208r7zra7ruia38a5yf.png "image.png")
!(data/attachment/forum/202506/30/113240kd7dn0tw4tz0cj9s.png "image.png")
F072已经支持CRC16了呀!
硬件CRC校验还是非常好用。 查了一下APM32E030,其尚未支持CRC硬件外设自定义校验多项式。 记忆花园 发表于 2025-6-30 19:09
查了一下APM32E030,其尚未支持CRC硬件外设自定义校验多项式。
APM32E030目前是不支持硬件CRC自定义的 #申请原创# @21小跑堂 我觉得CRC的计算方式非常适合硬件实现。
仅通过异或,移位便能轻松完成。 如果能使用硬件方式实现,还是首先硬件方式。
但又会带来移植性的问题。 crc-16的多项式公式是错的! Dick Hou 发表于 2025-7-1 09:18
crc-16的多项式公式是错的!
CRC16-MODBUS的多项式系数是0x8005哦,建议百度一下CRC16-MODBUS的多项式系数 heyanmei 发表于 2025-7-1 10:07
CRC16-MODBUS的多项式系数是0x8005哦,建议百度一下CRC16-MODBUS的多项式系数
8005前面那一栏,公式不对,你可以根据你的公式,算一下是不是8005
正确的应该是:
X^16+X^15+X^2+1,这样才能得到8005 heyanmei 发表于 2025-7-1 10:07
CRC16-MODBUS的多项式系数是0x8005哦,建议百度一下CRC16-MODBUS的多项式系数
如上,这个多项式,才能得到8005
Dick Hou 发表于 2025-7-1 10:20
如上,这个多项式,才能得到8005
这个是二进制,多项式系数换算成16进制是0x8005,上面那个写8005的函数,是把CRC16-MODBUS的多项式系数写进CRC的多项式寄存器 heyanmei 发表于 2025-7-1 14:47
这个是二进制,多项式系数换算成16进制是0x8005,上面那个写8005的函数,是把CRC16-MODBUS的多项式系数写 ...
算了,你还是没弄明白。
你根据自己的表格,将第二列的多项式,算一下十六进制,和第三列对一下,看是否正确。只有CRC16的第二列是错的。
我11楼已经贴图了,就是USB的CRC-16,那么大红框框出来的多项式,你视而不见?和你表格里的第二列是不一样的。11楼的二进制,换算过来十六进制就是8005,多项式和十六进制,是能对上的。
左边是你的表格,右边是百度的结果,还看不明白吗?
Dick Hou 发表于 2025-7-1 17:43
左边是你的表格,右边是百度的结果,还看不明白吗?
看到了,帖子里的常见多项式公式那里有问题,我是在网上找到一个图片截图的,我把帖子里的常见CRC多项式图片更新成正确的,感谢指正[抱拳] 厉害,我用STM32H7的硬件CRC测试很多次,算出来的CRC16-MODBUS都不对,难道我人品问题? 这个真方便。昨天我计算CRC32花了差不多一天的时间。 我还是在使用FreeModbus里面提供的CRC16校验算法
页:
[1]