C语言CRC-16 MODBUS格式校验函数

news2024/12/26 5:57:50

C语言CRC-16 MODBUS格式校验函数

CRC-16校验产生2个字节长度的数据校验码,通过计算得到的校验码和获得的校验码比较,用于验证获得的数据的正确性。基本的CRC-16校验算法实现,参考: C语言标准CRC-16校验函数。

不同应用规范通过对输入数据前处理和输出数据后处理的方式不同,又产生了不同的应用规范校验函数,这里介绍MODBUS格式的CRC-16校验函数。MODBUS格式对输入数据,预置值为0XFFFF(当做最初的余数),输入数据按照单个字节进行位反序。对于输出的校验码,进行整体位反序,。

生成多项式为x^16 + x^15 + x^2 + 1

正向算法

正向算法是符合标准CRC-16的计算理论,从左向右计算,也即计算过程中移位时,向左移出。几种正向算法的实现如下:

CRC-16 MODBUS格式校验函数一(8位输入数据格式,64位装载计算):

#include <stdio.h>
#include <stdlib.h>
uint16_t PY_CRC_16_MODBUS(uint8_t *di, uint32_t len)
{
    uint32_t crc_poly = 0x00018005;  //X^16+X^15+X^2+1 total 17 effective bits. Computed total data shall be compensated 16-bit '0' before CRC computing.

	uint8_t *datain;
	uint64_t cdata = 0; //Computed total data
    uint32_t data_t = 0; //Process data of CRC computing

	uint16_t index_t = 63;  ///bit shifting index for initial '1' searching
	uint16_t index = 63;    //bit shifting index for CRC computing
	uint8_t rec = 0; //bit number needed to be compensated for next CRC computing

    uint32_t cn=(len+2)/6;
    uint32_t cr=(len+2)%6;

	uint32_t j;

	datain = malloc(len+2);
	for(j=0;j<len;j++)
	{
		datain[j] = 0;
		for(uint8_t m=0; m<=7; m++)
		{
			datain[j] |= ( ( di[j]>>(7-m) ) & 1 ) << m;
		}
	}
        datain[len] = 0; datain[len+1] = 0;//Compensate 16-bit '0' for input data

        datain[0] ^= 0xff; datain[1] ^= 0xff;

    if(len<=6)   //Mount data for only one segment
     {
    	 for(j=0;j<=(len+1);j++)
    	 {
    		 cdata = (cdata<<8);
    		 cdata = cdata|datain[j];
    	 }
    	 cn = 1;
     }
    else
     {
    	 if(cr==0)
    	 {
    		 cr = 6;
    	 }
         else if(cr==1)
         {
             cr = 7;

         }
         else if(cr==2)
         {
             cr = 8;

         }
    	 else
    	 {
    		 cn++;
    	 }

    	 for(j=0;j<cr;j++)
    	 {
    		 cdata = (cdata<<8);
    		 cdata = cdata|datain[j];
    	 }
     }

     do
     {
 		cn--;

 		while(index_t>0)
 		{
 			if( (cdata>>index_t)&1 )
 			{
 				index = index_t;
 				index_t = 0;

 				data_t |= (cdata>>(index-16));
 				{
 					data_t = data_t ^ crc_poly;
 				}

 	            while((index!=0x5555)&&(index!=0xaaaa))
 	            {

	 	    		for(uint8_t n=1;n<17;n++)
	 	    		{
	 	    			if ((data_t>>(16-n))&1) {rec = n;break;}
	 	    			if (n==16) rec=17;
	 	    		}

 	    			if((index-16)<rec)
 	    			{
 	    				data_t = data_t<<(index-16);
 	    				data_t |=  (uint32_t)((cdata<<(64-(index-16)))>>(64-(index-16)));
 	    				index = 0x5555;
 	    			}
 	    			else
 	    			{
 	        			for(uint8_t i=1;i<=rec;i++)
 	        			{
 	        				data_t = (data_t<<1)|((cdata>>(index-16-i))&1) ;
 	        			}

 	        			if(rec!= 17)
 	        			{
 	        				data_t = data_t ^ crc_poly;
 	        				index -= rec;
 	        			}
 	        			else
 	        			{
 	        				data_t = 0;
 	        				index_t = index-16-1;
 	        				index = 0xaaaa;

 	        			}

 	    			}

 	            }
 				if(index==0x5555) break;
 			}
 			else
 			{
 				index_t--;
 				if(index_t<16) break;
 			}
         }

 		if(cn>0) //next segment
 		{
  			cdata = data_t&0x00ffff;

 			for(uint8_t k=0;k<6;k++)
 			{
 	    		 cdata = (cdata<<8);
 	    		 cdata = cdata|datain[j++];

 			}

 	    	data_t = 0;
 	 		index_t = 63;  ///bit shifting index for initial '1' searching
 	 		index = 63;    //bit shifting index for CRC computing
 	 		rec = 0; //bit number needed to be compensated for next CRC computing
 		}

     }
     while(cn>0);

     free(datain);

     uint16_t i_data_t = 0;

     for(uint8_t n=0; n<=15; n++)
     {
    	 i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;
     }

     return i_data_t;
}

