一:常见的校验方式知识分享:
在工业控制中,通信之间为了保证数据传输的准确性或者是完整性,都会存在校验。
常见的校验方式有以下几种方式:
1. 奇偶校验(Parity Check)
原理:在数据后添加一个校验位,使数据中1的个数为奇数或偶数。
类型:奇校验:1的个数为奇数。偶校验:1的个数为偶数。
特点:简单,但只能检测奇数个错误。常用于串口之间的通讯。
2. 校验和(Checksum)
原理:将数据分段求和,结果作为校验和附加在数据后。
特点:实现简单,适合低错误率环境,但检测能力有限。
一般用于PC机与下位机之间的通讯方式。
3. 循环冗余校验(CRC, Cyclic Redundancy Check)
原理:通过多项式除法生成校验码,附加在数据后。
特点:检测能力强,适合高可靠性要求的场合。
4. MD5 和 SHA 校验
原理:使用哈希算法生成固定长度的校验值。
特点:主要用于验证数据完整性,抗碰撞性强。
5. Reed-Solomon 码
原理:通过添加冗余数据,检测并纠正多个错误。
特点:广泛应用于通信和存储系统,纠错能力强。
6. 前向纠错(FEC, Forward Error Correction)
原理:发送冗余信息,接收方直接纠正错误。
特点:无需重传,适合实时性要求高的场景。
7. 异或校验(XOR Check)
原理:对数据逐字节异或运算,结果作为校验值。
特点:简单,但检测能力有限。
二:STM32的硬件CRC 知识分享:
今天我们讨论一下,STM32的硬件CRC校验方式:
2.1:我们查看一下官方的手册:
CRC(循环冗余校验)计算单元用于使用可配置的生成器多项式值和大小来获取CRC代码。
在其他应用中,基于CRC的技术用于验证数据传输或存储的完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存完整性的方法。CRC计算单元有助于在运行时计算软件的签名,以便与在链接时生成并存储在给定存储器位置的引用名进行比较。
STM32 微控制器内置了 CRC(循环冗余校验)模块,用于计算数据的 CRC 校验值。CRC 是一种常用的数据校验方法,用于检测数据传输或存储过程中的错误。STM32 的 CRC 模块支持多种 CRC 标准,并且可以通过硬件加速计算,提高效率
2.2:STM32 CRC 模块的特点
支持多种 CRC 标准:STM32 的 CRC 模块支持多种 CRC 多项式,包括 CRC-32、CRC-16 等。
硬件加速:CRC 计算由硬件完成,速度快,不占用 CPU 资源。
可配置的初始值和输入输出反转:用户可以根据需要配置 CRC 计算的初始值,以及是否对输入和输出数据进行反转。
32 位数据宽度:STM32 的 CRC 模块通常支持 32 位数据宽度的计算。
2.3:STM32 CRC 模块的使用步骤
启用 CRC 时钟:在使用 CRC 模块之前,需要先启用 CRC 模块的时钟。
配置 CRC 模块(可选):根据需要配置 CRC 的初始值、多项式、输入输出反转等参数。
计算 CRC:将数据写入 CRC 数据寄存器,CRC 模块会自动计算 CRC 值。
读取 CRC 结果:计算完成后,从 CRC 数据寄存器中读取 CRC 值。
三:STM32 cubeMX 软件配置如下:

硬件CRC校验代码如下:
  hcrc.Instance = CRC;   //CRC示例
  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE; //失能默认的多项式
  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;   //使用默认的初始值
  hcrc.Init.GeneratingPolynomial = 101;
  hcrc.Init.CRCLength = CRC_POLYLENGTH_7B;    //数据长度为7个字节
  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;      //输入数据不反转
  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; //输出数据不反转
  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; //输入数据格式为32位字
  if (HAL_CRC_Init(&hcrc) != HAL_OK)
  {
    Error_Handler();
  }CRC (循环冗余校验) 计算单元计算从 8 位数据(字节)缓冲区派生的 7 位 CRC 码。用户定义的生成多项式被手动设置为 0x65,即 X^7 + X^6 + X^5 + X^2 + 1,如列车通信网络 IEC 60870-5[17] 中使用的那样。
宏定义一些变量:
static const uint8_t CRC7_DATA8_TEST5[5]   = {0x12, 0x34, 0xBA, 0x71, 0xAD};
static const uint8_t CRC7_DATA8_TEST17[17] = {0x12, 0x34, 0xBA, 0x71, 0xAD,
                                              0x11, 0x56, 0xDC, 0x88, 0x1B,
                                              0xEE, 0x4D, 0x82, 0x93, 0xA6,
                                              0x7F, 0xC3
                                             };
