14:HAL---CRC校验

2024-05-12 02:44
文章标签 校验 14 crc hal

本文主要是介绍14:HAL---CRC校验,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

103系列只有一个CRC

前言:

        CRC(Cyclic Redundancy Check),即循环冗余校验,是一种根据网络数据包或电脑文件等数据产生简短固定位数校核码的快速算法,主要用来检测或校核数据传输或者保存后可能出现的错误。CRC校验的工作原理主要基于以下步骤:

  1. 选定一个标准除数(一个K位二进制数据串)。
  2. 在要发送的数据(m位)后面加上K-1位0,然后将这个新数(M+K-1位)以模2除法的方式除以上面这个标准除数,所得到的余数(余数必须比除数少且只少一位,不够就补0)也就是该数据的CRC校验码。
  3. 将这个校验码附在原m位数据后面,构成新的M+K-1位数据,发送给接收端。
  4. 接收端将接收到的数据除以标准除数,如果余数为0则认为数据正确。

        CRC校验被广泛应用于各种通信协议中,如以太网、USB、串口通信协议等,以及存储介质中,如硬盘、光盘等。在数据传输和存储过程中,由于各种原因(如磁场干扰、光盘划伤等),数据可能会发生错误,CRC校验可以有效地检测并纠正这些错误。

        此外,CRC校验还常用于文件传输、数据库和防篡改检测中。在文件传输过程中,发送方会计算文件的CRC校验码,并将其与文件一同发送给接收方。接收方在接收到文件后,重新计算CRC校验码并与接收到的校验码进行比较,以判断文件是否传输正确。在数据库中,每当数据进行插入、更新或删除操作时,会先计算CRC校验码,并将其与数据一同存储在数据库中。在读取数据时,再次计算CRC校验码并与存储的校验码进行比较,以检测数据是否被篡改。在数据加密中,为了防止被黑客篡改,常常会使用CRC校验技术。

        总之,CRC校验是一种非常有效的数据错误检测和纠正技术,在各种数据传输和存储场景中都有广泛的应用。

一:CRC

CRC种类:CRC8,CRC16,CRC32

CRC8:校验结果为1个字节。

CRC16:校验结果为5个字节。

CRC32:校验结果为4个字节。

在我们整个103系列中只有CRC32的硬件校验。

初始值和多项式:2种通信在确定CRC校验种类后,然后就是确定多项式和初值的一致。

对于我们整个103系列的来说这两个都是固定的值。

多项式:

初值:

二:HAL的配置

 

三:代码

A:硬件CRC单次校验计算

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "CRC.h"uint32_t verify[4]={0x01020304,0x05060708,0x090A0B0C,0x0D0E0F00};int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */LED_Init();                        /* LED初始化 */Uart_Init(115200);CRC_Init();uint32_t inspection_data=HAL_CRC_Calculate(&CRC_Handle,verify,4);//因为采用的是硬件CRC32的校验,返回的为4个字节。所以必须采用uint32_t //uint32_t 为4个字节。如果使用其他的那么返回值错误,不是4个字节。printf("%x\r\n",inspection_data);while (1){}   
}#include "stm32f1xx_hal.h"CRC_HandleTypeDef CRC_Handle;void CRC_Init(void)
{CRC_Handle.Instance=CRC;HAL_CRC_Init(&CRC_Handle);
}void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
{__HAL_RCC_CRC_CLK_ENABLE();}

HAL_CRC_Calculate()函数使用注意:

第二个参数:是按字节传输的的(一次4个字节),所以数据从传输检验必须为4字节的整数倍。

uint32_t pBuffer[]:这是一个指向要计算CRC的数据的指针。这个数组包含了要进行CRC计算的数据。由于STM32的CRC算法通常是基于32位数据的,所以这里的数组元素类型通常为uint32_t

我们采用uint32_t 类型的变量占用 4 个字节

第三个参数

  1. uint32_t BufferLength:这个参数指定了pBuffer数组中的元素数量,也就是要计算CRC的数据长度。这个值通常以32位为单位,表示有多少个32位数据需要进行CRC计算。