CRC-16 MODBUS格式校验函数二(8位输入数据格式):

uint16_t PY_CRC_16_S_MODBUS(uint8_t *di, uint32_t len)
{
    uint16_t crc_poly = 0x8005;  //X^16+X^15+X^2+1 total 16 effective bits without X^16. Computed total data shall be compensated 16-bit '0' before CRC computing.

	uint32_t clen = len+2;
	uint8_t cdata[clen] ;
	for(uint32_t j=0;j<len;j++)
	{
		cdata[j] = 0;

		for(uint8_t m=0; m<=7; m++)
		{
			cdata[j] |= ( ( di[j]>>(7-m) ) & 1 ) << m;
		}
	}
	cdata[len]=0; cdata[len+1]=0;

	cdata[0] ^= 0xff; cdata[1] ^= 0xff;

	uint16_t data_t = (((uint16_t)cdata[0]) << 8) + cdata[1]; //CRC register

    for (uint32_t i = 2; i < clen; i++)
    {
        for (uint8_t j = 0; j <= 7; j++)
        {
            if(data_t&0x8000)
            	data_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ^ crc_poly;
            else
            	data_t = ( (data_t<<1) | ( (cdata[i]>>(7-j))&0x01) ) ;
        }
    }

    uint16_t i_data_t = 0;

    for(uint8_t n=0; n<=15; n++)
    {
   	 i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;
    }

    return i_data_t;
}

CRC-16 MODBUS格式校验函数三(16位输入数据格式):

uint16_t PY_CRC_16_T16_MODBUS(uint16_t *di, uint32_t len)
{
	uint16_t crc_poly = 0x8005;  //X^16+X^15+X^2+1 total 16 effective bits without X^16. 
	uint16_t data_t = 0; //CRC register

	uint16_t cdata[len];
	for(uint32_t j=0;j<len;j++)
	{
		cdata[j] = 0;
		for(uint8_t m=0; m<=7; m++)
		{
			cdata[j] |= ( ( ( (di[j]>>8)>>(7-m) ) & 1 ) << m ) | ( ( ( ( (di[j]&0x00ff)>>(7-m) ) & 1 ) << m ) <<8 );
		}

	}

	cdata[0] ^= 0xffff;

    for(uint32_t i = 0; i < len; i++)
    {
    	data_t ^= cdata[i]; //16-bit data

        for (uint8_t j = 0; j < 16; j++)
        {
            if (data_t & 0x8000)
            	data_t = (data_t << 1) ^ crc_poly;
            else
            	data_t <<= 1;
        }
    }

    uint16_t i_data_t = 0;

    for(uint8_t n=0; n<=15; n++)
    {
   	 i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;
    }

    return i_data_t;
}

CRC-16 MODBUS格式校验函数四(8位输入数据格式):

uint16_t PY_CRC_16_T8_MODBUS(uint8_t *di, uint32_t len)
{
	uint16_t crc_poly = 0x8005;  //X^16+X^15+X^2+1 total 16 effective bits without X^16. 
	uint16_t data_t = 0; //CRC register

	uint8_t cdata[len];
	for(uint32_t j=0;j<len;j++)
	{
		cdata[j] = 0;
		for(uint8_t m=0; m<=7; m++)
		{
			cdata[j] |= ( ( di[j]>>(7-m) ) & 1 ) << m;
		}
	}

	cdata[0] ^= 0xff; cdata[1] ^= 0xff;

    for(uint32_t i = 0; i < len; i++)
    {
    	data_t ^= cdata[i]<<8; //8-bit data

        for (uint8_t j = 0; j < 8; j++)
        {
            if (data_t & 0x8000)
            	data_t = (data_t << 1) ^ crc_poly;
            else
            	data_t <<= 1;

        }
    }

    uint16_t i_data_t = 0;

    for(uint8_t n=0; n<=15; n++)
    {
   	 i_data_t |=  ( ( data_t>>(15-n) ) & 1 ) << n;
    }

    return i_data_t;
}

反向算法

反向算法是从由右向左计算,也即计算过程中移位时,向右移出。而计算过程中的输入数据高优先计算位和校验参数的对齐关系不变。因此把一个字节放在CRC计算寄存器的最低字节时,对于MODBUS格式,最右侧最低位实际上是高优先计算位,而校验参数要相应倒序,从而计算位置对照关系不变。

