1.需求分析
????????關于uart協(xié)議實現(xiàn)這部分大家可以參考我上一篇的博客?!禙PGA自學筆記--串口通信實現(xiàn)(vivado&verilog版)》。在上一篇博客中,主要實現(xiàn)了將單字節(jié)的數(shù)據(jù),我們其實就是用上一篇博客的模塊來實現(xiàn)多字節(jié)數(shù)據(jù)的發(fā)送。
????????在真實的數(shù)據(jù)傳輸過程中,我們不只是發(fā)送 6 7 8 位數(shù)據(jù),也有可能發(fā)送12 16 20位的數(shù)據(jù),所以我們需要調(diào)用多次串口發(fā)送模塊來發(fā)送多字節(jié)數(shù)據(jù)。通過狀態(tài)機實現(xiàn),假設我們這次發(fā)送一個40位,5字節(jié)的數(shù)據(jù),所以樸素的來講,我們可以有6個狀態(tài),0狀態(tài)是整個模塊等待狀態(tài),1,2,3,4,5狀態(tài)分別為5個字節(jié)數(shù)據(jù)的發(fā)送狀態(tài)。
2.總體模塊和狀態(tài)轉(zhuǎn)移圖。
????????上一篇博客中,單字節(jié)的串口發(fā)送模塊為uart_tx。實現(xiàn)的具體功能為,當send_go為高電平時,將data里的并行數(shù)據(jù)以串行數(shù)據(jù)發(fā)出,發(fā)送完成時 tx_done 產(chǎn)生一個單脈沖。我們需要在上層模塊中調(diào)用這個模塊。上層模塊的框圖如昨圖。需要調(diào)用的uart_tx模塊如右圖所示。
????????
所以,需要trans_go啟動狀態(tài)機,狀態(tài)機內(nèi)部產(chǎn)身send_go信號,傳輸一字節(jié)數(shù)據(jù)。發(fā)送完成后,uart_tx模塊會產(chǎn)生tx_done信號,tx_done信號用來激活狀態(tài)機的下一個狀態(tài),開始發(fā)送下一個數(shù)據(jù),再次產(chǎn)生一個send_go脈沖,送入data數(shù)據(jù),依次送完5字節(jié)數(shù)據(jù),當最后一個字節(jié)發(fā)送完成成,最后一個狀態(tài)5在tx_done下返回第一個狀態(tài),并產(chǎn)生五字節(jié)發(fā)送完成信號,trans_down.回到第一個狀態(tài)后,等待發(fā)送下一個四十位,五字節(jié)數(shù)據(jù)的trans_go。
狀態(tài)轉(zhuǎn)移圖如下。
當然,這個狀態(tài)轉(zhuǎn)移圖也可以簡化,由于我目前也是小白狀態(tài),只能寫出這種比較好理解,簡單的寫法,大家以后也可以嘗試比較高級的寫法。即只用兩個狀態(tài)機實現(xiàn),或者講后面五個狀態(tài)總結(jié)為一個大狀態(tài),
3.設計文件和testbench文件
????????在top文件中例化uart_byte_tx模塊,這部分具體代碼請參考上一個博客。代碼參考了B站小梅哥的視頻。新手強烈推薦。
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/04/30 20:20:59
// Design Name:
// Module Name: uart_tx_5byte
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
// 使用串口發(fā)送5個字節(jié)(40 bit)的數(shù)據(jù)到電腦
module uart_tx_5byte(
clk,
reset,
data40,
trans_go,
uart_tx,
trans_done
);
input clk;
input reset;
input trans_go;
input [39:0]data40;
output uart_tx;
output reg trans_done;
reg [7:0]data;
reg send_go;
//reg tx_done;
uart_byte_tx uart_byte_tx(
.clk(clk),
.reset(reset),
.send_go(send_go),
.data(data),
.baud_set(4),
.uart_tx(uart_tx),
.tx_done(tx_done)
);
reg [2:0]state;
always@(posedge clk or negedge reset)
if(!reset)begin
state <= 0;
send_go <= 0;
data <= 0;
trans_done <= 0;
end
else if(state == 0)begin
trans_done <= 0;
//if(tx_done)begin // 當發(fā)完的時候 發(fā)新的
if(trans_go)begin // 由trans_go 點燃第一個狀態(tài) 啟動狀態(tài) 用tx_done 是無法啟動狀態(tài)機的 tx_done 是 0狀態(tài)結(jié)束標志
data <= data40[7:0];
send_go <= 1;
state <= 1;
end
else begin
data <= data;
send_go <= 0;
state <= 0;
end
end
else if(state == 1)begin
if(tx_done)begin
data <= data40[15:8];
send_go <= 1;
state <= 2;
end
else begin
data <= data;
send_go <= 0;
state <= 1;
end
end
else if(state == 2)begin
if(tx_done)begin
data <= data40[23:16];
send_go <= 1;
state <= 3;
end
else begin
data <= data;
send_go <= 0;
state <= 2;
end
end
else if(state == 3)begin
if(tx_done)begin
data <= data40[31:24];
send_go <= 1;
state <= 4;
end
else begin
data <= data;
send_go <= 0;
state <= 3;
end
end
else if(state == 4)begin
if(tx_done)begin
data <= data40[39:32];
send_go <= 1;
state <= 5;
end
else begin
data <= data;
send_go <= 0;
state <= 4;
end
end
else if(state == 5)begin
if(tx_done)begin // 當發(fā)完的時候 回到初始狀態(tài)
send_go <= 0;
state <= 0;
trans_done <= 1;
end
else begin // 當沒發(fā)完的時候 等他發(fā)完
data <= data;
send_go <= 0;
state <= 5;
end
end
endmodule
對應的testbench文件
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2022/04/30 21:51:02
// Design Name:
// Module Name: uart_tx_5byte_tb
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module uart_tx_5byte_tb(
);
reg clk;
reg reset;
reg [39:0]data40;
reg trans_go;
wire trans_done;
wire uart_tx;
uart_tx_5byte uart_tx_5byte(
.clk(clk),
.reset(reset),
.data40(data40),
.trans_go(trans_go),
.uart_tx(uart_tx),
.trans_done(trans_done)
);
initial clk = 1;
always #10 clk = ~clk;
initial begin
reset = 0;
data40 = 0;
trans_go = 0;
# 201;
# 200;
reset = 1;
data40 = 40'h123456789a;
trans_go = 1;
# 20
trans_go = 0;
@(posedge trans_done);
# 200000;
data40 = 40'habc1234655;
trans_go = 1;
# 20
trans_go = 0;
@(posedge trans_done);
# 200000;
$stop;
end
endmodule
?4.仿真結(jié)果分析
文章來源:http://www.zghlxwxcb.cn/news/detail-416002.html
顯然,如圖所示,一定要注意,多字節(jié)發(fā)送,每個字節(jié)還是存在起始位和終止位的,所以應該還是10位10位的發(fā),看時序圖的時候一定不要看錯了,去除箭頭所示的標志位后,對比數(shù)據(jù),并行40位輸入和串行輸出,結(jié)果一致,從低位到高位,完全正確。有興趣的同學可以直接下載我的vivado工程。文章來源地址http://www.zghlxwxcb.cn/news/detail-416002.html
到了這里,關于FPGA自學筆記--串口通信發(fā)送多字節(jié)數(shù)據(jù)(verilog版)的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!