1. 程式人生 > 其它 >【專案1:uart_fsm_led】— 完結篇

【專案1:uart_fsm_led】— 完結篇

經過除錯,以及通過大佬的指點,終於實現這個小專案的功能:

使用上位機給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,就將燈反轉一次