1.原理
全双工:在同一时刻可以同时进行数据的接收和数据的发送,两者互不影响
半双工:在同一时刻只能进行数据的接收或者数据的发送,两者不能同时进行
差分信号幅值相同,相位相反,有更强的抗干扰能力。
干扰对差分信号的影响都是相同的,所以差分信号的干扰一相减就没有了
RS485的优点,采用差分信号有更强的抗干扰能力;相比RS232能能进行长距离传输(RS485要用到收发器芯片,收发器的灵敏度是很高的,可以检测到低至200mv的电压,表示传输信号在千米之外都可以恢复,最远的通信距离可以达到1200米左右,速度最快10MB/s,速度和距离是成反比的,速度越小,传输距离越长,长距离的通信可以增加RS485的中继器);缺点就是只支持半双工。
RE是低电平有效,表示数据的收,当接收时,RE=0,DE=0;然后芯片将差分信号转换为单端信号。当RE=1,DE=1时,数据发送,将单端信号转换为差分信号。
485和232使用相同的传输协议
2.代码
以上是控制板的波形图
以上是被控板的时序图
2.1 led_ctrl.v
module led_ctrl(input wire sys_clk ,input wire sys_rst_n ,input wire [3:0] led_out_w ,//流水灯input wire led_out_b ,//呼吸灯input wire [7:0] pi_data ,input wire key_flag_w ,input wire key_flag_b ,output reg [3:0] led ,output wire [7:0] po_data ,output wire po_flag
);reg w_en;
reg b_en;assign po_data={6'b000_000,b_en,w_en};
assign po_flag=key_flag_b||key_flag_w;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)w_en<=1'b0;else if(key_flag_b==1'b1)w_en<=1'b0;else if(key_flag_w==1'b1)w_en<=~w_en;elsew_en<=w_en;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)b_en<=1'b0;else if(key_flag_w==1'b1)b_en<=1'b0;else if(key_flag_b==1'b1)b_en<=~b_en;else b_en<=b_en;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)led<=4'b1111;else if(po_data[0]==1'b1)led<=led_out_w;else if(po_data[1]==1'b1)led<=led_out_b;elseled<=4'b1111;endmodule
2.2 uart_tx.v
闲杂输出的赋值条件不再是bit_flag信号,而是使能信号,rx下降沿延迟work_en一个周期,因为是时序逻辑,而且只延迟一个时钟周期,一个Bit传输有5208个周期。若是想对齐可以把work_en打一拍
module uart_tx
#(parameter UART_BPS='d9600,parameter CLK_FREQ='d50_000_000)(input wire sys_clk ,input wire sys_rst_n ,input wire [7:0] pi_data ,input wire pi_flag ,output reg work_en ,output reg tx
);parameter BAUD_CNT_MAX=CLK_FREQ/UART_BPS;reg [15:0] baud_cnt;
reg bit_flag;
reg [3:0]bit_cnt;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)work_en<=1'b0;else if ((bit_cnt==4'd9)&&(bit_flag==1'b1))work_en<=1'b0;else if(pi_flag==1'b1)work_en<=1'b1;elsework_en<=work_en;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)baud_cnt<=16'd0;else if((baud_cnt==BAUD_CNT_MAX-1'b1)||(work_en==1'b0))baud_cnt<=16'd0;else if(work_en==1'b1)baud_cnt<=baud_cnt+1'b1;elsebaud_cnt<=baud_cnt;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)bit_flag<=1'b0;else if (baud_cnt==BAUD_CNT_MAX-1'b1) //因为只有使能信号为高电平时,使能信号才进行计数,使能信号为低电平,波特计数器为0。所以不适合用计数值为0来作为条件bit_flag<=1'b1;else bit_flag<=1'b0;
always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)bit_cnt<=4'd0;else if((bit_cnt==4'd9)&&(bit_flag==1'b1))bit_cnt<=4'd0;else if(bit_flag==1'b1)bit_cnt<=bit_cnt+1'b1;elsebit_cnt<=bit_cnt;always@(posedge sys_clk or negedge sys_rst_n)if(sys_rst_n==1'b0)tx<=1'b1;else if(work_en==1'b1)case(bit_cnt)4'd0: tx<=1'b0;4'd1: tx<=pi_data[0];4'd2: tx<=pi_data[1];4'd3: tx<=pi_data[2];4'd4: tx<=pi_data[3];4'd5: tx<=pi_data[4];4'd6: tx<=pi_data[5];4'd7: tx<=pi_data[6];4'd8: tx<=pi_data[7];4'd9: tx<=1'b1;default:tx<=1'b1;endcase
endmodule
2.3 rs485.v
module rs485(input wire sys_clk ,input wire sys_rst_n ,input wire key_in_w ,input wire key_in_b ,input wire rx ,output wire tx ,output wire re ,output wire[3:0]led
);parameter KEY_CNT_MAX=20'd999_999;
parameter WATER_LED_CNT_MAX=25'd24_999_999;parameter CNT_1US_MAX = 6'd49 ,CNT_1MS_MAX = 10'd999 ,CNT_1S_MAX = 10'd999 ;parameter UART_BPS=9600,CLK_FREQ=50_000_000;wire w_flag;
wire b_flag;
wire [3:0]w_led;
wire b_led;
wire [7:0]rx_data;
wire [7:0]po_data;
wire po_flag;key_filter
#(.CNT_MAX(KEY_CNT_MAX)
)
key_filter_inst_w
(.sys_clk (sys_clk ) ,.sys_rst_n (sys_rst_n ) ,.key_in (key_in_w ) ,.key_flag (w_flag)
);key_filter
#(.CNT_MAX(KEY_CNT_MAX)
)
key_filter_inst_b
(.sys_clk (sys_clk ) ,.sys_rst_n (sys_rst_n ) ,.key_in (key_in_b ) ,.key_flag (b_flag )
);water_led
#(.CNT_MAX(WATER_LED_CNT_MAX)
)
water_led_inst
(.sys_clk (sys_clk ),.sys_rst_n (sys_rst_n ),.led_out (w_led )
);breath_led#(.CNT_1US_MAX(CNT_1US_MAX ),.CNT_1MS_MAX(CNT_1MS_MAX ),.CNT_1S_MAX (CNT_1S_MAX ))
breath_led_inst
(.sys_clk (sys_clk ) ,.sys_rst_n (sys_rst_n),.led_out (b_led )
);uart_rx
#(.UART_BPS(UART_BPS),.CLK_FREQ( CLK_FREQ )
)
uart_rx_inst
(.sys_clk (sys_clk ) ,.sys_rst_n (sys_rst_n ) ,.rx (rx ) ,.po_data (rx_data ) ,.po_flag ()
);led_ctrl led_ctrl_inst(.sys_clk (sys_clk) ,.sys_rst_n (sys_rst_n),.led_out_w (w_led),.led_out_b (b_led),.pi_data (rx_data) ,.key_flag_w (w_flag),.key_flag_b (b_flag),.led (led) ,.po_data (po_data) ,.po_flag (po_flag)
);uart_tx
#(.UART_BPS(UART_BPS ),.CLK_FREQ(CLK_FREQ ))
uart_tx_inst
(.sys_clk (sys_clk) ,.sys_rst_n (sys_rst_n) ,.pi_data (po_data) ,.pi_flag (po_flag) ,.work_en (re) ,.tx (tx)
);endmodule
2.4 tb_rs485.v
`timescale 1ns/1nsmodule tb_rs485();reg sys_clk;
reg sys_rst_n;
reg key_in_w ;
reg key_in_b ;
reg rx ;
wire tx;
wire re;
wire [3:0]led;initial beginsys_clk=1'b1;sys_rst_n<=1'b0;key_in_b<=1'b1;key_in_w<=1'b1;#20sys_rst_n<=1'b1;//流水灯#2000000 key_in_w<=1'b0; //按下流水灯的按键#20 key_in_w<=1'b1;#20 key_in_w<=1'b0;#20 key_in_w<=1'b1; //模拟前抖动#20 key_in_w<=1'b0; //模拟稳定状态#200 key_in_w<=1'b1; //模拟后抖动#20 key_in_w<=1'b0;#20 key_in_w<=1'b1;#20 key_in_w<=1'b0;#20 key_in_w<=1'b1;//呼吸灯#2000000 key_in_b<=1'b0;#20 key_in_b<=1'b1;#20 key_in_b<=1'b0;#20 key_in_b<=1'b1;#20 key_in_b<=1'b0;#200 key_in_b<=1'b1;#20 key_in_b<=1'b0;#20 key_in_b<=1'b1;#20 key_in_b<=1'b0;#20 key_in_b<=1'b1;//呼吸灯#2000000 key_in_b<=1'b0;#20 key_in_b<=1'b1;#20 key_in_b<=1'b0;#20 key_in_b<=1'b1;#20 key_in_b<=1'b0;#200 key_in_b<=1'b1;#20 key_in_b<=1'b0;#20 key_in_b<=1'b1;#20 key_in_b<=1'b0;#20 key_in_b<=1'b1;//流水灯#2000000 key_in_w<=1'b0;#20 key_in_w<=1'b1;#20 key_in_w<=1'b0;#20 key_in_w<=1'b1;#20 key_in_w<=1'b0;#200 key_in_w<=1'b1;#20 key_in_w<=1'b0;#20 key_in_w<=1'b1;#20 key_in_w<=1'b0;#20 key_in_w<=1'b1;endalways #10 sys_clk=~sys_clk;defparam rs485_inst0.KEY_CNT_MAX=5;
defparam rs485_inst0.WATER_LED_CNT_MAX=4000;
defparam rs485_inst1.WATER_LED_CNT_MAX=4000;
defparam rs485_inst0.CNT_1US_MAX=4;
defparam rs485_inst1.CNT_1US_MAX=4;
defparam rs485_inst0.CNT_1MS_MAX=9;
defparam rs485_inst1.CNT_1MS_MAX=9;
defparam rs485_inst0.CNT_1S_MAX=9;
defparam rs485_inst1.CNT_1S_MAX=9;
defparam rs485_inst0.UART_BPS=1000_000;
defparam rs485_inst1.UART_BPS=1000_000;//越大越快//控制板不用rx信号
rs485 rs485_inst0(.sys_clk (sys_clk) ,.sys_rst_n (sys_rst_n),.key_in_w (key_in_w ),.key_in_b (key_in_b ),.rx (),//对于控制板来说,rx是无效的,因为我们只需要两路按键.tx (tx),.re (re),.led ()//控制板的led灯一直是熄灭状态不需要引出来
);//被控板
rs485 rs485_inst1(.sys_clk (sys_clk) ,.sys_rst_n (sys_rst_n),.key_in_w ( ),//对于被控板来说,按键信号是无效的.key_in_b ( ),.rx (tx),.tx (),//tx和re没有用到不需要引出.re (),.led (led)
);endmodule
看控制模块
看被控模块