实验目的: 以模块化设计为基础利用已编写的串口收发模块、按键模块以及RAM的IP模块来设计一个简易应用系统。通过串口发送数据到FPGA中,FPGA接收到数据后将数据存储在双口RAM的一段连续空间中,当需要时,按下按键0,则FPGA将RAM中存储的数据通过串口发送出去。
1.串口接收模块:uart_tybe_rx.v
2.按键消抖模块:key_fliter.v
3.RAM模块:dpram.v
4.串口发送模块:uart_tybe_tx.v
5.控制模块:ctrl.v
module ctrl(
Clk ,
Rst_n ,
key_flag ,
key_state ,
rx_done ,
tx_done ,
wren ,
rdaddress ,
wraddress ,
send_en
);
input Clk ;
input Rst_n ;
input key_flag ;
input key_state ;
input rx_done ;
input tx_done ;
output wren ;
output [7:0] rdaddress ;
output [7:0] wraddress ;
output send_en ;
reg [7:0] rdaddress ;
reg [7:0] wraddress ;
//控制ram的写地址
assign wren = rx_done;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
wraddress <= 8'd0;
else if(wren)
wraddress <= wraddress + 1'b1;
else
wraddress <= wraddress;
//通过按键控制读操作
reg do_send;
wire tx_done;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
do_send <= 1'd0;
else if(key_flag && !key_state)
do_send <= ~do_send;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
rdaddress <= 8'd0;
else if(do_send && tx_done)
rdaddress <= rdaddress + 8'd1;
else
rdaddress <= rdaddress;
//将send_en信号延迟两拍输出
reg r0_send_done,r1_send_done;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)begin
r0_send_done <= 1'b0;
r1_send_done <= 1'b0;
end
else begin
r0_send_done <= (do_send && tx_done);
r1_send_done <= r0_send_done;
end
//send_en
reg send_en;
always@(posedge Clk or negedge Rst_n)
if(!Rst_n)
send_en <= 1'b0;
else if(key_flag && !key_state)
send_en <= 1'b1;
else if(r1_send_done)
send_en <= 1'b1;
else
send_en <= 1'b0;
endmodule
module uart_dpram(
Clk ,
Rst_n ,
key_in ,
rs232_rx ,
rs232_tx
);
input Clk ;
input Rst_n ;
input key_in ;
input rs232_rx ;
output rs232_tx ;
wire key_in ;
wire key_flag ;
wire key_state ;
wire rx_done ;
wire wren ;
wire [7:0] rdaddress ;
wire [7:0] wraddress ;
wire send_en ;
wire baud_set = 3'b0;//9600波特率
wire [7:0] data_byte_rx ;
wire [7:0] data_byte_tx ;
wire tx_state;
wire tx_done;
//控制模块
ctrl ctrl_inst(
.Clk (Clk ),
.Rst_n (Rst_n ),
.key_flag (key_flag ),
.key_state (key_state ),
.rx_done (rx_done ),
.tx_done (tx_done ),
.wren (wren ),
.rdaddress (rdaddress ),
.wraddress (wraddress ),
.send_en (send_en )
);
//按键消抖模块
key_filter key_filter_inst(
.Clk (Clk ),
.Rst_n (Rst_n ),
.key_in (key_in ),
.key_flag (key_flag ),
.key_state (key_state )
);
//存储模块
dpram dpram_inst(
.clock (Clk ),
.data (data_byte_rx ),
.rdaddress (rdaddress ),
.wraddress (wraddress ),
.wren (wren ),
.q (data_byte_tx )
);
//发送模块
uart_byte_tx uart_byte_tx_inst(
.Clk (Clk ),//50M时钟
.Rst_n (Rst_n ),//复位信号
.send_en (send_en ),//发送使能信号
.baud_set (baud_set ),//波特率选项
.data_byte (data_byte_tx ),//要发送的单字节数据
.rs232_tx (rs232_tx ),//要发送出去的单比特数据
.tx_done (tx_done ),//发送接收标志
.tx_state (tx_state ) //发送的状态
);
//接收模块
uart_byte_rx uart_byte_rx_inst(
.Clk (Clk ),
.Rst_n (Rst_n ),
.rs232_rx (rs232_rx ),
.baud_set (baud_set ),
.data_byte (data_byte_rx ),
.rx_done (rx_done )
);
endmodule
`timescale 1ns/1ns
`define clock_period 20
module uart_dpram_tb;
reg Clk ;
reg Rst_n ;
wire key_in ;
wire rs232_rx ;
wire rs232_tx ;
reg press ;
reg [7:0] data_byte ;
reg [2:0] baud_set ;
reg send_en ;
wire tx_done ;
wire tx_state ;
uart_dpram uart_dpram_inst(
.Clk (Clk ),
.Rst_n (Rst_n ),
.key_in (key_in ),
.rs232_rx (rs232_rx ),
.rs232_tx (rs232_tx )
);
uart_byte_tx uart_byte_tx_inst(
.Clk (Clk ),//50M时钟
.Rst_n (Rst_n ),//复位信号
.send_en (send_en ),//发送使能信号
.baud_set (baud_set ),//波特率选项
.data_byte (data_byte ),//要发送的单字节数据
.rs232_tx (rs232_rx ),//要发送出去的单比特数据
.tx_done (tx_done ),//发送接收标志
.tx_state (tx_state ) //发送的状态
);
key_model key_model(
.press(press),
.key(key_in)
);
//产生时钟
initial Clk = 1'b1;
always #(`clock_period/2) Clk = ~Clk;
//产生激励信号
initial begin
Rst_n = 1'b0;
press = 0;
data_byte = 8'b0;
send_en = 1'b0;
baud_set = 3'd0;
#(`clock_period*20 + 1);
Rst_n = 1'b1;
#(`clock_period*50);
data_byte = 8'haa;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge tx_done);
#(`clock_period*5000);
data_byte = 8'h55;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge tx_done);
#(`clock_period*5000);
data_byte = 8'hdc;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge tx_done);
#(`clock_period*5000);
data_byte = 8'hcd;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge tx_done);
#(`clock_period*5000);
press = 1;
#(`clock_period *3)
press = 0;
$stop;
end
endmodule