参考链接
负责计算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