前一篇讲了串口发送,这一篇把串口接收补上。原本小鱼有水同学想这么做的,串口接收到什么就发送什么,无奈,小鱼有水写的发送模块和接收模块没对上号,导致上位机接收的字节数和发送的字节数不等,很郁闷,正应了那句话:时序是事先设计出来的,不是事后测出来的,更不是凑出来的。这个给小鱼有水同学好好上了一课。
既然这条道行不通,小鱼有水就想了另一个办法,用数码管显示接收到的字节数。
首先给出串口接收代码如下:
CODE:
/*
作者:小鱼有水
本设计只限于学习,欢迎大家拍砖
*/
`timescale 1ns/1ns
module async_receiver(rst_n,clk,rxd,rxd_data_ready,rxd_data);
input rst_n,clk;
input rxd;
output reg rxd_data_ready;
output[7:0] rxd_data;
parameter clk_prescaler=81; //时钟分频系数,本设计波特率选取的是19200,数据位为8位,停止位为1位
reg rxd_start; //串口接收标志位,如果该位为1'b1,则表示正在接收数据
reg[7:0] cnt_div; //分频计数器,产生16倍波特率的时钟
reg clk16; //16倍波特率的时钟
reg[3:0] cnt_div16; //16倍分频计数器
reg[3:0] cnt_bit; //累加已经接收到的一帧数据的位数
reg[2:0] collect_bit; //采集数据缓冲区,3取2算法
reg[9:0] rxd_shift_reg,rxd_hold_reg; //接收移位寄存器和接收保持寄存器,保存串口接收到的数据
always@(negedge rst_n,posedge clk)
begin
if(!rst_n)
begin
cnt_div<=8'd0;
clk16<=1'b0;
end
else
begin
if(cnt_div==clk_prescaler)
begin
clk16<=~clk16;
cnt_div<=8'd0;
end
else
begin
cnt_div<=cnt_div+1'd1;
end
end
end
always@(negedge rst_n,posedge clk16)
begin
if(!rst_n)
begin
rxd_start<=1'b0;
cnt_div16<=4'h0;
cnt_bit<=4'h0;
rxd_data_ready<=1'b0;
end
else
if(rxd_start==1'b0)
begin
if(rxd==1'b0)
begin
rxd_start<=1'b1;
cnt_div16<=4'h0;
cnt_bit<=4'h0;
rxd_data_ready<=1'b0;
end
else
begin
cnt_div16<=4'h0;
cnt_bit<=4'h0;
rxd_data_ready<=1'b0;
end
end
else
begin
if(cnt_bit<=4'd9)
begin
case(cnt_div16)
4'd0: cnt_div16<=cnt_div16+1'd1;
4'd1: cnt_div16<=cnt_div16+1'd1;
4'd2: cnt_div16<=cnt_div16+1'd1;
4'd3: cnt_div16<=cnt_div16+1'd1;
4'd4: cnt_div16<=cnt_div16+1'd1;
4'd5: cnt_div16<=cnt_div16+1'd1;
4'd6: begin
collect_bit[0]<=rxd;
cnt_div16<=cnt_div16+1'd1;
end
4'd7: begin
collect_bit[1]<=rxd;
cnt_div16<=cnt_div16+1'd1;
end
4'd8: begin
collect_bit[2]<=rxd;
cnt_div16<=cnt_div16+1'd1;
end
4'd9: begin
rxd_shift_reg[8:0]<=rxd_shift_reg[9:1];
rxd_shift_reg[9]<=(collect_bit[0] & collect_bit[1]) |
(collect_bit[0] & collect_bit[2]) |
(collect_bit[1] & collect_bit[2]);
cnt_bit<=cnt_bit+1'b1;
cnt_div16<=cnt_div16+1'd1;
end
4'd10: cnt_div16<=cnt_div16+1'd1;
4'd11: cnt_div16<=cnt_div16+1'd1;
4'd12: cnt_div16<=cnt_div16+1'd1;
4'd13: cnt_div16<=cnt_div16+1'd1;
4'd14: cnt_div16<=cnt_div16+1'd1;
default: cnt_div16<=4'd0;
endcase
if((cnt_bit==1'b1) && (rxd_shift_reg[9]==1'b1)) //假的起始位,丢弃
begin
rxd_start<=1'b0;
end
end
else
begin
rxd_start<=1'b0;
rxd_data_ready<=1'b1;
rxd_hold_reg<=rxd_shift_reg;
end
end
end
assign rxd_data=rxd_hold_reg[8:1];
endmodule再给出数码管显示接收到的字节数代码,如下:
CODE:
`timescale 1ns/1ns
module UART(rst_n,clk50M,rxd,hex0,hex1,hex2,hex3);
input rst_n,clk50M;
input rxd;
//output txd;
output[6:0] hex0,hex1,hex2,hex3;
wire rxd_data_ready;
wire[7:0] rxd_data;
async_receiver u0(.rst_n(rst_n),.clk(clk50M),.rxd(rxd),
.rxd_data_ready(rxd_data_ready),.rxd_data(rxd_data));
reg[3:0] dig0,dig1,dig2,dig3;
SEG7_LUT u1(.Dig_in(dig0),.Seg_o(hex0));
SEG7_LUT u2(.Dig_in(dig1),.Seg_o(hex1));
SEG7_LUT u3(.Dig_in(dig2),.Seg_o(hex2));
SEG7_LUT u4(.Dig_in(dig3),.Seg_o(hex3));
/*
reg txd_start;
reg[7:0] txd_data;
wire txd_busy;
async_transmitter u1(.rst_n(rst_n),.clk(clk50M),.txd_start(txd_start),
.txd_data(txd_data),.txd_busy(txd_busy),.txd(txd));
*/
reg rxd_ready1,rxd_ready2,rxd_ready3;
wire rxd_ready4;
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
rxd_ready1<=1'b0;
rxd_ready2<=1'b0;
rxd_ready3<=1'b0;
end
else
begin
rxd_ready1<=rxd_data_ready;
rxd_ready2<=rxd_ready1;
rxd_ready3<=rxd_ready2;
end
end
/*
rxd_data_ready信号相对于clk50M时钟来说,是慢速时钟域的信号,这里采用检测上升沿的方法
*/
assign rxd_ready4= rxd_ready2 & (!rxd_ready3);
always@(negedge rst_n,posedge clk50M)
begin
if(!rst_n)
begin
dig0<=4'h0;
dig1<=4'h0;
dig2<=4'h0;
dig3<=4'h0;
end
else
begin
if(rxd_ready4==1'b1)
begin
if(dig0==8'h9)
begin
if(dig1==8'h9)
begin
if(dig2==8'h9)
begin
dig3<=dig3+1'b1;
dig2<=4'h0;
end
else
dig2<=dig2+1'b1;
dig1<=4'h0;
end
else
dig1<=dig1+1'b1;
dig0<=4'h0;
end
else
dig0<=dig0+1'b1;
end
end
end
endmodule关于数码管驱动代码,前面已经给出。下面一幅是上位机已发送字节数的图: