5 . 各模块详细设计
1)波特率发生器模块:假定系统时钟为50M,波特率为115200,则传输每一位所需的时间为8.6805us,而将其分频至波特率的16倍则需计数则在系统时钟下当计数值为27时则将Baud16Tick置为1,其他时间都为0。要得到波特率脉冲时则在Baud16Tick节拍下计数至16时将BaudTick置为1,其他值时为0。程序如下:
always @(posedge clk )
begin
if (rst)
begin
OverSampleCnt <=8'b0;
Baud16Tick <= 1'b0;
end
elseif(OverSampleCnt== OverSampleCntnum)
OverSampleCnt <= 1'b0;
else
OverSampleCnt <=OverSampleCnt+1;
case(OverSampleCnt== OverSampleCntnum/2)
OverSampleCntnum/2:Baud16Tick <= 1'b1;
default:Baud16Tick <= 1'b0;
endcase
End
always @(posedge clk or negedge rst)
begin
if (rst)
begin
BaudTick <= 1'b0;
BaudTickCnt <= 4'b0000 ;
end
else if (Baud16Tick&&BaudTick_EN)
BaudTickCnt = BaudTickCnt +1 ;
elseif((BaudTickCnt== 4’b1111)
BaudTickCnt <= 4'b0000 ;
case(BaudTickCnt)
4'b1000:BaudTick <= 1'b1;
default:BaudTick <= 1'b0;
endcase
end
2)数据发送器模块:在Baud16Tick的节拍下捕捉TXD_start的下降沿,之后将din8的数据存入缓冲器tbr中,再启动BaudTick脉冲并计数,在计数为4’b0000时发送停止位0,在4’b0001至4’b1000时发送数据位,并在之后两位发送奇偶校验位和停止位。没有发送是则发送空闲位1。校验每发一位就将parity进行异或数据位得到其值并发送。当发送停止位后,即将发送完成标志位TXD_done置1.程序如下:
always@(posedge clk)
begin
if(rst)
begin
{TxD_start0,TxD_start1} <= {1'b0,1'b0};
end
else
TxD_start0 <= TxD_start;
TxD_start1 <= TxD_start0;
end
assign start = TxD_start1&!TxD_start0;
always@(posedge clk or posedge rst)
begin
if(rst)
tbr<= 8'b0;
else if(BaudTick_EN&&BaudTick)
tbr <= TxD_data;
end
always @(posedge clk or posedge rst)
begin
if (rst)
BaudTick_EN <= 1'b0;
else if (start)
BaudTick_EN <= 1'b1 ;
else if (no_bits_tran == 4'b1100)
BaudTick_EN <= 1'b0 ;
end
always @(posedge clk or negedge rst )
begin
if (rst)
no_bits_tran <= 4'b0000;
else if (BaudTick&&Baud16Tick)
no_bits_tran <= no_bits_tran + 1 ;
else if (no_bits_tran ==4'b1100)
no_bits_tran <= 4'b0000 ;
end
always @(posedge clk or negedge rst)
if (rst)
begin
TxD <= 1'b1;
tbr <= 8'b0 ;
tsr <= 8'b0 ;
parity <= 1'b0 ;
TxD_done <= 1'b0;
end
else
begin
if(BaudTick)
begin
case (no_bits_tran)
4'b0000: begin
TxD <= 1'b0;
tsr <= tbr;
parity <= ^tsr ;
TxD_done <= 1'b0;
end
4'b0001: begin TxD <= tsr[0]; end
4'b0010: begin TxD <= tsr[1]; end
4'b0011: begin TxD <= tsr[2]; end
4'b0100: begin TxD <= tsr[3]; end
4'b0101: begin TxD <= tsr[4]; end
4'b0110: begin TxD <= tsr[5]; end
4'b0111: begin TxD <= tsr[6]; end
4'b1000: begin TxD <= tsr[7]; end
4'b1001: begin TxD <= parity; end
4'b1010: begin TxD <= 1'b1; end
4'b1011: begin
TxD_done <= 1'b1;
end
default: TxD_done <= 1'b0 ;
endcase
end
end
3)数据接收器模块:首先利用波特率16的采样脉冲对发送模块发送过来的串行数据进行下降沿采样,若采集到下降沿则开始启动BaudTick,并开启计数使能。在BaudTick的脉冲下进行计数并逐位读取发送端发过来的数据位,奇偶校验在case值为4’b0001至4’b1000时进行,当计数为4’b1001时发送判断校验位和检测停止位,在4’b1010时将奇偶校验和帧检查结果发送到端口中。程序如下所示:
always@(posedge clk or negedge rst)
begin
if(rst)
begin
{TxD_start0,TxD_start1} <= {1'b0,1'b0};
end
else
TxD_start0 <= TxD_start;
TxD_start1 <= TxD_start0;
end
assign start = TxD_start1&!TxD_start0;
always @(posedge clk or negedge rst )
begin
if (rst)
no_bits_tran <= 4'b0000;
else if (BaudTick&&Baud16Tick)
no_bits_tran <= no_bits_tran + 1 ;
else if (no_bits_tran ==4'b1100)
no_bits_tran <= 4'b0000 ;
End
always@(posedge clk or posedge rst)
begin
if(rst)
tbr<= 8'b0;
else if(BaudTick_EN&&BaudTick)
tbr <= TxD_data;
end
always @(posedge clk or negedge rst )
begin
if (rst)
no_bits_tran <= 4'b0000;
else if (BaudTick&&Baud16Tick)
no_bits_tran <= no_bits_tran + 1 ;
else if (no_bits_tran ==4'b1100)
no_bits_tran <= 4'b0000 ;
end
always @(posedge clk or negedge rst)
if (rst)
begin
TxD <= 1'b1; tbr <= 8'b0 ;
tsr <= 8'b0 ; parity <= 1'b0 ;
TxD_done <= 1'b0;
end
else
begin
if(BaudTick)
begin
case (no_bits_tran)
4'b0000: begin
TxD <= 1'b0; tsr <= tbr; parity <= ^tsr ;TxD_done <= 1'b0;
end
4'b0001: begin TxD <= tsr[0]; end
4'b0010: begin TxD <= tsr[1]; end
4'b0011: begin TxD <= tsr[2]; end
4'b0100: begin TxD <= tsr[3]; end
4'b0101: begin TxD <= tsr[4]; end
4'b0110: begin TxD <= tsr[5]; end
4'b0111: begin TxD <= tsr[6]; end
4'b1000: begin TxD <= tsr[7]; end
4'b1001: begin TxD <= parity; end
4'b1010: begin TxD <= 1'b1; end
4'b1011: begin
TxD_done <= 1'b1;
end
default: TxD_done <= 1'b0 ;
endcase
end
end
3)顶层文件设计:两模块之间用wire类型连接,公共端用分别在两个模块中连接。顶层端口定义最终需要的端口即可。顶层模块如下:
TxD_Module u1(
.clk(clk_sys),
.rst(rst_N),
.TxD_data(din8),
.TxD_done(TxDdne_rdn),
.TxD(TxD_RxD),
.TxD_start(TxD_start_in)
);
RxD_Module u2 (
.clk(clk_sys),
.rst(rst_N),
.rdn(TxDdne_rdn),
.RxD(TxD_RxD),
.RxD_data(dout8),
.parity_error(parity_err_out),
.framing_error(frame_err_out),
.RxD_data_ready(RxD_data_rdy)
);
6.Modelsim仿真验证
1)测试激励:高电平初始化后进行发送递加的数据,并观察输入输出数据的差异,以及奇偶校验位和帧检查的正确性。
initial
begin
clk_sys = 0;
rst_N = 1;
din8 = 0;
TxD_start_in = 0;
#100;
rst_N = 0;
repeat(100) begin
# 86800;
TxD_start_in = 1;
# 86800;
TxD_start_in = 0;
end
end
always #10 clk_sys = ~clk_sys;
always @(posedge TxD_start_in)
begin
din8 = din8 + 8'd1;
end
2)输入输出结果。激励文件和输出结果如下:
3) 结果分析:由上图可知
1 整个联合模块的并行输入与并行输出结果相同,接发送和接收正确。
2 奇偶校验位发现当数据为01010010时校验的结果为1,当数据为01010011时校验结果为0;由此可知奇偶校验正确
3 检查帧结果显示一致为0,而发送端的数据均为8位且停止位都为1。所以帧检查结果正确。