fpga项目: uart收发通信 - minichao9901/TangNano-20k-Zynq-7020 GitHub Wiki

1)说明

  • 完全自己手画时序图,完全自己实现。
  • 采用了状态机的方法。代码是从spi/mcu修改过来的,感觉这种写法可以统一。
  • 写一个通用的gen_tx_data.v,每10ms发送一次data和start_pulse,这个可以用于测试任意接口。我们先用它测试uart_tx.v,测试完了后,再用uart_tx.v的输出去测试uart_rx.v,形成一个回环测试。这也算一个小技巧吧。

2)时序图

uart_tx时序图

image

uart_rx时序图(注意rx_s和rx_ss是用于跨时钟域同步)

image

3)代码

代码结构

image

代码如下:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 19:16:41
// Design Name: 
// Module Name: rs232
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module rs232(
    input clk,
    input rst,
    
    input rx, 
    output tx
);

wire [7:0] pi_data; 
wire [7:0] po_data; 

assign rst_n=~rst;
    
uart_tx 
#(.FCLK(27_000_000),
.BPS(115200)
)
u_uart_tx(
    .clk(clk),
    .rst_n(rst_n),

    .pi_start_pulse(end_pulse_rx),    
    .pi_data(po_data),          
    
    .tx(tx),
    .end_pulse(end_pulse_tx)
    ); 
    
uart_rx 
#(.FCLK(27_000_000),
.BPS(115200)
)
u_uart_rx(
    .clk(clk),
    .rst_n(rst_n),
    
    .rx(rx),  
    .po_data(po_data),          
    .end_pulse(end_pulse_rx)
    );       

endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 18:34:12
// Design Name: 
// Module Name: uart_rx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


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


parameter FCLK=50_000_000;
parameter BPS=9600;
parameter CNT_MAX=FCLK/BPS-1;

parameter IDLE=3'b001;
parameter CMD=3'b010;
parameter DATA=3'b100;

reg [12:0] baud_cnt;  //50MHz/9600=5208
reg [3:0] bit_cnt;
reg [2:0] state;
reg rx_s;
reg rx_ss;
reg rx_sss;
wire end_pulse_r;
reg [7:0] data_r;

//sync
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
    rx_s<=0;
    rx_ss<=0;
    rx_sss<=0;
 end
else begin
    rx_s<=rx;
    rx_ss<=rx_s;
    rx_sss<=rx_ss;
end

//start_pulse
assign start_pulse=(~rx_ss)&rx_sss;

//baud_cnt
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    baud_cnt<=0;
 else if(start_pulse && state==IDLE)
    baud_cnt<=0;
 else if(baud_cnt==CNT_MAX)
    baud_cnt<=0;
 else if(state!=IDLE)
    baud_cnt<=baud_cnt+1;
    
 //end_pulse_r
assign end_pulse_r=(bit_cnt==8)&&(baud_cnt==CNT_MAX);

//cnt_bytes
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    bit_cnt<=0;
else if(bit_cnt==8 && baud_cnt==CNT_MAX)
    bit_cnt<=0;
else if(baud_cnt==CNT_MAX)
    bit_cnt<=bit_cnt+1;

//state
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    state<=IDLE;
else case(state)
        IDLE: if(start_pulse)
                state<=DATA;
        DATA: if(bit_cnt==8 && baud_cnt==CNT_MAX)
                state<=IDLE;
        default: state<=state;
    endcase
    
//data_r
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    data_r<=8'h00;  
 else if(state==DATA  && baud_cnt==CNT_MAX/2 && (bit_cnt>=1 && bit_cnt<=8))
    data_r<={rx_sss,data_r[7:1]};

//po_data
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    po_data<=8'h00;  
else if(end_pulse_r)
    po_data<=data_r;
    
//end_pulse
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    end_pulse<=0;  
else
    end_pulse<=end_pulse_r;    
    
endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 16:28:05
// Design Name: 
// Module Name: uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module uart_tx(
    input clk,
    input rst_n,

    input pi_start_pulse,    
    input [7:0] pi_data,          
    
    output reg tx,
    output end_pulse
    );


parameter FCLK=50_000_000;
parameter BPS=9600;
parameter CNT_MAX=FCLK/BPS-1;

parameter IDLE=3'b001;
parameter CMD=3'b010;
parameter DATA=3'b100;

reg [12:0] baud_cnt;  //50MHz/9600=5208
reg [3:0] bit_cnt;
reg [2:0] state;


