1.CRC
1.1基本概念
1.1.1CRC的简介
- CRC校验:即循环冗余校验(Cyclic Redundancy Check),就是计算一组校验码,用于核对
数据传输过程中是否出错。 - CRC校验本质上是数学上的多项式除法,被除数是要进行校验的数据,除数是所选用的多项
式,把运算得到的余数用二进制数表示,这个二进制数就是CRC校验值。 - 余数初始值:CRC初值不是0,而是FFFFFFFF;
- 结果异或值:把正常计算得到的结果和另一个值进行异或后,再输出
- 输入数据反转:把要计算的数据进行高低位颠倒(如数据位1011,反转后为1101)后,再计算CRC
- 输出数据反转:把计算得到的结果高低位颠倒再输出
1.1.2CRC的框图
- CRC计算单元主要由单个32位数据寄存器组成,该寄存器:
(1)用作输入寄存器,向CRC计算器中输入新数据 (向寄存器写入数据时)
(2)可保存之前的CRC计算结果 (读取寄存器时)
- 对数据寄存器的每个写操作都会把当前新输入的数值和之前生成在数据寄存器中的CRC值做一次 CRC 计算 (CRC 计算针对整个 32 位数据字完成,而非逐字节进行)。
-
使用CRC_CR寄存器中的RESET控制位即可将CRC计算器复位为0xFFFF FFFF。此操作不影响CRC_IDR寄存器的内容
1.1.3CRC的计算和校验
- 数据在发送方存在M位的数据位和R位校验位,R位校验位的值是通过M位数据位计算出来,然后传递给数据接收方,数据接收方再根据数据发送方的数据位计算校验位,再进行判断数据接收位和数据发送方的数据校验位是否正确。
1.2HAL的API函数
1.2.1API功能函数
(1)以前一次CRC校验的结果作为初始值继续进行校验 (适用于连续多次校验的第2、3、4... ...次)
uint32_t HAL_CRC_Accumulate (CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)*hcrc: 指向 CRC_HandleTypeDef CRC 校验总控制结构体的指针pBuffer:待校验的数据BufferLength:待校验的数据长度返回值:校验结果该函数在第一使用时需要调用HAL_CRC_Calculate,计算出第一次数据的校验位,然后由第一位的数据位的校验位作为下一位的的初始值。计算出最后一位的数据位作为整个传递数据的校验位
(2)使用默认初始值进行校验计算 (适用于单次校验 or 多次校验的第一次)
uint32_t HAL_CRC_Calculate (CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)该函数一次性将全部数据的校验位检测出来,且初值仍为0xFFFFFFFF
(3)获取状态的函数
HAL_CRC_StateTypeDef HAL_CRC_GetState(CRC_HandleTypeDef *hcrc返回值:CRC校验总控制结构体内的 State 值、即HAL_CRC_STATE_RESET 尚未初始化HAL_CRC_STATE_READY 初始化并准备使用HAL_CRC_STATE_BUSY 忙HAL_CRC_STATE_TIMEOUT 超时HAL_CRC_STATE_ERROR 错误
1.2.1API宏定义
(1)复位CRC数据寄存器
__HAL_CRC_DR_RESET(__HANDLE__)关联寄存器 CRC_CR 位 0 RESET 置位 设置数据寄存器为0xFFFFFFFF(2)临时存放1字节的数据到IDR寄存器__HAL_CRC_SET_IDR(__HANDLE__, __VALUE__)__VALUE__ (待存放的数据)关联寄存器 CRC_IDR 存放临时数据(3)复位CRC总控结构体中状态变量State变量复位成HAL_CRC_STATE_RESET__HAL_CRC_RESET_HANDLE_STATE(__HANDLE__)(4)读取IDR寄存器临时存放的1字节数据__HAL_CRC_GET_IDR(__HANDLE__)
1.3CRC的实验
硬件本身的多项式和初始值的函数
/* USER CODE BEGIN 2 */
uint32_t a;
uint32_t b;
uint32_t CRCBUF[4]={0x66203040,0x66230301,0x67337923,0x68328923};//数据寄存器的要校验的数据。
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
a=HAL_CRC_Calculate(&hcrc,(uint32_t *)CRCBUF,4);//一次性计算出数据寄存器CRCBUF的CRC的校验,初始值为0xFFFFFFFF
printf("单次检测的值:a=%x\r\n",a);
/*计算CRC硬件的校验位*/
HAL_CRC_Calculate(&hcrc,&CRCBUF[0],1);//先计算出数据寄存器CRCBUF[0]的CRC的校验,再传递给CRCBUF[1],初始值为0xFFFFFFFF
HAL_CRC_Accumulate(&hcrc,&CRCBUF[1],1);
HAL_CRC_Accumulate(&hcrc,&CRCBUF[2],1);
b=HAL_CRC_Accumulate(&hcrc,&CRCBUF[3],1);
printf(" 连续检测的值:b=%x\r\n",b);
HAL_Delay(500);
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
自定义CRC函数(多项式和初始值)
//init为初始值FFFFFFFF,len为字节长度,data每次传送一个2字节
uint32_t CRC32(uint8_t *data,uint16_t len,uint32_t init)
{
uint32_t poly=0x04C11DB7; //硬件CRC32的多项式
uint8_t i;
while(len--)//一个字节一个字节的计算
{
init=init^(*data<<24);//左移到最高处后和初值异或,结果变为新初值
for(i=0;i<8;i++) //每次计算一位
{
if(init&80000000) //if成立,二进制数为1
{
init=(init<<1)^poly;//位数为1,则与多项式进行异或
}
else //不成立此时二进制为0
{
init=(init<<1);//此时仅需左移就行
}
data++; //地址递增,一次是2个字节
}
}
return init; //此时返回校验值
}
视频链接:
这里我推荐两个视频非常清晰,听完你将会对CRC,存在更加清楚(完美)