[讨论] FPGA初步之串口接收 代码分享

gauson   2009-12-10 10:54 楼主
前一篇讲了串口发送,这一篇把串口接收补上。原本小鱼有水同学想这么做的,串口接收到什么就发送什么,无奈,小鱼有水写的发送模块和接收模块没对上号,导致上位机接收的字节数和发送的字节数不等,很郁闷,正应了那句话:时序是事先设计出来的,不是事后测出来的,更不是凑出来的。这个给小鱼有水同学好好上了一课。
既然这条道行不通,小鱼有水就想了另一个办法,用数码管显示接收到的字节数。
首先给出串口接收代码如下:

/*
作者:小鱼有水
本设计只限于学习,欢迎大家拍砖
*/
`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


再给出数码管显示接收到的字节数代码,如下:
`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

回复评论

暂无评论,赶紧抢沙发吧
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复