异步串口通信

UART 和 RS232

1、UART 的全称叫做通用异步收发传输器。将数据在串行通信和并行通信间的传 输转换。通俗的讲就是把多比特的数据转化为单比特的数据,或者把单比特的数 据转化为多比特的数据。工作原理是将数据的每个 bit 一位接一位地传输。

2、UART 是一种通用串行数据总线,用于异步通信。该总线双向通信,可以实现 全双工传输和接收。

3、RS232 是 UART 的一种,是目前最常用的一种串行通讯接口,用于 pc 机跟外 部板级通信。RS232 通信协议 1、rs232 是 uart 的一种,有两根线,分别是 rx 和 tx,这两根线都是 1 比特位 宽的。其中 rx 是接收线,tx 是发送线。 2、rx,位宽为 1 比特,pc 机通过串口往 FPGA 发 8 比特数据时,FPGA 通过串口 线 rx 一位一位地接收,从最低位到最高位依次接收,最后在 FPGA 里面位拼接成 8 比特数据。

4、在不发送或者不接收数据的情况下,rx 和 tx 处于空闲状态,此时 rx 和 tx 线都保持高电平(1),如果有数据传递,首先会有一个起始位(0),然后是 8 比特的数据位,接着有 1 比特的停止位(1),如果停止位以后不再发数据,将进入空闲状态,否则又将数据线拉低(进入起始位状态)。

5、波特率:在串口通信时的速率,单位时间内载波变化的次数,这里选用的是 9600Bd,即发送一比特数据需要的时间为 1/9600 秒。

6、用串口发送或者接收数据(起始位、数据位、停止位)时,每发送或者接收一 位数据的时间都需要 1 个波特,即 1/9600 秒。

7、串口发送或者接收一比特数据的时间为一个波特(1/9600),因此如果用 50M 的系统时钟来计数,就需要记数 cnt=(1/9600s)/20ns≈5208 个系统时钟,才再 次发送或者接收下一个数据。

8、上位机通过串口发 8 比特数据时,会自动在发 8 位有效数据前发一个波特时 间的起始位,也会自动在发完 8 位有效数据后发一个停止位。同理,串口助手接 收 fpga 发送的数据前,必须检测到一波特的起始位才会接收数据,接收完数据 后,再接收一个停止位,所以 FPGA 通过串口除了发数据以外,还要发起始位和 停止位。

设计要求:

写一个测试回环:上位机由串口助手通过 rx 线往 FPGA 发 8 比特数据,当 FPGA 接收到 8 比特数据后,再通过 tx 线把接收到的 8 比特数据给上位机发回去,要 求上位机接收到的数据和上位机发送的数据一样,并且保证连续发送也没问题。 rx 和 tx 写在两个单独的模块里面。

顶层模块设计

 

顶层模块示意图:

 

顶层模块代码实现:

module uart_top(
    input         wire          clk,
    input         wire          rst_n,
    input         wire          rx,
    input         wire          tx
    );

wire [7:0]   po_data;
wire         po_flag;

    uart_rx uart_rx_inst(
    .clk(clk),
    .rst_n(rst_n),
    .rx(rx),
    .po_data(po_data),
    .po_flag(po_flag)
    );
    uart_tx uart_tx_inst(
    .clk(clk),
    .rst_n(rst_n),
    .pi_flag(po_flag),
    .pi_data(po_data),
    .tx(tx)
    );
endmodule

                                                                           接收模块设计

接收模块示意图:

 

接收模块波形图:

 

接收模块代码实现:

module uart_rx(
    input       wire        clk,
    input       wire        rst_n,
    input       wire        rx,
    output      reg  [7:0]  po_data,
    output      reg         po_flag
    );

reg        rx1;
reg        rx2;
reg        rx2_reg;
reg        rx_flag;
reg        bit_flag;

reg  [3:0] bit_cnt;
reg  [12:0] baud_cnt;

always @(posedge clk) begin
    rx1<=rx;
    rx2<=rx1;
    rx2_reg<=rx2;
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        baud_cnt<='d0;
    end
    else if(baud_cnt=='d5207) begin
        baud_cnt<='d0;
    end
    else if(bit_cnt=='d8 &&  bit_flag==1'b1) begin
        baud_cnt<='d0;

   end
    else if (rx_flag==1'b1) begin
        baud_cnt<=baud_cnt+1'b1;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        bit_flag<=1'b0;
    end
    else if (baud_cnt=='d2603) begin
        bit_flag<=1'b1;
    end
    else begin
        bit_flag<=1'b0;
    end

end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        bit_cnt<='d0;
    end
    else if(bit_cnt=='d8) begin
        bit_cnt<='d0;
    end
    else if (bit_flag==1'b1) begin
        bit_cnt<=bit_cnt+1'b1;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        rx_flag<=1'b0;
    end
    else if (rx2_reg==1'b1 && rx2==1'b0) begin
        rx_flag<=1'b1;
    end
    else if(bit_cnt=='d8 &&  bit_flag==1'b1) begin
        rx_flag<=1'b0;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        po_data<='d0;
    end
    else if (bit_flag==1'b1 && bit_cnt>=1'b1) begin
        po_data<={rx2,po_data[7:1]};
    end
end
always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        po_flag<=1'b0;
    end
    else if (bit_cnt=='d8 &&  bit_flag==1'b1) begin
        po_flag<=1'b1;
    end
    else begin
        po_flag<=1'b0;
    end
end
endmodule

发送模块设计

发送模块示意图:

 

发送模块波形图:

 发送模块代码实现:

module uart_tx(
    input     wire           clk,
    input     wire           rst_n,
    input     wire           pi_flag,
    input     wire  [7:0]    pi_data,
    output    reg            tx
    );
reg   [7:0]    data_reg;//data_reg,数据缓存,避免上个模块输出变量发生变化而影响

reg            tx_flag;
reg            bit_flag;
reg   [3:0]    bit_cnt;
reg   [12:0]   baud_cnt;

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        bit_flag<=1'b0;
    end
    else if (baud_cnt==5206) begin
        bit_flag<=1'b1;
    end
    else begin
        bit_flag<=1'b0;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        bit_cnt<='d0;
    end
    else if(bit_cnt=='d8 && bit_flag==1'b1 ) begin
        
    end
    else if (bit_flag==1'b1) begin
        bit_cnt<=bit_cnt+1'b1;
    end
end
always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        data_reg<='d0;
    end
    else if (pi_flag==1'b1) begin
        data_reg<=pi_data;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        tx_flag<=1'b0;
    end
    else if (pi_flag==1'b1) begin
        tx_flag<=1'b1;
    end
    else if(bit_cnt=='d8 && bit_flag==1'b1) begin
        tx_flag<=1'b0;
    end
end

always @(posedge clk or posedge rst_n) begin
    if (!rst_n) begin
        tx<=1'b1;
    end
    else if(pi_flag==1'b1) begin
        tx<=1'b0;
    end
    else if(bit_flag==1'b1 && bit_cnt<=7) begin
        tx<=data_reg[bit_cnt];
    end
    else if(bit_cnt=='d8 && bit_flag==1'b1) begin
        tx<=1'b1;
    end
end

endmodule


版权声明:本文为qq_45565330原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。