【协议时序】-UART-RS232串口通信-接收模块

一、设计文件

第一种写法:未使用状态机(参考开源骚客程序-SDRAM第一季)

`define SIM
module uart_rx
(
//    system signals
input                    sclk                    ,
input                    s_rst_n                ,
// uart interface
input                    rs232_rx                ,
//    output signals
output    reg [7:0]rx_data                ,// 8位的寄存器,对串口接收到的数据进行:串转并,使用位拼接
output    reg        po_flag                 // 拉高:接收模块完成数据接收,告诉其他模块可以来使用我接收到的数据了


);
//--------------------------------------------------------
//            difine parameter and internal signals
//--------------------------------------------------------
`ifndef SIM
localparam            BAUD_END            =            5207                    ;
`else
localparam            BAUD_END            =            56                        ;
`endif
localparam            BAUD_M            =            BAUD_END/2    -    1    ;
localparam            BIT_END            =            8                        ;

reg                    rx_r1                    ;
reg                    rx_r2                    ;
reg                    rx_r3                    ;// 打3拍、捕获rx下降沿——单bit信号跨时钟域处理
reg                    rx_flag                ;// 拉高:FPGA正在接收数据;以rx_r3波形为准
reg        [12:0]    baud_cnt                ;// 波特率计数器,表示串口发送一个bit所占用的系统时钟数,5208需要13位
reg                    bit_flag                ;// 波特率计数器记到中间值后立刻拉高(中间采样)
reg        [3:0]        bit_cnt                ;// 计数传了8位数据

wire                    rx_neg                ;// 定义rx的下降沿
//--------------------------------------------------------
//                          Main code
//--------------------------------------------------------

// 检测rx下降沿

assign        rx_neg        =            ~ rx_r2 & rx_r3            ; // ??:为什么不直接检测rx_r3的下降沿

// 打3拍处理
always@(posedge sclk)begin

rx_r1        <=        rs232_rx        ;
rx_r2        <=        rx_r1            ;
rx_r3        <=        rx_r2            ;

end

