串口收发与存取双口ram简易应用
1 原理图
2 Verilog 代码
3 Modelsim仿真
4. FPGA板级验证
1. 原理图
2. Verilog 代码
//----top---------------------------------------
module uart_dual_ram(
input clk,
input rst_n,
input rs232_rx,
input key_in,
output rs232_tx
);
wire [7:0] rx_data;
wire [7:0] tx_data;
wire tx_done;
wire rx_done;
wire key_flag;
wire key_state;
wire [7:0] rdaddress;
wire [7:0] wraddress;
wire wren;
wire send_en;
fsm_key_filter uut_key_filter(
.clk(clk),
.rst_n(rst_n),
.key(key_in),
.key_flag(key_flag),
.key_state(key_state)
);
uart_rx_r0 uut_uart_rx(
.clk(clk),
.rst_n(rst_n),
.rs232_rx(rs232_rx),
.baud_set(3'd0),
.rx_done(rx_done),
.data_byte(rx_data)
);
uart_tx_r0 uut_uart_tx(
.clk(clk),
.rst_n(rst_n),
.send_en(send_en),
.baud_set(3'd0),
.data_byte(tx_data),
.rs232_tx(rs232_tx),
.tx_done(tx_done),
.uart_state()
);
ip ram_dual(
.clock(clk),
.data(rx_data),
.rdaddress(rdaddress),
.wraddress(wraddress),
.wren(wren),
.q(tx_data)
);
uart_ctrl uut_controller(
.clk(clk),
.rst_n(rst_n),
.key_flag(key_flag),
.key_state(key_state),
.rx_done(rx_done),
.tx_done(tx_done),
.rdaddress(rdaddress),
.wraddress(wraddress),
.wren(wren),
.send_en(send_en)
);
endmodule
//--------------------------------------------------------------
//----controller------------------------------------------------
module uart_ctrl(
input clk,
input rst_n,
input key_flag,
input key_state,
input rx_done,
input tx_done,
output reg [7:0] rdaddress,
output reg [7:0] wraddress,
output wren,
output reg send_en
);
reg read_send; //
reg reg1_done;
reg reg2_done;
assign wren = rx_done;
//----wraddress-------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)
wraddress <= 8'd0;
else if(rx_done)
wraddress <= wraddress +8'd1;
else
wraddress <= wraddress;
//----rdaddress-------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)
read_send <= 1'd0;
else if(key_flag && !key_state)
read_send <= ~read_send;
else
read_send <= read_send;
always@(posedge clk or negedge rst_n)
if(!rst_n)
rdaddress <= 8'd0;
else if(read_send && tx_done)
rdaddress <= rdaddress +8'd1;
else
rdaddress <= rdaddress;
//----send_en---------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
reg1_done <= 1'd0;
reg2_done <= 1'd0;
end
else begin
reg1_done <= (read_send && tx_done);
reg2_done <= reg1_done;
end
always@(posedge clk or negedge rst_n)
if(!rst_n)
send_en <= 1'd0;
else if(key_flag && !key_state)
send_en <= 1'd1;
else if(reg2_done)
send_en <= 1'd1;
else
send_en <= 1'd0;
endmodule
//---------------------------------------------------------------------
//----uart_rx----------------------------------------------------------
//请看上一节文章
//---------------------------------------------------------------------
//----uart_tx----------------------------------------------------------
//请看上一节文章
//---------------------------------------------------------------------
//----key_filter-------------------------------------------------------
module fsm_key_filter#(
parameter IDLE = 4'b0001,
parameter FILTER1 = 4'b0010,
parameter DOWN = 4'b0100,
parameter FILTER2 = 4'b1000
)
(
input clk, //50MHz 20us
input rst_n,
input key,
output key_flag,
output reg key_state
);
reg cnt_en;
reg cnt_full;
reg [19:0] cnt1;
//reg [19:0] cnt2;
reg [3:0] state;
reg key_syn1;
reg key_syn2;
reg key_reg1;
reg key_reg2;
wire pos_edge;
wire neg_edge;
always@(posedge clk or negedge rst_n)
if(!rst_n)begin
state <= IDLE;
cnt_en <= 1'b0;
end else
begin
case(state)
IDLE:
begin
if(neg_edge)begin
state <= FILTER1;
cnt_en <= 1'b1;
end else
begin
state <= IDLE;
cnt_en <= 1'b0;
end
end
FILTER1:
begin
if(cnt_full)//20ms
begin
state <= DOWN;
cnt_en <= 1'b0;
end
else if(pos_edge)
begin
state <= IDLE;
cnt_en <= 1'b0;
end else
begin
state <= FILTER1;
cnt_en <= cnt_en;
end
end
DOWN:
begin
if(pos_edge)begin
cnt_en <= 1'b1;
state <= FILTER2;
end else
begin
cnt_en <= 1'b0;
state <= DOWN;
end
end
FILTER2:
begin
if(cnt_full)
state <= IDLE;
else if(neg_edge)begin
cnt_en <= 1'b0;
state <= DOWN;
end
else
state <= FILTER2;
end
default: begin
state <= IDLE;
cnt_en <= 1'b0;
end
endcase
end
//----cnt--------------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt1 <= 20'd0;
else if(cnt_en)
cnt1 <= cnt1 + 20'd1;
else
cnt1 <= 20'd0;
end
always@(posedge clk or negedge rst_n)begin
if(!rst_n)
cnt_full <= 1'b0;
else if(cnt1 == 20'd999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
end
//----asyn_key-->syn---------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_syn1 <= 1'b0;
key_syn2 <= 1'b0;
end else
begin
key_syn1 <= key;
key_syn2 <= key_syn1;
end
end
//----key edge detect--------------------------------
always@(posedge clk or negedge rst_n)begin
if(!rst_n)begin
key_reg1 <= 1'b0;
key_reg2 <= 1'b0;
end else
begin
key_reg1 <= key_syn2;
key_reg2 <= key_reg1;
end
end
assign neg_edge = (!key_reg1) & key_reg2;
assign pos_edge = key_reg1 & (!key_reg2);
//----key_flag---------------------------------------
assign key_flag = (cnt1 == 20'd999_999)? 1'b1:1'b0;
//----key_state--------------------------------------
always@(posedge clk or negedge rst_n)
if(!rst_n)
key_state <= 1;
else if(cnt_full)
key_state <= ~key_state;
else
key_state <= key_state;
endmodule
3. Modelsim仿真
4. FPGA板级验证
----学习内容来自小梅哥FPGA视频
【注】:个人学习笔记,如有错误,望不吝赐教,这厢有礼了~~~