历史上的今天
今天是:2024年09月02日(星期一)
2019年09月02日 | STM32开发 -- CRC校验码
2019-09-02 来源:eefocus
通信协议里有CRC校验码,计算从报文的起始字节到报文内容最后一个字节的crc16的值。
举个例子:
远程控制命令集
5B 20 00 0A 00 01 0A 01 FE 00 01 00 AB 89
CRC校验码为:AB 89
一、RTU 檢查碼(CRC)計算器
第一种:
参看:RTU 檢查碼(CRC)計算器

大小端转换后,CRC检查码为:AB 89
说明,这个计算器还是可以用的。
第二种:
参看:On-line CRC calculation and free library

二、运算规则
RTU检查码(CRC)计算,运算规则如下:
步骤1:令16位暂存器(CRC暂存器)= 0xFFFF。
步骤2:异或第一个8位字节的消息指令与低位元16位CRC暂存器,做异或将结果存入CRC暂存器内。
步骤3:右移一位CRC暂存器,将0填入高位元处。
步骤4:检查右移的值,如果是0将步骤3的新值存入CRC暂存器内,否则异或0xA001与CRC暂存器,将结果存入CRC暂存器内。
步骤5:重复步骤3〜步骤4,将8位全部运算完成。
步骤6:重复步骤2〜步骤5,取下一个8位的消息指令,直到所有消息指令运算完成。最后,得到的CRC缓存器的值,即CRC的检查码。值得注意的是CRC的检查码必须交换放置于讯息指令的检查码中。
三、相关代码
扩展参看:C语言再学习 – 位操作
int16_t factory_crc16 ( uint8_t *bufData, uint16_t buflen)
{
uint16_t TCPCRC = 0xffff;
uint16_t POLYNOMIAL = 0xa001;
uint8_t i, j;
for (i = 0; i < buflen; i++)
{
TCPCRC ^= bufData[i];
for (j = 0; j < 8; j++)
{
if ((TCPCRC & 0x0001) != 0)
{
TCPCRC >>= 1;
TCPCRC ^= POLYNOMIAL;
}
else
{
TCPCRC >>= 1;
}
}
}
return TCPCRC;
}
四、CRC校验原理及步骤
参看:CRC校验原理及步骤
1、什么是CRC校验?
CRC即循环冗余校验码:是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。
2、CRC校验原理:
其根本思想就是先在要发送的帧后面附加一个数(这个就是用来校验的校验码,但要注意,这里的数也是二进制序列的,下同),生成一个新帧发送给接收端。当然,这个附加的数不是随意的,它要使所生成的新帧能与发送端和接收端共同选定的某个特定数整除(注意,这里不是直接采用二进制除法,而是采用一种称之为模2除法。到达接收端后,再把接收到的新帧除以(同样采用“模2除法”)这个选定的除数。因为在发送端发送数据帧之前就已通过附加一个数,做了“去余”处理(也就已经能整除了),所以结果应该是没有余数。如果有余数,则表明该帧在传输过程中出现了差错。
模2除法:
模2除法与算术除法类似,但每一位除的结果不影响其它位,即不向上一位借位,所以实际上就是异或。在循环冗余校验码(CRC)的计算中有应用到模2除法。
例:

3、CRC校验步骤:
CRC校验中有两个关键点,一是预先确定一个发送送端和接收端都用来作为除数的二进制比特串(或多项式),可以随机选择,也可以使用国际标准,但是最高位和最低位必须为1;二是把原始帧与上面计算出的除数进行模2除法运算,计算出CRC码。
4、具体步骤:
选择合适的除数
看选定除数的二进制位数,然后再要发送的数据帧上面加上这个位数-1位的0,然后用新生成的帧以模2除法的方式除上面的除数,得到的余数就是该帧的CRC校验码。注意,余数的位数一定只比除数位数少一位,也就是CRC校验码位数比除数位数少一位,如果前面位是0也不能省略。
将计算出来的CRC校验码附加在原数据帧后面,构建成一个新的数据帧进行发送;最后接收端在以模2除法方式除以前面选择的除数,如果没有余数,则说明数据帧在传输的过程中没有出错。
5、CRC校验码计算示例:
现假设选择的CRC生成多项式为G(X) = X4 + X3 + 1,要求出二进制序列10110011的CRC校验码。下面是具体的计算过程:
①将多项式转化为二进制序列,由G(X) = X4 + X3 + 1可知二进制一种有五位,第4位、第三位和第零位分别为1,则序列为11001
②多项式的位数位5,则在数据帧的后面加上5-1位0,数据帧变为101100110000,然后使用模2除法除以除数11001,得到余数。

③将计算出来的CRC校验码添加在原始帧的后面,真正的数据帧为101100110100,再把这个数据帧发送到接收端。
④接收端收到数据帧后,用上面选定的除数,用模2除法除去,验证余数是否为0,如果为0,则说明数据帧没有出错。
史海拾趣
|
Datasheet下载: 功能框图: DM6467实现了在各种视频终端产品间的无缝内容传输。它集成了ARM926EJ-S内核与600MHz C64x+ DSP内核,并采用高清视频/影像协处理器(HD-VICP)、视频数据转换引擎以及目标视频端口接口。在执行高达H.264 HP@ L4(10 ...… 查看全部问答> |
|
小弟刚刚接触ARM,跟着开发板的说明移植内核,发现自己的Linux系统下不会烧写镜像,可以说是啥也不会,望有经验的同志告之 PS:小弟用惯了Linux,不想回到Windows下去,望能有详细的方法(小白一个)… 查看全部问答> |
|
我想用用定时器输出微秒级的控制(mirco2440的板子),控制普通GPIO口输出高低电平(PWM被占用),整体思路是什么样的(驱动,应用程序调用)。。求助… 查看全部问答> |
|
接触WINCE5.0不久,不知道怎么办. WINCE 原来的缺省显示支持240*320的LCD,而我们用的LCD是320*240.在PB中把WINCE5.0自带的ImageViewer软件加入过来,发现很多地方,打开该应用程序菜单项窗口以后,有些窗口显示框超出了我的LCD.由于看不到WINCE源代码, ...… 查看全部问答> |
|
我用P1.2,1.3口捕获两个输入方波信号,均上升沿促发。两个捕获计数值差值得出时间差。但是计数差值很不稳定。。一段时间较为正常,一千多。一段时间突然保持在-几万。求助 #include long int cap1=0; long int cap2=0; long int ca ...… 查看全部问答> |
|
本帖最后由 chenzhufly 于 2015-1-19 15:54 编辑 SoC的Linux内核编译方法 这里介绍如何编译SD Card的image。这里并没有太多的原理需要讲述,但是大多数刚刚接触到linux 嵌入式的朋友还是需要花些时间找编译方法。这里提供了为SoCFPGA编译内核 ...… 查看全部问答> |




