485半双工用法和verilog仿真

RS-485以两线间的电压差为du+(2—6) V表示;逻辑“0”以两线间的电压差为-(2—6)V表示。接口信号电平比RS-232-C降低了,就不易损坏接口电路的芯片, 且该电平与TTL电平兼容,可方便与TTL 电路连接。数据最高传输速率为10Mbps,接口是采用平衡驱动器和差分接收器的组合,抗共模干能力增强,即抗噪声干扰性好。RS-485接口的最大传输距离标准值为4000英尺,实际上可达 3000米,另外RS-232-C接口在总线上只允许连接1个收发器, 即单站能力。而RS-485接口在总线上是允许连接多达128个收发器。即具有多站能力,这样用户可以利用单一的RS-485接口方便地建立起设备网络

RS485的半双工方式经常使用,真实的情况是RS485、RS422、RS232都是可以实现全双工的。在实际使用过程中我们一直是把RS485设计成半双工使用。其实RS485类似RS422,只不过在个别参数上比RS422更加灵活,也就是说RS485可以兼容RS422,但反过来就不一定了。RS485如果接成四线就是全双工,如果把输入和输出并接,并且只接两条线那么就是半双工的了。实际使用半双工的比较多。另外好多芯片内部就把输入和输出并接了。485半双工用法和verilog仿真_第1张图片

MAX485是一种实现RS485半双工工作模式的芯片,而RS485是一种串口通信标准,另外还有可以实现RS485全双工工作模式的芯片。MAX485并不是RS485的全部,可以说大多数人接触RS485时都被 MAX485给蒙骗了。切记:不是理论上RS485可以做到全双工,而是RS485本来就有全双工和半双工2种工作模式,RS485向下完全兼容RS422,两者亦有区别。看了MAX485手册只实现了半双工的功能就认为RS485通信是半双工的,MAX1482可以实现RS485全双工。

`timescale 1ns / 1ps
module RS485_half_duplex(
    input       sys_clk                     ,
    input       sys_rst_n                   ,
    input       PL_to_DSP_EL_UART_RXD       ,
    output      PL_to_DSP_EL_UART_TXD       ,
    input       PL_EL_Driver_RS485_RO       ,
    output      PL_EL_Driver_RS485_DI       ,
    output reg  PL_EL_Driver_RS485_RE_N     ,
    output reg  PL_EL_Driver_RS485_DE_P
    );
parameter   [32:0]  Baudrate_cnt    =   32'd104170    ;//104170//8680

reg     txd_cnt_start_en       ;//使能发送计数器开始计数
reg     RS485_txd_edge_d0      ;
reg     RS485_txd_edge_d1      ;
reg     RS485_txd_edge_d2      ;    
reg     RS485_txd_edge_d3      ;
reg     RS485_TXD_flag         ;

always@(posedge sys_clk or negedge sys_rst_n)
        if(~sys_rst_n)
            begin
                RS485_txd_edge_d0  <= 0     ;
                RS485_txd_edge_d1  <= 0     ;
                RS485_txd_edge_d2  <= 0     ;
                RS485_txd_edge_d3  <= 0     ;
                RS485_TXD_flag     <= 0     ;                
            end
        else
            begin
                RS485_txd_edge_d0  <=  PL_to_DSP_EL_UART_RXD    ;//从串口接受到的数据,即485需要发送的数据
                RS485_txd_edge_d1  <=  RS485_txd_edge_d0        ;
                RS485_txd_edge_d2  <=  RS485_txd_edge_d1        ;
                RS485_txd_edge_d3  <=  RS485_txd_edge_d2        ;
                RS485_TXD_flag     <=  RS485_txd_edge_d1 & (~RS485_txd_edge_d0) & txd_cnt_start_en;//发送标志,脉冲,下降沿且chk_en=1,switch to transmit
            end    
reg     [31:0]  RS485_RXD_cnt   ;
reg             RS485_RXD_flag  ; //switch to receive      
always@(posedge sys_clk or negedge sys_rst_n)
        begin
            if(~sys_rst_n)
                begin//复位默认
                    RS485_RXD_cnt       <= 32'hFFFF_FFFF    ;
                    RS485_RXD_flag      <= 0                ; //switch to receive
                    txd_cnt_start_en    <= 1                ;                       
                end
            else if(RS485_TXD_flag)//开始发送数据
                begin
                    RS485_RXD_cnt       <= 1        ;
                    RS485_RXD_flag      <= 0        ;//switch to receive
                    txd_cnt_start_en    <= 0        ;//检测到下降沿,并开始计数
                end
             else if(RS485_RXD_cnt < Baudrate_cnt)     //88000ns
                begin
                     RS485_RXD_cnt  <= RS485_RXD_cnt + 1    ;
                     RS485_RXD_flag <= 0                    ;//switch to receive
                end
             else if(RS485_RXD_cnt == Baudrate_cnt)     //88000ns(10bit data + 1200ns)
                begin
                     RS485_RXD_cnt  <= RS485_RXD_cnt + 1    ;
                     RS485_RXD_flag <= 1                    ;//switch to receive
                end
             else
                begin   
                    RS485_RXD_flag      <= 0        ;//switch to receive
                    txd_cnt_start_en    <= 1        ;
                end                                      
        end

always@(posedge sys_clk or negedge sys_rst_n)
        begin
               if(~sys_rst_n)//复位时默认接受
                    begin
                        PL_EL_Driver_RS485_RE_N    <= 1'b0;
                        PL_EL_Driver_RS485_DE_P    <= 1'b0;
                    end
               else if(RS485_TXD_flag)  //switch to transmit,脉冲检测到高电平,持续使能发送,直到切换到低电平
                    begin
                         PL_EL_Driver_RS485_RE_N    <= 1'b1;
                         PL_EL_Driver_RS485_DE_P    <= 1'b1;
                    end
               else if(RS485_RXD_flag)   //switch to receive,非发送状态下,脉冲检测到高电平,持续使能接收
                    begin
                        PL_EL_Driver_RS485_RE_N    <= 1'b0;
                        PL_EL_Driver_RS485_DE_P    <= 1'b0;
                    end
        end
     assign    PL_to_DSP_EL_UART_TXD =  PL_EL_Driver_RS485_RO;//485接收到的数据,转发给串口
     assign    PL_EL_Driver_RS485_DI =  RS485_txd_edge_d3;//从串口接受到的数据,即485需要发送的数据
endmodule

 

 

仿真:

`timescale 1ns / 1ps

