简介

  • 常见算法

Modbus通信协议 CRC16校验码详解

Modbus通信协议是一种用于在不同设备之间进行通信的协议,常用于工业自动化和控制系统。其中,CRC16校验码是用来验证通信数据的完整性的一部分。

CRC(Cyclic Redundancy Check)是一种错误检测码,通过对数据进行多项式除法运算,生成一个校验码,用于检测数据传输过程中的错误。CRC16是一种使用16位位宽的CRC校验码。

Modbus协议在通信中使用CRC16校验码来确保数据的准确传输。具体而言,CRC16校验码的计算方式是对要发送或接收的数据按照一定规则进行计算,然后将计算得到的校验码附加到数据中,接收方在接收数据后也会进行相同的校验计算,并比较计算得到的校验码是否与接收到的校验码相符,以判断数据是否完整、正确。

以下是CRC16校验码计算的主要步骤:

  1. 初始化CRC寄存器为0xFFFF。
  2. 针对每个字节(8位)的数据,从最高位开始,依次进行以下操作:
    • 将CRC寄存器的最低位与当前数据位异或(XOR)操作。
    • 对CRC寄存器进行右移一位。
    • 如果异或操作的结果为1,则将CRC寄存器与预定义的多项式(通常是0xA001)进行异或操作。
  3. 继续处理下一个字节的数据,重复步骤2,直到所有数据字节都被处理。
  4. 最终CRC寄存器中的值即为CRC16校验码。

在接收方,接收到数据后,同样使用相同的计算方式进行CRC16校验计算,然后将计算得到的校验码与接收到的校验码比较。如果相符,则说明数据传输没有错误,否则可能存在错误。

需要注意的是,CRC校验并不能纠正错误,而只能检测错误。如果CRC校验不通过,通常需要进行数据重传等处理来保证数据的正确传输。

上述解释是CRC16校验码的基本原理,实际使用中可能会涉及一些细节和配置参数,取决于通信协议的具体要求。不同的Modbus协议变种可能会有稍微不同的CRC16计算方法,因此在实际应用中,需要参考相关的协议文档或标准来进行实现。

C modbus crc16 校验码 示例

Modbus通信协议中常使用CRC16校验码来验证数据的完整性。以下是一个示例,展示如何计算Modbus CRC16校验码。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include <stdio.h>
#include <stdint.h>

// 计算CRC16校验码
uint16_t calculate_crc16(const uint8_t *data, size_t length) {
    uint16_t crc = 0xFFFF;

    for (size_t i = 0; i < length; ++i) {
        crc ^= data[i];
        for (int j = 0; j < 8; ++j) {
            if (crc & 0x0001) {
                crc >>= 1;
                crc ^= 0xA001;
            } else {
                crc >>= 1;
            }
        }
    }

    return crc;
}

int main() {
    uint8_t data[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x02}; // 示例数据
    size_t data_length = sizeof(data) / sizeof(data[0]);

    uint16_t crc = calculate_crc16(data, data_length);

    printf("CRC16: 0x%04X\n", crc);

    return 0;
}

在上述示例中,calculate_crc16 函数接受一个字节数组和其长度作为参数,并计算其CRC16校验码。main 函数演示了如何调用该函数来计算示例数据的CRC16校验码。

需要注意的是,CRC16校验码的计算是Modbus通信协议中的一部分,不同的实现可能会有细微的差异。上述示例展示了一个常见的CRC16计算方法,但在实际应用中,你需要根据通信协议的规范和要求来进行计算。

查找算法

在C++中,可以使用标准库提供的范围查找算法来在容器中查找特定元素或满足特定条件的元素。以下是一些常用的范围查找算法:

  1. std::find():在指定范围内查找指定值的第一个匹配项。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    auto it = std::find(numbers.begin(), numbers.end(), 3);
    if (it != numbers.end()) {
        // 找到了元素
    } else {
        // 没有找到元素
    }

    return 0;
}
  1. std::find_if():在指定范围内查找满足特定条件的第一个元素。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <algorithm>
