Ch8 應用範例

8.1 按鍵防彈跳

程式( 防彈跳 ):

module KEY_Debounce( CLK, RST, KEY_In, KEY_Out );

    parameter    DeB_Num = 4;        // 取樣次數
    parameter    DeB_SET = 4'b0000;  // 設置
    parameter    DeB_RST = 4'b1111;  // 重置

    input   CLK, RST;
    input   KEY_In;
    output  KEY_Out;
    reg     KEY_Out = 1'b1;
    reg     [DeB_Num-1:0] Bounce = 4'b1111; // 初始化

    always @( posedge CLK, negedge RST ) begin  // 一次約200Hz 5ms
        if( !RST )
            Bounce <= DeB_RST;    // Bounce重置
        else begin    // 取樣4次
            integer    i;
            Bounce[0] <= KEY_In;
            for( i=0; i<DeB_Num-1; i=i+1 )
                Bounce[i+1] <= Bounce[i];
        end
        case( Bounce )
            DeB_SET:    KEY_Out <= 1'b0;
            default:    KEY_Out <= 1'b1;
        endcase
    end

endmodule

8.2 除頻器

程式( 除頻器 50MHz to 1kHz ):

module Freq_Divider( CLK, RST, CLK_Out ); /* 除頻器 Use 50MHz OSC */

    // 除頻設定  1kHz 1ms
    Parameter    Div  = 16'd50_000;  // 除頻數(Even)
    parameter    Div2 = 16'd25_000;  // Div/2
    parameter    DivW = 16;          // Divide寬度

    input   CLK, RST;
    output  CLK_Out;
    reg     rCLK_Out;
    reg     [DivW-1:0] CLK_Cnt = 0;

    always @( posedge CLK, negedge RST ) begin
        if( !RST )
            CLK_Cnt <= 0;
        else if( CLK_Cnt == Div-1 )
            CLK_Cnt <= 0;
        else
            CLK_Cnt <= CLK_Cnt + 1'b1;
    end
    always @( posedge CLK or negedge RST ) begin
        if( !RST )
            CLK_Out <= 0;
        else if( CLK_Cnt <= Div2-1 )
            CLK_Out = 0;
        else
            CLK_Out = 1'b1;
    end

endmodule

8.3 LED流水燈

程式( 流水燈 ):

