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语言的异或运算有着一样的规则。

模2运算乘除法规则
- [ ] 乘法规则:0×0=0 0×1=0 1×0=0 1×1=1
- [ ] 除法规则:0÷1=0 1÷1=1
- [ ] 模2的乘除法运算,与普通的运算有着类似的演算规则。但是在乘法时乘积相加,除法时余数和除数相减,就需要按照模2加减法规则运算。
- [ ] 除法:当被除数位数大于除数时,商1,不够则商为0。然后被除数的位数补下来,如果最终余数小于除数时,那么除法终止运算。

CRC校验
CRC校验的检测过程
在计算过程中,我们首先要知道二进制多项式,这个多项式其实就是除数,而待校验的数据就是被除数,最终进行模2除法运算得到的余数,就是CRC校验码。
- 先约定好收发双方选择的CRC多项式,这个多项式其实就是计算过程中的除数。
- 在待校验的数据(可看作是发送方的数据)后面加上n个0,这个n是多少取决于你所选择的多项式。比如你选择的多项式是:P(x)=x^4+x+1。那么CRC检验码的位宽就是4,也就是说你要补4个0
- 对待校验数据进行模2除法运算,得出的余数就是CRC校验值。
- 然后把CRC检验码添加到待检验数据的末尾。
- 接收方,把接收到的数据,也进行模2除法的计算过程,如果余数为0,那么接收正确,如果不为0,那么数据在传输过程中出错。
CRC校验码计算演示过程
- [ ] 下面以多项式:P(x)=x^4+x+1为例,该多项式对应的二进制数就是:10011,进行计算演示。
- [ ] 原始数据假设是:1100110

常见的CRC多项式
CRC应用中的多项式不用我们自己去设计。前人经过研究,已经积累了各种应用场合的多项式了,不同的场合有不同的多项式,以便实现最大的纠错能力。下表列出了一小部分常用CRC的多项式表示:

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[index]);
}
return (CRC->DATA);
}
CRC16-MODBUS演示和验证
demo验证和CRC在线网站计算的CRC16-MODBUS值一致,说明CRC16-MODBUS验证OK


|