嵌入式常见的五种校验算法(c语言)

一.概述

   为了在串口通信或者固件升级时防止数据传输错误导致出现问题,一般要引入校验算法,嵌入式常见简易校验算法(c语言)主要有:

奇偶校验发,校验和,异或校验,CRC校验,md5,每种校验方法都有自己的特点,在不同场景可以选择合适的算法进行应用。

二.各种校验算法详细介绍

1.奇偶校验法

  奇偶校验算法(Parity Check Algorithm)是一种简单的错误检测方法,用于验证数据传输中是否发生了位错误。

  

1.1 原理示例

   采用奇偶校验数据是四个byte:0xf1,0xf3,0xf7,0xff,  那加入奇偶校验后发送数据为多少?

对于给定的四个byte数据:0xf1, 0xf3, 0xf7, 0xff,我们首先需要将这些byte转换为二进制形式,并统计其中“1”的总数。然后,根据选择的奇偶校验类型(奇校验或偶校验),我们会在数据末尾添加一个额外的bit作为校验位。

首先,将给定的byte转换为二进制:

0xf1: 1111 0001

0xf3: 1111 0011

0xf7: 1111 0111

0xff: 1111 1111

接下来,统计这四个byte中“1”的总数:

0xf1中有4个“1”

0xf3中有4个“1”

0xf7中有4个“1”

0xff中有8个“1”

总共是 4 + 4 + 4 + 8 = 20 个“1”。

现在,我们需要决定是添加“0”还是“1”作为校验位:

如果选择奇校验,因为当前“1”的总数是偶数(20),我们需要添加一个“1”来使总数变为奇数。

如果选择偶校验,因为当前“1”的总数是偶数(20),我们实际上不需要改变它(即添加一个“0”),但在这里,为了明确表示我们添加了一个校验位,并且这个校验位是为了满足偶校验的要求(尽管在这个特定情况下它看起来是多余的),我们仍然会添加一个“0”。但请注意,在大多数情况下,如果原始数据中“1”的数量已经是偶数,并且我们正在进行偶校验,那么我们不会添加额外的bit,或者可以说校验位是隐式的“0”。

然而,为了回答这个问题,并且假设我们确实需要显式地添加一个校验位,那么:

对于奇校验,发送的数据(包括校验位)将是:1111 0001 1111 0011 1111 0111 1111 1111 1(校验位)

对于偶校验,虽然在这个特定情况下添加“0”是多余的,但按照问题的要求,发送的数据(包括校验位)将是:1111 0001 1111 0011 1111 0111 1111 1111 0(校验位)

但请注意,在实际通信中,校验位通常是作为单独的一部分来处理的,而不是直接附加在数据字节的末尾形成一个更长的字节序列。此外,校验位的处理也取决于通信协议和硬件/软件的实现方式。

1.2 代码实现

1.2.1 发送方函数

void sender_send_data_with_parity(unsigned char* data, int length) {

    // 统计数据字节中1的个数

    int count = 0;

    for (int i = 0; i < length; i++) {

        unsigned char byte = data[i];

        for (int j = 0; j < 8; j++) {

            if ((byte >> j) & 1) {

                count++;

            }

        }

    }

    // 计算奇偶校验位,如果1的个数是偶数,则校验位为0,否则为1

    unsigned char parity_bit = (count % 2 == 0) ? 0 : 1;

    // 发送数据字节和奇偶校验位

    for (int i = 0; i < length; i++) {

        send_byte(data[i]);

    }

    send_byte(parity_bit);

}

1.2.2接收方函数

