参考链接

https://www.cnblogs.com/shangdawei/p/4603921.html

https://blog.csdn.net/suiying00/article/details/139223995

负责计算CRC的寄存器为CRC中的DR寄存器,DR寄存器为32位寄存器,即每次只能按32位整来计算不满32位的数据其填充0

同时,stm32中硬件CRC遵循准则位CRC32-MPEG-2,即不带输入输出数据反转

小端序下内存拼凑

同时,也要注意stm32遵循小端序,即内存中最低有效字节(LSB)存储在最低的内存地址

(P.S. 小端序是主流方式,因为低位内存地址中存储数据的低位数据,方便加法进位计算——因为加法计算从数据的低位开始算)

例如

bytes的存储顺序为 (最低内存地址)|0x01|0x02|0x03|0x04|(最高内存地址)

memcpy搬运顺序为 从目标地址的低地址搬运到到目的地址的低地址

即,先搬运0x01到word的LSB(低八位 0-7位),0x02搬运到8-15位,依次搬运,0x04在MSB(25-31位),共32位,8字节

最后word为 (LSB)|0x01|0x02|0x03|0x04|(MSB) 即 (MSB)0x04030201(LSB)

uint8_t bytes[4] = {0x01, 0x02, 0x03, 0x04};

uint32_t word;

memcpy(&word, bytes, sizeof(word));

// 小端序
word = 0x04030201;
//大端序
word = 0x01020304;

了解了小端序后,就能理解 8位的变量是如何搬运到32位中,memcpy从低地址内存拷贝数据,按地址递增顺序来依次拷贝数据。

CRC运算过程

通常我们校验的数据为串口字符串数据的CRC校验,字符串均为uint8_t类型数据,这就需要把8位数据拼凑为32位数据。

这里按缺省位置0

具体实现如下

uint32_t calculate_CRC(uint8_t* p_data, uint32_t length){
	uint32_t crc_result;
	uint32_t temp_buf[64];  // 假设最多256字节 (64*4 = 256)
	uint16_t aligned_length = (length + 3) / 4;  // 计算 4 字节对齐后的长度

	memset(temp_buf, 0, sizeof(temp_buf));  // 清空缓冲区,避免脏数据影响,同时缺省位置0
	memcpy(temp_buf, p_data, length);  // 复制字符串数据到缓冲区
    for(uint16_t i = 0; i<aligned_length; i++){	//小端序转换大端序
		temp_buf[i] = __REV(temp_buf[i]);
	}

	crc_result = HAL_CRC_Calculate(&hcrc, temp_buf, aligned_length);  // 计算 CRC

	return crc_result;
}

注意,前面我说这里的crc校验遵循CRC32-MPEG-2,即不带输入输出数据反转;确保在读取数据端也遵循相同的校验方式

由于为小端序标准,在把四个uint8_t类型的数据拼成uint32_t类型后,顺序不正确,需要变为大端序

即:uint8_t a[] = "abcd" = {0x61, 0x62, 0x63, 0x64} -> uint32_t b = 0x64636261 -> uint32_t b_rev = 0x61626364

山和山不相遇,人与人要相逢