【项目1:uart_fsm_led】- 完结篇-tx-rx-fsm

经过调试,以及通过大佬的指点,终于实现这个小项目的功能:

使用上位机给FPGA发送数据,当FPGA检测到 led 字符串后就将灯反转

一、设计文件

模块一:tx发送模块

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 

模块二:rx接收模块

module uart_rx
#(
    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 
    output reg[7:0]              rx_8bit,          //received serial data
    output reg                   rx_done,    //received serial data is valid
    input                        rx_en,    //data receiver module ready
    input                        rx_1bit            //serial data input
);
//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_REC_BYTE  = 3; //data bits
localparam                       S_STOP      = 4; //stop bit
localparam                       S_DATA      = 5;

reg[2:0]                         state;
reg[2:0]                         next_state;
reg                              rx_d0;            //delay 1 clock for rx_1bit
reg                              rx_d1;            //delay 1 clock for rx_d0
wire                             rx_negedge;       //negedge of rx_1bit
reg[7:0]                         rx_bits;          //temporary storage of received data
reg[15:0]                        cycle_cnt;        //baud counter
reg[2:0]                         bit_cnt;          //bit counter

// 边沿检测
assign rx_negedge = rx_d1 && ~rx_d0;


// 异步串口通信:这里需要将输入信号打2拍
// 目的:将输入信号与系统时钟同步,防止出现亚稳态
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
    begin
        rx_d0 <= 1'b0;
        rx_d1 <= 1'b0;    
    end
    else
    begin
        rx_d0 <= rx_1bit;
        rx_d1 <= rx_d0;
    end
end

//第一段:同步时序,描述状态转移
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(rx_negedge)
                next_state <= S_START;
            else
                next_state <= S_IDLE;
        S_START:
            if(cycle_cnt == CYCLE - 1)//one data cycle 
                next_state <= S_REC_BYTE;
            else
                next_state <= S_START;
        S_REC_BYTE:
            if(cycle_cnt == CYCLE - 1  && bit_cnt == 3'd7)  //receive 8bit data
                next_state <= S_STOP;
            else
                next_state <= S_REC_BYTE;
        S_STOP:
            if(cycle_cnt == CYCLE/2 - 1)//half bit cycle,to avoid missing the next byte receiver
                next_state <= S_DATA;
            else
                next_state <= S_STOP;
        S_DATA:
            if(rx_en)    //data receive complete
                next_state <= S_IDLE;
            else
                next_state <= S_DATA;
        default:
            next_state <= S_IDLE;
    endcase
end

always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_done <= 1'b0;
    else if(state == S_STOP && next_state != state)
        rx_done <= 1'b1;
    else if(state == S_DATA && rx_en)
        rx_done <= 1'b0;
end

//第三段:同步时序,描述每个状态的输出
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_8bit <= 8'd0;
    else if(state == S_STOP && next_state != state)
        rx_8bit <= rx_bits;//latch received data
end

// 接收的数据计数位
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        begin
            bit_cnt <= 3'd0;
        end
    else if(state == S_REC_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_REC_BYTE && cycle_cnt == CYCLE - 1) || next_state != state)//next_state != state:状态发生跳转
        cycle_cnt <= 16'd0;
    else
        cycle_cnt <= cycle_cnt + 16'd1;    
