uart RS232通信


波特率指的是异步时钟的频率。

source code

top module

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/04/28 15:48:05
// Design Name: 
// Module Name: uart
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module uart(
    input           sys_clk,            //外部50M时钟
    input           sys_rst_n,          //外部复位信号,低有效
    input           uart_rxd,           //UART接收端口
    output          uart_txd            //UART发送端口
    );
    reg [7:0] fifo[7:0];
    reg [2:0] read_ptr;
    reg [2:0] write_ptr;
    reg [7:0] send_data;
    wire [7:0] uart_data;
    wire send_busy;
    reg send_en;
    wire uart_doing;
    reg uart_doing_d1,uart_doing_d0;
    wire uart_doing_neg;
    assign uart_doing_neg = uart_doing_d0 &!uart_doing_d1;
    always @(posedge sys_clk or negedge sys_rst_n) begin
         if(!sys_rst_n)begin send_en<=0; read_ptr<=3'd0;end 
         else
            begin
                if(send_en)send_en<=0;
                else if(write_ptr!=read_ptr && !send_busy)
                    begin
                        send_en<=1;
                        send_data<=fifo[read_ptr];
                        read_ptr<=read_ptr+3'd1;
                    end
            end
    end
    always @(posedge sys_clk or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
        begin
            uart_doing_d0<=0;
            uart_doing_d1<=0;
        end
        else
        begin
            uart_doing_d0<=uart_doing_d1;
            uart_doing_d1<=uart_doing;
        end
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin
        if(!sys_rst_n)write_ptr<=3'd0;
        else if(uart_doing_neg &&(write_ptr+3'd1)!=read_ptr)
        begin
            fifo[write_ptr]<=uart_data;
            write_ptr<=write_ptr+3'd1;
        end
    end
    
    uart_send send1(.sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    .send_en(send_en),
    .send_data(send_data),
    .uart_txd(uart_txd),
    .send_busy(send_busy));

    uart_recv recv1 (.sys_clk(sys_clk),
    .sys_rst_n(sys_rst_n),
    .uart_rxd(uart_rxd),   
    .uart_doing(uart_doing), 
    .uart_data(uart_data));
endmodule

uart_send module

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/04/28 16:08:19
// Design Name: 
// Module Name: uart_send
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////
module uart_send(
    input sys_clk,
    input sys_rst_n,
    input send_en,
    input [7:0] send_data,
    output reg uart_txd,
    output reg send_busy
    );
    reg [7:0] tx_data;
    reg send_en_d0,send_en_d1;
    wire en_neg;
    parameter clk_fre=50000000;
    parameter fps=115200;
    parameter fps_count=clk_fre/fps;
    reg [15:0] clk_count;
    reg [4:0] num_count;
    assign en_neg = send_en_d0 & (!send_en_d1);
    always @(posedge sys_clk or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
        begin
            send_en_d0<=0;
            send_en_d1<=0;
        end
        else
        begin
            send_en_d0<=send_en_d1;
            send_en_d1<=send_en;
        end
    end
    always @(posedge sys_clk or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
        begin
            send_busy<=0;
            clk_count<=16'd0;
            num_count<=5'd0;
        end
        else if(en_neg)
        begin
            send_busy<=1;
            tx_data<=send_data;
            clk_count<=16'd0;
            num_count<=5'd0;
        end
        else if(send_busy)
        begin
            if(clk_count==fps_count-1) 
            begin 
                clk_count<=16'd0;
                if(num_count==5'd9)begin num_count<=5'd0;send_busy<=0; end
                else num_count<=num_count+1;
            end
            else clk_count<=clk_count+1; 
        end
    end
    always @(posedge sys_clk or negedge sys_rst_n) begin        
    if (!sys_rst_n)  
        uart_txd <= 1'b1;        
    else if (send_busy)
        case(num_count)
            4'd0: uart_txd <= 1'b0;         //起始位 
            4'd1: uart_txd <= tx_data[0];   //数据位最低位
            4'd2: uart_txd <= tx_data[1];
            4'd3: uart_txd <= tx_data[2];
            4'd4: uart_txd <= tx_data[3];
            4'd5: uart_txd <= tx_data[4];
            4'd6: uart_txd <= tx_data[5];
            4'd7: uart_txd <= tx_data[6];
            4'd8: uart_txd <= tx_data[7];   //数据位最高位
            4'd9: uart_txd <= 1'b1;         //停止位
            default: ;
        endcase
    else 
        uart_txd <= 1'b1;                   //空闲时发送端口为高电平
    end
endmodule

uart_recv module

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/04/29 09:17:28
// Design Name: 
// Module Name: uart_recv
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_recv(
    input			  sys_clk,                  //系统时钟
    input             sys_rst_n,                //系统复位,低电平有效
    input             uart_rxd,                 //UART接收端口
    output  reg       uart_doing,                //接收一帧数据完成标志
    output  reg [7:0] uart_data                 //接收的数据
    );
    reg uart_rxd_d0;
    reg uart_rxd_d1;
    parameter clk_fre=50000000;
    parameter fps=115200;
    parameter fps_count=clk_fre/fps;
    reg [15:0] clk_count;
    reg [4:0] num_count;
    wire uart_rxd_neg;
    assign uart_rxd_neg = uart_rxd_d0 & (!uart_rxd_d1);
    always @(posedge sys_clk or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
        begin
            uart_rxd_d0<=0;
            uart_rxd_d1<=0;
        end
        else
        begin
            uart_rxd_d0<=uart_rxd_d1;
            uart_rxd_d1<=uart_rxd;
        end
    end
    always @(posedge sys_clk or negedge sys_rst_n)
    begin
        if(!sys_rst_n)
        begin
            clk_count<=16'd0;
            num_count<=5'd0;
            uart_doing<=0;
        end
        else if(uart_rxd_neg && !uart_doing)
        begin
            clk_count<=16'd1;
            num_count<=5'd0;
            uart_doing<=1;
        end
        else if(uart_doing)
        begin
            if(clk_count==fps_count-1) 
            begin 
                clk_count<=16'd0;
                if(num_count==5'd9)begin num_count<=5'd0;end
                else num_count<=num_count+1;
            end
            else clk_count<=clk_count+1; 
            if(clk_count==fps_count/2)
            begin
                case(num_count)
                4'd1: uart_data[0] <= uart_rxd;   //数据位最低位
                4'd2: uart_data[1] <= uart_rxd;
                4'd3: uart_data[2] <= uart_rxd;
                4'd4: uart_data[3] <= uart_rxd;
                4'd5: uart_data[4] <= uart_rxd;
                4'd6: uart_data[5] <= uart_rxd;
                4'd7: uart_data[6] <= uart_rxd;
                4'd8: uart_data[7] <= uart_rxd;   //数据位最高位
                4'd9: begin uart_doing <= 0;clk_count<=16'd0;num_count<=5'd0;end 
                default: ;
                endcase
            end
        end
    end
endmodule

xdc

create_clock -period 20.000 -name clk [get_ports sys_clk]
set_property -dict {PACKAGE_PIN U18 IOSTANDARD LVCMOS33} [get_ports sys_clk]
set_property -dict {PACKAGE_PIN N16 IOSTANDARD LVCMOS33} [get_ports sys_rst_n]
set_property -dict {PACKAGE_PIN T19 IOSTANDARD LVCMOS33} [get_ports uart_rxd]
set_property -dict {PACKAGE_PIN J15 IOSTANDARD LVCMOS33} [get_ports uart_txd]

仿真文件

仿真参考意义不大,真正调试还得看开ILA。

uart_recv_test

module uart_recv_test;
reg sys_clk;
reg sys_rst_n;
reg uart_rxd;
wire uart_doing;
wire [7:0] uart_data;
initial begin
    sys_clk = 1'b0;
    #(2);
    forever
        #(2) sys_clk = ~sys_clk;
end
initial begin
    sys_rst_n = 1'b0;
    uart_rxd = 1'b1;
    #4;
    sys_rst_n = 1'b1;
    #4;
    uart_rxd = 1'b0;
    #40
    uart_rxd = 1'b1;
end

uart_recv recv1 (.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.uart_rxd(uart_rxd),   
.uart_doing(uart_doing), 
.uart_data(uart_data)   
);
endmodule

uart_send_test

module uart_test;
reg sys_clk;
reg sys_rst_n;
reg send_en;
reg [7:0] send_data;
wire uart_txd;
wire send_busy;
initial begin
      sys_clk= 1'b0;
      #(2);
      forever
         #(2) sys_clk = ~sys_clk;
end
initial
begin
    sys_rst_n=0;
    send_en=0;
    send_data=7'd60;
    #2 sys_rst_n=1;
    #10 send_en=1;
    #4 send_en=0;
end
uart_send send1(.sys_clk(sys_clk),
.sys_rst_n(sys_rst_n),
.send_en(send_en),
.send_data(send_data),
.uart_txd(uart_txd),
.send_busy(send_busy));
endmodule
posted @ 2023-05-12 10:42  心比天高xzh  阅读(21)  评论(0)    收藏  举报