CRC-16 MODBUS格式校验函数五(反向算法,8位输入数据格式):

uint16_t PY_CRC_16_T8_MODBUS_i(uint8_t *di, uint32_t len)
{
	uint16_t crc_poly = 0xA001; //Bit sequence inversion of 0x8005
	uint16_t data_t = 0xFFFF; //CRC register

    for(uint32_t i = 0; i < len; i++)
    {
    	data_t ^= di[i]; //8-bit data

        for (uint8_t j = 0; j < 8; j++)
        {
            if (data_t & 0x0001)
            	data_t = (data_t >> 1) ^ crc_poly;
            else
            	data_t >>= 1;
        }
    }

    return data_t;
}

算法验证

5种算法结果相同:
在这里插入图片描述

通过在线CRC工具对照验证成功:

在这里插入图片描述

–End–

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/484900.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Simulink 自动代码生成电机控制:弱磁控制从仿真到硬件开发板验证实验

目录 前言 仿真 生成代码在硬件上运行 总结 前言 测试了一个新的小电机&#xff0c;24V只能跑2000RPM左右&#xff0c;在此基础上测试一下弱磁控制&#xff0c;由于MTPA只适用于表贴电机&#xff0c;测试效果不能直观看出来&#xff0c;一般是通过测试效率。而前馈解耦的响…

【Paper】2019_DoS/数据注入攻击下基于一致性的信息物理系统安全性研究_曹雄

2019_DoS/数据注入攻击下基于一致性的信息物理系统安全性研究_曹雄 文章目录 第2章 拒绝服务攻击下多智能体系统安全性研究2.1 问题描述2.1.1 系统模型2.1.2 拒绝服务攻击模型 2.2 安全估计与一致性分析2.4 数值仿真2.4.1 观测器网络受到攻击下的结果及分析2.4.1.1 线性多智能体…

视频分享平台PeerTube的搭建

老苏下载了吴恩达的 Prompt for developer 课程&#xff0c;不管是否有兴趣&#xff0c;都可以看看&#xff0c;早晚我们都得学会使用 ChatGPT 虽然课程对话是英文&#xff0c;但有中文字幕&#xff0c;课程地址&#xff1a;https://www.aliyundrive.com/s/H3CpaapD87Z 这个软…

使用ChatGPT+Xmind一键生成思维导图,简直泰裤辣

&#x1f4cb; 个人简介 &#x1f496; 作者简介&#xff1a;大家好&#xff0c;我是阿牛&#xff0c;全栈领域优质创作者。&#x1f61c;&#x1f4dd; 个人主页&#xff1a;馆主阿牛&#x1f525;&#x1f389; 支持我&#xff1a;点赞&#x1f44d;收藏⭐️留言&#x1f4d…

python 编写K210控制步进电机的程序示例

今天正好看到K210的脉冲章节&#xff0c;就顺便拿出步进电机做个小实验&#xff0c;也好巩固一下所学的知识。下面是K210关于脉冲的相关介绍&#xff1a; 构造函数 machine.PWM(tim, freq, duty, pin, enableTrue) PWM 对象在 machine 模块下 【tim】K210 的 PWM 依赖…

789. 数的范围(C++和Python3)——2023.5.3打卡

文章目录 QuestionIdeasCode Question 给定一个按照升序排列的长度为 n 的整数数组&#xff0c;以及 q 个查询。 对于每个查询&#xff0c;返回一个元素 k 的起始位置和终止位置&#xff08;位置从 0 开始计数&#xff09;。 如果数组中不存在该元素&#xff0c;则返回 -1 -…

【C++从0到王者】第二站:类和对象(上)

文章目录 一、面向过程与面向对象二、类的引入三、类的访问限定符四、类的定义五、封装六、类的作用域七、类的实例化八、类对象模型1.如何计算类对象的大小2.类对象存储方式猜测 九、this指针1.this指针的引出2.this指针的特性 一、面向过程与面向对象 C语言是面向过程的&…

Web2与Web3开发的不同之处

Web2是引入交互功能的第二代互联网&#xff0c;也是我们今天所熟悉的。随着Web的不断发展&#xff0c;第三代互联网&#xff0c;也被称为Web3&#xff0c;正处于积极开发中。Web3引入了在区块链上运行的去中心化和无需许可的系统。但是Web2和Web3开发之间有什么区别呢&#xff…

23.5.1总结

这几天都在写项目&#xff1a; 在实现页面&#xff0c;调用数据库的时候&#xff0c;总是把数据库的表改了又改&#xff0c;然后完善了下数据库的表。 存储的思路大概是&#xff1a; 一个课程下可以有多个班级&#xff0c;所以以课程id作为主键建一个表&#xff0c;内容包括…