#include <vector>

bool isEven(int num) {
    return num % 2 == 0;
}

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    auto it = std::find_if(numbers.begin(), numbers.end(), isEven);
    if (it != numbers.end()) {
        // 找到满足条件的元素
    } else {
        // 没有找到满足条件的元素
    }

    return 0;
}
  1. std::binary_search():在已排序的范围内执行二分查找,判断指定值是否存在。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <algorithm>
#include <vector>

int main() {
    std::vector<int> numbers = {1, 2, 3, 4, 5};

    bool exists = std::binary_search(numbers.begin(), numbers.end(), 3);
    if (exists) {
        // 值存在
    } else {
        // 值不存在
    }

    return 0;
}

这些是一些常见的范围查找算法示例,您可以根据具体的需求选择适合的算法来执行查找操作。请注意,在使用这些算法之前,确保容器已经按照所需的顺序进行了排序(如果需要)。

射线法,判断点在多边形内

  • 思路
    • 该算法的思路很简单,就是从目标点出发引一条射线,看这条射线和多边形所有边的交点数目。
    • 如果有奇数个交点,则说明在内部,如果有偶数个交点,则说明在外部。
  • 步骤
    • 已知点point(x,y)和多边形Polygon的点有序集合(x1,y1;x2,y2;….xn,yn;)
    • 以point为起点,以无穷远为终点作平行于X轴的射线line(x,y; -∞,y);循环取得多边形的每一条边side(xi,yi;xi+1,yi+1):
      • 判断point(x,y)是否在side上,如果是,则返回true。
      • 判断line与side是否有交点,如果有则count++。
    • 判断交点的总数count,如果为奇数则返回true,偶数则返回false。

判断矩形框是否在多边形区域内

要判断一个矩形框是否在多边形区域内,可以使用点与多边形边界的位置关系进行判断。下面是一个简单的示例,展示了如何判断一个矩形框是否在多边形区域内部:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
#include <iostream>
#include <vector>

struct Point {
    double x;
    double y;

    Point(double x, double y) : x(x), y(y) {}
};

// 判断点是否在多边形内部
bool isInsidePolygon(const Point& point, const std::vector<Point>& polygon) {
    int n = polygon.size();
    bool inside = false;

    for (int i = 0, j = n - 1; i < n; j = i++) {
        if (((polygon[i].y > point.y) != (polygon[j].y > point.y)) &&
            (point.x < (polygon[j].x - polygon[i].x) * (point.y - polygon[i].y) / (polygon[j].y - polygon[i].y) + polygon[i].x)) {
            inside = !inside;
        }
    }

    return inside;
}

// 判断矩形框是否在多边形区域内部
bool isRectangleInsidePolygon(const std::vector<Point>& rectangle, const std::vector<Point>& polygon) {
    for (const Point& point : rectangle) {
        if (!isInsidePolygon(point, polygon)) {
            return false;
        }
    }

    return true;
}

int main() {
    std::vector<Point> polygon = {
        {0.0, 0.0},
        {5.0, 0.0},
        {5.0, 5.0},
        {0.0, 5.0}
    };

    std::vector<Point> rectangle = {
        {1.0, 1.0},
        {4.0, 1.0},
        {4.0, 4.0},
        {1.0, 4.0}
    };

    if (isRectangleInsidePolygon(rectangle, polygon)) {
        std::cout << "矩形框在多边形区域内" << std::endl;
    } else {
        std::cout << "矩形框不在多边形区域内" << std::endl;
    }

    return 0;
}

在上述示例中,我们使用了射线法的思想来判断点是否在多边形内部,然后将该方法应用到矩形框的每个顶点。函数 isInsidePolygon 判断点是否在多边形内部,函数 isRectangleInsidePolygon 判断矩形框的每个顶点是否都在多边形区域内。