void receiver_receive_data_with_parity() {

    // 接收数据

    unsigned char received_data[MAX_LENGTH];

    int length = receive_data(received_data);

    // 统计接收到的数据字节中1的个数

    int count = 0;

    for (int i = 0; i < length - 1; i++) {

        unsigned char byte = received_data[i];

        for (int j = 0; j < 8; j++) {

            if ((byte >> j) & 1) {

                count++;

            }

        }

    }

    // 比较接收到的奇偶校验位与数据字节中1的个数是否一致

    unsigned char expected_parity_bit = (count % 2 == 0) ? 0 : 1;

    unsigned char received_parity_bit = received_data[length - 1];

    if (expected_parity_bit != received_parity_bit) {

        // 发生了位错误

        handle_error();

    } else {

        // 数据传输正常

        process_data(received_data, length - 1);

    }

}

2.校验和

2.1原理介绍

校验和是最基本,也是嵌入式软件工程师最常用的一种校验算法,其实现方法很简单。

实现原理:按每个字节,计算累加和。

实现的方式方法很多,不同的编程语言,不同的应用有所不同,有Checksum-8/16/32等,下面以C语言8位校验和为例:

2.2代码示例

uint8_t CheckSum(uint8_t *Buf, uint8_t Len)

{

  uint8_t i = 0;

  uint8_t sum = 0;

  uint8_t checksum = 0;

  for(i=0; i<Len; i++)

  {

    sum += *Buf++;

  }

  checksum = sum & 0xff;

  return checksum;

}

3.异或校验

3.1原理介绍

【异或校验】与【校验和】类似,对数据进行“异或”,最终得到一个“异或值”。

实现原理:按每个字节异或,求结果。

校验和、异或校验的方式有很多种,比如有的还会传入一个参数作为异或校验的值。实现的方式方法很多,不同的编程语言,不同的应用有所不同,下面以C语言为例:

3.2代码示例

uint8_t CheckXOR(uint8_t *Buf, uint8_t Len)

{

  uint8_t i = 0;

  uint8_t x = 0;

  for(i=0; i<Len; i++)

  {

    x = x^(*(Buf+i));

  }

  return x;

}

4.CRC校验

4.1基本原理

CRC:Cyclic Redundancy Check,即循环冗余校验。

CRC是数据通信领域中最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。循环冗余检查(CRC)是一种数据传输检错功能,对数据进行多项式计算,并将得到的结果附在帧的后面,接收设备也执行类似的算法,以保证数据传输的正确性和完整性。

实现原理:设置crc值和多项式码;依次遍历每个字节,与crc值进行异或;crc值取出最低位的值,并右移一位;如果最低位值位1,则于多项式码进行异或;循环直到8位结束。

CRC校验属于冗余校验中的一种,大学学计算机相关专业的同学都应该学过CRC校验。

CRC有多种变体,比如:CRC-1、 CRC-5-USB、 CRC-8、 CRC-16、 CRC-32、 CRC-64等。其中,在嵌入式领域,CRC-16用的比较多。

4.2 RC算法的具体实现过程如下

将待发送的数据视为一个二进制多项式D(x),其中每一位代表一个系数。

选取一个生成多项式G(x),该多项式的长度决定了CRC校验码的长度。

对D(x)乘以x^n(n为生成多项式的长度减1),形成一个与G(x)同阶的多项式。

使用生成多项式G(x)对该扩展后的多项式进行模2除法,得到的余数即为CRC校验码。

将CRC校验码附加到原始数据的末尾,形成完整的数据包。

在接收端,对数据包再次进行相同的模2除法运算,若余数为零,则认为数据包未发生错误。

4.3 下面是一个CRC-16算法的C语言实现示例

uint16_t Crc16(uint8_t *data,uint16_t len)

{

    uint16_t crc16 = 0xFFFF;

    uint32_t uIndex ; //CRC查询表索引

    while (len --)

    {

        uIndex = (crc16&0xff) ^ ((*data) & 0xff) ; //计算CRC

data = data + 1;

        crc16 = ((crc16>>8) & 0xff) ^ crc16_tab[uIndex];

    }

    return crc16 ;//返回CRC校验值

}

4.4 下面是一个CRC-32算法的C语言实现示例

include <stdint.h>