在win11搭建ubuntu目标机器的QT开发环境的实践

环境&#xff1a; 笔记本电脑 16G内存 win11 尝试wsl的方案&#xff1a; wsl2 ubuntu gnome xrdp wsl安装ubuntu并设置gnome图形界面详细步骤&#xff08;win11ubuntu18&#xff09;_heusjh的博客-CSDN博客 wsl2 ubuntu gnome VcXsrv Windows中WSL2 配置运行GNOM…

Centos7快速安装Elasticsearch 7.17.7

从 Elasticsearch 7.x 版本开始&#xff0c;Elasticsearch 发行版包括了自己的 JDK。因此&#xff0c;您不需要单独安装 Java。以下是在 CentOS 7 上安装 Elasticsearch 7.17.7 的完整步骤&#xff1a;&#xff08;数据默认保存在/var/lib/elasticsearch下&#xff0c;自行更改…

vmware安装arch linux

vmware安装arch linux 1、下载镜像2、安装2.1、VMware 系统版本选择 其他Linux 5.x 内核 64位2.2、进行磁盘分区 3、重启系统后登录进来发现没有地址 由于安装系统时没有安装任何软件 只安装了1个vim 无法动态获取地址4、安装必需的软件 最小化安装5、编辑/etc/ssh/sshd_config…

【Python】flask框架学习 flask框架的基本使用

flask框架是什么&#xff1f; Flask 是一个轻量级的 Web 框架&#xff0c;用于构建 Web 应用程序。它基于 Python 编程语言和 Werkzeug 工具包&#xff0c;提供了简单易用的 API&#xff0c;可以轻松地创建 RESTful API 和 Web 应用程序。 flask的特点 轻量级&#xff1a;Fl…

学会这些常用调试技巧,让你的C/C++代码调试起来如虎添翼

本篇博客主要讲解程序员最应该掌握的技能之一——调试。我个人认为&#xff0c;学习编程&#xff0c;有2件事情非常重要&#xff0c;一是画图&#xff0c;一是调试。下面我会以Visual Studio 2022为例&#xff08;VS的其他版本大同小异&#xff09;&#xff0c;演示如何调试一个…

怎么体验gpt4-国内怎么使用chatGPT

gpt4api要等多久 目前&#xff0c;OpenAI尚未公布GPT-4 API的发布计划和时间表。GPT-4 将是前置还增加强大的自然语言处理能力和推理能力&#xff0c;OpenAI正在为其开发和研究&#xff0c;以使其更加流畅、准确和智能。因此&#xff0c;GPT-4 API的发布时间尚未确定。但是&am…

云原生Istio安装和使用

目录 1 Kubernetes集群环境2 安装Istio2.1 快速部署Istio2.2 回顾K8S组件以及使用2.2.1 Deployment2.2.2 Labels and Selectors2.2.3 Namespace2.2.4 Service2.2.5 Ingress 2.3 初步感受istio2.4 手动注入2.5 自动注入sidecar 1 Kubernetes集群环境 Istio支持在不同的平台下安装…

华为OD机试真题(Java),计算字符串的编辑距离(100%通过+复盘思路)

一、题目描述 Levenshtein 距离&#xff0c;又称编辑距离&#xff0c;指的是两个字符串之间&#xff0c;由一个转换成另一个所需的最少编辑操作次数。许可的编辑操作包括将一个字符替换成另一个字符&#xff0c;插入一个字符&#xff0c;删除一个字符。编辑距离的算法是首先由…

STM32CubeMX时钟树配置详解(F103)

外部时钟配置 学习时使用的是stm32f103系列芯片&#xff0c;文档的时钟树属实不适合新手阅读&#xff0c;STM32cube的功能很强大&#xff0c;时钟树清晰明了&#xff1a; 首先我们要知道&#xff0c;芯片需要一个频率来进行工作&#xff0c;通常选用的是晶振来提供工作频率&a…

数据存储系统概要

可靠、可扩展与可维护性 现在有很多都属于数据密集型&#xff0c;而不是计算密集型。对于这些类型应用&#xff0c;CPU的处理能力往往不是第一限制性因素&#xff0c;关键在于数据量、数据的复杂度及数据的快速多边形。 数据密集型应用模块&#xff1a; 数据库&#xff1a;存…

不会JVM调优怎么进互联网大厂

&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3;&#x1f4e3; &#x1f38d;大家好&#xff0c;我是慕枫 &#x1f38d;前阿里巴巴高级工程师&#xff0c;InfoQ签约作者、阿里云专家博主&#xff0c;一直致力于用大白话讲解技术知识 &#x…