【嵌入式常用算法】累加和校验算法(CheckSum算法)
“我这一生都是坚定不移的唯物主义者,唯有你,我希望有来生。”
-- 周恩来
一、概述
因为我们所处的环境之中,存在各种或强或弱的信号,这些不速之客总会对电路存在或多或少的干扰,尤其是对于数字信号,很可能会导致传输的数据变得与原来相差甚远。
对于很多注重安全的场合,尤其是一些数据可能会影响一些硬件的动作(诸如嵌入式的一些设备、机器人的控制等),错误的数据可能会带来一些比较严重的风险,不进行适当的检测和约束,可能会造成严重的安全事故。
如何避免这种意外事故呢?很容易想到两点:纠正错误数据和放弃错误数据。本文所讲的就是如何利用校验算法发现数据的错误,从而放弃错误数据的使用。
对于嵌入式一些比较简单的领域,对成本也比较关注,这种要基于成本的考虑注定所选用的单片机的性能都比较弱,所以 所使用的的检验算法都比较简单,诸如 UART
使用的奇偶校验。
今天的主角,累加和校验算法,又名 CheckSum
算法。实现起来同样比较简单,但是比较有效,尤其对于一些性能一般的硬件。
至于算法出处,没找到是哪位大佬首先发明的,只能抱以深深地敬意,这里就不细细考究了。
二、原理与实现
这种算法的实现非常,主要是发送方之间的配合:
-
发送方:对所有的数据累加,得到一个数据和,对和求反,即得到我们的校验值。然后把要发的数据和这个校验值一起发送给接收方。
-
接收方:对接收的数据(包括校验和)进行累加,然后加1,如果得到0,那么说明数据没有出现传输错误。(注意,此处发送方和接收方用于保存累加结果的类型一定要一致,否则加1就无法实现溢出从而无法得到0,校验就会无效)
还是举个例子:
-
发送方:要发送
0xA8
,0x50
,我们使用unsigned char
(8位)类型的变量来保存累加和,即为0xF8
(0b11111000
),取反得到校验和为0x07
(0b00000111
)。然后将这三个数据发送出去。 -
接收方:如果接收正确,这三个数据的累加和就是(
0b11111111
),此时加1
,则得到的结果为0
(实际得到的应该是0b100000000
,但是由于是使用unsigned char
(8位)来保存累加和,所以高位溢出被截取掉,只剩下了低八位的8
个0
)。
由上面的例子,我们可以知道算法的目的是:使累加和和校验值相加得到一个二进制下每一位都是 1
的结果,这个结果很明显很好处理,这种算法实现起来也很简单,下面给出 C
语言的代码示例。
发送方:以下是如何得到校验值的代码,结果就是我们想要的校验值。
uint8_t TX_CheckSum(uint8_t *buf, uint8_t len) //buf为数组,len为数组长度
{
uint8_t index = 0;
uint8_t ret = 0;
for (index = 0; index < len; index++)
{
ret += *(buf++);
}
ret = ~ret;
return ret;
}
接收方:输入已包含发送发发来的校验值,如果函数返回的值如果是0,说明数据正确。
uint8_t RX_CheckSum(uint8_t *buf, uint8_t len) //buf为数组,len为数组长度
{
uint8_t index = 0;
uint8_t ret = 0;
for (index = 0; index < len; index++)
{
ret += *(buf++);
}
ret = ret;
return ret + 1;
}