module tb_RS485_half_duplex(
    );  
//input
reg     sys_clk                     ;
reg     sys_rst_n                   ;
reg     PL_to_DSP_EL_UART_RXD       ;
reg     PL_EL_Driver_RS485_RO       ;
//output
wire    PL_to_DSP_EL_UART_TXD       ;
wire    PL_EL_Driver_RS485_DI       ;
wire    PL_EL_Driver_RS485_RE_N     ;
wire    PL_EL_Driver_RS485_DE_P     ;
   
RS485_half_duplex RS485_half_duplex_inst(
.sys_clk                         (sys_clk                   ),
.sys_rst_n                       (sys_rst_n                 ),
.PL_to_DSP_EL_UART_RXD           (PL_to_DSP_EL_UART_RXD     ),
.PL_to_DSP_EL_UART_TXD           (PL_to_DSP_EL_UART_TXD     ),
.PL_EL_Driver_RS485_RO           (PL_EL_Driver_RS485_RO     ),
.PL_EL_Driver_RS485_DI           (PL_EL_Driver_RS485_DI     ),
.PL_EL_Driver_RS485_RE_N         (PL_EL_Driver_RS485_RE_N   ),
.PL_EL_Driver_RS485_DE_P         (PL_EL_Driver_RS485_DE_P   )
);
//clock
always
    begin
        #5 sys_clk = ~sys_clk;
    end
//reset
initial begin
    sys_clk = 0;
    sys_rst_n = 0;
    PL_to_DSP_EL_UART_RXD = 1'b1;
    
// Wait 100 ns for global reset to finish    
    #96;    
    sys_rst_n=1;
    PL_to_DSP_EL_UART_RXD= 1'b1;
    PL_EL_Driver_RS485_RO= 1'b1;
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;    
    #104170
//data1    
    PL_to_DSP_EL_UART_RXD = 1'b0;//start    
    //1001_0101    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;            
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;//stop                 
    #808320
//data2    
    //00000101    
    PL_EL_Driver_RS485_RO = 1'b0;//start    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b1;    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b0;    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b1;    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b0;    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b0;    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b0;    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b0;    
    #104170    
    PL_EL_Driver_RS485_RO = 1'b0;            
    #104170    
    PL_EL_Driver_RS485_RO = 1'b1;//stop       
//data3          
    #808320    
    //10000100    
    PL_to_DSP_EL_UART_RXD = 1'b0;//start    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b0;    
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;               
    #104170    
    PL_to_DSP_EL_UART_RXD = 1'b1;//stop      
end

endmodule

 

你可能感兴趣的:(485半双工用法和verilog仿真)