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如果接成四线就是全双工,如果把输入和输出并接,并且只接两条线那么就是半双工的了。实际使用半双工的比较多。另外好多芯片内部就把输入和输出并接了。
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