小学霸这次做的项目需要Modbue -TCP协议转化为Modbus- RTU协议并通过串口输出,RTU协议中在数据发送的最后需要发送CRC16 校验码,关于CRC16校验码的计算方式有很多种,在此小学霸用的是移位计算法,具体的步骤是:
1、预置一个值为0XFFFF的16位寄存器,即CRC寄存器;
2、将第一个八位数据与16 CRC寄存器的第八位相异或,结果仍存于CRC寄存器中;
3、将CRC寄存器的内容右移一位,最高位补0 ;
4、若移出位为0则重复3步骤再右移一次,若移出为1,则CRC寄存器与0XA001进行异或;
5、重复3 4 步骤直到八位数据处理完成。
6、重复2–5步骤将通信消息帧下一字节处理,直至处理完成;
处理完成后在发送CRC校验位时,要先发送低字节,后发送高字节;
Verilog实现程序为:
    module CRC_count(clk,rst_n,CRC_out,signal_read,signal_write,arm_device_rddata,data_1,
    
    
    
    signal_start,signal_start_status,signal_CRC_start,cnt_reg,cnt_data,
    
    
    
    CRC,num_data);
    input clk;
    
    input rst_n;
    
    input signal_read;
    
    input signal_write;
    
    input [7:0] arm_device_rddata;
    
    output [15:0] CRC_out;
    
    input [7:0] data_1;
    
    input signal_start;
    
    output signal_start_status;
    
    output signal_CRC_start;
    
    output cnt_reg;
    
    output cnt_data;   //测试标志
    
    output CRC;
    
    input [7:0] num_data;
integer i;
    reg signal_start_reg1,signal_start_reg2;
    
    wire signal_start_status,signal_start_status1;
    
    reg [7:0] cnt_reg ;
    
    reg [7:0] cnt_data;
    
    reg [15:0] CRC_out;
    reg [15:0] CRC = 16’hffff;
    
    reg [15:0] data_buffer = 16’ha001;
    
    reg signal_CRC_start;
    always@(posedge clk)
    
    begin
    
    
    
    signal_start_reg1 <= signal_start;
    
    
    
    signal_start_reg2 <= signal_start_reg1;
    
    end
    assign signal_start_status = signal_start_reg1 && (~signal_start_reg2);
    
    assign signal_start_status1 = signal_start_reg2 && (~signal_start_reg1);
    always@(posedge clk)
    
    begin
    
    
    
    if(signal_start_status == 1)
    
    
    
    begin
    
    
    
    CRC = CRC ^ data_1;
    
    
    
    signal_CRC_start <= 1;
    
    
    
    cnt_data <= cnt_data + 1;
    
    
    
    
    
    
    end
    
    
    
    else
    
    
    
    if(cnt_reg == 8)
    
    
    
    begin
    
    
    
    signal_CRC_start <= 0;
    
    
    
    cnt_reg <= 0;
    
    
    
    if(signal_read == 1 && cnt_data == 5)
    
    
    
    begin
    
    
    
    CRC_out <= CRC;
    
    
    
    CRC <= 16’hffff;
    
    
    
    cnt_data <= 0;
    
    
    
    end
    
    
    
    else
    
    
    
    if(signal_write == 1 && cnt_data == 7 && num_data == 2)
    
    
    
    begin
    
    
    
    CRC_out <= CRC;
    
    
    
    CRC <= 16’hffff;
    
    
    
    cnt_data <= 0;
    
    
    
    end
    
    
    
    else
    
    
    
    if(signal_write == 1 && cnt_data == 6 && num_data == 1)
    
    
    
    begin
    
    
    
    CRC_out <= CRC;
    
    
    
    CRC <= 16’hffff;
    
    
    
    cnt_data <= 0;
    
    
    
    end
    
    
    
    
    
    
    end
    
    
    
    else
    
    
    
    if(signal_CRC_start == 1)
    
    
    
    begin
    
    
    
    for(i=7;i>=0;i=i-1)
    
    
    
    begin
    
    
    
    cnt_reg = cnt_reg +1;
    
    
    
    if(CRC[0] == 0)
    
    
    
    begin
    
    
    
    CRC = CRC>>1;
    
    
    
    end
    
    
    
    else
    
    
    
    if(CRC[0] == 1)
    
    
    
    begin
    
    
    
    CRC = (CRC>>1)^ data_buffer;
    
    
    
    end
    
    
    
    end
    
    
    
    end
end
endmodule
最后推荐一个计算CRC16校验码的计算器,在程序运行完可以做一下校对:http://www.3158bbs.com/tool-59.html
 