B:硬件CRC连续计算

        

        当我们的数据量太大的时候,一次性的计算对于我们来说有点困难,或者内存不够。我们采用连续CRC校验的方式(一次校验一个字)。

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "CRC.h"uint32_t verify[5]={0x01020304,0x05060708,0x090A0B0C,0x0D0E0F00,0x01020304};int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */LED_Init();                        /* LED初始化 */Uart_Init(115200);CRC_Init();uint32_t inspection_data=HAL_CRC_Calculate(&CRC_Handle,verify,5);//因为采用的是硬件CRC32的校验,返回的为4个字节。所以必须采用uint32_t //uint32_t 为4个字节。如果使用其他的那么返回值错误,不是4个字节。printf("单次校验结果=%x\r\n",inspection_data);HAL_CRC_Calculate(&CRC_Handle,&verify[0],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[1],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[2],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[3],1);uint32_t Continuous_check=HAL_CRC_Accumulate(&CRC_Handle,&verify[4],1);printf("连续校验结果=%x\r\n",Continuous_check);while (1){}   
}#include "stm32f1xx_hal.h"CRC_HandleTypeDef CRC_Handle;void CRC_Init(void)
{CRC_Handle.Instance=CRC;HAL_CRC_Init(&CRC_Handle);
}void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
{__HAL_RCC_CRC_CLK_ENABLE();}

C:软件CRC校验计算

        软件的CRC校验相对于我们硬件CRC的检验,来说非常灵活,初始值和多项式我们可以自己调节。

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "CRC.h"uint32_t verify[5]={0x01020304,0x05060708,0x090A0B0C,0x0D0E0F00};
uint8_t software_verify[16]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint32_t res;int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */LED_Init();                        /* LED初始化 */Uart_Init(115200);CRC_Init();uint32_t inspection_data=HAL_CRC_Calculate(&CRC_Handle,verify,4);//因为采用的是硬件CRC32的校验,返回的为4个字节。所以必须采用uint32_t //uint32_t 为4个字节。如果使用其他的那么返回值错误,不是4个字节。printf("硬件单次校验结果=%x\r\n",inspection_data);HAL_CRC_Calculate(&CRC_Handle,&verify[0],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[1],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[2],1);//HAL_CRC_Accumulate(&CRC_Handle,&verify[3],1);uint32_t Continuous_check=HAL_CRC_Accumulate(&CRC_Handle,&verify[3],1);printf("硬件连续校验结果=%x\r\n",Continuous_check);uint32_t software_data= CRC32(software_verify,16,0XFFFFFFFF);printf("软件单次校验结果=%x\r\n",software_data);res=CRC32(&software_verify[0],4,0XFFFFFFFF);res=CRC32(&software_verify[4],4,res);res=CRC32(&software_verify[8],4,res);printf("软件连续校验结果=%x\r\n",CRC32(&software_verify[12],4,res));while (1){} }#include "stm32f1xx_hal.h"CRC_HandleTypeDef CRC_Handle;void CRC_Init(void)
{CRC_Handle.Instance=CRC;HAL_CRC_Init(&CRC_Handle);
}void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
{__HAL_RCC_CRC_CLK_ENABLE();}/*** @brief  软件CRC32校验计算*         * @param  data:校验的数据我们一次校验一个字节* @param  len:  检验数据的长度 * @param  inti:  检验的初值* @retval 返回4个字节的校验数据*/
uint32_t CRC32(uint8_t *data,uint16_t len,uint32_t init)
{//^=异或不同为1uint32_t poly=0x04C11DB7; //多项式	while(len--){	//data<<24:因为CRC32返回去的校验值为4个字节;我们校验的是一个字节;//所以把他左移3个字节到最高位。3*8=24也就是左移24位。init=init^(*data<<24);for(uint8_t i=0;i<8;i++){if((init&0x80000000)){init=(init<<1)^poly;		}else{init=(init<<1);}}data++;}return init;
}

