• CRC校验——以SHT4xA温湿度传感器为例


    一、简介

    循环冗余校验码(CRC)的基本原理是:在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码又叫(N,K)码。对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)。根据G(x)可以生成K位信息的校验码,而G(x)叫做这个CRC码的生成多项式。

    在这里插入图片描述

    二、计算方法

    具体参考CRC校验——以SHT30温湿度传感器为例(内附SHT30的驱动代码)

    (一)步骤

    (1) 预置一个值为0xFFFF的16位寄存器,此寄存器为CRC寄存器
    (2) 把第一个8位二进制数与16位的CRC寄存器相异或,异或的结果存在CRC寄存器中
    (3) CRC寄存器的内容左移一位,用0填补最低位,并检测移出位是0还是1
    (4) 如果移出位是0,则重复步骤3,如果移出位是1,则与多项式进行异或
    (5) 重复步骤3、4,直到左移8位,这样整个8位数据都进行了处理
    (6) 重复步骤2~5,进行下一个字节的处理
    (7)最后得到的CRC寄存器的内容即为CRC校验码

    在这里插入图片描述

    (二)参考代码(C语言)

    #include 
    typedef unsigned char uint8_t;
    
    /*
     * crc8校验函数,data为要校验的数据,len为要校验的数据的字节数
     */
    uint8_t crc8(const uint8_t *data, int len)
    {
         const uint8_t POLYNOMIAL = 0x31;
         uint8_t crc = 0xFF;
         int i, j;
       
    	 for (i=0; i<len; ++i) 
    	 {
         	crc ^= *data++;
     
         	for (j=0; j<8; ++j) 
    		{
            	crc = ( crc & 0x80 )? (crc << 1) ^ POLYNOMIAL: (crc << 1);
           	}
      	 }
    	
    	 return crc;
    }
    
    int main(int argc, const char *argv[])
    {
    	unsigned char data1[2] = {0x61, 0x04};
    	unsigned char data2[2] = {0xBE, 0xEF};
    	printf("0x%02X\n", crc8(data1, 2));
    	printf("0x%02X\n", crc8(data2, 2));
    
    	return 0;
    }
    /* 输出结果
    linux@linux-VirtualBox:~$ ./a.out 
    0xE4
    0x92
    */
    
    
    • 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

    (三)检验:CRC(0xBEEF)= 0x92

    多项式:0x31 ( x 8 x^8 x8+ x 5 x^5 x5+ x 4 x^4 x4+1)换成二进制为 9‘b1_0011_0001
    检验:CRC(0xBEEF)= 0x92

    1.第一个8位数据0xBE:CRC寄存器值为8'hFF,两者异或

              1   0   1   1     1   1  1   0
    XOR     1   1   1   1     1   1  1   1
    ————————————————————
              0   1   0   0     0   0  0   1

    1)左移一位,移出0,CRC值变成

               1   0   0   0     0   0   1   0

    2)左移一位,移出1,与多项式0x31异或

               0   0   0   0     0   1   0   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                0   0   1   1     0   1   0   1

    3)左移一位,移出0,CRC值变成

                0   1   1   0     1   0   1   0

    4)左移一位,移出0,CRC值变成

                1   1   0   1     0   1   0   0

    5)左移一位,移出1,与多项式0x31异或

               1   0   1   0     1   0   0   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                1   0   0   1     1   0   0   1

    6)左移一位,移出1,与多项式0x31异或

               0   0   1   1     0   0   1   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                0   0   0   0     0   0   1   1

    7)左移一位,移出0,CRC值变成

                0   0   0   0     0   1   1   0

    8)左移一位,移出0,CRC值变成

                0   0   0   0     1   1   0   0


    2.第二个8位数据0xEF,CRC寄存器值0x0C,两者异或:
              1   1   1   0    1   1   1   1
    XOR    0   0   0   0    1   1   0   0
    ————————————————————
              1   1   1   0     0   0   1   1

    1)左移一位,移出1,与多项式0x31异或

               1   1   0   0     0   1   1   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                1   1   1   1     0   1   1   1

    2)左移一位,移出1,与多项式0x31异或

               1   1   1   0     1   1   1   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                1   1   0   1     1   1   1   1

    3)左移一位,移出1,与多项式0x31异或

               1   0   1   1     1   1   1   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                1   0   0   0     1   1   1   1

    4)左移一位,移出1,与多项式0x31异或

               0   0   0   1     1   1   1   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                0   0   1   0     1   1   1   1

    5)左移一位,移出0,CRC值变成

                0   1   0   1     1   1   1   0

    6)左移一位,移出0,CRC值变成

                1   0   1   1    1   1   0   0

    7)左移一位,移出1,与多项式0x31异或

               0   1   1   1     1   0   0   0
    XOR       0   0   1   1     0   0   0   1
    ————————————————————
                0   1   0   0     1   0   0   1

    8)左移一位,移出0,CRC值变成

                1   0   0   1     0   0   1   0

    (3)可以看出CRC值最终变成了0x92.


    三、Verilog检验CRC

    (一)实现

        module crc(
            input                   clk     ,//时钟信号
            input                   rst_n   ,//复位信号
            input       [23:0]      din     ,
            input                   din_vld ,
            output reg  [15:0]      dout    ,
            output reg              dout_vld,
            output reg              right    //判断正确错误                
        );
        //参数定义
            localparam  CNT_SHIFT = 8       ,
                        DATA_NUM  = 2       ;
            localparam  CRC_INIT  = 8'hFF   ,//初始值
                        POLY      = 8'h31   ;//多项式
            localparam  IDLE      = 5'b00001,
                        START     = 5'b00010,
                        SHIFT     = 5'b00100,
                        CHANGE    = 5'b01000,
                        DONE      = 5'b10000;   
                         
    
        //信号定义
            reg   [4:0]    state_c ;
            reg   [4:0]    state_n ;
            reg   [23:0]   din_latch;
            reg   [7:0]    data     ;
            // reg            msb      ;//高有效位
            reg   [7:0]    crc      ;//crc寄存器
            reg   [2:0]    shift_cnt;
            reg            data_cnt ;
            reg            data_done;
    
        //din_latch
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                   din_latch<= 0;
                else if(din_vld)
                   din_latch<= din;
            end
        //状态机设计
            always @(posedge clk or negedge rst_n) begin 
                if (rst_n==0) 
                    state_c <= IDLE ;
                else 
                    state_c <= state_n;
            end 
        //状态跳转  
            always @(*) begin 
                case(state_c)  
                    IDLE  :begin
                            if(din_vld)
                                state_n = START ;
                            else 
                                state_n = state_c;
                           end  
                    START :state_n = SHIFT ;
                    SHIFT :begin
                            if(shift_cnt== CNT_SHIFT-1)
                                state_n = CHANGE;
                            else 
                                state_n = state_c;
                           end 
                    CHANGE:begin
                            if(!data_done)
                                state_n = START  ;
                            else if(data_done)
                                state_n = DONE  ;
                            else 
                                state_n = state_c;
                           end 
                    DONE  :state_n = IDLE ;
                    default : state_n = IDLE ; 
                endcase
            end
    
         //shift_cnt
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                    shift_cnt <= 0;
                else if(shift_cnt== CNT_SHIFT-1) 
                    shift_cnt <= 0;
                else if(state_c == SHIFT)
                    shift_cnt <= shift_cnt + 1'b1;
            end
        //data_cnt
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                    data_cnt <= 0;
                else if((data_cnt== DATA_NUM-1)&(shift_cnt== CNT_SHIFT-1)) 
                    data_cnt <= 0;
                else if(shift_cnt== CNT_SHIFT-1)
                    data_cnt <=  data_cnt + 1'b1;
            end
        //data
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                   data<= 0;
                else if(din_vld)
                   data<= din[23:16];
                else if((shift_cnt== CNT_SHIFT-2)&(data_cnt== DATA_NUM-2))
                   data<= din_latch[15:8];
            end
        //crc
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                   crc<= CRC_INIT;
                else if(din_vld)
                   crc<= CRC_INIT;
                else if(state_c == START)
                   crc= crc^data;
                else if(crc[7]&(state_c == SHIFT))
                   crc<= (crc<<1)^POLY;
                else if(!crc[7]&((state_c == SHIFT)))
                   crc<= (crc<<1);
                
            end
        //data_done
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                   data_done<= 0;
                else if((data_cnt== DATA_NUM-1)&(shift_cnt== CNT_SHIFT-1))
                   data_done<= 1'b1;
                else
                   data_done<= 1'b0;
            end
        //right
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                   right <= 0;
                else if(din_vld)
                   right <= 1'b0;
                else if((crc==din_latch[7:0])&data_done)
                   right <= 1'b1;
                else if((crc!=din_latch[7:0])&data_done)
                   right <= 1'b0;
            end
        //dout
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                   dout<= 0;
                else if(data_done)
                   dout<= din_latch[23:8];
            end
        //dout_vld
            always@(posedge clk or negedge rst_n)begin
                if(!rst_n)
                   dout_vld<= 0;
                else if(state_n ==DONE)
                   dout_vld<= 1'b1;
                else
                   dout_vld<= 1'b0;
            end
        endmodule
    
    • 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
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153

    (二)仿真

    `timescale 1 ns / 1 ps
        module tb;
            reg               clk     ;
            reg               rst_n   ;
            reg   [23:0]      din     ;
            reg               din_vld ;
            wire  [15:0]      dout    ;
            wire              dout_vld;
            wire              right   ;
    
            always #20 clk =~clk;
        //初始化
          initial begin
             clk = 1'b1;
             rst_n =1'b1;
             #40 ;
             rst_n = 1'b0;
             #80
             rst_n = 1'b1;
             #100000;
             $stop;
          end
        integer i = 0,j = 0;
        //初始化
          initial begin
            din     = 0;
            din_vld = 0;
            #200;
            for(i=0;i<30;i=i+1)begin
              if((i==1)|(i==10)|(i==20))
                din     = 24'hBEEF92;
              else
                din     = {$random};
              @(posedge clk) ;
              for(j=0;j<50;j=j+1)begin
                if(j==1)
                  din_vld = 1'b1;
                else
                  din_vld =1'b0;
                @(posedge clk) ;
              end
            end
              
          end
        
        //模块例化
          crc tb_crc(
            /* input             */.clk      (clk     ),//时钟信号
            /* input             */.rst_n    (rst_n   ),//复位信号
            /* input   [23:0]    */.din      (din     ),
            /* input             */.din_vld  (din_vld ),
            /* output  [15:0]    */.dout     (dout    ),
            /* output            */.dout_vld (dout_vld),
            /* output            */.right    (right   ) //判断正确错误                
          );
    endmodule
    
    
    
    
    • 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

    (三)波形

    1.检验CRC(0xBEEF)= 0x92?
    可以看到输入数据din=24’hBEEF92(数据16'hBEEF + CRC8'h92),输出结果为right(right==1),此时CRC校验结果是正确的。
    在这里插入图片描述

    2.检验CRC(0x895E)= 0x81?
    可以看到输入数据din=24’895E81(数据16'h895E + CRC8'h81),输出结果为wrong(right==0),此时CRC校验结果是错误的。正确的CRC应该是8'h00,非8’h81

    在这里插入图片描述

    参考

    模2除法(CRC)循环冗余校验码在线计算器
    CRC校验——以SHT30温湿度传感器为例(内附SHT30的驱动代码)

  • 相关阅读:
    单例模式(初学)
    【目标检测】39、一文看懂计算机视觉中的数据增强
    做自媒体视频二次剪辑,怎样剪辑不算侵权
    基于QML和JavaScript的嵌入式自助零售服务终端界面:整合SQLite、OAuth 2.0与Qt Linguist实现多功能解决方案(代码示例))
    【flask入门系列】Flask-SQLAlchemy的使用
    人工智能-循环神经网络通过时间反向传播
    SpringSecurity系列——RememberMe实战day7-3(源于官网5.7.2版本)
    mybatis中foreach使用
    C++知识精讲14 | 算法篇之二分查找算法
    frps内网穿透
  • 原文地址:https://blog.csdn.net/weixin_56102526/article/details/128183436