【项目1:uart_fsm_led】- 第一部分-tx

最近学了状态机、串口通信,于是想要使用串口通信去控制LED翻转

主要需要3个模块去实现,于是我考虑分步骤去依次实现每个模块,并且对其仿真验证

这一篇先对数据发送模块进行测试验证

设计的框图如下:

 

一、设计文件

module uart_tx
#(
    parameter CLK_FRE = 50,      //clock frequency(Mhz)
    parameter BAUD_RATE = 115200 //serial baud rate
)
(
    input                        clk,              //clock input
    input                        rst_n,            //asynchronous reset input, low active 
    input[7:0]                   tx_8bit,          //data to send
    input                        tx_en,    //data to be sent is valid
    output reg                   tx_done,    //send ready
    output                       tx_1bit            //serial data output
);
//calculates the clock cycle for baud rate 
localparam                       CYCLE = CLK_FRE * 1000000 / BAUD_RATE;
//state machine code
localparam                       S_IDLE       = 1;
localparam                       S_START      = 2;//start bit
localparam                       S_SEND_BYTE  = 3;//data bits
localparam                       S_STOP       = 4;//stop bit

reg[2:0]                         state;
reg[2:0]                         next_state;
reg[15:0]                        cycle_cnt; //baud counter
reg[2:0]                         bit_cnt;//bit counter
reg[7:0]                         tx_data_latch; //latch data to send
reg                              tx_reg; //serial data output
assign tx_1bit = tx_reg;

//第一段:同步时序,描述状态转移
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        state <= S_IDLE;
    else
        state <= next_state;
end

//(*)第二段:组合逻辑判断状态转移条件、描述状态转移规律
always@(*)
begin
    case(state)
        S_IDLE:
            if(tx_en == 1'b1)
                next_state <= S_START;
            else
                next_state <= S_IDLE;
        S_START:
            if(cycle_cnt == CYCLE - 1)
                next_state <= S_SEND_BYTE;
            else
                next_state <= S_START;
        S_SEND_BYTE:
            if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)
                next_state <= S_STOP;
            else
                next_state <= S_SEND_BYTE;
        S_STOP:
            if(cycle_cnt == CYCLE - 1)
                next_state <= S_IDLE;
            else
                next_state <= S_STOP;
        default:
            next_state <= S_IDLE;
    endcase
end

// 发送完成标志位
    always@(posedge clk or negedge rst_n)
    begin
        if(rst_n == 1'b0)
            begin
                tx_done <= 1'b0;
            end
        else if(state == S_IDLE)
            if(tx_en == 1'b1)
                tx_done <= 1'b0;
            else
                tx_done <= 1'b1;
        else if(state == S_STOP && cycle_cnt == CYCLE - 1)
                tx_done <= 1'b1;
    end

// 输入数据锁存,方便后面并转串
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        begin
            tx_data_latch <= 8'd0;
        end
    else if(state == S_IDLE && tx_en == 1'b1)
            tx_data_latch <= tx_8bit; // 将输入数据锁存
        
end

// 位计数器
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        begin
            bit_cnt <= 3'd0;
        end
    else if(state == S_SEND_BYTE)
        if(cycle_cnt == CYCLE - 1)
            bit_cnt <= bit_cnt + 3'd1;
        else
            bit_cnt <= bit_cnt;
    else
        bit_cnt <= 3'd0;
end

// 波特率计数器
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        cycle_cnt <= 16'd0;
    else if((state == S_SEND_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)
        cycle_cnt <= 16'd0;
    else
        cycle_cnt <= cycle_cnt + 16'd1;    
end

//第三段:同步时序,描述每个状态的输出
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        tx_reg <= 1'b1;
    else
        case(state)
            S_IDLE,S_STOP:
                tx_reg <= 1'b1; 
            S_START:
                tx_reg <= 1'b0; 
            S_SEND_BYTE:
                tx_reg <= tx_data_latch[bit_cnt];
            default:
                tx_reg <= 1'b1; 
        endcase
end

endmodule 

二、测试文件

`timescale 1ns/1ns

// 第一步:测试发送模块能否将并行数据转成串行数据

module tb_step_01;

reg clk;
reg rst_n;
reg [7:0]tx_8bit;
reg tx_en ;

wire tx_1bit;
wire tx_done;

initial begin
clk = 1'b0;
rst_n = 1'b0;
#12;
rst_n = 1'b1;
begin 

tx_8bit = 8'd0;
tx_en = 1'b0;

// 产生输入数据
# 1000;//延迟50个时钟周期
tx_8bit = 8'b0100_1111;
tx_en = 1'b1;//tx_en拉高,发送端开始接收数据,当tx_en拉高1000ns后将其拉低,等数据传完后,等着tx_done拉高,就完成一个H的发送
#1000;
tx_en = 1'b0;
@(posedge tx_done)

tx_8bit = 8'b0110_0101;
tx_en = 1'b1;
# 100000;
tx_en = 1'b0;

end

end

always #10 clk = ~ clk;

// 调用发送模块
uart_tx uart_tx_inst
(
.clk(clk),              //clock input
.rst_n(rst_n),            //asynchronous reset input, low active 
.tx_8bit(tx_8bit),          //data to send
.tx_en(tx_en),    //data to be sent is valid

.tx_done(tx_done),    //send ready
.tx_1bit(tx_1bit)            //serial data output
);

endmodule 

三、波形图

 

 

posted @ 2022-04-11 22:30  刘小颜  阅读(81)  评论(0)    收藏  举报