FPGA串口发送Demo

串口发送Demo

简单介绍

在发送数据时将并行数据转换成串行数据来传输

FPGA串口发送Demo_第1张图片

空闲状态为高电平,发送的起始位为一个低电平,发送的停止位为一个高电平

分析
时序

FPGA串口发送Demo_第2张图片

总框图

FPGA串口发送Demo_第3张图片

状态机

FPGA串口发送Demo_第4张图片

内部框图

FPGA串口发送Demo_第5张图片

verilog
`timescale 1ns / 1ps
// 
// Engineer: wkk
// Create Date: 2022/12/02 20:41:01
// Module Name: uart_tx
// Description: uart_tx demo
//
module uart_tx(
    input                   sys_clk     ,
    input                   sys_rst_n   ,
    input                   uart_w_en   ,
    input  wire [7:0]       uart_data   ,
    output                  uart_out
);

parameter   SYS_CLK         = 100_000_000   ;
parameter   TIME_MAX_COUNT  = 868           ;
parameter   TIME_COUNT_LEN  = 12            ;

localparam   IDLE_STATE     = 4'd0  ;
localparam   START_STATE    = 4'd1  ;
localparam   D0_STATE       = 4'd2  ;
localparam   D1_STATE       = 4'd3  ;
localparam   D2_STATE       = 4'd4  ;
localparam   D3_STATE       = 4'd5  ;
localparam   D4_STATE       = 4'd6  ;
localparam   D5_STATE       = 4'd7  ;
localparam   D6_STATE       = 4'd8  ;
localparam   D7_STATE       = 4'd9  ;
localparam   END_STATE       = 4'd10;

reg [7:0] uart_tx_data;

reg [3:0] next_state;
reg [3:0] curr_state;

reg     [TIME_COUNT_LEN-1:0]    time_counter;
wire    time_en;
reg     count_en;

reg    uart_tx_out;

// update state
always @(*) begin
    if(!sys_rst_n) 
        curr_state = IDLE_STATE;
    else
        curr_state = next_state;
end


assign time_en = (time_counter == TIME_MAX_COUNT -1)? 1'b1:1'b0;
// timer
always @(posedge sys_clk or negedge sys_rst_n ) begin
     if(!sys_rst_n || count_en == 0 ) 
        time_counter <= 'd0;
     else if(time_counter == TIME_MAX_COUNT -1 )
        time_counter <= 'd0;
     else
        time_counter <= time_counter + 1'd1;
end

// create next state
always @(posedge sys_clk or negedge sys_rst_n ) begin
    if(!sys_rst_n) begin
        next_state <= IDLE_STATE;
    end
    else 
    case(curr_state)
    IDLE_STATE :
        if(uart_w_en)
            next_state <= START_STATE;
        else
            next_state <= next_state;
    START_STATE:
        if(time_en)
            next_state <= D0_STATE;
        else
            next_state <= next_state;
    D0_STATE   :
        if(time_en)
            next_state <= D1_STATE;
        else
            next_state <= next_state;
    D1_STATE   :
        if(time_en)
            next_state <= D2_STATE;
        else
            next_state <= next_state;
    D2_STATE   :
        if(time_en)
            next_state <= D3_STATE;
        else
            next_state <= next_state;
    D3_STATE   :
        if(time_en)
            next_state <= D4_STATE;
        else
            next_state <= next_state;
    D4_STATE   :
        if(time_en)
            next_state <= D5_STATE;
        else
            next_state <= next_state;
    D5_STATE   :
        if(time_en)
            next_state <= D6_STATE;
        else
            next_state <= next_state;
    D6_STATE   :
        if(time_en)
            next_state <= D7_STATE;
        else
            next_state <= next_state;
    D7_STATE   :
        if(time_en)
            next_state <= END_STATE;
        else
            next_state <= next_state;
    END_STATE  :
        if(time_en)
            next_state <= IDLE_STATE;
        else
            next_state <= next_state;
    default:
        next_state <= IDLE_STATE;
    endcase
end

assign  uart_out = uart_tx_out;
// out
always @(posedge sys_clk or negedge sys_rst_n ) begin
    if(!sys_rst_n)begin
        uart_tx_out <= 1'b1;
        uart_tx_data <= 8'd0;
        count_en <= 1'b0;   
    end
    else case(curr_state)
    IDLE_STATE :  begin                      
        uart_tx_out <= 1'b1;   
        count_en <= 1'b0;   
    end
    START_STATE:  begin                      
        uart_tx_out <= 1'b0;  
        count_en <= 1'b1; 
        uart_tx_data <= uart_data;  
    end      
    D0_STATE   :                      
        uart_tx_out <= uart_tx_data[0]; 
    D1_STATE   :                        
        uart_tx_out <= uart_tx_data[1];      
    D2_STATE   :                        
        uart_tx_out <= uart_tx_data[2];      
    D3_STATE   :                        
        uart_tx_out <= uart_tx_data[3];       
    D4_STATE   :                        
        uart_tx_out <= uart_tx_data[4];     
    D5_STATE   :                        
        uart_tx_out <= uart_tx_data[5];    
    D6_STATE   :                        
        uart_tx_out <= uart_tx_data[6]; 
    D7_STATE   :                        
        uart_tx_out <= uart_tx_data[7]; 
    END_STATE  :  begin                      
        uart_tx_out <= 1'b1; 
        count_en <= 1'b0;  
    end    
    default: begin
        uart_tx_out <= 1'b1; 
        count_en <= 1'b0;  
    end             
endcase   
end                          
endmodule
testbench
`timescale 1ns / 1ns
// 
// Engineer: wkk
// Create Date: 2022/12/02 20:41:01
// Module Name: uart_tx_tb
// Description: uart_tx demo testbench
//
module uart_tx_tb;
reg             sys_clk     ;    
reg             sys_rst_n   ;  
reg             uart_w_en   ;  
reg   [7:0]     uart_data   ;  
wire            uart_out    ;

uart_tx #(
    .TIME_MAX_COUNT (2),
    .TIME_COUNT_LEN (2)
)u_uart_tx(
    .sys_clk   (sys_clk  ),  
    .sys_rst_n (sys_rst_n),
    .uart_w_en (uart_w_en),
    .uart_data (uart_data),
    .uart_out  (uart_out )
);
initial begin
    sys_clk             = 1'b0;
    sys_rst_n           = 1'b0;
    uart_w_en           = 1'b0;
end

always #5  sys_clk = ~sys_clk;

initial begin
    #10 sys_rst_n = 1;
    #10
    uart_data = 8'b10011101;
    uart_w_en = 1;
    #20
    uart_w_en = 0;
    #20000
    $stop;
end
endmodule

FPGA串口发送Demo_第6张图片

  • uart_w_en 信号最少要持续2个时钟周期
  • uart_w_en 信号如果持续超过一个串口数据帧的时间长度,会重复发送

你可能感兴趣的:(FPGA,fpga开发)