??歡迎來(lái)到FPGA專(zhuān)欄~搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng)
- ☆* o(≧▽≦)o *☆嗨~我是小夏與酒??
- ?博客主頁(yè):小夏與酒的博客
- ??該系列文章專(zhuān)欄:FPGA學(xué)習(xí)之旅
- 文章作者技術(shù)和水平有限,如果文中出現(xiàn)錯(cuò)誤,希望大家能指正??
- ?? 歡迎大家關(guān)注! ??
![]()
一、效果演示
??輸入數(shù)據(jù):
??輸出數(shù)據(jù):
??串口助手分析:
按下第一次按鍵,F(xiàn)PGA開(kāi)始連續(xù)發(fā)送數(shù)據(jù),按下第二次按鍵,F(xiàn)PGA停止發(fā)送數(shù)據(jù)。
二、基礎(chǔ)知識(shí)
2.1 實(shí)現(xiàn)目標(biāo)
使用按鍵消抖、串口發(fā)送與接收模塊,以及雙端口RAM模塊實(shí)現(xiàn)串口發(fā)送數(shù)據(jù)到FPGA中,F(xiàn)PGA接收到數(shù)據(jù)后將數(shù)據(jù)存儲(chǔ)在雙口RAM中,當(dāng)按下按鍵時(shí)FPGA將RAM中存儲(chǔ)的數(shù)據(jù)再通過(guò)串口發(fā)送出去,再次按下按鍵后,F(xiàn)PGA停止發(fā)送數(shù)據(jù)。
2.2 所需基礎(chǔ)模塊
相關(guān)模塊學(xué)習(xí)文章:
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#10】按鍵消抖模塊設(shè)計(jì)與驗(yàn)證(一段式狀態(tài)機(jī)實(shí)現(xiàn));
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#13】串口發(fā)送模塊設(shè)計(jì)與驗(yàn)證;
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#14】串口發(fā)送字符串;
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#15】串口接收模塊設(shè)計(jì)與驗(yàn)證(工業(yè)環(huán)境);
??【FPGA零基礎(chǔ)學(xué)習(xí)之旅#16】嵌入式塊RAM-雙口ram的使用。
三、系統(tǒng)分析
參考小梅哥FPGA設(shè)計(jì)的系統(tǒng)框圖:
通過(guò)串口發(fā)送數(shù)據(jù)到FPGA中,F(xiàn)PGA接收到數(shù)據(jù)后將數(shù)據(jù)存儲(chǔ)在雙口RAM的一段連續(xù)空間中。當(dāng)需要時(shí),按下按鍵S0,則FPGA將RAM中存儲(chǔ)的數(shù)據(jù)通過(guò)串口發(fā)送出去;再次按下S0,則停止數(shù)據(jù)發(fā)送。
進(jìn)行功能劃分:串口接收模塊、按鍵消抖模塊、RAM模塊、串口發(fā)送模塊以及控制模塊。
在此給出所需使用的模塊代碼:
按鍵消抖模塊:
//
//模塊:按鍵消抖模塊
//key_state:輸出消抖之后按鍵的狀態(tài)
//key_flag:按鍵消抖結(jié)束時(shí)產(chǎn)生一個(gè)時(shí)鐘周期的高電平脈沖
//
module KeyFilter(
input Clk,
input Rst_n,
input key_in,
output reg key_flag,
output reg key_state
);
//按鍵的四個(gè)狀態(tài)
localparam
IDLE = 4'b0001,
FILTER1 = 4'b0010,
DOWN = 4'b0100,
FILTER2 = 4'b1000;
//狀態(tài)寄存器
reg [3:0] curr_st;
//邊沿檢測(cè)輸出上升沿或下降沿
wire pedge;
wire nedge;
//計(jì)數(shù)寄存器
reg [19:0]cnt;
//使能計(jì)數(shù)寄存器
reg en_cnt;
//計(jì)數(shù)滿標(biāo)志信號(hào)
reg cnt_full;//計(jì)數(shù)滿寄存器
//------<邊沿檢測(cè)電路的實(shí)現(xiàn)>------
//邊沿檢測(cè)電路寄存器
reg key_tmp0;
reg key_tmp1;
//邊沿檢測(cè)
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
key_tmp0 <= 1'b0;
key_tmp1 <= 1'b0;
end
else begin
key_tmp0 <= key_in;
key_tmp1 <= key_tmp0;
end
end
assign nedge = (!key_tmp0) & (key_tmp1);
assign pedge = (key_tmp0) & (!key_tmp1);
//------<狀態(tài)機(jī)主程序>------
//狀態(tài)機(jī)主程序
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
curr_st <= IDLE;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
else begin
case(curr_st)
IDLE:begin
key_flag <= 1'b0;
if(nedge)begin
curr_st <= FILTER1;
en_cnt <= 1'b1;
end
else
curr_st <= IDLE;
end
FILTER1:begin
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b0;
curr_st <= DOWN;
en_cnt <= 1'b0;
end
else if(pedge)begin
curr_st <= IDLE;
en_cnt <= 1'b0;
end
else
curr_st <= FILTER1;
end
DOWN:begin
key_flag <= 1'b0;
if(pedge)begin
curr_st <= FILTER2;
en_cnt <= 1'b1;
end
else
curr_st <= DOWN;
end
FILTER2:begin
if(cnt_full)begin
key_flag <= 1'b1;
key_state <= 1'b1;
curr_st <= IDLE;
en_cnt <= 1'b0;
end
else if(nedge)begin
curr_st <= DOWN;
en_cnt <= 1'b0;
end
else
curr_st <= FILTER2;
end
default:begin
curr_st <= IDLE;
en_cnt <= 1'b0;
key_flag <= 1'b0;
key_state <= 1'b1;
end
endcase
end
end
//------<20ms計(jì)數(shù)器>------
//20ms計(jì)數(shù)器
//Clk 50_000_000Hz
//一個(gè)時(shí)鐘周期為20ns
//需要計(jì)數(shù)20_000_000 / 20 = 1_000_000次
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
cnt <= 20'd0;
else if(en_cnt)
cnt <= cnt + 1'b1;
else
cnt <= 20'd0;
end
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
cnt_full <= 1'b0;
else if(cnt == 999_999)
cnt_full <= 1'b1;
else
cnt_full <= 1'b0;
end
endmodule
串口接收模塊:
//
//模塊名稱(chēng):串口接收模塊(工業(yè)環(huán)境)
//
module uart_byte_rx(
input Clk,//50M
input Rst_n,
input [2:0] baud_set,
input data_rx,
output reg [7:0] data_byte,
output reg Rx_Done
);
reg s0_Rx,s1_Rx;//同步寄存器
reg tmp0_Rx,tmp1_Rx;//數(shù)據(jù)寄存器
reg [15:0]bps_DR;//分頻計(jì)數(shù)器計(jì)數(shù)最大值
reg [15:0]div_cnt;//分頻計(jì)數(shù)器
reg bps_clk;//波特率時(shí)鐘
reg [7:0]bps_cnt;
reg uart_state;
reg [2:0] r_data_byte [7:0];
reg [2:0]START_BIT;
reg [2:0]STOP_BIT;
wire nedge;
//--------<同步寄存器處理>--------
//用于消除亞穩(wěn)態(tài)
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
s0_Rx <= 1'b0;
s1_Rx <= 1'b0;
end
else begin
s0_Rx <= data_rx;
s1_Rx <= s0_Rx;
end
end
//--------<數(shù)據(jù)寄存器處理>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
tmp0_Rx <= 1'b0;
tmp1_Rx <= 1'b0;
end
else begin
tmp0_Rx <= s1_Rx;
tmp1_Rx <= tmp0_Rx;
end
end
//--------<下降沿檢測(cè)>--------
assign nedge = !tmp0_Rx & tmp1_Rx;
//--------<div_cnt模塊>--------
//得到不同計(jì)數(shù)周期的計(jì)數(shù)器
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
div_cnt <= 16'd0;
else if(uart_state)begin
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
end
//--------<bps_clk信號(hào)的產(chǎn)生>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
end
//--------<bps_clk計(jì)數(shù)模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
bps_cnt <= 8'd0;
else if(bps_cnt == 8'd159 || (bps_cnt == 8'd12 && (START_BIT > 2)))
bps_cnt <= 8'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
end
//--------<Rx_Done模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Rx_Done <= 1'b0;
else if(bps_cnt == 8'd159)
Rx_Done <= 1'b1;
else
Rx_Done <= 1'b0;
end
//--------<波特率查找表>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
bps_DR <= 16'd324;
else begin
case(baud_set)
0:bps_DR <= 16'd324;
1:bps_DR <= 16'd162;
2:bps_DR <= 16'd80;
3:bps_DR <= 16'd53;
4:bps_DR <= 16'd26;
default:bps_DR <= 16'd324;
endcase
end
end
//--------<采樣數(shù)據(jù)接收模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
START_BIT <= 3'd0;
r_data_byte[0] <= 3'd0;
r_data_byte[1] <= 3'd0;
r_data_byte[2] <= 3'd0;
r_data_byte[3] <= 3'd0;
r_data_byte[4] <= 3'd0;
r_data_byte[5] <= 3'd0;
r_data_byte[6] <= 3'd0;
r_data_byte[7] <= 3'd0;
STOP_BIT <= 3'd0;
end
else if(bps_clk)begin
case(bps_cnt)
0:begin
START_BIT <= 3'd0;
r_data_byte[0] <= 3'd0;
r_data_byte[1] <= 3'd0;
r_data_byte[2] <= 3'd0;
r_data_byte[3] <= 3'd0;
r_data_byte[4] <= 3'd0;
r_data_byte[5] <= 3'd0;
r_data_byte[6] <= 3'd0;
r_data_byte[7] <= 3'd0;
STOP_BIT <= 3'd0;
end
6,7,8,9,10,11:START_BIT <= START_BIT + s1_Rx;
22,23,24,25,26,27:r_data_byte[0] <= r_data_byte[0] + s1_Rx;
38,39,40,41,42,43:r_data_byte[1] <= r_data_byte[1] + s1_Rx;
54,55,56,57,58,59:r_data_byte[2] <= r_data_byte[2] + s1_Rx;
70,71,72,73,74,75:r_data_byte[3] <= r_data_byte[3] + s1_Rx;
86,87,88,89,90,91:r_data_byte[4] <= r_data_byte[4] + s1_Rx;
102,103,104,105,106,107:r_data_byte[5] <= r_data_byte[5] + s1_Rx;
118,119,120,121,122,123:r_data_byte[6] <= r_data_byte[6] + s1_Rx;
134,135,136,137,138,139:r_data_byte[7] <= r_data_byte[7] + s1_Rx;
150,151,152,153,154,155:STOP_BIT <= STOP_BIT + s1_Rx;
default:begin
START_BIT <= START_BIT;
r_data_byte[0] <= r_data_byte[0];
r_data_byte[1] <= r_data_byte[1];
r_data_byte[2] <= r_data_byte[2];
r_data_byte[3] <= r_data_byte[3];
r_data_byte[4] <= r_data_byte[4];
r_data_byte[5] <= r_data_byte[5];
r_data_byte[6] <= r_data_byte[6];
r_data_byte[7] <= r_data_byte[7];
STOP_BIT <= STOP_BIT;
end
endcase
end
end
//--------<數(shù)據(jù)狀態(tài)判定模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
data_byte <= 8'd0;
else if(bps_cnt == 8'd159)begin
data_byte[0] <= r_data_byte[0][2];
data_byte[1] <= r_data_byte[1][2];
data_byte[2] <= r_data_byte[2][2];
data_byte[3] <= r_data_byte[3][2];
data_byte[4] <= r_data_byte[4][2];
data_byte[5] <= r_data_byte[5][2];
data_byte[6] <= r_data_byte[6][2];
data_byte[7] <= r_data_byte[7][2];
end
else
;
end
//--------<uart_state模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
uart_state <= 1'b0;
else if(nedge)
uart_state <= 1'b1;
else if(Rx_Done || (bps_cnt == 8'd12 && (START_BIT > 2)))
uart_state <= 1'b0;
else
uart_state <= uart_state;
end
endmodule
串口發(fā)送模塊:
//
//模塊名稱(chēng):串口發(fā)送模塊
//
module uart_byte_tx(
input Clk,
input Rst_n,
input [7:0] data_byte,
input send_en,
input [2:0] baud_set,
output reg uart_tx,
output reg Tx_Done,
output reg uart_state
);
reg bps_clk;//波特率時(shí)鐘
reg [15:0]div_cnt;//分頻計(jì)數(shù)器
reg [15:0]bps_DR;//分頻計(jì)數(shù)最大值
reg [3:0]bps_cnt;//波特率計(jì)數(shù)時(shí)鐘
//定義數(shù)據(jù)的起始位和停止位
localparam START_BIT = 1'b0;
localparam STOP_BIT = 1'b1;
reg [7:0]r_data_byte;//數(shù)據(jù)寄存器
//--------<uart狀態(tài)模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
uart_state <= 1'b0;
else if(send_en)
uart_state <= 1'b1;
else if(bps_cnt == 4'd11)//bps_cnt計(jì)數(shù)達(dá)到11次,即發(fā)送結(jié)束
uart_state <= 1'b0;
else
uart_state <= uart_state;
end
//--------<使能分頻計(jì)數(shù)模塊>-------
// assign en_cnt = uart_state;
//--------<寄存待發(fā)送的數(shù)據(jù),使數(shù)據(jù)保持穩(wěn)定>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
r_data_byte <= 8'd0;
else if(send_en)
r_data_byte <= data_byte;
else
r_data_byte <= r_data_byte;
end
//--------<波特率查找表>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
bps_DR <= 16'd5207;
else begin
case(baud_set)
0:bps_DR <= 16'd5207;
1:bps_DR <= 16'd2603;
2:bps_DR <= 16'd1301;
3:bps_DR <= 16'd867;
4:bps_DR <= 16'd433;
default:bps_DR <= 16'd5207;
endcase
end
end
//--------<Div_Cnt模塊>--------
//得到不同計(jì)數(shù)周期的計(jì)數(shù)器
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
div_cnt <= 16'd0;
else if(uart_state)begin // assign en_cnt = uart_state;
if(div_cnt == bps_DR)
div_cnt <= 16'd0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 16'd0;
end
//--------<bps_clk信號(hào)的產(chǎn)生>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
bps_clk <= 1'b0;
else if(div_cnt == 16'd1)
bps_clk <= 1'b1;
else
bps_clk <= 1'b0;
end
//--------<bps_cnt計(jì)數(shù)模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
bps_cnt <= 4'd0;
else if(bps_cnt == 4'd11)//clr信號(hào)
bps_cnt <= 4'd0;
else if(bps_clk)
bps_cnt <= bps_cnt + 1'b1;
else
bps_cnt <= bps_cnt;
end
//--------<Tx_Done模塊>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
Tx_Done <= 1'b0;
else if(bps_cnt == 4'd11)
Tx_Done <= 1'b1;
else
Tx_Done <= 1'b0;
end
//--------<數(shù)據(jù)位輸出模塊-10選1多路器>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
uart_tx <= 1'b1;
else begin
case(bps_cnt)
0:uart_tx <= 1'b1;
1:uart_tx <= START_BIT;
2:uart_tx <= r_data_byte[0];
3:uart_tx <= r_data_byte[1];
4:uart_tx <= r_data_byte[2];
5:uart_tx <= r_data_byte[3];
6:uart_tx <= r_data_byte[4];
7:uart_tx <= r_data_byte[5];
8:uart_tx <= r_data_byte[6];
9:uart_tx <= r_data_byte[7];
10:uart_tx <= STOP_BIT;
default:uart_tx <= 1'b1;
endcase
end
end
endmodule
四、代碼編寫(xiě)
上述已給出按鍵消抖模塊和串口收發(fā)模塊,在本文中主要編寫(xiě)控制模塊和頂層模塊。
4.1 控制模塊
為了實(shí)現(xiàn)FPGA將接收到的數(shù)據(jù)存儲(chǔ)到雙口RAM的一段連續(xù)空間中,就需要設(shè)計(jì)一個(gè)可以實(shí)現(xiàn)寫(xiě)地址數(shù)據(jù)自加的控制邏輯,且其控制信號(hào)為串口接收模塊輸出的Rx_Done信號(hào)。每來(lái)一個(gè)Rx_Done就表明接收成功一字節(jié)數(shù),地址數(shù)進(jìn)行加一:
assign wren = Rx_Done;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
wraddress <= 8'd0;
else if(Rx_Done)
wraddress <= wraddress + 1'b1;
else
wraddress <= wraddress;
end
當(dāng)按下按鍵S0,F(xiàn)PGA將RAM中存儲(chǔ)的數(shù)據(jù)通過(guò)串口發(fā)送出去。需要實(shí)現(xiàn)按鍵按下即啟動(dòng)連續(xù)讀操作,再次按下可暫停讀操作:
reg do_send;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
do_send <= 1'd0;
else if(Key_flag && !Key_state)
do_send <= ~do_send;
end
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
rdaddress <= 8'd0;
else if(do_send && Tx_Done)
rdaddress <= rdaddress + 8'd1;
else
rdaddress <= rdaddress;
end
在仿真雙端口RAM時(shí)發(fā)現(xiàn)其輸出會(huì)延遲兩個(gè)系統(tǒng)時(shí)鐘周期。這是為了保證數(shù)據(jù)變化穩(wěn)定之后才進(jìn)行數(shù)據(jù)輸出,所以在此將驅(qū)動(dòng)Send_en的信號(hào)接兩級(jí)寄存器進(jìn)行延遲兩拍。當(dāng)按鍵按下后啟動(dòng)一次發(fā)送,然后判斷上一字節(jié)是否發(fā)送結(jié)束,是則進(jìn)行下一字節(jié)發(fā)送否則不進(jìn)行下一次發(fā)送:
reg r0_send_done,r1_send_done;
always@(posedge Clk or negedge Rst_n)begin
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
end
always@(posedge Clk or negedge Rst_n)begin
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;
end
為了保證RAM地址操作的有效性,在寫(xiě)地址和讀地址代碼部分加上范圍限制:
//--------<dpram寫(xiě)地址加1>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
wraddress <= 8'd0;
else if(Rx_Done)
wraddress <= wraddress + 1'b1;
else if(wraddress > 8'd255) //當(dāng)寫(xiě)地址大于配置ip核時(shí)的值時(shí),返回到0地址;
wraddress <= 8'd0;
else
wraddress <= wraddress;
end
//--------<dpram讀地址加1>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
rdaddress <= 8'd0;
else if(do_send && Tx_Done)
rdaddress <= rdaddress + 8'd1;
else if(rdaddress > 8'd255) //當(dāng)讀地址大于255時(shí),返回到0地址;
rdaddress <= 8'd0;
else
rdaddress <= rdaddress;
end
完整的控制模塊代碼:system_ctrl.v
module system_ctrl(
input Clk,
input Rst_n,
input Key_flag,
input Key_state,
input Rx_Done,
input Tx_Done,
output wren,
output reg Send_en,
output reg [7:0] rdaddress,
output reg [7:0] wraddress
);
assign wren = Rx_Done;
reg do_send;
reg r0_send_done;
reg r1_send_done;
//--------<dpram寫(xiě)地址加1>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
wraddress <= 8'd0;
else if(Rx_Done)
wraddress <= wraddress + 1'b1;
else if(wraddress > 8'd255) //當(dāng)寫(xiě)地址大于配置ip核時(shí)的值時(shí),返回到0地址;
wraddress <= 8'd0;
else
wraddress <= wraddress;
end
//--------<翻轉(zhuǎn)標(biāo)志信號(hào)>--------
//按下一次按鍵開(kāi)始連續(xù)發(fā)送數(shù)據(jù),再按一次按鍵停止發(fā)送;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
do_send <= 1'b0;
else if(Key_flag && !Key_state)
do_send <= ~do_send;
end
//--------<dpram讀地址加1>--------
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)
rdaddress <= 8'd0;
else if(do_send && Tx_Done)
rdaddress <= rdaddress + 8'd1;
else if(rdaddress > 8'd255) //當(dāng)讀地址大于255時(shí),返回到0地址;
rdaddress <= 8'd0;
else
rdaddress <= rdaddress;
end
//--------<RAM的兩拍延遲>--------
//雙端口RAM的輸出延遲兩個(gè)系統(tǒng)時(shí)鐘周期;
always@(posedge Clk or negedge Rst_n)begin
if(!Rst_n)begin
r0_send_done <= 1'b0;
r1_send_done <= 1'b1;
end
else begin
r0_send_done <= (do_send && Tx_Done);
r1_send_done <= r0_send_done;
end
end
//--------<按鍵控制與連續(xù)讀操作>--------
//Send_en由按鍵信號(hào)和r1_send_done信號(hào)同時(shí)控制;
//r1_send_done信號(hào)使得串口連續(xù)讀取dpram的數(shù)據(jù);
always@(posedge Clk or negedge Rst_n)begin
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;
end
endmodule
控制模塊的RTL視圖:
4.2 頂層模塊
將串口接收模塊、按鍵消抖模塊、RAM模塊、串口發(fā)送模塊以及控制模塊例化到頂層模塊中。
uart_system_top.v:
module uart_system_top(
input Clk,
input Rst_n,
input key_in,
input uart_rx,
output uart_tx
);
wire [7:0]rx_data;
wire [7:0]tx_data;
wire Key_flag;
wire Key_state;
wire Rx_Done;
wire Tx_Done;
wire wren;
wire Send_en;
wire [7:0]rdaddress;
wire [7:0]wraddress;
uart_byte_rx uart_byte_rx(
.Clk(Clk),
.Rst_n(Rst_n),
.baud_set(3'd0),
.data_rx(uart_rx),
.data_byte(rx_data),
.Rx_Done(Rx_Done)
);
dpram dpram(
.clock(Clk),
.data(rx_data),
.rdaddress(rdaddress),
.wraddress(wraddress),
.wren(wren),
.q(tx_data)
);
KeyFilter KeyFilter(
.Clk(Clk),
.Rst_n(Rst_n),
.key_in(key_in),
.key_flag(Key_flag),
.key_state(Key_state)
);
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Rst_n(Rst_n),
.data_byte(tx_data),
.send_en(Send_en),
.baud_set(3'd0),
.uart_tx(uart_tx),
.Tx_Done(Tx_Done),
.uart_state()
);
system_ctrl system_ctrl(
.Clk(Clk),
.Rst_n(Rst_n),
.Key_flag(Key_flag),
.Key_state(Key_state),
.Rx_Done(Rx_Done),
.Tx_Done(Tx_Done),
.wren(wren),
.Send_en(Send_en),
.rdaddress(rdaddress),
.wraddress(wraddress)
);
endmodule
頂層模塊的RTL視圖:
五、仿真測(cè)試激勵(lì)文件
5.1 key_model
key_model仿真模型用于有按鍵控制信號(hào)的項(xiàng)目進(jìn)行仿真測(cè)試,模擬實(shí)際情況中的按鍵抖動(dòng)。 在仿真時(shí)將該模型也添加到工程中使用。
key_model.v:
`timescale 1ns/1ns
module key_model(press,key);
input press;
output reg key;
reg [15:0]myrand;
initial begin
key = 1'b1;
end
always@(posedge press)
press_key;
task press_key;
begin
repeat(50)begin
myrand = {$random}%65536;//0~65535;
#myrand key = ~key;
end
key = 0;
#25000000;
repeat(50)begin
myrand = {$random}%65536;//0~65535;
#myrand key = ~key;
end
key = 1;
#25000000;
end
endtask
endmodule
5.2 testbench編寫(xiě)
完整的仿真測(cè)試激勵(lì)文件:
uart_system_top_tb.v:
`timescale 1ns/1ns
`define clock_period 20
module uart_system_top_tb;
reg Clk;
reg Rst_n;
wire Key_in;
wire uart_rx;
wire uart_tx;
reg [7:0]data_byte_t;
reg send_en;
wire [2:0]baud_set;
wire Tx_Done;
reg press;
assign baud_set = 3'd0;
uart_system_top uart_system_top(
.Clk(Clk),
.Rst_n(Rst_n),
.key_in(Key_in),
.uart_rx(uart_tx),
.uart_tx(uart_rx)
);
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Rst_n(Rst_n),
.data_byte(data_byte_t),
.send_en(send_en),
.baud_set(baud_set),
.uart_tx(uart_tx),
.Tx_Done(Tx_Done),
.uart_state()
);
key_model key_model(
.press(press),
.key(Key_in)
);
initial Clk = 1;
always#(`clock_period / 2) Clk = ~Clk;
initial begin
Rst_n = 1'b0;
press = 0;
data_byte_t = 8'd0;
send_en = 1'd0;
#(`clock_period*20 + 1 );
Rst_n = 1'b1;
#(`clock_period*50);
data_byte_t = 8'haa;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge Tx_Done)
#(`clock_period*5000);
data_byte_t = 8'h55;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge Tx_Done)
#(`clock_period*5000);
data_byte_t = 8'h33;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge Tx_Done)
#(`clock_period*5000);
data_byte_t = 8'haf;
send_en = 1'd1;
#`clock_period;
send_en = 1'd0;
@(posedge Tx_Done)
#(`clock_period*5000);
press = 1;
#(`clock_period*3)
press = 0;
#(`clock_period*2000000)
$stop;
end
endmodule
5.3 仿真結(jié)果
六、板級(jí)驗(yàn)證
??輸入數(shù)據(jù)儲(chǔ)存到雙口RAM中:
??輸出RAM中的數(shù)據(jù):
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-713679.html
??結(jié)尾文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-713679.html
- ?? 感謝您的支持和鼓勵(lì)! ????
- ??您可能感興趣的內(nèi)容:
- 【FPGA零基礎(chǔ)學(xué)習(xí)之旅#14】串口發(fā)送字符串
- 【Python】串口通信-與FPGA、藍(lán)牙模塊實(shí)現(xiàn)串口通信(Python+FPGA)
- 【Arduino TinyGo】【最新】使用Go語(yǔ)言編寫(xiě)Arduino-環(huán)境搭建和點(diǎn)亮LED燈
- 【全網(wǎng)首發(fā)開(kāi)源教程】【Labview機(jī)器人仿真與控制】Labview與Solidworks多路支配關(guān)系-四足爬行機(jī)器人仿真與控制
![]()
到了這里,關(guān)于【FPGA零基礎(chǔ)學(xué)習(xí)之旅#17】搭建串口收發(fā)與儲(chǔ)存雙口RAM系統(tǒng)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!