新聞中心

        EEPW首頁 > 嵌入式系統 > 設計應用 > 經典的verilog鍵盤掃描程序

        經典的verilog鍵盤掃描程序

        作者: 時間:2016-11-28 來源:網絡 收藏
        拿到威百仕( VibesIC )的板子后就迫不及待的開始我的學習計劃,從最基礎的分頻程序開始,但看到這個鍵盤掃描程序后,直呼經典,有相見恨晚的感覺,還想說一句:威百仕( VibesIC ),我很看好你!WHY?待我慢慢道來,這個程序的綜合后是0error,0warning。想想自己編碼的時候那個warning是滿天飛,現在才明白HDL設計有那么講究了,代碼所設計的不僅僅是簡單的邏輯以及時序的關系,更重要的是你要在代碼中不僅要表現出每一個寄存器,甚至每一個走線。想想我寫過的代碼,只注意到了前者,從沒有注意過后者,還洋洋自得以為自己也算是個高手了,現在想來,實在慚愧??!學習學習在學習,這也重新激發了我對HDL設計的激情,威百仕給了我一個方向,那我可要開始努力嘍!
        廢話說了一大堆,看程序吧:(本代碼經過ise7.1i綜合并下載到SP306板上驗證通過)
        //當三個獨立按鍵的某一個被按下后,相應的LED被點亮;再次按下后,LED熄滅,按鍵控制LED亮滅
        `timescale 1ns/1ns
        module keyscan(
        clk,
        rst_n,
        sw1_n,
        sw2_n,
        sw3_n,
        //output
        led_d3,
        led_d4,
        led_d5
        );
        input clk; //主時鐘信號,48MHz
        input rst_n; //復位信號,低有效
        input sw1_n,sw2_n,sw3_n; //三個獨立按鍵,低表示按下
        output led_d3,led_d4,led_d5; //發光二極管,分別由按鍵控制
        // ---------------------------------------------------------------------------
        reg [19:0] cnt; //計數寄存器
        always @ (posedge clk or negedge rst_n)
        if (!rst_n) //異步復位
        cnt <= 20d0;
        else
        cnt <= cnt + 1b1;
        reg [2:0] low_sw;
        always @(posedge clk or negedge rst_n)
        if (!rst_n)
        low_sw <= 3b111;
        else if (cnt == 20hfffff) //滿20ms,將按鍵值鎖存到寄存器low_sw中
        low_sw <= {sw3_n,sw2_n,sw1_n};
        // ---------------------------------------------------------------------------
        reg [2:0] low_sw_r; //每個時鐘周期的上升沿將low_sw信號鎖存到low_sw_r中
        always @ ( posedge clk or negedge rst_n )
        if (!rst_n)
        low_sw_r <= 3b111;
        else
        low_sw_r <= low_sw;
        //當寄存器low_sw由1變為0時,led_ctrl的值變為高,維持一個時鐘周期
        wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
        reg d1;
        reg d2;
        reg d3;
        always @ (posedge clk or negedge rst_n)
        if (!rst_n)
        begin
        d1 <= 1b0;
        d2 <= 1b0;
        d3 <= 1b0;
        end
        else
        begin //某個按鍵值變化時,LED將做亮滅翻轉
        if ( led_ctrl[0] ) d1 <= ~d1;
        if ( led_ctrl[1] ) d2 <= ~d2;
        if ( led_ctrl[2] ) d3 <= ~d3;
        end
        assign led_d5 = d1 ? 1b1 : 1b0; //LED翻轉輸出
        assign led_d3 = d2 ? 1b1 : 1b0;
        assign led_d4 = d3 ? 1b1 : 1b0;
        endmodule
        也許初看起來這段代碼似乎有點吃力,好多的always好多的wire啊,而我們通常用得最多的判斷轉移好像不是主流。的確是這樣,一個好的verilog代碼,用多個always語句來分攤一個大的always來執行,會使得綜合起來更快,這也是接前兩篇日志說到代碼優化的一個值得學習的方面。其次是wire連線很多,你要是仔細研究代碼,不難發現所有的鎖存器的連線關系編程者都考慮到了,這樣就不會平白無故的生成意想不到的寄存器了,這也是一個優秀代碼的必備要素。
        上面說的是代碼風格,下面就看程序的編程思想吧。前兩個always語句里其實是做了一個20ms的計數,每隔20ms就會讀取鍵值,把這個鍵值放到寄存器low_sw中,接下來的一個always語句就是把low_sw的值鎖存到low_sw_r里,這樣以來,low_sw和low_sw_r就是前后兩個時鐘周期里的鍵值了,為什么要這樣呢?看下一個語句吧:
        wire [2:0] led_ctrl = low_sw_r[2:0] & ( ~low_sw[2:0]);
        仔細分析,你會發現當沒有鍵按下時,low_sw=low_sw_r=3’b111,此時的led_ctrl=3’b000;只有當low_sw和low_sw_r的某一位分別為0和1時,才可能使led_ctrl的值改變(也就是把led_ctrl的某一位拉高)。那么這意味著當鍵值由1跳變到0時才可能把led_ctrl拉高?;仡櫱懊娴?0ms賦鍵值,也就是說每20ms內如果出現按鍵被按下,那么有一個時鐘周期里led_ctrl是會被拉高的,而再看后面的程序,led_ctrl的置高就使得相應的LED燈的亮滅做一次改變,這就達到了目的。


        關鍵詞: verilog鍵盤掃

        評論


        技術專區

        關閉
        主站蜘蛛池模板: 兖州市| 梧州市| 拜泉县| 尤溪县| 南宫市| 偏关县| 鄂州市| 菏泽市| 舞阳县| 浠水县| 阿尔山市| 惠安县| 密山市| 庆城县| 获嘉县| 太谷县| 郯城县| 英吉沙县| 慈利县| 罗甸县| 阳高县| 盘锦市| 驻马店市| 彰武县| 晋江市| 高要市| 南溪县| 福泉市| 酒泉市| 搜索| 虹口区| 江山市| 延吉市| 佛教| 板桥市| 昭通市| 资阳市| 佳木斯市| 嘉义县| 丹江口市| 同江市|