2020-09-29線上檢測模組 有時鐘和脈衝兩種模式 學習筆記

2020-10-01 14:00:52

線上檢測模組    有時鐘和脈衝兩種模式

module online_detect #(
    parameter                    SYS_CLK_period    = 100        ,    //系統時鐘週期
    parameter                    DETECT_period    = 100        ,    //檢測週期
    parameter                    MODE_select        = 1                //模式選擇                                                            
    )                                                       
    (                                                       
    input                         i_sys_clk                    ,    //輸入系統時鐘
    input                        i_sys_rst                    ,    //輸入系統復位
    input                        i_det_sig                    ,    //輸入被測訊號
    output                        o_det_state                        //輸出被檢測訊號
    );                                                      
    reg                            oline_flag        = 1'b0        ;   //線上標誌,如果線上,訊號正常,反之不正常                                                  
    reg    [31:0]                    cnt_1pps        = 32'd0        ;    //1pps的計數器
    reg                            div_1pps        = 1'b0        ;    //1pps脈衝
    reg    [1:0]                    mux_reg            = 2'b0        ;    //檢測訊號被打兩拍之後的訊號
    wire                        mux_select_sig                ;    //模式選擇之後的訊號
    wire                        mux_sig_pose                ;    //最終被檢測訊號的上升沿
    wire[31:0]                    div_param                    ;   //誤差允許範圍                                                   
    reg    [31:0]                    pulse_cnt        = 32'd0        ;    //脈衝計數器
    reg    [3:0]                    online_state    = 4'd0        ;    //狀態機
    reg                            runout_flag        = 0            ;   //溢位標誌    
    wire [31:0]                    MAX_TAGE                    ;    //誤差上限
    wire [31:0]                    MIX_TAGE                    ;   //誤差下限                      
    parameter                    FSM_online_no     = 4'd0        ;    //不線上狀態
    parameter                    FSM_MID1        = 4'd1        ;    //中間狀態1
    parameter                    FSM_MID2         = 4'd2        ;    //中間狀態2
    parameter                    FSM_online_ok     = 4'd3        ;    //線上狀態    
    parameter    [31:0]            DIV_1S            = 32'd200    ;    //1s時間間隔
    parameter    [31:0]            DIV_F_10M        = 32'd200    ;    //10M訊號檢測
    parameter                    test_period        = 4*DIV_1S    ;    //測試周期
        
    assign        o_det_state        = oline_flag                            ;    //線上標誌賦值給輸出埠
    assign        mux_select_sig    = MODE_select    ? div_1pps    : i_det_sig    ;    //選擇線上檢測還是1pps分頻之後檢測
    assign        mux_sig_pose    = !mux_reg[1]     && mux_reg[0]            ;    //被檢測訊號的上升沿訊號
    assign        div_param        = MODE_select    ? DIV_1S    : DIV_F_10M    ;    //選擇檢測模式是時鐘還是脈衝,這裡選擇脈衝
    assign        MAX_TAGE        = div_param    + div_param/10_000_000        ;    //誤差上限
    assign        MIX_TAGE        = div_param    - div_param/10_000_000        ;    //誤差下限

 

    always @ (posedge i_det_sig or posedge i_sys_rst)    //i_det_sig訊號1s分頻
    begin
        if(i_sys_rst)
        begin
            div_1pps    <= 0                        ;
            cnt_1pps    <= DETECT_period            ;
        end 
        else if(cnt_1pps == DIV_1S)        //計數到1s時輸出一個1pps
        begin
            div_1pps    <= 1                        ;
            cnt_1pps    <= DETECT_period            ;
        end 
        else 
        begin
            div_1pps    <= 0                        ;
            cnt_1pps    <= cnt_1pps + DETECT_period    ;
        end
    end 
    
    always @ (posedge i_sys_clk)            //被檢測訊號打兩拍
    begin
        mux_reg            <= {mux_reg[0],mux_select_sig}    ;
    end 
        
    always @ (posedge i_sys_clk or posedge i_sys_rst)//溢位標誌和脈衝計數
    begin
        if(i_sys_rst)
        begin
            pulse_cnt        <= SYS_CLK_period    ;    //脈衝計數清零
            runout_flag        <= 0                ;    //溢位標誌拉低
        end 
        else if(mux_sig_pose)
        begin
            pulse_cnt        <= SYS_CLK_period    ;    //上升沿來的時候計數器清零
            runout_flag        <= 0                ;    //上升沿來的時候溢位標誌拉低
        end 
        else if(pulse_cnt >=  test_period)            //計數器大於檢測週期的時候溢位標誌拉高,計數器保持不變
        begin
            pulse_cnt        <= pulse_cnt        ;    
            runout_flag        <= 1                ;    
        end 
        else 
        begin
            pulse_cnt         <= pulse_cnt + SYS_CLK_period    ;
            runout_flag        <= 0            ;
        end 
    end     
        
    always @ (posedge i_sys_clk or posedge i_sys_rst)    //狀態機
    begin
        if (i_sys_rst)
        begin
            online_state    <= FSM_online_no    ;
        end 
        else 
        begin
        case(online_state)
        FSM_online_no    :
            begin
            if( !runout_flag && mux_sig_pose )        //如果沒有溢位並且上升沿來到的時候
            begin
                if( (pulse_cnt >=MIX_TAGE) && pulse_cnt <=MIX_TAGE) //並且脈衝計數器在誤差範圍之內的時候,調到下一個狀態
                begin
                online_state    <= FSM_MID1    ;
                end     
                else 
                begin
                online_state    <= FSM_online_no    ;
                end     
            end
            else  
            begin
                online_state    <= FSM_online_no    ;
            end
            end      
        FSM_MID1    :
            begin
            if(runout_flag ) //如果溢位,跳到不線上狀態
            begin
                    online_state    <= FSM_online_no    ;
            end 
            else if(mux_sig_pose)
            begin
                if(pulse_cnt >=MIX_TAGE && pulse_cnt <=MIX_TAGE) //如果上升沿來的時候並且脈衝計數器在誤差範圍內跳到下一個狀態
                begin
                    online_state    <= FSM_MID2    ;
                end     
                else 
                begin
                    online_state    <= FSM_online_no    ;
                end 
            end     
            else         
            begin
                    online_state    <= FSM_MID1            ;
            end         
            end 
        FSM_MID2    :
            begin
            if(runout_flag) //如果溢位,跳到不線上狀態
            begin
                    online_state    <= FSM_online_no    ;
            end 
            else if(mux_sig_pose)
            begin
                if(pulse_cnt >=MIX_TAGE && pulse_cnt <=MIX_TAGE) //如果上升沿來的時候並且脈衝計數器在誤差範圍內跳到下一個狀態
                begin
                    online_state    <= FSM_online_ok    ;
                end     
                else         
                begin
                    online_state    <= FSM_MID1            ;    //如果上升沿沒有來返回到上一個狀態重新檢測
                end 
            end     
            else 
            begin
                    online_state    <= FSM_MID2    ;
            end         
            end 
        FSM_online_ok    :
            begin
            if(runout_flag) //如果溢位,跳到不線上狀態
            begin
                    online_state    <= FSM_online_no    ;
            end 
            else if(mux_sig_pose)
            begin
                if((pulse_cnt >=MIX_TAGE) && (pulse_cnt <=MIX_TAGE))  //如果上升沿來的時候並且脈衝計數器在誤差範圍內跳到下一個狀態
                begin
                    online_state    <= FSM_online_ok    ;
                end     
                else 
                begin
                    online_state    <= FSM_MID2            ;    //如果上升沿沒有來返回到上一個狀態重新檢測
                end 
            end     
            else 
            begin
                    online_state    <= FSM_MID1    ;
            end         
            end
        default        :
            begin
                    online_state    <= FSM_online_no    ;
            end 
    endcase
    end 
    end 
    
    always @ (posedge i_sys_clk )    //訊號線上標誌模組
    begin
        case(online_state)
        FSM_online_no    :
        begin
            oline_flag    <= 1'b0            ;
        end 
        FSM_online_ok    :
        begin
            oline_flag    <= 1'b1            ;
        end 
        default     :
        begin
            oline_flag    <= oline_flag    ;
        end 
        endcase    
    end 
endmodule
 


  測試程式碼部分

 

module online_ddetect_tb();
    reg                i_sys_clk    ;
    reg                i_sys_rst    ;
    reg                i_det_sig    ;
    wire            o_det_state    ;
    initial
    begin
        i_sys_clk    =    0    ;
        i_sys_rst    =     0    ;
        i_det_sig    =     0    ;
    #100 i_sys_rst    =     1    ; 
    #20  i_sys_rst    =     0    ;           
    end 
    
    always # 50    i_sys_clk = ~i_sys_clk      ;
    always    #50    i_det_sig = ~i_det_sig        ;

    online_detect #(
    .SYS_CLK_period    (100    ),//系統時鐘週期
    .DETECT_period    (100    ),    //檢測週期
    .MODE_select    (1        )    //模式選擇
    
    )
     online_detect_inst    (
    .i_sys_clk    (i_sys_clk),//輸入系統時鐘
    .i_sys_rst    (i_sys_rst),//輸入系統復位
    .i_det_sig    (i_det_sig),//輸入被測訊號
    .o_det_state(o_det_state)    //輸出被檢測訊號
    );

endmodule