// 数据接收开始、结束的标志信号
always@(posedge sclk or negedge s_rst_n)begin
        if(s_rst_n == 1'b0)
                rx_flag    <=        1'b0                    ;
        else if(rx_neg == 1'b1)
                rx_flag    <=        1'b1                    ;
        else if(bit_cnt == 1'b0 && baud_cnt == BAUD_END)
                rx_flag    <=     1'b0                    ;    

end

// 波特率计数器记到中间值拉高
always@(posedge sclk or negedge s_rst_n)begin
        if(s_rst_n == 1'b0)
                bit_flag    <=        1'b0                    ;
        else if(baud_cnt == BAUD_M)
                bit_flag    <=        1'b1                    ;
        else
                bit_flag    <=        1'b0                    ;
        
end


// 波特率计数器

always@(posedge sclk or negedge s_rst_n)begin
        if(s_rst_n == 1'b0)
                baud_cnt    <=        1'b0                    ;
        else if(baud_cnt == BAUD_END)
                baud_cnt    <=        1'b0                    ;
        else    if(bit_flag == 1'b1)
                baud_cnt    <=        baud_cnt + 1'b1    ;
        else 
                baud_cnt  <=   1'b0                    ;
        
end

// 计数传到第几位数据
always@(posedge sclk or negedge s_rst_n)begin
        if(s_rst_n == 1'b0)
                bit_cnt    <=        1'b0                    ;
        else if(bit_cnt == BIT_END && bit_flag == 1'b1)
                bit_cnt    <=        1'b0                    ;
        else
                bit_cnt    <=        bit_cnt + 1'b1        ;
        
end

// 输入数据

always@(posedge sclk or negedge s_rst_n)begin
        if(s_rst_n == 1'b0)
                rx_data    <=        1'b0                                        ;
        else if(bit_cnt >=1'b1 && bit_flag == 1'b1)
                rx_data    <=        {rx_r2,rx_data[7:1]}                    ;//??:为啥是rx_r2和输入数据按位拼接
end

// 数据传输完成标志位

always@(posedge sclk or negedge s_rst_n)begin
        if(s_rst_n == 1'b0)
                po_flag    <=        1'b0                                        ;
        else if(bit_cnt == BIT_END && bit_flag == 1'b1)            //    
                po_flag    <=        1'b1                                        ;
        else
                po_flag    <=        1'b0                                        ;    
end




endmodule 

第二种写法:使用三段式状态机(参考黑金程序)

//================================================================================
//  Revision History:
//  Date          By            Revision    Change Description
//--------------------------------------------------------------------------------
//2017/8/1                    1.0          Original
//*******************************************************************************/
module uart_rx
#(
    parameter CLK_FRE = 50,      //clock frequency(Mhz)
    parameter BAUD_RATE = 115200 //serial baud rate ??????为什么是串行波特率
)
(
    input                        clk,              //clock input
    input                        rst_n,            //asynchronous reset input, low active 
    output reg[7:0]              rx_data,          //received serial data
    output reg                   rx_data_valid,    //received serial data is valid
    input                        rx_data_ready,    //data receiver module ready
    input                        rx_pin            //serial data input
);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       S_IDLE      = 1;
localparam                       S_START     = 2; //start bit
localparam                       S_REC_BYTE  = 3; //data bits
localparam                       S_STOP      = 4; //stop bit
localparam                       S_DATA      = 5;

reg[2:0]                         state;
reg[2:0]                         next_state;
reg                              rx_d0;            //delay 1 clock for rx_pin
reg                              rx_d1;            //delay 1 clock for rx_d0
wire                             rx_negedge;       //negedge of rx_pin
reg[7:0]                         rx_bits;          //temporary storage of received data
reg[15:0]                        cycle_cnt;        //baud counter
reg[2:0]                         bit_cnt;          //bit counter

assign rx_negedge = rx_d1 && ~rx_d0;

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        rx_d0 <= 1'b0;
        rx_d1 <= 1'b0;    
    end
    else
    begin
        rx_d0 <= rx_pin;
        rx_d1 <= rx_d0;
    end
end


always@(posedge clk or negedge rst_n)//第一段:同步时序,描述状态转移
begin
    if(rst_n == 1'b0)
        state <= S_IDLE;
    else
        state <= next_state;
end

always@(*) //(*)第二段:组合逻辑判断状态转移条件、描述状态转移规律
begin
    case(state)
        S_IDLE:
            if(rx_negedge)
                next_state <= S_START;
            else
                next_state <= S_IDLE;
        S_START:
            if(cycle_cnt == CYCLE - 1)//one data cycle 
                next_state <= S_REC_BYTE;
            else
                next_state <= S_START;
        S_REC_BYTE:
            if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)  //receive 8bit data
                next_state <= S_STOP;
            else
                next_state <= S_REC_BYTE;
        S_STOP:
            if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver
                next_state <= S_DATA;
            else
                next_state <= S_STOP;
        S_DATA:
            if(rx_data_ready)    //data receive complete
                next_state <= S_IDLE;
            else
                next_state <= S_DATA;
        default:
            next_state <= S_IDLE;
    endcase
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_data_valid <= 1'b0;
    else if(state == S_STOP && next_state != state)
        rx_data_valid <= 1'b1;
    else if(state == S_DATA && rx_data_ready)
        rx_data_valid <= 1'b0;
end

always@(posedge clk or negedge rst_n)//第三段:同步时序,描述每个状态的输出
begin
    if(rst_n == 1'b0)
        rx_data <= 8'd0;
    else if(state == S_STOP && next_state != state)
        rx_data <= rx_bits;//latch received data
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        begin
            bit_cnt <= 3'd0;
        end
    else if(state == S_REC_BYTE)
        if(cycle_cnt == CYCLE - 1)
            bit_cnt <= bit_cnt + 3'd1;
        else
            bit_cnt <= bit_cnt;
    else
        bit_cnt <= 3'd0;
end


always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        cycle_cnt <= 16'd0;
    else if((state == S_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
        cycle_cnt <= 16'd0;
    else
        cycle_cnt <= cycle_cnt + 16'd1;    
end
//receive serial data bit data
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_bits <= 8'd0;
    else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
        rx_bits[bit_cnt] <= rx_pin;
    else
        rx_bits <= rx_bits; 
end
endmodule 

 

二、测试文件

`timescale 1ns/1ns
module tb_uart_rx;

reg                    sclk            ;
reg                    s_rst_n        ;
reg                    rs232_rx        ;

wire                    po_flag        ;
wire            [7:0] rx_data        ;

reg            [7:0] mem_a[3:0]    ; //存储器,位宽8bit,深度4bit

initial begin

    sclk        =        1'b1            ;
    s_rst_n    =        1'b0            ;
    rs232_rx    =        1'b1            ;
    #100                                ;
    s_rst_n    =        1'b1            ;
    #100                                ;
    tx_byte()                        ;
    
    
end 
    
always # 10 sclk = ~ sclk    ;

// 读入数据

initial $readmemh ("./tx_data.txt", mem_a)        ; //将tx_data.txt文件汇总的输入传入定义好的mem_a存储器中,存放:55、12、34、aa


// 发送数据
    
task tx_byte();
        integer i;
        for(i=0;i<4; i=i+1)begin
        
            tx_bit(mem_a[i]); // 任务中调用另一个任务
        
        end
    
endtask
        
task            tx_bit(    //    任务名
                            input        [7:0]     data    // 声明输入端口
                    );
                    
                integer    i    ;
                
                for(i=0 ; i<10 ; i=i+1)begin
                
                    case(i)
                            0:        rs232_rx        <=        1'b0            ;
                            1:        rs232_rx        <=        data[0]        ;
                            2:        rs232_rx        <=        data[1]        ;
                            3:        rs232_rx        <=        data[2]        ;
                            4:        rs232_rx        <=        data[3]        ;
                            5:        rs232_rx        <=        data[4]        ;
                            6:        rs232_rx        <=        data[5]        ;
                            7:        rs232_rx        <=        data[6]        ;
                            8:        rs232_rx        <=        data[7]        ;
                            9:        rs232_rx        <=        1'b1            ;
                    endcase
                    # 11200;
                    
                end              
                
    endtask


uart_rx a1
(

.sclk(sclk)                            ,
.s_rst_n(s_rst_n)                     ,

.rs232_rx(rs232_rx)                ,

.rx_data(rx_data)                    ,// 8位的寄存器,对串口接收到的数据进行:串转并,使用位拼接
.po_flag(po_flag)                     // 拉高:接收模块完成数据接收,告诉其他模块可以来使用我接收到的数据了


);


endmodule 

 

 

三、波形图

波形图还有一点问题

四、RTL图

posted @ 2022-03-30 20:45  刘小颜  阅读(424)  评论(0)    收藏  举报