打印
[APM32F0]

APM32F072实现CRC16-MODBUS

[复制链接]
79|5
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主

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

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。然后被除数的位数补下来,如果最终余数小于除数时,那么除法终止运算。

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

image.png

常见的CRC多项式

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

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[index]);
    }

    return (CRC->DATA);
}

CRC16-MODBUS演示和验证

demo验证和CRC在线网站计算的CRC16-MODBUS值一致,说明CRC16-MODBUS验证OK

image.png

image.png

使用特权

评论回复
沙发
霜咬回响| | 2025-6-30 14:35 | 只看该作者
F072已经支持CRC16了呀!
硬件CRC校验还是非常好用。

使用特权

评论回复
板凳
记忆花园| | 2025-6-30 19:09 | 只看该作者
查了一下APM32E030,其尚未支持CRC硬件外设自定义校验多项式。

使用特权

评论回复
地板
heyanmei|  楼主 | 2025-6-30 19:17 | 只看该作者
记忆花园 发表于 2025-6-30 19:09
查了一下APM32E030,其尚未支持CRC硬件外设自定义校验多项式。

APM32E030目前是不支持硬件CRC自定义的

使用特权

评论回复
5
heyanmei|  楼主 | 2025-6-30 19:20 | 只看该作者
#申请原创# @21小跑堂

使用特权

评论回复
6
转瞬回声| | 2025-6-30 20:27 | 只看该作者
我觉得CRC的计算方式非常适合硬件实现。
仅通过异或,移位便能轻松完成。

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

3

主题

8

帖子

0

粉丝