CRC_user.h
#ifndef __CRC_user_H__
#define __CRC_user_H__
#include <cstdint>
uint32_t CRC32(uint8_t *, uint16_t, uint32_t);
uint8_t InverUint8(uint8_t data);
uint32_t InverUint32(uint32_t data);
uint16_t CRC16(uint8_t *data, uint16_t len, uint16_t init);
uint8_t CRC8(uint8_t *data, uint16_t len, uint8_t init);
#endif
CRC_user.c
#include "stm32g4xx_hal.h"
#include "CRC_user.h"
uint32_t CRC32(uint8_t *data, uint16_t len, uint32_t init)
{
uint32_t poly = 0x04C11DB7;
while(len--)
{
init = init ^(InverUint8(*data) << 24);
for(uint8_t i = 0; i<8;i++)
{
if(init&0x80000000) // if成立,该二进制位是1
{
init = (init<<1)^poly;
}
else // else成立,该二进制位是0
{
init = init<<1;
}
}
data++;
}
return InverUint32(init);
}
/* CRC校验计算原理
本节实验我们利用程序自己编写CRC32校验计算,多项式初值都可以自由设定,灵活性比硬件CRC32高。
注意:按字节进行计算,利用while循环个字节一个字节计算。
(1)取一个字节数据,因为是CRC32,将该字节左移到最高处。
(2)左移到最高处后和初值异或,结果变为新初值。
(3)利用for循环,循环8次,处理新初值中每个二进制位,如果是1,新初值左移1位后和多项式异或,
结果是再新一次的初值,如果是0,仅左移,不同多项式异或。
(4)再去取下一个字节重复操作,直到while循环处理完所有数据,将最终的新初值作为校验结果值返回。
*/
uint16_t CRC16(uint8_t *data, uint16_t len, uint16_t init)
{
uint16_t poly = 0x1021;
while(len--)
{
init = init ^(*data << 8);
for(uint8_t i = 0; i<8;i++)
{
if(init&0x8000) // if成立,该二进制位是1
{
init = (init<<1)^poly;
}
else // else成立,该二进制位是0
{
init = init<<1;
}
}
data++;
}
return init;
}
uint8_t CRC8(uint8_t *data, uint16_t len, uint8_t init)
{
uint8_t poly = 0x31;
while(len--)
{
init = init ^(InverUint8(*data) << 0);
for(uint8_t i = 0; i<8;i++)
{
if(init&0x80) // if成立,该二进制位是1
{
init = (init<<1)^poly;
}
else // else成立,该二进制位是0
{
init = init<<1;
}
}
data++;
}
return InverUint8(init);
}
uint8_t InverUint8(uint8_t data)
{
uint8_t temp = 0;
for(uint8_t i=0; i<8; i++)
{
if(data&(1<<i))
{
temp |= 1<<(7-i);
}
}
return temp;
}
uint16_t InverUint16(uint16_t data)
{
uint16_t temp = 0;
for(uint8_t i=0; i<16; i++)
{
if(data&(1<<i))
{
temp |= 1<<(15-i);
}
}
return temp;
}
uint32_t InverUint32(uint32_t data)
{
uint32_t temp = 0;
for(uint8_t i=0; i<32; i++)
{
if(data&(1<<i))
{
temp |= 1<<(31-i);
}
}
return temp;
}
/*
本节实验我们在上一节软件CRC32校验计算程序基础上,增加数据反转函数,适用于更多种情形下的CRC32校验方式。
注意:数据翻转包含:(1)待校数据,先反转后再参与计算 ----输入数据反转(REFIN)
(2)校验后的结果数据,先反转后再return返回 ----输出数据反转(REFOUT)
注意:反转指的是低位变高位,高位变低位,比如按字节翻转,原来的位0成为了位7,位1变成位6,
位1成为位6,原来高位的位7成为位0,位6变位1,以此类推。
*/
main.c
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2024 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "crc.h"
#include "dma.h"
#include "usart.h"
#include "gpio.h"
#include <stdio.h>
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
#include "CRC_user.h"
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
//uint32_t buff[4] = {0x01020304, 0x05060708, 0x090a0b0c, 0x0d0e0f00};
uint8_t buff2[16] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,0};
char buff_send[100];
char buff_send2[100];
char buff_send3[100];
char buff_send4[100];
uint8_t buff_receive[100] = {0};
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
if(huart->Instance == LPUART1)
{
// HAL_UART_Transmit_DMA(huart, (uint8_t*)buff_send, sizeof(buff_send));
HAL_UART_Transmit_DMA(huart, (uint8_t*)buff_send2, sizeof(buff_send2));
HAL_UARTEx_ReceiveToIdle_DMA(huart, buff_receive, sizeof(buff_receive));
__HAL_DMA_DISABLE_IT(huart->hdmarx, DMA_IT_HT);
}
}
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_LPUART1_UART_Init();
MX_CRC_Init();
/* USER CODE BEGIN 2 */
HAL_UARTEx_ReceiveToIdle_DMA(&hlpuart1, buff_receive, sizeof(buff_receive));
__HAL_DMA_DISABLE_IT(hlpuart1.hdmarx, DMA_IT_HT);
// sprintf(buff_send, "CRC_Value: %x\n", HAL_CRC_Calculate(&hcrc, buff, 4));
// HAL_CRC_Calculate(&hcrc, &buff[0], 1);
// HAL_CRC_Accumulate(&hcrc, &buff[1], 1);
// HAL_CRC_Accumulate(&hcrc, &buff[2], 1);
// sprintf(buff_send2,"CRC_continuous_calculate_Value: %x\n", HAL_CRC_Accumulate(&hcrc, &buff[3], 1));
sprintf(buff_send3, "CRC_user_calculate_Value:%x\n", CRC16(buff2, 16, 0x0000));
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)buff_send3, sizeof(buff_send3));
sprintf(buff_send3, "CRC_user_calculate_Value:%x\n", CRC8(buff2, 16, 0x00));
HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *)buff_send3, sizeof(buff_send3));
// uint32_t res;
// res = CRC32(buff2, 5, 0xFFFFFFFF);
// res = CRC32(&buff2[5], 3, res);
// res = CRC32(&buff2[8], 4, res);
// sprintf(buff_send4, "CRC_user_continue_calculate_Value:%x\n", CRC32(&buff2[12],4,res));
// HAL_UART_Transmit_DMA(&hlpuart1, (uint8_t *) buff_send4, sizeof(buff_send4));
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
}
/* USER CODE END 3 */
}
/**
* @brief System Clock Configuration
* @retval None
*/
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Configure the main internal regulator output voltage
*/
HAL_PWREx_ControlVoltageScaling(PWR_REGULATOR_VOLTAGE_SCALE1_BOOST);
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLM = RCC_PLLM_DIV3;
RCC_OscInitStruct.PLL.PLLN = 85;
RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2;
RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */