當并行數據準備好后,如果得到發送指令,則將數據按UART協議輸出,先輸出一個低電平的起始位,然后從低到高輸出8個數據位,接著是可選的奇偶校驗位,最后是高電平的停止位;
由于發送時鐘clk16x為波特率的16倍,因此對clk16x計數到16時,發送D0;計數到32時,發送D1……依此類推;
2.發送模塊代碼:
module tx_module(
input
clk16x,
/*
transmit clock,16×115200
*/
input
rst_n,
/*
glabol reset signal
*/
input
TransEn,
/*
transmit enable
*/
input [7:0]
DataToTrans, /*
Data prepared for transmitting
*/
output reg
BufFull,
/*
Data buffer is full
*/
output reg
tx
/*
serial data out
*/
);
/* capture the rising edge of TransEn */
reg TransEn_r;
wire pos_tri;
always@(posedge clk16x or negedge rst_n)
begin
if(!rst_n)
TransEn_r <= 1'b0;
else
TransEn_r <= TransEn;
end
assign pos_tri = ~TransEn_r & TransEn;
/*
* when the rising edge of DataEn comes up, load the Data to buffer
*/
reg [7:0] ShiftReg;
always@(posedge pos_tri or negedge rst_n)
begin
if(!rst_n)
ShiftReg <= 8'b0;
else
ShiftReg <= DataToTrans;
end
//----------------------------------------------
/*
counter control
*/
reg cnt_en;
always@(posedge clk16x or negedge rst_n)
begin
if(!rst_n)
begin
cnt_en <= 1'b0;
BufFull <= 1'b0;
end
else if(pos_tri==1'b1)
begin
cnt_en <=1'b1;
BufFull <=1'b1;
end
else if(cnt==8'd160)
begin
cnt_en<=1'b0;
BufFull <=1'b0;
end
end
//---------------------------------------------
/*
counter module
*/
reg [7:0] cnt;
always@(posedge clk16x or negedge rst_n)
begin
if(!rst_n)
cnt<=8'd0;
else if(cnt_en)
cnt<=cnt+1'b1;
else
cnt<=8'd0;
end
//---------------------------------------------
/*
transmit module
*/
always@(posedge clk16x or negedge rst_n)
begin
if(!rst_n)
begin
tx <= 1'b1;
end
else if(cnt_en)
case(cnt)
8'd0 : tx <= 1'b0;
8'd16 : tx <= ShiftReg[0];
8'd32 : tx <= ShiftReg[1];
8'd48 : tx <= ShiftReg[2];
8'd64 : tx <= ShiftReg[3];
8'd80 : tx <= ShiftReg[4];
8'd96 : tx <= ShiftReg[5];
8'd112 : tx <= ShiftReg[6];
8'd128 : tx <= ShiftReg[7];
8'd144 : tx <= 1'b1;
endcase
else
tx <= 1'b1;
end
endmodule
測試結果:正確率100%
3.如需要校驗位或其它風格的設計,可以參考Xilinx的發送模塊:
module txmit (din,tbre,tsre,rst,clk16x,wrn,sdo) ;
output tbre ; /*數據緩存區滿指示*/
output tsre ; /*移位寄存器空指示*/
output sdo ;
/*串行數據發送端*/
input [7:0] din ;/*并行數據輸入*/
input rst ;
/*復位,高電平有效*/
input clk16x ; /*發送時鐘*/
input wrn ;
/*發送使能,低電平有效*/
reg sdo ;
reg tsre ;
reg tbre ;
reg[3:0] clkdiv ;
wire clk1x ;
reg [3:0] no_bits_sent ;
/*捕獲發送使能的下降沿*/
reg wrn1 ;
reg wrn2 ;
always @(posedge clk16x or posedge rst)
begin
if (rst)
begin
wrn1 <= 1'b1 ;
wrn2 <= 1'b1 ;
end
else
begin
wrn1 <= wrn ;
wrn2 <= wrn1 ;
end
end
/* 計數控制模塊 */
reg clk1x_enable ; /*發送時鐘允許信號*/
always @(posedge clk16x or posedge rst)
begin
if (rst)
begin
tbre <= 1'b0 ;
clk1x_enable <= 1'b0 ;
end
else if (!wrn1 && wrn2)
/*如果捕獲到使能信號的下降沿,則開始計數*/
begin
clk1x_enable <= 1'b1 ;
tbre <= 1'b1 ;
/*數據緩存區滿標志置1*/
end
else if (no_bits_sent == 4'b0010)
tbre <= 1'b1 ;
else if (no_bits_sent == 4'b1101)
begin
clk1x_enable <= 1'b0 ;
tbre <= 1'b0 ;
end
end
/* 使能信號的下降沿,載入輸入數據到緩沖區*/
reg [7:0] tbr ;
always @(negedge wrn or posedge rst)
begin
if (rst)
tbr = 8'b0 ;
else
tbr = din ;
end
/*16分頻,產生發送時鐘*/
always @(posedge clk16x or posedge rst)
begin
if (rst)
clkdiv = 4'b0 ;
else if (clk1x_enable)
clkdiv = clkdiv + 1 ;
end
assign clk1x = clkdiv[3] ;
評論
查看更多