uint32_t crc32(const unsigned char *buf, size_t len) {

    uint32_t crc = 0xFFFFFFFF;

    const unsigned char *end = buf + len;

    uint32_t table[256];

    // Pre-compute the CRC table

    for (int i = 0; i < 256; i++) {

        uint32_t c = i;

        for (int j = 0; j < 8; j++) {

            if (c & 1) {

                c = 0xEDB88320 ^ (c >> 1);

            } else {

                c = c >> 1;

            }

        }

        table[i] = c;

    }

    // Process each byte of the data

    while (buf < end) {

        crc = table[(crc ^ *buf++) & 0xFF] ^ (crc >> 8);

    }

    return crc ^ 0xFFFFFFFF;

}

4.4 查表法

在CRC(Cyclic Redundancy Check)算法的实现中,经常使用一个预计算的查找表(lookup table),这个查找表就是一个数组,用来加速CRC的计算过程。这个数组通常被称为“CRC表”或“CRC查找表”。

CRC算法的核心是基于二进制的多项式除法,其中使用的除数是一个固定的多项式(即生成多项式)。在软件实现中,特别是当需要快速计算CRC校验值时,查找表可以显著减少计算量。

查找表的工作原理:

预计算: 在CRC算法的初始化阶段,程序会预先计算出所有可能的8位(或其他位数,取决于查找表的设计)输入与生成多项式进行模2除法的结果,并将这些结果存储在一个数组中。这个数组的大小通常是256个元素,每个元素对应一个8位输入的CRC校验值。

快速计算: 当实际计算数据的CRC校验值时,算法会对数据进行逐字节处理。对于每个字节,算法会在查找表中查找对应的CRC值,然后与之前计算得到的部分CRC值进行异或操作。这个过程会重复直到所有的数据字节都被处理完毕。

最终CRC值: 在处理完所有数据后,累积的CRC值会经过可能的反转(reflect)和初始值(seed)调整,得到最终的CRC校验值。

查找表优点:

使用查找表的主要优点是减少了每次迭代中的复杂计算,尤其是避免了多项式除法,而代之以简单的数组查找和异或操作,这在大多数现代计算机架构上是非常快速的。

查找表的生成:

查找表的生成涉及对每一个可能的8位输入(从0到255)执行CRC算法的完整计算过程,并存储最终结果。这个过程只在程序启动时执行一次,之后就可以复用这个查找表来快速计算任何数据的CRC校验值。

查找表的使用使得CRC计算在软件中变得既快速又高效,尤其在实时系统和大量数据处理中,这一点尤为重要。

5.MD5算法

MD5:Message-Digest Algorithm 5,即“信息-摘要算法。消息摘要算法又称为哈希算法、散列算法,输出的消息摘要又称为哈希值、散列值。

从名字来看就知道它是从MD3、MD4发展而来的一种加密算法,其主要通过采集文件的信息摘要,以此进行计算并加密。

压缩性:MD5可以将任意长度的输入转化为128位长度的输出;

不可逆性:MD5是不可逆的,我们无法通过常规方式从MD5值倒推出它的原文;

抗修改性:对原文做一丁点儿改动,MD5值就会有巨大的变动,也就是说就算两个MD5值非常相似,你也不能想当然地认为它们俩对应的原文也非常相似。

实现原理:MD5是输入不定长度信息,输出固定长度128-bits的算法。经过程序流程,生成四个32位数据,最后联合起来成为一个128-bits散列。基本方式为,求余、取余、调整长度、与链接变量进行循环运算。得出结果。

因为MD5可以被暴力破解,所以MD5不再是安全的了,对安全性要求较高的场合,不建议直接使用MD5。

MD5的源码在网上都能找到现成的,而且有不同编程语言(C、 C++、 JAVA)版本。

应用:可以对升级包进行MD5校验,在嵌入式linux下可以直接通过命令进行MD5计算,应用非常方便。

  • 21
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

AI+程序员在路上

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值