module LED_Water( CLK, RST, LED_Out );

    input CLK, RST;
    output [3:0] LED_Out;

    reg    [23:0] Delay_Count = 24'd0;    // USE 50MHz OSC
    reg    [3:0] LED_State = 4'b0001;

    always @( posedge CLK, negedge RST ) begin
        if( !RST ) begin
            Delay_Count <= 24'd0;
            LED_State <= 4'b0001;
        end
        else if( Delay_Count == 24'd25_000_000 ) begin        // 500ms
            Delay_Count <= 24'd0;
            if( LED_State == 4'b0000 )
                LED_State <= 4'b0001;
            else
                LED_State <= LED_State << 1;
        end
        else
            Delay_Count <= Delay_Count + 1'b1;
    end

    assign LED_Out = ~LED_State;

endmodule

8.4 掃描鍵盤

程式( 掃描鍵盤 ):

/* 掃描鍵盤 KEY_Row讀取, KEY_Col掃描 */

module KEY_Scan( CLK, RST, KEY_Row, KEY_Col, KEY );

    /* STATE */
    parameter Col_1 = 4'b1110;
    parameter Col_2 = 4'b1101;
    parameter Col_3 = 4'b1011;
    parameter Col_4 = 4'b0111;

    input   CLK, RST;
    input   [3:0] KEY_Row;
    output  [3:0] KEY_Col;
    output  [15:0] KEY;

    reg    [15:0] KEY = 16'h0000;
    reg    [3:0] KEY_Col = Col_1;

    always @( posedge CLK, negedge RST ) begin
        if( !RST ) begin
            KEY <= 16'b0;
            KEY_Col <= Col_1;
        End

        else begin
            case( KEY_Col )
                Col_1: begin
                    KEY[3:0] <= KEY_Row;
                    KEY_Col <= Col_2;
                end
                Col_2: begin
                    KEY[7:4] <= KEY_Row;
                    KEY_Col <= Col_3;
                end
                Col_3: begin
                    KEY[11:8] <= KEY_Row;
                    KEY_Col <= Col_4;
                end
                Col_4: begin
                    KEY[15:12] <= KEY_Row;
                    KEY_Col <= Col_1;
                end
                default:    KEY_Col <= Col_1;
            endcase
        end
    end

endmodule

8.5 計數器 ( 七段顯示器 )

程式( Top_Module ):

module Top_Module( CLK, RST,SEL_Out, DIG_Out );

    input   CLK, RST;
    output  [5:0] SEL_Out;
    output  [7:0] DIG_Out;

    wire    [3:0] Cnt_Up;
    wire    CLK_1Hz;

    Freq_Divider Freq_Div_1Hz(
        .CLK(CLK),
        .RST(RST),
        .CLK_Out(CLK_1Hz)
    );

    Counter_Up Counter_Up(
        .CLK(CLK_1Hz),
        .RST(RST),
        .Cnt(Cnt_Up)
    );

    Seg_Seven DIG_SEG(
        .SEL_In(Cnt_Up),
        .DIG_In(Cnt_Up),
        .SEL_Out(SEL_Out),
        .DIG_Out(DIG_Out)
    );

endmodule

程式( 除頻 1MHz ):

/* 除頻器 Use 50MHz OSC */

module Freq_Divider( CLK, RST, CLK_Out );

    input   CLK, RST;
    output  CLK_Out;

    reg     CLK_Out;
    reg     [DivW-1:0] CLK_Cnt = 0;

    // 除頻設定   1Hz 1s
    parameter    Div  = 26'd50_000_000;  // 除頻數(Even)
    parameter    Div2 = 26'd25_000_000;  // Div/2
    parameter    DivW = 26;              // Divide寬度

    always @( posedge CLK,negedge RST ) begin
        if( !RST )
            CLK_Cnt <= 0;
        else if( CLK_Cnt == Div-1 )
            CLK_Cnt <= 0;
        else
            CLK_Cnt <= CLK_Cnt + 1'b1;
    end

    always @( posedge CLK,negedge RST ) begin
        if( !RST )
            CLK_Out <= 0;
        else if( CLK_Cnt <= Div2-1 )
            CLK_Out <= 0;
        else
            CLK_Out <= 1'b1;
    end

endmodule

程式( 上數計數器 ):

/* 上數計數器 */

module Counter_Up( CLK, RST, Cnt );

    /* 計數資訊 */
    parameter Cnt_SB  = 4;      // 計數寬度
    parameter Cnt_UP  = 1'b1;   // 計數值
    parameter Cnt_Min = 4'd0;   // 計數最小值
    parameter Cnt_Max = 4'd8;   // 計數最大值

    input   CLK, RST;
    output  [Cnt_SB-1:0] Cnt;

    reg     [Cnt_SB-1:0] Cnt = Cnt_Min;

    always @( posedge CLK or negedge RST ) begin
        if( !RST )
            Cnt <= Cnt_Min;
        else if( Cnt == Cnt_Max )
            Cnt <= Cnt_Min;
        else
            Cnt <= Cnt + Cnt_UP;
    end

endmodule

程式( 七段顯示器解碼 ):

/* 七段顯示器解碼(共陽) */
module Seg_Seven( SEL_In, DIG_In, SEL_Out, DIG_Out );

    input  [2:0] SEL_In;    // Use PNP
    input  [3:0] DIG_In;    // MSB D, C, B, A LSB
    output [5:0] SEL_Out;   // 七段顯示器選擇
    output [7:0] DIG_Out;   // MSB dp, g, f, e, d, c, b, a LSB
    reg [5:0] SEL_Out;
    reg [7:0] DIG_Out;

    always @( SEL_In ) begin
        case( SEL_In )
            3'b000:    SEL_Out <= 6'b000000;    // all on
            3'b001:    SEL_Out <= 6'b111110;    // 1
            3'b010:    SEL_Out <= 6'b111101;    // 2
            3'b011:    SEL_Out <= 6'b111011;    // 3
            3'b100:    SEL_Out <= 6'b110111;    // 4
            3'b101:    SEL_Out <= 6'b101111;    // 5
            3'b110:    SEL_Out <= 6'b011111;    // 6
            3'b111:    SEL_Out <= 6'b111111;    // all off
        endcase
    end
    always @( DIG_In ) begin
        case( DIG_In )
            4'b0000:    DIG_Out <= 8'b11000000;    // 0
            4'b0001:    DIG_Out <= 8'b11111001;    // 1
            4'b0010:    DIG_Out <= 8'b10100100;    // 2
            4'b0011:    DIG_Out <= 8'b10110000;    // 3
            4'b0100:    DIG_Out <= 8'b10011001;    // 4
            4'b0101:    DIG_Out <= 8'b10010010;    // 5
            4'b0110:    DIG_Out <= 8'b10000011;    // 6
            4'b0111:    DIG_Out <= 8'b11111000;    // 7
            4'b1000:    DIG_Out <= 8'b10000000;    // 8
            4'b1001:    DIG_Out <= 8'b10010000;    // 9
            4'b1010:    DIG_Out <= 8'b01111111;    // dp
            default:    DIG_Out <= 8'b11111111;    // off
        endcase
    end

endmodule