Menu Close

uart通信tx模块在FPGA实现的一种Verilog状态机写法(一)

uart通信方式因其简单易于实现和成本低的特点,是工业现场经常用到的一种通信方式,大部分的数字仪表,模块和设备都能支持。常见的Rs232,Rs485,Rs422皆与uart格式相同;不同的是Uart一般是TTL电平的,RS232指的是RS232电平的串口,Rs485指的是Rs485电平(或电气特性)的。

本文实现的是通信参数固定的一种简单情况,参数可变模块后面再整理下。话不多说,直接上代码。

// 9600, N, 8, 1
module uart_st #
(
    parameter BAUD_RATE = 115200
)
(
    input  clk50m,
    input  rst,
    input  [7:0] data,
    input  enable,
    output reg tx,
    output reg busy // 指示外部调用模块,在忙的时候,不接收新的数据
);

localparam BAUD_CNT = (BAUD_RATE == 9600) ? 5208 - 1 : (BAUD_RATE == 115200) ? 434 - 1 : 434 - 1 ;

// 缓存外部数据data
reg [7:0] data_r;

always @ (posedge clk50m or posedge rst)
if(rst)
    data_r <= 0;
else if (enable && busy == 0)
    data_r <= data;
else
    data_r <= data_r;

// 用状态机来完成发送
reg [12:0] cnt;
reg [3:0] num;
// 定义状态空间
localparam FSM_IDLE     = 0;
localparam FSM_START    = 1;
localparam FSM_DATA     = 2;
localparam FSM_PARITY   = 3;
localparam FSM_STOP     = 4;
// 定义状态变量
reg [2:0] cstate;
// 完成状态机,每一个状态里,状态转移和判断,根据状态输出
always @ (posedge clk50m or posedge rst)
if(rst)
begin
    cstate <= FSM_IDLE;
    busy <= 0;
    tx <= 1;
    cnt <= 0;
    num <= 0;
end
else case (cstate)
FSM_IDLE:// 空闲状态
begin
    tx <= 1; // 空闲发送 1
    if(enable) // 需要发送数据
    begin
        cstate <= FSM_START;
        busy <= 1;
        cnt <= 0;
    end
    else cstate <= FSM_IDLE;
end
FSM_START:
begin
    tx <= 0; // 发送起始位
    if(cnt == BAUD_CNT)
    begin
        cnt <= 0;
        cstate <= FSM_DATA;
    end
    else
    begin
        cnt <= cnt + 1;
        cstate <= FSM_START;
    end
end
FSM_DATA:
begin
    tx <= data_r[num]; // 并串转换
    
    if(cnt == BAUD_CNT && num == 8 - 1 )
    begin
        cstate <= FSM_STOP;
        cnt <= 0;
        num <= 0;
    end
    else if(cnt == BAUD_CNT && num < 8 - 1 )
    begin
        num <= num + 1;
        cnt <= 0;
    end
    else
    begin
        cnt <= cnt + 1;
        cstate <= FSM_DATA;
        num <= num;
    end
end
FSM_PARITY:  
begin
    cstate <= FSM_STOP;
end
FSM_STOP:
begin
    tx <= 1;
    if(cnt == BAUD_CNT )
    begin
        cnt <= 0;
        cstate <= FSM_IDLE;
        busy <= 0;
    end
    else
    begin
        cnt <= cnt + 1;
        cstate <= FSM_STOP;
    end
end
default:
begin
    cstate <= FSM_IDLE;
    busy <= 0;
    tx <= 1;
    cnt <= 0;
    num <= 0;
end
endcase

endmodule

 

仿真程序:

module tb();

reg clk = 0;
always #10 clk = ~clk;


wire busy;

reg [7:0] data;
reg tx_en = 0;
reg rst = 0;
initial
begin
    data = 0;
    tx_en = 0;
    rst = 1;
    #20;
    rst = 0;
    #10;
    
    @(posedge clk);
    repeat(10)
    begin
        while(busy)  @(posedge clk);
        
        data = data + 1;
        tx_en = 1;
        @(posedge clk);
        tx_en = 0;
        @(posedge clk);
    end
    #200;
    $stop;
    
end

    
wire tx;


uart_st   uart_st_inst
(
    .clk50m (clk),
    .rst    (rst),
    .data   (data),
    .enable (tx_en),
    .tx     (tx),
    .busy   (busy)  // 指示外部调用模块,在忙的时候,不接收新的数据
);



endmodule

 

仿真波形:

 

Posted in FPGA 教材教案, Verilog, Verilog

发表回复

相关链接