Modbus RTU协议实现

Modbus协议简介

Modbus串行链路系统可以使用不同的物理接口(RS 485,RS 232),最常用的是RS 485两线制接口。为了提高通信模块在工业应用中的抗干扰性和稳定性,接口芯片和FPGA核心模块之间应加入高速光耦进行隔离,总线两端处放置线路终端电阻,采用屏蔽双绞线作为通信线等。
在串行链路上,Modbus RTU(Remote Terminal Unit)模式报文中每8个位字节含有两个4位十六进制字符,这种模式的主要优点是较高的数据密度,在相同的波特率下比ASCII模式有更高的吞吐率。RTU模式每个字节(11位)的格式如图1所示,支持奇、偶和无校验,使用无校验时要求2个停止位。Modbus RTU帧最大为256B,由发送设备将Modbus报文构造为带有已知起始和结束标记的帧,报文帧由时长至少为3.5个字符时间的空闲间隔区分,整个报文帧必须以连续的字符流发送,如果两个字符之间的空闲间隔大于1.5个字符时间,则报文帧被认为不完整被接收节点丢弃,如图所示。
Modbus RTU协议实现_第1张图片
在应用层上,Modbus是一个请求/应答协议,并且提供功能码规定的服务。有三类Modbus功能码:公共码、用户定义码和保留码,大多数情况下只用公共码,其主要包括比特(线圈)访问、16 b(寄存器)访问、文件记录访问、诊断和其他信息访问。

CRC校验

  1. 循环校验码(CRC码)
    数据通信领域中最常用的一种差错校验码,其特征是信息字段和校验字段的长度可以任意选定。这个校验方式的根本思想是在发送数据的后面拼接上一些额外的数据位,使得这个拼接之后的数据可以被一个固定的数模2整除(这里的模2整除是一种区别于普通的除法的运算方法,也不难理解),之后将数据发送……接收端同样将整个拼接后的数据与之前确定的固定的数据做模2除法,若能整除,则说明传输过程没有出错,若不能整除,则可以根据余数判断是哪一位发生了错误。
  2. 生成CRC码的基本原理
    任意一个由二进制位串组成的代码都可以和一个系数仅为‘0’和‘1’取值的多项式一一对应。例如:代码1010111对应的多项式为x6+x4+x2+x+1,而多项式为x5+x3+x2+x+1对应的代码101111。标准CRC生成多项式如下表:
    Modbus RTU协议实现_第2张图片CRC校验是前面几段数据内容的校验值,为一个16位数据,发送时,低8位在前,高8位在末使用相同的计算方法计算出信息字段的校验码,对比接收到的实际校验码,如果相等及信息正确,不相等则信息错误;或者将接受到的所有信息除多项式,如果能够除尽,则信息正确。
  3. CRC-16校验码的计算方法
    计算法
    (1).预置1个16位的寄存器为十六进制FFFF(即全为1),称此寄存器为CRC寄存器;
    (2).把第一个8位二进制数据(既通讯信息帧的第一个字节)与16位的CRC寄存器的低8位相异或,把结果放于CRC寄存器,高八位数据不变;
    (3).把CRC寄存器的内容右移一位(朝低位)用0填补最高位,并检查右移后的移出位;
    (4).如果移出位为0:重复第3步(再次右移一位);如果移出位为1,CRC寄存器与多项式A001【 (CRC-16)8005按位颠倒后的结果】(1010 0000 0000 0001)进行异或;
    (5).重复步骤3和4,直移8次,这样整个8位数据全部进行了处理;
    (6).重复步骤2到步骤5,进行通讯信息帧下一个字节的处理;
    (7).将该通讯信息帧所有字节按上述步骤计算完成后,得到的16位CRC寄存器的高、低字节进行交换;
    (8).最后得到的CRC寄存器内容即为:CRC码。
    //表示计算一个字节的校验值,实际收到多少个字节数,就循环调用该计算程序多少次
    reg [7:0] cnt_reg,cnt_data,x;
    reg signal_CRC_start;
    reg [15:0] CRC;
    always@(posedge clk100m or negedge rst_n)
    begin
    if( !rst_n ) begin
        CRC <= 16'hFFFF;
    end
    else begin
        if(rx_done )  begin                 //表收到一个完整的字节
            CRC[7:0] = CRC[7:0] ^ rx_byte;
            signal_CRC_start <= 1;         //该字节校验值计算开始标志
            cnt_data <= cnt_data + 1;      //收到字节数+1
        end
        else begin
            if(cnt_reg == 8)  begin      	//该字节的8位校验值全部计算完
                signal_CRC_start <= 0;
                cnt_reg <= 0;
            end
            else
                if(signal_CRC_start == 1)begin //对8位依次计算
                    cnt_reg = cnt_reg +1;
                    if(CRC[0] == 0)
                        CRC = CRC>>1;
                    else
                        CRC = (CRC>>1)^ 16'hA001;
                end
        	end
    	end
    end
    
    查表法
    查表法是将移位异或的计算结果做成了一个表,就是将0~256放入一个长度为16位的寄存器中的低八位,高八位填充0,然后将该寄存器与多项式0XA001按照上述3、4步骤,直到八位全部移出,最后寄存器中的值就是表格中的数据,高八位、低八位分别单独一个表。

你可能感兴趣的:(FPGA之协议设计)