static const uint8_t CRC7_DATA8_TEST1[1]   = {0x19};
static const uint8_t CRC7_DATA8_TEST2[2]   = {0xAB, 0xCD};
uint32_t * CRC7_DATA8_PTR_TEST1 = (uint32_t *)CRC7_DATA8_TEST1;
uint32_t * CRC7_DATA8_PTR_TEST2 = (uint32_t *)CRC7_DATA8_TEST2;
/* Expected CRC Values */
/* The 7 LSB bits are the 7-bit long CRC */
uint32_t uwExpectedCRCValue_1 = 0x00000057;    /* First byte stream CRC  */
uint32_t uwExpectedCRCValue_2 = 0x0000006E;    /* Second byte stream CRC */
uint32_t uwExpectedCRCValue_3 = 0x0000004B;    /* Third byte stream CRC  */
uint32_t uwExpectedCRCValue_4 = 0x00000027;    /* Fourth byte stream CRC */测试代码如下所示:
 uwCRCValue = HAL_CRC_Accumulate(&hcrc, (uint32_t *)&CRC7_DATA8_TEST5, BUFFER_SIZE_5);
  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_1)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }
  uwCRCValue = HAL_CRC_Accumulate(&hcrc, (uint32_t *)&CRC7_DATA8_TEST17, BUFFER_SIZE_17);
  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_2)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }
  uwCRCValue = HAL_CRC_Accumulate(&hcrc, (uint32_t *)CRC7_DATA8_PTR_TEST1, BUFFER_SIZE_1);
  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_3)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }
  uwCRCValue = HAL_CRC_Calculate(&hcrc, (uint32_t *)CRC7_DATA8_PTR_TEST2, BUFFER_SIZE_2);
  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_4)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }
  else
  {
    /* Right CRC value: Turn LED4 on */
    BSP_LED_On(LED4);
  }代码测试图如下所示:

程序执行的过程如下所示:
首先,处理一个 5 字节长的缓冲区以产生第一个 CRC。
接下来,从 17 字节长的缓冲区计算第二个 CRC。对于后者,CRC 计算器不会重新初始化,而是使用先前计算的 CRC 作为初始值。
然后,从 1 字节长的缓冲区计算第三个 CRC。同样,CRC 计算器不会重新初始化,而是将先前计算的 CRC 用作初始值。
最后,从 2 字节长的缓冲区计算第四个 CRC。这一次,CRC 计算器使用为 7 位 CRC 0x7F的 IP 默认值重新初始化。这是通过调用 HAL_CRC_Calculate() 而不是 HAL_CRC_Accumulate() 来完成的。
后记:CRC校验在使用过程中的注意事项
数据对齐:STM32 的 CRC 模块通常要求输入数据是 32 位对齐的。如果数据不是 32 位对齐的,可能需要手动处理。
多项式选择:默认情况下,STM32 使用 CRC-32 多项式(0x04C11DB7)。如果需要使用其他多项式,可以通过配置寄存器来实现。
初始值:默认初始值为 0xFFFFFFFF,可以根据需要修改。
第二部分:软件CRC-8校验方式:
/**
  * @brief  计算CRC8校验值
  * @param  *pdat:数据首地址
  * @param  len:计算数据长度
  * @retval 无
  */
unsigned char calcCRC(unsigned char *pdat, unsigned int len)
{
	unsigned char i; 
	unsigned char crc=0x00; /* 计算的初始crc值 */ 
	while(len--)
	{
    			crc ^= *pdat++;  /* 每次先与需要计算的数据异或,计算完指向下一数据 */  
    			for (i=8; i>0; --i)   /* 下面这段计算过程与计算一个字节crc一样 */  
    			{ 
    					if (crc & 0x80)
    							crc = (crc << 1) ^ 0xD5;
    					else
    							crc = (crc << 1);
    			}
	} 
	return (crc); 
}到这里:STM32硬件CRC校验方式和软件CRC-8校验方式,基本上就是这样,大家可以根据自己项目需求,自行取舍。

 
					
				
 
			
			
			
						
			 我要赚赏金
 我要赚赏金 STM32
STM32 MCU
MCU 通讯及无线技术
通讯及无线技术 物联网技术
物联网技术 电子DIY
电子DIY 板卡试用
板卡试用 基础知识
基础知识 软件与操作系统
软件与操作系统 我爱生活
我爱生活 小e食堂
小e食堂

