vlambda博客
学习文章列表

【嵌入式常用算法】累加和校验算法(CheckSum算法)

“我这一生都是坚定不移的唯物主义者,唯有你,我希望有来生。”

-- 周恩来

一、概述

因为我们所处的环境之中,存在各种或强或弱的信号,这些不速之客总会对电路存在或多或少的干扰,尤其是对于数字信号,很可能会导致传输的数据变得与原来相差甚远。

对于很多注重安全的场合,尤其是一些数据可能会影响一些硬件的动作(诸如嵌入式的一些设备、机器人的控制等),错误的数据可能会带来一些比较严重的风险,不进行适当的检测和约束,可能会造成严重的安全事故。

如何避免这种意外事故呢?很容易想到两点:纠正错误数据和放弃错误数据。本文所讲的就是如何利用校验算法发现数据的错误,从而放弃错误数据的使用。

对于嵌入式一些比较简单的领域,对成本也比较关注,这种要基于成本的考虑注定所选用的单片机的性能都比较弱,所以 所使用的的检验算法都比较简单,诸如 UART 使用的奇偶校验。

今天的主角,累加和校验算法,又名 CheckSum 算法。实现起来同样比较简单,但是比较有效,尤其对于一些性能一般的硬件。

至于算法出处,没找到是哪位大佬首先发明的,只能抱以深深地敬意,这里就不细细考究了。

二、原理与实现

这种算法的实现非常,主要是发送方之间的配合:

  • 发送方:对所有的数据累加,得到一个数据和,对和求反,即得到我们的校验值。然后把要发的数据和这个校验值一起发送给接收方。

  • 接收方:对接收的数据(包括校验和)进行累加,然后加1,如果得到0,那么说明数据没有出现传输错误。(注意,此处发送方和接收方用于保存累加结果的类型一定要一致,否则加1就无法实现溢出从而无法得到0,校验就会无效)

还是举个例子:

  • 发送方:要发送 0xA80x50,我们使用 unsigned char(8位)类型的变量来保存累加和,即为 0xF80b11111000),取反得到校验和为 0x070b00000111)。然后将这三个数据发送出去。

  • 接收方:如果接收正确,这三个数据的累加和就是(0b11111111),此时加 1 ,则得到的结果为 0(实际得到的应该是0b100000000,但是由于是使用 unsigned char(8位)来保存累加和,所以高位溢出被截取掉,只剩下了低八位的 80 )。

由上面的例子,我们可以知道算法的目的是:使累加和和校验值相加得到一个二进制下每一位都是 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;
}