D:软件CRC数据反转

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "CRC.h"uint32_t verify[5]={0x01020304,0x05060708,0x090A0B0C,0x0D0E0F00};
uint8_t software_verify[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint32_t res;int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */LED_Init();                        /* LED初始化 */Uart_Init(115200);CRC_Init();uint32_t inspection_data=HAL_CRC_Calculate(&CRC_Handle,verify,4);//因为采用的是硬件CRC32的校验,返回的为4个字节。所以必须采用uint32_t //uint32_t 为4个字节。如果使用其他的那么返回值错误,不是4个字节。printf("硬件单次校验结果=%x\r\n",inspection_data);HAL_CRC_Calculate(&CRC_Handle,&verify[0],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[1],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[2],1);//HAL_CRC_Accumulate(&CRC_Handle,&verify[3],1);uint32_t Continuous_check=HAL_CRC_Accumulate(&CRC_Handle,&verify[3],1);printf("硬件连续校验结果=%x\r\n",Continuous_check);uint32_t software_data= CRC32(software_verify,16,0XFFFFFFFF);printf("软件单次校验结果=%x\r\n",software_data);//软件的输入反转+输出反转的时候不能使用连续的校验;//因为在连续的过程种会不只一次的反转输出的结果(一直调用CRC32函数)//只有输入反转的时候可以使用//	res=CRC32(&software_verify[0],4,0XFFFFFFFF);
//	res=CRC32(&software_verify[4],4,res);
//	res=CRC32(&software_verify[8],4,res);
//	//res=CRC32(&software_verify[12],4,res);
//	printf("软件连续校验结果=%x\r\n",CRC32(&software_verify[12],4,res));while (1){} }
#include "stm32f1xx_hal.h"uint8_t Inveruint8(uint8_t data);
uint32_t Inveruint32(uint32_t data);CRC_HandleTypeDef CRC_Handle;void CRC_Init(void)
{CRC_Handle.Instance=CRC;HAL_CRC_Init(&CRC_Handle);
}void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
{__HAL_RCC_CRC_CLK_ENABLE();}/*** @brief  软件CRC32校验计算*         * @param  data:校验的数据我们一次校验一个字节* @param  len:  检验数据的长度 * @param  inti:  检验的初值* @retval 返回4个字节的校验数据*/
uint32_t CRC32(uint8_t *data,uint16_t len,uint32_t init)
{//^=异或不同为1uint32_t poly=0x04C11DB7; //多项式	while(len--){	//data<<24:因为CRC32返回去的校验值为4个字节;我们校验的是一个字节;//所以把他左移3个字节到最高位。3*8=24也就是左移24位。init=init^(Inveruint8(*data)<<24);   //输入反转for(uint8_t i=0;i<8;i++){if((init&0x80000000)){init=(init<<1)^poly;		}else{init=(init<<1);}}data++;}return Inveruint32(init);    //输出反转
}//数据反转
uint8_t Inveruint8(uint8_t data)
{uint8_t i;uint8_t temp;temp=0;for(i=0;i<8;i++){if(data&(1<<i)){temp|=1<<(7-i);}}return temp;
}//数据反转
uint32_t Inveruint32(uint32_t data)
{uint8_t i;uint32_t temp;temp=0;for(i=0;i<32;i++){if(data&(1<<i)){temp|=1<<(31-i);}}return temp;
}

E:软件的CRC16和CRC8

CRC16

#include "stm32f1xx_hal.h"
#include "rcc.h"
#include "led.h"
#include "delay.h"
#include "UART.h"
#include <stdarg.h>
#include "stdio.h"
#include "CRC.h"uint32_t verify[5]={0x01020304,0x05060708,0x090A0B0C,0x0D0E0F00};
uint8_t software_verify[20]={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
uint32_t res;int main(void)
{HAL_Init();                         /* 初始化HAL库 */sys_stm32_clock_init(RCC_PLL_MUL9); /* 设置时钟, 72Mhz */delay_init(72);                     /* 延时初始化 */LED_Init();                        /* LED初始化 */Uart_Init(115200);CRC_Init();uint32_t inspection_data=HAL_CRC_Calculate(&CRC_Handle,verify,4);//因为采用的是硬件CRC32的校验,返回的为4个字节。所以必须采用uint32_t //uint32_t 为4个字节。如果使用其他的那么返回值错误,不是4个字节。printf("硬件单次校验结果=%x\r\n",inspection_data);HAL_CRC_Calculate(&CRC_Handle,&verify[0],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[1],1);HAL_CRC_Accumulate(&CRC_Handle,&verify[2],1);//HAL_CRC_Accumulate(&CRC_Handle,&verify[3],1);uint32_t Continuous_check=HAL_CRC_Accumulate(&CRC_Handle,&verify[3],1);printf("硬件连续校验结果=%x\r\n",Continuous_check);uint16_t software_data= CRC16(software_verify,16,0XFFFF);printf("软件单次校验结果=%x\r\n",software_data);//软件的输入反转+输出反转的时候不能使用连续的校验;//因为在连续的过程种会不只一次的反转输出的结果(一直调用CRC32函数)//只有输入反转的时候可以使用//	res=CRC32(&software_verify[0],4,0XFFFFFFFF);
//	res=CRC32(&software_verify[4],4,res);
//	res=CRC32(&software_verify[8],4,res);
//	//res=CRC32(&software_verify[12],4,res);
//	printf("软件连续校验结果=%x\r\n",CRC32(&software_verify[12],4,res));while (1){} }#include "stm32f1xx_hal.h"uint8_t Inveruint8(uint8_t data);
uint32_t Inveruint32(uint32_t data);
uint16_t Inveruint16(uint16_t data);
CRC_HandleTypeDef CRC_Handle;void CRC_Init(void)
{CRC_Handle.Instance=CRC;HAL_CRC_Init(&CRC_Handle);
}void HAL_CRC_MspInit(CRC_HandleTypeDef *hcrc)
{__HAL_RCC_CRC_CLK_ENABLE();}/*** @brief  软件CRC32校验计算*         * @param  data:校验的数据我们一次校验一个字节* @param  len:  检验数据的长度 * @param  inti:  检验的初值* @retval 返回4个字节的校验数据*/
uint32_t CRC32(uint8_t *data,uint16_t len,uint32_t init)
{//^=异或不同为1uint32_t poly=0x04C11DB7; //多项式	while(len--){	//data<<24:因为CRC32返回去的校验值为4个字节;我们校验的是一个字节;//所以把他左移3个字节到最高位。3*8=24也就是左移24位。init=init^(Inveruint8(*data)<<24);   //输入反转for(uint8_t i=0;i<8;i++){if((init&0x80000000)){init=(init<<1)^poly;		}else{init=(init<<1);}}data++;}return Inveruint32(init);    //输出反转
}/*** @brief  软件CRC16校验计算*         * @param  data:校验的数据我们一次校验一个字节* @param  len:  检验数据的长度 * @param  inti:  检验的初值* @retval 返回4个字节的校验数据*/
uint16_t CRC16(uint8_t *data,uint16_t len,uint16_t init)
{//^=异或不同为1uint32_t poly=0x8005; //多项式	while(len--){	init=init^(Inveruint8(*data)<<8);   //输入反转for(uint8_t i=0;i<8;i++){if((init&0x8000)){init=(init<<1)^poly;		}else{init=(init<<1);}}data++;}return Inveruint16(init);    //输出反转
}//数据反转---输入
uint8_t Inveruint8(uint8_t data)
{uint8_t i;uint8_t temp;temp=0;for(i=0;i<8;i++){if(data&(1<<i)){temp|=1<<(7-i);}}return temp;
}//数据反转----输出
uint32_t Inveruint32(uint32_t data)
{uint8_t i;uint32_t temp;temp=0;for(i=0;i<32;i++){if(data&(1<<i)){temp|=1<<(31-i);}}return temp;
}//数据反转
uint16_t Inveruint16(uint16_t data)
{uint8_t i;uint16_t temp;temp=0;for(i=0;i<16;i++){if(data&(1<<i)){temp|=1<<(15-i);}}return temp;
}

CRC8

/*** @brief  软件CRC8校验计算*         * @param  data:校验的数据我们一次校验一个字节* @param  len:  检验数据的长度 * @param  inti:  检验的初值* @retval 返回4个字节的校验数据*/
uint8_t CRC8(uint8_t *data,uint16_t len,uint8_t init)
{//^=异或不同为1uint32_t poly=0x07; //多项式	while(len--){	init=init^(*data<<8);   for(uint8_t i=0;i<8;i++){if((init&0x80)){init=(init<<1)^poly;		}else{init=(init<<1);}}data++;}uint8_t software_data= CRC8(software_verify,16,0XFF);printf("软件单次校验结果=%x\r\n",software_data);

这篇关于14:HAL---CRC校验的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/981383

相关文章

业务中14个需要进行A/B测试的时刻[信息图]

在本指南中,我们将全面了解有关 A/B测试 的所有内容。 我们将介绍不同类型的A/B测试,如何有效地规划和启动测试,如何评估测试是否成功,您应该关注哪些指标,多年来我们发现的常见错误等等。 什么是A/B测试? A/B测试(有时称为“分割测试”)是一种实验类型,其中您创建两种或多种内容变体——如登录页面、电子邮件或广告——并将它们显示给不同的受众群体,以查看哪一种效果最好。 本质上,A/B测

校验码:奇偶校验,CRC循环冗余校验,海明校验码

文章目录 奇偶校验码CRC循环冗余校验码海明校验码 奇偶校验码 码距:任何一种编码都由许多码字构成,任意两个码字之间最少变化的二进制位数就称为数据检验码的码距。 奇偶校验码的编码方法是:由若干位有效信息(如一个字节),再加上一个二进制位(校验位)组成校验码。 奇校验:整个校验码中1的个数为奇数 偶校验:整个校验码中1的个数为偶数 奇偶校验,可检测1位(奇数位)的错误,不可纠错。

PMP–一、二、三模–分类–14.敏捷–技巧–看板面板与燃尽图燃起图

文章目录 技巧一模14.敏捷--方法--看板(类似卡片)1、 [单选] 根据项目的特点,项目经理建议选择一种敏捷方法,该方法限制团队成员在任何给定时间执行的任务数。此方法还允许团队提高工作过程中问题和瓶颈的可见性。项目经理建议采用以下哪种方法? 易错14.敏捷--精益、敏捷、看板(类似卡片)--敏捷、精益和看板方法共同的重点在于交付价值、尊重人、减少浪费、透明化、适应变更以及持续改善等方面。

2021-8-14 react笔记-2 创建组件 基本用法

1、目录解析 public中的index.html为入口文件 src目录中文件很乱,先整理文件夹。 新建components 放组件 新建assets放资源   ->/images      ->/css 把乱的文件放进去  修改App.js 根组件和index.js入口文件中的引入路径 2、新建组件 在components文件夹中新建[Name].js文件 //组件名首字母大写

2021-08-14 react笔记-1 安装、环境搭建、创建项目

1、环境 1、安装nodejs 2.安装react脚手架工具 //  cnpm install -g create-react-app 全局安装 2、创建项目 create-react-app [项目名称] 3、运行项目 npm strat  //cd到项目文件夹    进入这个页面  代表运行成功  4、打包 npm run build

用Python实现时间序列模型实战——Day 14: 向量自回归模型 (VAR) 与向量误差修正模型 (VECM)

一、学习内容 1. 向量自回归模型 (VAR) 的基本概念与应用 向量自回归模型 (VAR) 是多元时间序列分析中的一种模型,用于捕捉多个变量之间的相互依赖关系。与单变量自回归模型不同,VAR 模型将多个时间序列作为向量输入,同时对这些变量进行回归分析。 VAR 模型的一般形式为: 其中: ​ 是时间  的变量向量。 是常数向量。​ 是每个时间滞后的回归系数矩阵。​ 是误差项向量,假

STM32CubeMX和HAL库-新建项目

目录 新建项目 选择开发板  MCU图形化配置界面总览 MCU配置 新建项目 新建项目包含选择MCU创建项目、选择开发板新建项目和交叉选择MCU新建项目三部分。 1. 选择MCU创建项目 单击主菜单项File→New Project,或Home视图上的ACCESS TO MCU SELECTOR 按钮,都可以打开的New Project from a MCU/MPU对话框。

PMP–一、二、三模–分类–14.敏捷–技巧–原型MVP

文章目录 技巧一模14.敏捷--原型法--项目生命周期--迭代型生命周期,通过连续的原型或概念验证来改进产品或成果。每个新的原型都能带来新的干系人新的反馈和团队见解。题目中明确提到需要反馈,因此原型法比较好用。23、 [单选] 一个敏捷团队的任务是开发一款机器人。项目经理希望确保在机器人被实际建造之前,团队能够收到关于需求的早期反馈并相应地调整设计。项目经理应该使用以下哪一项来实现这个目标?

STM32 HAL CAN通讯 实操

1、简介 相比于串口通讯,对于刚接触CAN通讯的小白来说,CAN通讯相对复杂,看各种视频、帖子理论,总是一知半解。本次通过傻瓜式操作,先实现CAN通讯的交互,以提高小白的信心,也便于自己复习观看。本次以STM32CubeMX进行初始化配置,通过Keil 5软件进行软件设计,通过CAN盒实现进行数据的交互。该流程实际以STM32F0、F1、F3、F4、F7实测好用(理论上都适用),这三种型号单片机

我在高职教STM32——准备HAL库工程模板(1)

新学期开学在即,又要给学生上 STM32 嵌入式课程了。这课上了多年了,一直用的都是标准库来开发,已经驾轻就熟了。人就是这样,有了自己熟悉的舒适圈,就很难做出改变,老师上课也是如此,排斥新课和不熟悉的内容。显然,STM32 的开发,HAL 库已是主流,自己其实也在使用,只不过更换库就意味着教学内容有很大变化,自己也就迟迟没有迈出调整这一步。现在,是时候做出变化了,笔者计划保持教学项