end
//receive serial data bit data
always@(posedge clk or negedge rst_n)
begin
    if(rst_n == 1'b0)
        rx_bits <= 8'd0;
    else if(state == S_REC_BYTE && cycle_cnt == CYCLE/2 - 1)
        rx_bits[bit_cnt] <= rx_1bit;//串并转换
    else
        rx_bits <= rx_bits; 
end
endmodule 

模块三:状态机模块

module fsm_led
(
input clk                           ,
input rst_n                         ,
input [7:0]fsm_8bit                 ,
input fsm_en                        ,
        
output reg led
);

// 定义状态位宽
reg [2:0]    state             ; 
reg [2:0]    next_state        ; 

// 状态编码
parameter l = 3'd1, e = 3'd2, d = 3'd3 ,IDLE  = 3'd0;

//第一段:固定格式得到状态
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
    state <= IDLE;
else 
    state <= next_state;
end    

//第二段:组合逻辑,描述状态转移
always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
    next_state <= IDLE;
else if(fsm_en == 1'b1)begin//输入使能信号拉高
//else    begin
    case(state) 
    IDLE:
        if(fsm_8bit == "l")
            next_state <= l;
        else 
            next_state <= IDLE;    
    l:
        if(fsm_8bit == "e")
            next_state <= e;
        else 
            next_state <= IDLE;
    e:
        if(fsm_8bit == "d")
            next_state <= d;
        else 
            next_state <= IDLE;
    d:
        if(fsm_8bit == "l")
            next_state <= l;
        else 
            next_state <= IDLE;
        default: next_state <= IDLE;
        endcase
        end
end

//第三段:输出信号

always @(posedge clk or negedge rst_n)begin
if(rst_n == 1'b0)
led <= 1'b0;
else if(state == e && next_state == d)begin
led <= ~led;
end
else begin
led <= led;
end
end

endmodule 

顶层模块

module top_final
(
    input                        clk,              
    input                        rst_n,            
    input                        rx_1bit,
    output                       led ,
    output                       tx_1bit
);

wire [7:0]rx_8bit,rx_done;


uart_tx uart_tx_inst
(
    .clk(clk),              //clock input
    .rst_n(rst_n),            //asynchronous reset input, low active 
    .tx_8bit(rx_8bit),          //data to send
    .tx_en(rx_done),    //data to be sent is valid
    .tx_done(),    //send ready
    .tx_1bit(tx_1bit)            //serial data output
);


uart_rx uart_rx_inst
(
    .clk(clk),              //clock input
    .rst_n(rst_n),            //asynchronous reset input, low active 
    .rx_8bit(rx_8bit),          //received serial data
    .rx_done(rx_done),    //received serial data is valid
    .rx_en(1'b1),    //data receiver module ready
    .rx_1bit(rx_1bit)            //serial data input
);

fsm_led
(
.clk(clk)                         ,
.rst_n(rst_n)                     ,
.fsm_8bit(rx_8bit)                ,
.fsm_en(rx_done)                  ,

.led(led)
);

endmodule 

二、测试文件

`timescale 1ns/1ns

// 第三步:甲状态机

module tb_step_03;

reg clk;
reg rst_n;

// tx输入
reg [7:0] tx_8bit ;
reg tx_en ;

// tx输出
wire tx_1bit;
wire tx_done;

//// rx输入
reg rx_1bit;
reg rx_en;

// rx输出
wire [7:0]rx_8bit;
wire rx_done;
// led 输出
wire led;
//assign fsm_en = 1'b1;

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

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

// 产生输入数据

# 1000;
tx_8bit = 8'b0100_1111;//O
tx_en = 1'b1;
rx_en = 1'b1;
@(posedge tx_done)

tx_8bit = 8'b0110_1100;//l
@(posedge tx_done)// 发送数据的过程中

tx_8bit = 8'b0110_0101;//e
@(posedge tx_done)

tx_8bit = 8'b0110_0100;//d
@(posedge tx_done)

tx_8bit = 8'b0110_1100;//l
@(posedge tx_done)

tx_8bit = 8'b0100_1111;//O
@(posedge tx_done)

tx_8bit = 8'b0110_0100;//d
@(posedge tx_done)

tx_8bit = 8'b0110_1100;//l
@(posedge tx_done)

tx_8bit = 8'b0110_0101;//e
@(posedge tx_done)

tx_8bit = 8'b0110_0100;//d
@(posedge tx_done)

tx_8bit = 8'b0110_1100;//l
@(posedge tx_done)

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
);

uart_rx uart_rx_inst
(
    .clk(clk),              //clock input
    .rst_n(rst_n),            //asynchronous reset input, low active
    
    .rx_8bit(rx_8bit),          //received serial data
    .rx_done(rx_done),    //received serial data is valid
    
    .rx_en(rx_en),    //data receiver module ready
    .rx_1bit(tx_1bit)            //serial data input
);

fsm_led fsm_led_inst
(
.clk(clk)                ,
.rst_n(rst_n)            ,
.fsm_8bit(rx_8bit)    ,
.fsm_en(rx_done)        ,

.led(led)
);

endmodule 

三、波形图

 四、上板验证

使用上位机发送led,每检测到一次led,就将灯反转一次

 

posted @ 2022-04-14 22:06  刘小颜  阅读(136)  评论(0编辑  收藏  举报