//baud_cnt
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    baud_cnt<=0;
 else if(pi_start_pulse)
    baud_cnt<=0;
 else if(baud_cnt==CNT_MAX)
    baud_cnt<=0;
 else if(state!=IDLE)
    baud_cnt<=baud_cnt+1;
    
 //end_pulse
assign end_pulse=(bit_cnt==9)&&(baud_cnt==CNT_MAX);

//cnt_bytes
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    bit_cnt<=0;
else if(bit_cnt==9 && baud_cnt==CNT_MAX)
    bit_cnt<=0;
else if(baud_cnt==CNT_MAX)
    bit_cnt<=bit_cnt+1;

//state
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    state<=IDLE;
else case(state)
        IDLE: if(pi_start_pulse)
                state<=DATA;
        DATA: if(bit_cnt==9 && baud_cnt==CNT_MAX)
                state<=IDLE;
        default: state<=state;
    endcase
    
//tx
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    tx<=1;
else if(state==DATA && baud_cnt==1) begin    
    if(bit_cnt==0 )
         tx<=0;    
    else if(bit_cnt>=1 && bit_cnt<=8)
         tx<=pi_data[bit_cnt-1];
    else if(bit_cnt==9)
         tx<=1;
end     
     
    
endmodule

4)testbench代码

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 16:44:51
// Design Name: 
// Module Name: gen_tx_data
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module gen_tx_data(
    output clk,
    output rst_n,    
    output reg po_start_pulse,
    output reg [7:0] po_data   
    );
    
parameter FCLK=50_000_000;
parameter DLY_MS=FCLK/100;
parameter EVENT_MAX=10;     

reg rst_n;
reg clk;
reg [19:0] timer;
reg [5:0] event_t;
reg timer_flag;
wire [5:0] event_o;

initial begin
    rst_n=0;
    #100;
    rst_n=1;
end

initial begin
    clk=0;
    forever #10 clk=~clk;
end

always @(posedge clk or negedge rst_n)
if(rst_n==0)
    timer<=0;
else if(timer==DLY_MS-1)
    timer<=0;    
else
    timer<=timer+1;


always @(posedge clk or negedge rst_n)
if(rst_n==0)
    timer_flag<=0;
else if(timer==DLY_MS-2)
    timer_flag<=1;
else
    timer_flag<=0;
    
always @(posedge clk or negedge rst_n)
if(rst_n==0)
    event_t<=0;
else if(event_t==EVENT_MAX)
    event_t<=0;
else if(timer_flag)
    event_t<=event_t+1;

assign event_o=timer_flag? event_t: 0;  //generate counter-value pulse    
 
always @(posedge clk or negedge rst_n)
if(rst_n==0) begin
    po_start_pulse<=0;
    po_data<=0;
end
else if(event_o)
    case(event_o)
        1: send_data(8'h11);
        2: send_data(8'h29);
        3: send_data(8'h3a); 
    endcase
else
    po_start_pulse<=0; 
 
task send_data;
    input [7:0] datax;
    begin
       po_start_pulse<=1;
       po_data<=datax;
    end
endtask    

endmodule
`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date: 2023/12/08 17:10:04
// Design Name: 
// Module Name: tb_uart_tx
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//////////////////////////////////////////////////////////////////////////////////


module tb_uart_tx;

wire [7:0] pi_data; 
wire [7:0] po_data; 
    
gen_tx_data 
#(.FCLK(50_000))
u_gen_tx_data(
    .clk(clk),
    .rst_n(rst_n),   
    .po_start_pulse(pi_start_pulse),
    .po_data(pi_data)   
    );
    
uart_tx 
#(.FCLK(50_000))
u_uart_tx(
    .clk(clk),
    .rst_n(rst_n),

    .pi_start_pulse(pi_start_pulse),    
    .pi_data(pi_data),          
    
    .tx(tx),
    .end_pulse(end_pulse_tx)
    ); 
    
uart_rx 
#(.FCLK(50_000))
u_uart_rx(
    .clk(clk),
    .rst_n(rst_n),
    
    .rx(tx),  
    .po_data(po_data),          
    .end_pulse(end_pulse_rx)
    );       


endmodule

5)tang nano 20k引脚约束

//IO_LOC "clk" 10;  //30MHz
//IO_LOC "clk" 11;  //5MHz
IO_LOC "clk" 4;    //27MHz
IO_LOC "rst" 88;

IO_LOC "rx" 70;
IO_LOC "tx" 69;

6)仿真波形

gen_tx_data.v --> uart_tx.v --> uart_rx.v

image image

7)运行结果(tx与rx回环)

pc上位机 --> uart_rx.v --> uart_tx.v--->pc上位机

image