/*************RS485 半双工测试************* --使用到了UART 发送和接收驱动 --通过FIFO缓存数据,并且检测到接收总线一段时间没有时间达到,进入发送模式,发送之前接收到的数据。 *********************************************************************/ `timescale 1ns / 1ns //仿真时间刻度/精度
module rs485_top( input I_sysclk,//系统时钟输入 output O_rs485_de, // 485 de控制,控制输入 输出方向,0 输入 1输出 input I_rs485_rx, // 485 RX输入总线 output O_rs485_tx // 485 TX输出总线 );
localparam SYSCLKHZ = 50_000_000;
wire reset_n; //内部上电延迟复位 wire rs485_rx; //内部RX 接收 wire rs485_fifo_empty; //FIFO空 wire rs485_fifo_rd_en; //FIFO 读使能 wire rs485_rvalid; //读数据有效 wire [7:0] rs485_rdata; //串口读数据(接收) wire [7:0] rs485_wdata; //串口写数据(发送) wire rs485_wbusy; //写忙 reg rs485_de; //485芯片的DE控制0 输入 1输出 reg rs485_wreq = 1'b0; //串口写请求 wire rs485_tx_start; //发送启动 reg rs485_tx_start_r = 1'b0; //发送启动寄存 reg [17:0] T_dcnt; //延迟计数器 reg [11:0] rstn_cnt = 12'd0; //复位计数器
//当rs485_de=0,设置rs485内部逻辑准备接收总线数据 assign rs485_rx = (rs485_de == 1'b0) ? I_rs485_rx : 1'b1; //当FIFO中有数据,并且串口发送不忙,启动发送 assign rs485_tx_start = rs485_de&&(rs485_wbusy == 1'b0)&&(!rs485_fifo_empty); //读FIFO使能,用rs485_tx_start的上升沿触发读FIFO assign rs485_fifo_rd_en = (rs485_tx_start_r == 1'b0 & rs485_tx_start == 1'b1);//read fifo enable //当rs485_de=0,设置rs485内部逻辑准备接收总线数据,否则,可以发送数据 assign O_rs485_de = rs485_de;
assign reset_n = rstn_cnt[11];//上电延迟复位
//复位计数器 always @(posedge I_sysclk)begin if(rstn_cnt[11] == 1'b0) rstn_cnt <= rstn_cnt + 1'b1; else rstn_cnt <= rstn_cnt; End
//T_dcnt用于一段时间内,判断接收总线是否空闲 always @(posedge I_sysclk or negedge reset_n)begin if(reset_n == 1'b0) T_dcnt <= 17'd0; else if(rs485_rx && (!rs485_fifo_empty))//如果RX总线是高电平,并且FIFO非空(有数据) T_dcnt <= (T_dcnt[17] == 1'b1) ? T_dcnt : T_dcnt + 1'b1; //计数器累加 else T_dcnt <= 0; //否则重置归零 End
//当rs485_de=0,设置rs485内部逻辑准备接收总线数据,否则,可以发送数据 always @(posedge I_sysclk )begin if(reset_n ==1'b0)//if(rs485_de | reset_n ==1'b0) rs485_de <= 1'b0;//重置rs485_de,切换到接收 else if((T_dcnt[17]==1'b1)|rs485_wreq|rs485_wbusy)//当T_dcnt延迟计数器到达计数值,或者串口发送控制器正在发送(rs485_wreq,rs485_wbusy有效) rs485_de <= 1'b1;//设置rs485_de else rs485_de <= 1'b0;//设置rs485_de End
//打拍寄存一次 always @(posedge I_sysclk) rs485_tx_start_r <= rs485_tx_start;
//rs485_wreq,延迟于rs485_fifo_rd_en,1个时钟,用于数据同步 always @(posedge I_sysclk) rs485_wreq <= rs485_fifo_rd_en;
//例化FIFO IP,FIFO设置标准模式,用户缓存接收到的帧 fifo_generator_0 inst_fifo ( .wr_clk(I_sysclk), //写时钟输入 .wr_rst(reset_n == 1'b0), //写复位 .rd_clk(I_sysclk), //读时钟输入 .rd_rst(reset_n == 1'b0), //读复位 .din(rs485_rdata), //RX接收到的数据 .wr_en(rs485_rvalid&(rs485_de==1'b0)), // 写FIFO 使能,当rs485_rvalid有效,写入数据 .rd_en(rs485_fifo_rd_en), //FIFO读使能 .dout(rs485_wdata), //写数据 .empty(rs485_fifo_empty) //FIFO 空 );
//例化串口发送模块 uiuart_tx# ( .BAUD_DIV(SYSCLKHZ/115200 -1) //设置波特率 ) uiuart_tx_u ( .I_clk(I_sysclk), //系统时钟 .I_uart_rstn(reset_n), //系统复位 .I_uart_wreq(rs485_wreq), //串口发送驱动器发送请求 .I_uart_wdata(rs485_wdata), //串口发送,数据 .O_uart_wbusy(rs485_wbusy), //串口发送总线忙 .O_uart_tx(O_rs485_tx) //串口发送总线 );
//例化串口接收模块 uiuart_rx# ( .BAUD_DIV(SYSCLKHZ/115200 -1) //设置波特率 ) uiuart_rx_u ( .I_clk(I_sysclk), //系统时钟 .I_uart_rstn(reset_n), //系统复位 .I_uart_rx(rs485_rx), //串口接收总线 .O_uart_rdata(rs485_rdata), //串口接收数据 .O_uart_rvalid(rs485_rvalid)//串口接收数据有效 );
endmodule |