Serial port (UART) receiving module-verilog implementation-VCS simulation

1. Main points

Refer to the previous sending module https://blog.csdn.net/a1254484594/article/details/100190162

Second, realize

1. Architecture: Implemented using a finite state machine, which mainly includes two parts: data sampling and state transition.

Data sampling is generally sampled in the middle of each data bit because it is the furthest away from the rising or falling edge at this time.

The state machine can define 11 states, corresponding to a frame of data, according to the time sequence: WAIT waiting for the start bit state, STARD start bit, D0, D1, D2, D3, D4, D5, D6, D7 8bit data, END stop bit. Use a counter to time the time required for each bit under a certain baud rate, and transfer between states.

2. Create a new uart_rx.v file and use Verilog to describe

`timescale 1ns/1ps
module uart_rx(
    input clk,
    input nrst,
    input rx_en,
    input rx_pin,
    output reg [7:0]rx_data,
    output reg rx_done
);

parameter INPUT_CLK = 125000000 , BUDO = 115200;
localparam B_CNT_MAX = (INPUT_CLK/BUDO)-1;//波特率计数器最大值

parameter [3:0]
    WAIT = 4'd12,   //等待起始位状态
    STARD= 4'd13,   //起始位
    END  = 4'd8,    //停止位
    D0 = 0, D1 = 1, D2 = 2, D3 = 3, D4 = 4, D5 = 5, D6 = 6, D7 = 7;//8bit数据

reg [3:0]CS;    //状态
reg [10:0]b_cnt; //用来产生波特率时钟

The above defines a uart_tx module, defines the port signal, and defines the required parameters and signals

//状态转移逻辑
always @(posedge clk) begin
    if (!nrst) begin//复位
        CS <= WAIT;
        b_cnt <= 'd0;
    end
    else if(rx_en) begin
        case(CS)
            WAIT:/*等待起始位*/
                begin
                    if(!rx_pin) CS <= STARD;//rx被拉低后进入起始位
                    else CS <= CS;
                end
            STARD:/*起始位*/
                begin
                     if (b_cnt == B_CNT_MAX) begin//计数满1bti时间,计数器清零,进入第一bit的接收
                        CS <= 4'd0; //转移到接收第一bit的状态
                        b_cnt <= 'd0;
                    end
                    else begin //计数中
                        b_cnt <= b_cnt + 1'b1;
                        CS <= CS;
                    end
                end
            END:/*停止位*/
                begin
                    if (b_cnt == B_CNT_MAX) begin//计数满1bti时间,计数器清零,进入等待状态
                        CS <= WAIT; //转移到等待状态
                        b_cnt <= 'd0;
                    end
                    else begin //计数中
                        b_cnt <= b_cnt + 1'b1;
                        CS <= CS;
                    end
                end
            D0,D1,D2,D3,D4,D5,D6,D7:/*采样数据*/
                begin
                    if (b_cnt == B_CNT_MAX) begin//计数满1bti时间,计数器清零,进入下一bit
                        CS <= CS + 1'b1; //转移到下一bit
                        b_cnt <= 'd0;
                    end
                    else begin //计数中
                        b_cnt <= b_cnt + 1'b1;
                        CS <= CS;
                    end
                end
            default:
                begin
                    CS <= CS;
                    b_cnt <= 'd0;
                end
        endcase
    end //end else if (rx_en)
end

In the state transition part, the transition operation is performed when rx_en is valid, and the register b_cnt is used to count to realize the sequential transition of waiting for the start bit, start bit, 8 data bits, and stop bit.

//根据CS状态和b_cnt计数器值采样rx_pin
always @(posedge clk) begin
    if (!nrst) begin//复位
        rx_data <= 8'd0;
        rx_done <= 1'b0;
    end
    else if (CS < 'd8) begin
        rx_done <= 1'b0;
        if (b_cnt == B_CNT_MAX/2)//在中点采样
            rx_data[CS] <= rx_pin;
        else
            rx_data <= rx_data;
    end
    else if (CS == 'd8) begin
        if (!rx_pin) //停止位错误
            rx_done <= 1'b0;
        else
            rx_done <= 1'b1;
    end
    else begin
        rx_data <= rx_data;
        rx_done <= rx_done;
    end
end

endmodule // uart_rx

According to the status register CS, the value of the counting register b_cnt is judged, and sampling is performed at the intermediate moment when b_cnt is equal to half of the maximum value.

So far the receiving module is complete.

3. Test file writing, VCS simulation

1. Test using the sending code of the previous article, and then instantiate a receiving module on this basis, the code is as follows

`timescale 1ns/1ps
module usart_tb();

reg nrst;
reg clk;

reg en_tx;
reg [7:0] tx_data;
wire tx_pin,tx_done;
reg [7:0]tx_cnt;

reg en_rx;
wire [7:0] rx_data;
wire rx_done;

//实例化
uart_tx uart_tx(
    .clk(clk),
    .nrst(nrst),
    .tx_en(en_tx),
    .tx_data(tx_data),
    .tx_pin(tx_pin),
    .txdone(tx_done)
);

uart_rx uart_rx(
    .clk(clk),
    .nrst(nrst),
    .rx_en(en_rx),
    .rx_pin(tx_pin),//txpin连接到rxpin
    .rx_data(rx_data),
    .rx_done(rx_done)
);

//产生125Mhz的时钟
initial begin
    clk = 0;
    forever begin
        #4;
        clk = ~clk; 
    end
end

initial begin
    en_tx = 0;
    tx_data = 8'b0;
    tx_cnt = 'd0;
    nrst = 1;
    #100;
    nrst = 0;//复位信号
    #103;
    nrst = 1;
    tx_data = 'd64;
    en_rx = 1;
end

//产生循环发送的信号
always @(negedge clk) begin
    if (nrst) begin
        if (tx_done) begin
            if (en_tx)//刚刚发送完成
                en_tx <= 1'b0;
            else begin//发送完成一段时间
                if (tx_cnt == 'd250) begin
                    tx_cnt <= 'd0;
                    en_tx <= 1'b1;//重启发送
                end
                else
                    tx_cnt <= tx_cnt + 1'b1;
            end
        end
        else begin
            en_tx <= en_tx;
            tx_cnt <= tx_cnt;
        end
    end
end
endmodule // usart_tb

 

Guess you like

Origin blog.csdn.net/a1254484594/article/details/100676080