本學(xué)習(xí)筆記主要參考小梅哥B站教學(xué)視頻,網(wǎng)址如下:
https://www.bilibili.com/video/BV1va411c7Dz?p=1
使用的編譯器為Vivado,HDL語言為verilog
一、串口通信之發(fā)送數(shù)據(jù)
原理
設(shè)計(jì)代碼
module uart_byte_tx(
Clk,
Reset_n,
Data,
Send_en,
Baud_set, //波特率選擇
uart_tx,
Tx_done,
);
input Clk;
input Reset_n;
input [7:0] Data;
input Send_en;
input [2:0] Baud_set;
output reg uart_tx;
output reg Tx_done;
//Baud_set =0 波特率 = 9600;
//Baud_set =1 波特率 = 19200;
//Baud_set =2 波特率 = 38400;
//Baud_set =3 波特率 = 57600;
//Baud_set =4 波特率 = 115200;
reg [17:0] bps_DR;//定義某一波特率下需要計(jì)數(shù)的次數(shù)
always@(*)begin
case(Baud_set)
3'd0: bps_DR = 1000000000/9600/20;
3'd1: bps_DR = 1000000000/19200/20;
3'd2: bps_DR = 1000000000/38400/20;
3'd3: bps_DR = 1000000000/57600/20;
3'd4: bps_DR = 1000000000/115200/20;
default: bps_DR = 1000000000/9600/20;
endcase
end
reg [17:0] div_cnt; //波特率最小為300時(shí),1s/300=3333333ns發(fā)一個(gè)bit,3333333/20=166666個(gè)周期,18位
//分頻得到基本時(shí)鐘
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(Send_en)
if(div_cnt == bps_DR - 1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
else
div_cnt <= 0;
reg[3:0] bps_cnt; //計(jì)數(shù)11個(gè)端點(diǎn),10位數(shù)據(jù)
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(div_cnt == bps_DR - 1)begin
if(bps_cnt == 11)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1'b1;
end
always@(posedge Clk or negedge Reset_n)begin //根據(jù)bps_cnt的值,給數(shù)據(jù)
if(!Reset_n)begin
Tx_done <= 0;
uart_tx <= 1'b1; //空閑的時(shí)候?yàn)楦唠娖?/span>
end
else begin
case(bps_cnt)
0: begin uart_tx <= 0;Tx_done <= 0; end
1: uart_tx <= Data[0];
2: uart_tx <= Data[1];
3: uart_tx <= Data[2];
4: uart_tx <= Data[3];
5: uart_tx <= Data[4];
6: uart_tx <= Data[5];
7: uart_tx <= Data[6];
8: uart_tx <= Data[7];
9: uart_tx <= Data[7]; //這里有兩個(gè)Data[7]。是因?yàn)樵髡咴诖颂幧賹懥艘粋€(gè)狀態(tài)6
10: uart_tx <= 1;
11: begin uart_tx <= 1; Tx_done <= 1'b1; end//至少維持一個(gè)單位的電平
default: uart_tx <= 1;
endcase
end
end
endmodule
測(cè)試代碼
`timescale 1ns / 1ps
module uart_tx_tb();
reg Clk;
reg Reset_n;
reg [7:0] Data;
reg Send_en;
reg [2:0] Baud_set;
wire uart_tx;
wire Tx_done;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_en(Send_en),
.Baud_set(Baud_set), //波特率選擇
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
initial Clk = 1;
always#10 Clk=~Clk;
initial begin
Reset_n = 0;
Data = 0;
Send_en = 0;
Baud_set = 4;
#201;
Reset_n = 1;
#100;
Data = 8'h57;
Send_en = 1;
#20;
@(posedge Tx_done);
Send_en = 0;
#20000;
Data = 8'h75;
Send_en = 1;
#20;
@(posedge Tx_done);
#20000;
Send_en = 0;
$stop;
end
endmodule
仿真結(jié)果
發(fā)現(xiàn)Send_en拉高之前,uart_tx就置為0了,不符合常理。
轉(zhuǎn)到第二個(gè)發(fā)送信號(hào)處,發(fā)現(xiàn)Send_en為1時(shí),uart_tx仍為1,有延遲一個(gè)一位數(shù)據(jù)的時(shí)間后,才開始發(fā)送起始位:0。
觀察代碼,bps_cnt = 0時(shí),就讓它發(fā)送起始位。
但是觀察上面的仿真圖,bps_cnt在此時(shí)仍為11,不是0.
所以bps_cnt也應(yīng)該受Send_en的控制。
將此處的代碼修改為
再次仿真
發(fā)現(xiàn)Send_en為1時(shí),bps_cnt卻一直為0;
再次修改代碼(加個(gè)begin end)
仿真
發(fā)現(xiàn) bps_cnt的問題被解決了。再看看Send_en和uart_tx的關(guān)系
uart_tx在空閑的時(shí)候應(yīng)該為高電平,但從仿真結(jié)果來看,并不是如此。在發(fā)送起始位之前,有一段的低電平。
放大仿真圖觀察,在uart_tx被拉低時(shí),bps_cnt為0.按照代碼,uart_tx也被置為0.
修改代碼
讓bps_cnt從1到12,0在很多時(shí)候空閑狀態(tài)下是這個(gè)值,用它會(huì)產(chǎn)生一定的麻煩。
仿真
發(fā)現(xiàn)Send_en為0時(shí),uart_tx為高電平。但同樣又出現(xiàn)了,Send_en為1時(shí),uart_tx滯后一個(gè)位的時(shí)間,才發(fā)送起始位的問題。因?yàn)閎ps_cnt為0時(shí),才開始發(fā)送起始位,而此處bps_cnt仍為0.
觀察代碼,計(jì)滿才加一次,耽誤了一位的時(shí)間。
計(jì)滿需要很長(zhǎng)時(shí)間,但是計(jì)到1不需要很長(zhǎng)時(shí)間。(這里大體意思是說:原來代碼的div_cnt需要計(jì)數(shù)一個(gè)完整的周期才能夠?qū)ps_cnt加一,而每一段計(jì)數(shù)過程都會(huì)經(jīng)過1這個(gè)數(shù),所以直接讓它跑到值為1的時(shí)候就讓bps_cnt加1,節(jié)省了很多時(shí)間,同樣也是一段div_cnt的計(jì)數(shù)周期僅對(duì)應(yīng)一個(gè)數(shù)值1,也就是一個(gè)bps_cnt+1的過程)改為
仿真結(jié)果
從結(jié)果來看,Send_en變?yōu)楦唠娖剑瑑蓚€(gè)時(shí)鐘周期后,Tx開始發(fā)起始位。
波特率驗(yàn)證:從仿真結(jié)果來看,發(fā)一位需要8.68us,符合115200的波特率。
另外:將程序修改為:bps_clk來控制的思路
仿真發(fā)現(xiàn),的確出現(xiàn)了bps_clk一樣的脈沖。但是數(shù)數(shù)發(fā)現(xiàn),12個(gè)bps_clk將bps_cnt分成了11段。但算上起始位和終止位,理應(yīng)10段才行。
再次修改代碼
仿真結(jié)果
這下終于正常了??!
完整正確代碼:
module uart_byte_tx(
Clk,
Reset_n,
Data,
Send_en,
Baud_set, //波特率選擇
uart_tx,
Tx_done,
);
input Clk;
input Reset_n;
input [7:0] Data;
input Send_en;
input [2:0] Baud_set;
output reg uart_tx;
output reg Tx_done;
//Baud_set =0 波特率 = 9600;
//Baud_set =1 波特率 = 19200;
//Baud_set =2 波特率 = 38400;
//Baud_set =3 波特率 = 57600;
//Baud_set =4 波特率 = 115200;
reg [17:0] bps_DR;//定義某一波特率下需要計(jì)數(shù)的次數(shù)
always@(*)begin
case(Baud_set)
3'd0: bps_DR = 1000000000/9600/20;
3'd1: bps_DR = 1000000000/19200/20;
3'd2: bps_DR = 1000000000/38400/20;
3'd3: bps_DR = 1000000000/57600/20;
3'd4: bps_DR = 1000000000/115200/20;
default: bps_DR = 1000000000/9600/20;
endcase
end
wire bps_clk;
assign bps_clk = (div_cnt == 1);
reg [17:0] div_cnt; //波特率最小為300時(shí),1s/300=3333333ns發(fā)一個(gè)bit,3333333/20=166666個(gè)周期,18位
//分頻得到基本時(shí)鐘
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(Send_en)begin
if(div_cnt == bps_DR - 1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1'b1;
end
else
div_cnt <= 0;
reg[3:0] bps_cnt; //計(jì)數(shù)11個(gè)端點(diǎn),10位數(shù)據(jù)
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(Send_en)begin
if(bps_clk)begin
if(bps_cnt == 11)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1'b1;
end
end
else
bps_cnt <= 0;
always@(posedge Clk or negedge Reset_n)begin //根據(jù)bps_cnt的值,給數(shù)據(jù)
if(!Reset_n)begin
Tx_done <= 0;
uart_tx <= 1'b1; //空閑的時(shí)候?yàn)楦唠娖?/span>
end
else begin
case(bps_cnt)
1: begin uart_tx <= 0;Tx_done <= 0; end
2: uart_tx <= Data[0];
3: uart_tx <= Data[1];
4: uart_tx <= Data[2];
5: uart_tx <= Data[3];
6: uart_tx <= Data[4];
7: uart_tx <= Data[5];
8: uart_tx <= Data[6];
9: uart_tx <= Data[7];
10: uart_tx <= 1;
11: begin uart_tx <= 1; Tx_done <= 1'b1; end//至少維持一個(gè)單位的電平
default: uart_tx <= 1;
endcase
end
end
endmodule
二、每10ms以115200的波特率發(fā)送一個(gè)數(shù)據(jù),每次發(fā)送的數(shù)據(jù)比以前一個(gè)數(shù)據(jù)大一(計(jì)數(shù)器)
思路:頂層模塊調(diào)用
設(shè)計(jì)文件:
module uart_tx_test(
Clk,
Reset_n,
uart_tx
);
input Clk;
input Reset_n;
output uart_tx;
reg Send_en;
reg [7:0] Data;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_en(Send_en),
.Baud_set(3'd4), //波特率選擇
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
reg [18:0] counter;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 500_000-1)
counter <= 0;
else
counter <= counter + 1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Send_en <= 0;
else if(counter == 1)
Send_en <= 1;
else if(Tx_done)
Send_en <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Data <= 0;
else if(Tx_done)
Data <= Data + 1'b1;
endmodule
測(cè)試文件:
`timescale 1ns / 1ps
module uart_tx_test_tb();
reg Clk;
reg Reset_n;
wire uart_tx;
uart_tx_test uart_tx_test(
.Clk(Clk),
.Reset_n(Reset_n),
.uart_tx(uart_tx)
);
initial Clk = 1;
always#10 Clk = ~Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#50_000_000;
end
endmodule
仿真結(jié)果:
發(fā)現(xiàn)Send_en高電平僅占一個(gè)時(shí)鐘周期,的確是在counter為1時(shí)就被拉高,根據(jù)代碼,Tx_done為1時(shí),Send_en就被拉低。而仿真結(jié)果顯示,Tx_done一直顯示為高電平。
在觀察仿真結(jié)果前面部分,的確成功發(fā)送了一個(gè)Data。
再看看Tx_done為何后面不被拉低
bps_cnt等于1時(shí)才拉低,由于第一次發(fā)送完之后Tx_done=1,然后Send_en變?yōu)?,而由于此時(shí)Send_en不為1,就不會(huì)再計(jì)數(shù),bps_cnt也不能變?yōu)?,Tx_done就不能變?yōu)?.
而由于bps_cnt常態(tài)為0,讓bps_cnt為0時(shí),不去操作uart_tx,而是去操作Tx_done。
即修改為:
再次觀察仿真結(jié)果發(fā)現(xiàn)
Data發(fā)了0之后,直接發(fā)3了。
觀察代碼:
進(jìn)一步觀察細(xì)節(jié):
Data很快的加了三次,Tx_done占據(jù)了三個(gè)機(jī)器周期。Tx_done的脈沖時(shí)間周期很重要,應(yīng)該為一個(gè)時(shí)鐘周期的高脈沖。
試著去看看Tx_done部分的語句
當(dāng)bps_cnt為11的時(shí)候,Tx_done被拉高,看看仿真
11持續(xù)了三個(gè)周期,還是不夠短
梳理一下邏輯:
當(dāng)div_cnt=1時(shí),產(chǎn)生bps_clk這個(gè)脈沖,然后讓bps_cnt+1,進(jìn)入了11,才會(huì)產(chǎn)生Tx_done為高電平的信號(hào)。又因?yàn)闄z測(cè)到了Tx_done信號(hào),所以又將Send_en拉低。
bps_cnt要想清零,在下一拍才會(huì)生效(非阻塞賦值的緣故)
在下圖所示的黃線這一時(shí)刻,檢測(cè)到Send_en=0,bps_cnt清零,下一個(gè)時(shí)鐘沿到來時(shí),檢測(cè)到bps_cnt=0, Tx_done才置零。
進(jìn)一步嘗試著修改程序(把控制Tx_done的語句單獨(dú)拿出來寫)
觀察仿真結(jié)果:Tx_done僅維持一個(gè)時(shí)鐘周期
以上過程的最終代碼:
設(shè)計(jì)文件uart_byte_tx:
module uart_byte_tx(
Clk,
Reset_n,
Send_en,
Data,
Baud_set,
uart_tx,
Tx_done
);
input Clk;
input Reset_n;
input Send_en;
input [2:0]Baud_set;
input [7:0] Data;
output reg uart_tx;
output reg Tx_done;
wire bps_clk;
assign bps_clk = (div_cnt == 1);
//波特率選擇
reg [17:0] bps_DR; //波特率最小為300時(shí)算得
always@(*)begin
case(Baud_set)
3'd0: bps_DR = 1000000000/9600/20;
3'd1: bps_DR = 1000000000/19200/20;
3'd2: bps_DR = 1000000000/38400/20;
3'd3: bps_DR = 1000000000/57600/20;
3'd4: bps_DR = 1000000000/115200/20;
default: bps_DR = 1000000000/9600/20;
endcase
end
//位寬時(shí)間計(jì)數(shù)
reg [17:0] div_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(Send_en)begin
if(div_cnt == bps_DR -1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1;
end
else
div_cnt <= 0;
//數(shù)位數(shù)
reg [3:0] bps_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(Send_en)begin
if(bps_clk)begin
if(bps_cnt == 11)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1;
end
end
else
bps_cnt <= 0;
always@(posedge Clk or negedge Reset_n)begin
if(!Reset_n)begin
uart_tx <= 1;
end
else begin
case(bps_cnt)
1:uart_tx <= 0;
2:uart_tx <= Data[0];
3:uart_tx <= Data[1];
4:uart_tx <= Data[2];
5:uart_tx <= Data[3];
6:uart_tx <= Data[4];
7:uart_tx <= Data[5];
8:uart_tx <= Data[6];
9:uart_tx <= Data[7];
10:uart_tx <= 1;
11:begin uart_tx <= 1; end
default: uart_tx <= 1;
endcase
end
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Tx_done <= 0;
else if((bps_clk == 1)&& (bps_cnt == 10))
Tx_done <= 1;
else
Tx_done <= 0;
endmodule
設(shè)計(jì)文件uart_tx_test:
module uart_tx_test(
Clk,
Reset_n,
uart_tx
);
input Clk;
input Reset_n;
output uart_tx;
reg Send_en;
reg [7:0] Data;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_en(Send_en),
.Baud_set(3'd4), //波特率選擇
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
// 10ms
reg [18:0] counter;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 500_000-1)
counter <= 0;
else
counter <= counter + 1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Send_en <= 0;
else if(counter == 1)
Send_en <= 1;
else if(Tx_done)
Send_en <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Data <= 0;
else if(Tx_done)
Data <= Data + 1'b1;
endmodule
測(cè)試文件uart_tx_test_tb:
`timescale 1ns / 1ps
module uart_tx_test_tb();
reg Clk;
reg Reset_n;
wire uart_tx;
uart_tx_test uart_tx_test(
.Clk(Clk),
.Reset_n(Reset_n),
.uart_tx(uart_tx)
);
initial Clk = 1;
always#10 Clk = ~Clk;
initial begin
Reset_n = 0;
#201;
Reset_n = 1;
#50_000_000;
end
endmodule
考慮一個(gè)數(shù)據(jù)采集模塊,直接將Data_done作為Send_en信號(hào)
修改代碼,把控制Send_en的代碼放在byte_tx內(nèi)部來完成。
而為了防止數(shù)據(jù)在發(fā)送過程中的變化,需要提前將待發(fā)送數(shù)據(jù)存起來。
仿真結(jié)果正確
板級(jí)驗(yàn)證
沒毛??!
以上過程的最終代碼:
設(shè)計(jì)文件uart_byte_tx:
module uart_byte_tx(
Clk,
Reset_n,
Send_Go,
Data,
Baud_set,
uart_tx,
Tx_done
);
input Clk;
input Reset_n;
input Send_Go;
input [2:0]Baud_set;
input [7:0] Data;
output reg uart_tx;
output reg Tx_done;
reg Send_en;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Send_en <= 0;
else if(Send_Go)
Send_en <= 1;
else if(Tx_done)
Send_en <= 0;
//用來存儲(chǔ)數(shù)據(jù)
reg [7:0]r_Data;
always@(posedge Clk)
if(Send_Go)
r_Data <= Data;
else
r_Data <= r_Data;
wire bps_clk;
assign bps_clk = (div_cnt == 1);
//波特率選擇
reg [17:0] bps_DR; //波特率最小為300時(shí)算得
always@(*)begin
case(Baud_set)
3'd0: bps_DR = 1000000000/9600/20;
3'd1: bps_DR = 1000000000/19200/20;
3'd2: bps_DR = 1000000000/38400/20;
3'd3: bps_DR = 1000000000/57600/20;
3'd4: bps_DR = 1000000000/115200/20;
default: bps_DR = 1000000000/9600/20;
endcase
end
//位寬時(shí)間計(jì)數(shù)
reg [17:0] div_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(Send_en)begin
if(div_cnt == bps_DR -1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1;
end
else
div_cnt <= 0;
//數(shù)位數(shù)
reg [3:0] bps_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(Send_en)begin
if(bps_clk)begin
if(bps_cnt == 11)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1;
end
end
else
bps_cnt <= 0;
always@(posedge Clk or negedge Reset_n)begin
if(!Reset_n)begin
uart_tx <= 1;
end
else begin
case(bps_cnt)
1:uart_tx <= 0;
2:uart_tx <= r_Data[0];
3:uart_tx <= r_Data[1];
4:uart_tx <= r_Data[2];
5:uart_tx <= r_Data[3];
6:uart_tx <= r_Data[4];
7:uart_tx <= r_Data[5];
8:uart_tx <= r_Data[6];
9:uart_tx <= r_Data[7];
10:uart_tx <= 1;
11:begin uart_tx <= 1; end
default: uart_tx <= 1;
endcase
end
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Tx_done <= 0;
else if((bps_clk == 1)&& (bps_cnt == 10))
Tx_done <= 1;
else
Tx_done <= 0;
endmodule
uart_tx_test
module uart_tx_test(
Clk,
Reset_n,
uart_tx
);
input Clk;
input Reset_n;
output uart_tx;
reg Send_Go;
reg [7:0] Data;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_Go(Send_Go),
.Baud_set(3'd4), //波特率選擇
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
// 10ms
reg [24:0] counter;//板級(jí)驗(yàn)證時(shí),改成100ms發(fā)一個(gè)
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
counter <= 0;
else if(counter == 5_000_000-1)
counter <= 0;
else
counter <= counter + 1;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Send_Go <= 0;
else if(counter == 1)
Send_Go <= 1;
else
Send_Go <= 0;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Data <= 0;
else if(Tx_done)
Data <= Data + 1'b1;
endmodule
三、采用狀態(tài)機(jī)實(shí)現(xiàn)多字節(jié)數(shù)據(jù)發(fā)送
其實(shí)也就是發(fā)送40位數(shù)據(jù)到電腦
拆分12位的數(shù)據(jù)為8位+4位
兩種情況:
1.沒有開始發(fā)送(上一次的發(fā)送已經(jīng)完成,新的40位數(shù)據(jù)的發(fā)送請(qǐng)求沒有出現(xiàn))
2.來了發(fā)送40位數(shù)據(jù)的請(qǐng)求信號(hào)
3.依次發(fā)送數(shù)據(jù)的狀態(tài)
狀態(tài)機(jī)的概念
第一個(gè)狀態(tài):第一種情況的時(shí)候,咱干什么事情?等待傳輸請(qǐng)求(Trans_Go)的到來
Data[7:0]給到uart_byte_tx的Data,并同時(shí)產(chǎn)生Send_Go信號(hào),啟動(dòng)第一個(gè)字節(jié)的發(fā)送
接著等待Tx_done信號(hào)的到來
1.40位的數(shù)據(jù)是否發(fā)完了?發(fā)完了,回到第一個(gè)狀態(tài)繼續(xù)等Trans_Go,沒發(fā)完,啟動(dòng)下一個(gè)8位數(shù)據(jù)的發(fā)送。
設(shè)計(jì)文件uart_tx_data
module uart_tx_data(
Clk,
Reset_n,
Data40, //40位的數(shù)據(jù)
Trans_Go,
uart_tx,
Trans_Done
);
input Clk;
input Reset_n;
input [39:0]Data40;
input Trans_Go;
output uart_tx;
output reg Trans_Done;
reg [7:0]Data;
reg Send_Go;
wire Tx_done;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_Go(Send_Go),
.Baud_set(4),
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
reg [2:0]state;//定義一個(gè)狀態(tài)信號(hào)
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)begin
state <= 0;
Data <= 0;
Send_Go <= 0;
Trans_Done <= 0;
end
else if(state == 0)begin
Trans_Done <= 0;
if(Trans_Go)begin
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
Send_Go <= 0;
state <= 0;
Trans_Done <= 1;
end
else begin
Data <= Data;
Send_Go <= 0;
state <= 5;
end
end
endmodule
設(shè)計(jì)文件uart_byte_tx
module uart_byte_tx(
Clk,
Reset_n,
Send_Go,
Data,
Baud_set,
uart_tx,
Tx_done
);
input Clk;
input Reset_n;
input Send_Go;
input [2:0]Baud_set;
input [7:0] Data;
output reg uart_tx;
output reg Tx_done;
reg Send_en;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Send_en <= 0;
else if(Send_Go)
Send_en <= 1;
else if(Tx_done)
Send_en <= 0;
//用來存儲(chǔ)數(shù)據(jù)
reg [7:0]r_Data;
always@(posedge Clk)
if(Send_Go)
r_Data <= Data;
else
r_Data <= r_Data;
wire bps_clk;
assign bps_clk = (div_cnt == 1);
//波特率選擇
reg [17:0] bps_DR; //波特率最小為300時(shí)算得
always@(*)begin
case(Baud_set)
3'd0: bps_DR = 1000000000/9600/20;
3'd1: bps_DR = 1000000000/19200/20;
3'd2: bps_DR = 1000000000/38400/20;
3'd3: bps_DR = 1000000000/57600/20;
3'd4: bps_DR = 1000000000/115200/20;
default: bps_DR = 1000000000/9600/20;
endcase
end
//位寬時(shí)間計(jì)數(shù)
reg [17:0] div_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
div_cnt <= 0;
else if(Send_en)begin
if(div_cnt == bps_DR -1)
div_cnt <= 0;
else
div_cnt <= div_cnt + 1;
end
else
div_cnt <= 0;
//數(shù)位數(shù)
reg [3:0] bps_cnt;
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
bps_cnt <= 0;
else if(Send_en)begin
if(bps_clk)begin
if(bps_cnt == 11)
bps_cnt <= 0;
else
bps_cnt <= bps_cnt + 1;
end
end
else
bps_cnt <= 0;
always@(posedge Clk or negedge Reset_n)begin
if(!Reset_n)begin
uart_tx <= 1;
end
else begin
case(bps_cnt)
1:uart_tx <= 0;
2:uart_tx <= r_Data[0];
3:uart_tx <= r_Data[1];
4:uart_tx <= r_Data[2];
5:uart_tx <= r_Data[3];
6:uart_tx <= r_Data[4];
7:uart_tx <= r_Data[5];
8:uart_tx <= r_Data[6];
9:uart_tx <= r_Data[7];
10:uart_tx <= 1;
11:begin uart_tx <= 1; end
default: uart_tx <= 1;
endcase
end
end
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)
Tx_done <= 0;
else if((bps_clk == 1)&& (bps_cnt == 10))
Tx_done <= 1;
else
Tx_done <= 0;
endmodule
測(cè)試文件uart_tx_data_tb
`timescale 1ns / 1ps
module uart_tx_data_tb(
);
reg Clk;
reg Reset_n;
reg [39:0]Data40;
reg Trans_Go;
wire uart_tx;
uart_tx_data uart_tx_data(
Clk,//隱式例化不用打點(diǎn)
Reset_n,
Data40,
Trans_Go,
uart_tx,
Trans_Done
);
initial Clk =1;
always #10 Clk = ~Clk;
initial begin
Reset_n = 0;
Data40 = 0;
Trans_Go = 0;
#201;
Reset_n = 1;
#200;
Data40 = 40'h123456789a;
Trans_Go = 1;
#20;
Trans_Go = 0;
@(posedge Trans_Done)
#200000;
Data40 = 40'ha987654321;
Trans_Go = 1;
#20;
Trans_Go = 0;
@(posedge Trans_Done)
#200000;
$stop;
end
仿真結(jié)果:
初步正確!
換一種代碼風(fēng)格:
module uart_tx_data2(
Clk,
Reset_n,
Data40, //40位的數(shù)據(jù)
Trans_Go,
uart_tx,
Trans_Done
);
input Clk;
input Reset_n;
input [39:0]Data40;
input Trans_Go;
output uart_tx;
output reg Trans_Done;
reg [7:0]Data;
reg Send_Go;
wire Tx_done;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_Go(Send_Go),
.Baud_set(4),
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
reg [2:0]state;//定義一個(gè)狀態(tài)信號(hào)
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)begin
state <= 0;
Data <= 0;
Send_Go <= 0;
Trans_Done <= 0;
end
else begin
case(state)
0:
begin
Trans_Done <= 0;
if(Trans_Go)begin
Data <= Data40[7:0];
Send_Go <= 1;
state <= 1;
end
else begin
Data <= Data;
Send_Go <= 0;
state <= 0;
end
end
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
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
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
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
5:
begin
if(Tx_done)begin
Send_Go <= 0;
state <= 0;
Trans_Done <= 1;
end
else begin
Data <= Data;
Send_Go <= 0;
state <= 5;
end
end
default:
begin
Data <= Data;
Send_Go <= 0;
state <= 0;
end
endcase
end
endmodule
四、任務(wù):優(yōu)化狀態(tài)機(jī),實(shí)現(xiàn)只要2個(gè)或3個(gè)狀態(tài)實(shí)現(xiàn)發(fā)送的功能,并且易于修改為發(fā)送任意個(gè)字節(jié)的數(shù)據(jù)。
注:該題在駱神的指導(dǎo)下完成,特此致謝!
設(shè)計(jì)文件uart_tx_data3文章來源:http://www.zghlxwxcb.cn/news/detail-408296.html
module uart_tx_data3(
Clk,
Reset_n,
Data40, //40位的數(shù)據(jù)
Trans_Go,
uart_tx,
Trans_Done
);
input Clk;
input Reset_n;
input [39:0]Data40;
input Trans_Go;
output uart_tx;
output reg Trans_Done;
reg [7:0]Data;
reg Send_Go;
wire Tx_done;
uart_byte_tx uart_byte_tx(
.Clk(Clk),
.Reset_n(Reset_n),
.Data(Data),
.Send_Go(Send_Go),
.Baud_set(4),
.uart_tx(uart_tx),
.Tx_done(Tx_done)
);
reg state;//定義一個(gè)狀態(tài)信號(hào)
reg [2:0]counter_state;
reg [39:0]Data40_st;//存儲(chǔ)數(shù)據(jù)
parameter Num_Data = 40/8; //待發(fā)送的字節(jié)數(shù)
always@(posedge Clk or negedge Reset_n)
if(!Reset_n)begin
state <= 0;
Data <= 0;
Send_Go <= 0;
Trans_Done <= 0;
counter_state <= 0;
Data40_st <= 0;
end
else begin
case(state)
0:
begin
if(Trans_Go)begin
Trans_Done <= 0;
Data <= Data40[7:0];
Data40_st <= {Data40[7:0],Data40[39:8]};
Send_Go <= 1;
counter_state <= counter_state + 1;
state <= 1;
end
else begin
Data40_st <= 0;
Data <= Data;
Send_Go <= 0;
state <= 0;
counter_state <= 0;
Trans_Done <= 0;
end
end
1:
begin
if(Tx_done)begin
if(counter_state == Num_Data)begin
state <= 0;//發(fā)完了回狀態(tài)0
counter_state <= 0;
Send_Go <= 0;
Data40_st <= 0;
Trans_Done <= 1;
Data <= 0;
end
else begin
Data40_st <= {Data40_st[7:0],Data40_st[39:8]};
Data <= Data40_st[7:0];
Send_Go <= 1;
counter_state <= counter_state + 1;
state <= 1;
end
end
else begin
Data <= Data;
Send_Go <= 0;
state <= 1;
Data40_st <= Data40_st;
counter_state <= counter_state;
end
end
default:
begin
Data <= Data;
Send_Go <= 0;
state <= 0;
counter_state <= 0;
end
endcase
end
endmodule
仿真結(jié)果:
顯示正確!文章來源地址http://www.zghlxwxcb.cn/news/detail-408296.html
到了這里,關(guān)于FPGA學(xué)習(xí)筆記(三)——串口通信之發(fā)送數(shù)據(jù)(調(diào)試過程)的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!