FPGA-數(shù)字鬧鐘

用FPGA設(shè)計(jì)一個(gè)數(shù)字鬧鐘應(yīng)該說(shuō)是一個(gè)比較綜合的小系統(tǒng)门躯,包含了按鍵声旺、數(shù)碼
管、狀態(tài)機(jī)等內(nèi)容席楚,本文主要是講述三鍵輸入的數(shù)字鬧鐘總體的設(shè)計(jì),整個(gè)作品和小時(shí)候兩三塊一個(gè)的電子手表十分類(lèi)似

功能描述

1 用四個(gè)數(shù)碼管正常顯示時(shí)税稼、分高低位烦秩,實(shí)現(xiàn)正常顯示時(shí)間。
2 具備調(diào)分調(diào)時(shí)功能
3 鬧鐘功能

功能并不復(fù)雜郎仆,我們現(xiàn)在來(lái)分析一下需要哪些模塊闻镶。
首先是時(shí)鐘功能,正常顯示時(shí)間肯定是必須的丸升,為實(shí)現(xiàn)這一可以設(shè)計(jì)一個(gè)60進(jìn)制計(jì)數(shù)器和一個(gè)24進(jìn)制計(jì)數(shù)器铆农,當(dāng)然也可以根據(jù)邏輯直接書(shū)寫(xiě)出來(lái),但無(wú)論是什么辦法狡耻,這肯定需要一個(gè)模塊來(lái)實(shí)現(xiàn)它墩剖。

第二就是調(diào)分調(diào)時(shí)了,說(shuō)白了就是置數(shù)夷狰,要置數(shù)岭皂,那么就必須有一個(gè)區(qū)域去控制數(shù)據(jù),也需要一個(gè)地方存儲(chǔ)數(shù)據(jù)沼头,然后將置數(shù)的數(shù)據(jù)傳給時(shí)鐘爷绘,所以它應(yīng)該與鍵盤(pán)的聯(lián)系,內(nèi)部有存儲(chǔ)器进倍。

第三是鬧鐘土至,鬧鐘不難想,比較器猾昆,我設(shè)定鬧鐘時(shí)間陶因,然后與時(shí)鐘的時(shí)間比較,如果兩者相同垂蜗,輸出鬧鐘信號(hào)楷扬,就是如此解幽。

最后的便是顯示電路,主要是數(shù)碼管的顯示原理烘苹,驅(qū)動(dòng)數(shù)碼管顯示時(shí)間躲株。

就是這幾樣部分,貌似這么一說(shuō)镣衡,確實(shí)沒(méi)有什么東西徘溢,一個(gè)系統(tǒng)就是需要輸入和輸出相互協(xié)調(diào)好,這里面的邏輯必須是相互對(duì)應(yīng)的捆探,不出矛盾然爆,個(gè)人認(rèn)為,這是設(shè)計(jì)的難度所在黍图。

整體設(shè)計(jì)圖

image

模塊講解

鍵盤(pán)模塊(key)

輸入 功能說(shuō)明 輸出 功能說(shuō)明
add_in c_add 時(shí)鐘加
aub_in c_sub 時(shí)鐘減
model_in 模式控制端 a_hour 調(diào)鬧鐘小時(shí)
clk 時(shí)鐘 a_minute 調(diào)鬧鐘分鐘
rst_n 復(fù)位 cnt_control 計(jì)數(shù)器開(kāi)關(guān)
Display_Model 顯示控制
Time_model 調(diào)時(shí)鐘轉(zhuǎn)換信號(hào)

細(xì)節(jié)講解

model:模式的選擇寄存器

整個(gè)鬧鐘系統(tǒng)我設(shè)置為五個(gè)模式曾雕,所以model需要是三位的[2:0]
00:時(shí)鐘正常走時(shí)
01:時(shí)鐘調(diào)分模式,該模式下時(shí)鐘的計(jì)數(shù)器停止助被,時(shí)鐘是不走的剖张,同時(shí)顯示模式也會(huì)轉(zhuǎn)到調(diào)時(shí)鐘模式。
10:時(shí)鐘調(diào)時(shí)模式揩环,與調(diào)分模式類(lèi)似搔弄。
11:鬧鐘調(diào)分設(shè)置模式,此時(shí)時(shí)鐘走時(shí)丰滑,顯示模式為鬧鐘模式顾犹。

100:鬧鐘調(diào)時(shí)模式,與調(diào)分時(shí)類(lèi)似褒墨。

cnt_control:計(jì)數(shù)器開(kāi)關(guān)

正常走時(shí)和調(diào)鬧鐘模式下炫刷,計(jì)數(shù)器開(kāi),cnt_control = 0;
當(dāng)進(jìn)入調(diào)分和調(diào)時(shí)模式郁妈,計(jì)數(shù)器關(guān)閉浑玛,cnt_control = 1。

Time_Model:調(diào)時(shí)鐘轉(zhuǎn)換信號(hào)

這個(gè)是連接時(shí)鐘模塊(clock)的噩咪,是調(diào)分模式和調(diào)時(shí)模式的切換信號(hào)顾彰。

Display_Model:顯示控制

正常走時(shí),進(jìn)入調(diào)分和調(diào)時(shí)模式時(shí)胃碾,停止走時(shí)涨享,整個(gè)過(guò)程我設(shè)置為同一種顯示模式;
鬧鐘模式下书在,顯示模式轉(zhuǎn)換灰伟;
所以一共是兩種模式拆又,一根線(xiàn)足以儒旬。

代碼展示

module key(
    input clk,
    input rst_n,
    input add_in,//增加按鈕
    input sub_in,//減去按鈕
    input model_in,//模式選擇
                
    output reg Display_Model, 
      //時(shí)鐘與鬧鐘顯示選擇栏账,0 代表時(shí)鐘,1代表鬧鐘
    
    output reg cnt_control, //控制定時(shí)器
    output reg [2:0]Time_model,    
    output reg c_add,       //控制時(shí)鐘 加
    output reg c_sub,       //控制時(shí)鐘 減

    output reg a_add,       //控制鬧鐘 加
    output reg a_sub       //控制鬧鐘  減
            );
            
            
/************************************/
parameter T40MS = 20'd40_000;
parameter T1S = 30'd1_000_000;
/************************************/

///         add_in 按鍵      /////
reg add;
reg [19:0]cnt_a;
reg [1:0]a;
 always @(posedge clk or negedge rst_n)       
   begin
       if(!rst_n)
           begin
               cnt_a <= 0;
               a <= 0;
               add <= 1; 
           end
       else
       begin
           case(a) 
               0:begin
                   if(cnt_a < T40MS)
                     // 按下時(shí)間大于40MS 認(rèn)為有效
                       begin
                           if(!add_in) 
                               cnt_a = cnt_a+1'b1;
                           else
                               cnt_a = 0;
                         end
                   else //counter> 40MS 栈源,說(shuō)明確實(shí)按鍵是按下了
                         begin 
                               add = 0; 
                           // 給沖擊信號(hào) 挡爵,0~1 是上升沿
                               a = 1;  
                           //確定按鍵按下,轉(zhuǎn)到狀態(tài) 1
                               cnt_a = 0;  //計(jì)數(shù)器清零
                         end
                     end
                1:begin
                       add = 1;    //產(chǎn)生尖脈沖
                       if(cnt_a < T40MS) 
                         // 按下時(shí)間大于40MS 松開(kāi)有效
                           begin
                               if(add_in) 
                                       cnt_a = cnt_a+1'b1;
                               else
                                       cnt_a = 0; 
                             end
                        else
                            begin
                               a = 0; 
                    // 若松開(kāi)甚垦,回到狀態(tài) 0 茶鹃,等待下次按鍵到來(lái)
                               cnt_a = 0;
                            end
                   end
                   default : a = 1; 
           endcase
       end
   end
//////////////////////////////////////////////////////////

///        sub_in 按鍵       ///
reg sub;
reg [19:0]cnt_s;
reg [1:0]s;
 always @(posedge clk or negedge rst_n)       
   begin
       if(!rst_n)
           begin
               cnt_s <= 0;
               s <= 0;
               sub <= 1; 
           end
       else
       begin
           case(s) 
               0:begin
                   if(cnt_s < T40MS)
                     // 按下時(shí)間大于40MS 認(rèn)為有效
                       begin
                           if(!sub_in) 
                               cnt_s = cnt_s+1'b1;
                           else
                               cnt_s = 0;
                         end
                   else //counter> 40MS ,說(shuō)明確實(shí)按鍵是按下了
                         begin 
                               sub = 0; 
                           // 給沖擊信號(hào) 艰亮,0~1 是上升沿
                               s = 1; 
                           //確定按鍵按下闭翩,轉(zhuǎn)到狀態(tài) 1
                               cnt_s = 0;  //計(jì)數(shù)器清零
                         end
                     end
                1:begin
                       sub = 1;    //產(chǎn)生尖脈沖
                       if(cnt_s < T40MS) 
                         // 按下時(shí)間大于40MS 松開(kāi)有效
                           begin
                               if(sub_in) 
                                       cnt_s = cnt_s+1'b1;
                               else
                                       cnt_s = 0; 
                             end
                        else
                            begin
                               s = 0; 
                         // 若松開(kāi),回到狀態(tài) 0 迄埃,等待下次按鍵到來(lái)
                               cnt_s = 0;
                            end
                   end
                   default : s = 1; 
           endcase
       end
   end
////////////////////////////////////////////////////////////
      
///        model_in 按鍵       ///
reg model;
reg [19:0]cnt_m;
reg [1:0]m;
 always @(posedge clk or negedge rst_n)       
   begin
       if(!rst_n)
           begin
               cnt_m <= 0;
               m <= 0;
               model <= 1; 
           end
       else
       begin
           case(m) 
               0:begin
                   if(cnt_m < T40MS) 
                     // 按下時(shí)間大于40MS 認(rèn)為有效
                       begin
                           if(!model_in) 
                               cnt_m = cnt_m+1'b1;
                           else
                               cnt_m = 0;
                         end
                   else //counter> 40MS 疗韵,說(shuō)明確實(shí)按鍵是按下了
                         begin 
                               model = 0; 
                           // 給沖擊信號(hào) ,0~1 是上升沿
                               m = 1;   
                           //確定按鍵按下侄非,轉(zhuǎn)到狀態(tài) 1
                               cnt_m = 0;  //計(jì)數(shù)器清零
                         end
                     end
                1:begin
                       model = 1;    //產(chǎn)生尖脈沖
                       if(cnt_m < T40MS)
                         // 按下時(shí)間大于40MS 松開(kāi)有效
                           begin
                               if(model_in) 
                                       cnt_m = cnt_m+1'b1;
                               else
                                       cnt_m = 0; 
                             end
                        else
                            begin
                               m = 0; 
                        // 若松開(kāi)蕉汪,回到狀態(tài) 0 ,等待下次按鍵到來(lái)
                               cnt_m = 0;
                            end
                   end
                   default : m = 1; 
           endcase
       end
   end
////////////////////////////////////////////////////////////


/************************************************/
reg [2:0]type;
//00:時(shí)鐘正常跑模式
//01:時(shí)鐘調(diào)分模式,在該模式時(shí)間計(jì)數(shù)器停止計(jì)數(shù)
//10: 時(shí)鐘調(diào)時(shí)模式逞怨,在該模式時(shí)間計(jì)數(shù)器停止計(jì)數(shù)
//11:鬧鐘調(diào)分模式者疤,在該模式時(shí)間計(jì)數(shù)器正常計(jì)數(shù)
//100:鬧鐘調(diào)時(shí)模式,在該模式時(shí)間計(jì)數(shù)器正常計(jì)數(shù)
/************************************************/

always @(posedge clk or negedge rst_n)
    if(!rst_n) 
    begin
        Display_Model <= 1'b0;
        a_add <= 1'b0;
        a_sub <= 1'b0;
        c_add <= 1'b0;
        c_sub <= 1'b0;
        Time_model <= 3'b000;
        type <= 3'b000;
        cnt_control <= 1'b1;//啟動(dòng)計(jì)數(shù)
    end
    else
    begin
         if(!model) 
            begin
                if(type == 3'b100)
                    type = 3'b000;
                else
                    begin
                        type = type + 1'b1;
                    end
            end
        case(type)
        //時(shí)鐘正常開(kāi)始跑
            3'b000:
            begin
                Time_model <= 3'b000; 
                cnt_control <= 1'b1;//啟動(dòng)計(jì)數(shù)
                Display_Model <= 1'b0;
                a_add <= 1'b0;
                a_sub <= 1'b0;
                c_add <= 1'b0;
                c_sub <= 1'b0;
            end
            //調(diào)分模式            
            3'b001:
            begin 
            cnt_control <= 1'b0; //關(guān)閉計(jì)數(shù)
            Time_model <= 3'b001;
            Display_Model <= 1'b0;
                if(!add)//加
                    begin
                        c_add <=1'b1 ;
                    end
                else
                    begin
                        c_add <= 1'b0;
                    end
                    
                 if(!sub)//減
                    begin
                        c_sub <= 1'b1;
                    end
                 else
                    begin
                        c_sub <= 1'b0;
                    end
               end
            //調(diào)時(shí)模式
            3'b010:
            begin 
             cnt_control <= 1'b0;//關(guān)閉計(jì)數(shù)
             Time_model <= 2'b010;
             Display_Model <= 1'b0;
                if(!add)//加
                    begin
                        c_add <=1'b1 ;
                    end
                else
                    begin
                        c_add <= 1'b0;
                    end
                 if(!sub)//減
                    begin
                        c_sub <= 1'b1;
                    end
                 else
                    begin
                        c_sub <= 1'b0;
                    end
               end

           //調(diào)分模式            
                       3'b011:
                       begin 
                       cnt_control <= 1'b1; //kaijishu
                       Time_model <= 3'b011;
                       Display_Model <= 1'b1;
                           if(!add)//加
                               begin
                                   a_add <=1'b1 ;
                               end
                           else
                               begin
                                   a_add <= 1'b0;
                               end
                            if(!sub)//減
                               begin
                                   a_sub <= 1'b1;
                               end
                            else
                               begin
                                   a_sub <= 1'b0;
                               end
                          end
           
                       //調(diào)時(shí)模式
                       3'b100:
                       begin 
                        cnt_control <= 1'b1;//關(guān)閉計(jì)數(shù)
                        Time_model <= 3'b100;
                        Display_Model <= 1'b1;
                        
                           if(!add)//加
                               begin
                                   a_add <=1'b1 ;
                               end
                           else
                               begin
                                   a_add <= 1'b0;
                               end
                               
                            if(!sub)//減
                               begin
                                   a_sub <= 1'b1;
                               end
                            else
                               begin
                                   a_sub <= 1'b0;
                               end
                          end           
         
           default:type <= 3'b000;
        endcase
   end
endmodule

</div>

時(shí)鐘模塊(clock)

輸入 功能說(shuō)明 輸出 功能說(shuō)明
c_add hour_h 小時(shí)高位
c_sub hour_l 小時(shí)低位
Time_model 模式控制端 minute_h 分鐘高位
cot_control 計(jì)數(shù)器開(kāi)關(guān) minute_l 分鐘低位
clk 時(shí)鐘
rst_n 復(fù)位

細(xì)節(jié)講解

時(shí)鐘模塊的輸入都是來(lái)自鍵盤(pán)模塊叠赦,所以輸入不多說(shuō)了驹马,提一點(diǎn),我的板子上的輸入的時(shí)鐘(clk)除秀,用的是50MHz晶振,而時(shí)鐘是1Hz,也就是一秒走一下窥翩,所以?xún)?nèi)部必須分頻,代碼里注意看一下鳞仙,我為了方便調(diào)試寇蚊,分頻并不是分頻到1Hz,如果你有需要用到棍好,修改里面的參數(shù)就好仗岸。

模塊輸出

模塊的輸出就是時(shí)鐘的數(shù)據(jù),是傳給顯示模塊去驅(qū)動(dòng)數(shù)碼管顯示的借笙。
小時(shí)高位扒怖,0~2,三種情況业稼,兩根線(xiàn)[1:0]
小時(shí)低位盗痒,0~0,十種情況,四根線(xiàn)[3:0]
分鐘高位俯邓,0~5骡楼,六種情況,三根線(xiàn)[2:0]
分鐘低位稽鞭,0~9鸟整,十種情況,四根線(xiàn)[3:0]

代碼展示

module clock(
        input  clk, 
        input  rst_n,
        input  cnt_control, //控制定時(shí)器 ,1啟動(dòng) 朦蕴,0停止
        input  c_add,       //控制 加
        input  c_sub,       //控制 減
        input  [2:0]Time_model,
        
        output  [1:0]hour_h,     //小時(shí) 十位
        output  [3:0]hour_l,     //小時(shí) 個(gè)位
        output  [2:0]minute_h,   //分鐘 十位
        output  [3:0]minute_l   //分鐘 個(gè)位
    );
    parameter  S= 100000000;
    parameter  M=60;
    /*********************************************************/
    //1S計(jì)數(shù)器
    reg [31:0] cnt1s;
    always @(posedge clk or negedge rst_n)
        if(!rst_n) 
            cnt1s <= 15'd0;
        else if((cnt1s == S) || (!cnt_control)) 
                cnt1s <= 15'd0;
            else if(cnt_control)
                cnt1s <= cnt1s + 1'b1; 
                
    /*********************************************************/
    
    ///////////////////////////////////////////////////////////
 //                        功能控制                        //
 //////////////////////////////////////////////////////////
    reg [1:0]flag;//用來(lái)標(biāo)志reg1是否到了2篮条,到了2,reg2只能加到4
    reg [1:0] reg1;//時(shí)的第一位:0~2
    reg [3:0] reg2;
  //時(shí)的第二位:當(dāng)?shù)谝晃粸?和1時(shí),可以是0~9,當(dāng)?shù)谝晃粸?時(shí)吩抓,只能是0~9,
    reg [2:0] reg3;//分的第一位:只能是0~5
    reg [3:0] reg4;//分的第二位:是0~9
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
         begin
            reg1 <= 2'd0; //小時(shí) 高位
            reg2 <= 4'd0; //小時(shí) 低位
            reg3 <= 3'd0; //分鐘 高位
            reg4 <= 4'd0; //分鐘 低位
            flag <= 2'd0;
        end
        else
            case(Time_model)
            //時(shí)鐘正常開(kāi)始跑
                3'b000:
                begin    
                    if(cnt1s == S)  //一分鐘到了
                    begin
                        reg4 <= reg4 + 1'b1;    
                        if(reg4 == 4'd9)        
                        begin
                            reg4 <= 4'd0;
                            reg3 <= reg3 + 1'b1;
                            
                            if(reg3 == 3'd5)    
                            begin
                                reg3 <= 3'd0;        
                                if(reg1 == 2'd2)    
                                    begin
                                        reg2 <= reg2 + 1'b1;
                                        if(reg2 == 4'd3)
                                        begin
                                            reg2 <= 4'd0;                
                                            reg1 <= 2'd0;                            
                                        end
                                    end 
                                else 
                                    begin
                                        reg2 <= reg2 + 1'b1;
                                        if(reg2 == 4'd9)
                                        begin
                                        reg2 <= 4'd0;
                                        reg1 <= reg1 + 1'b1;
                                        end
                                    end
                             end
                            
                        end
                    end
                end
                
                //調(diào)分模式            
                3'b001:
                begin 
                    if(c_add)//加
                    begin
                        reg4 <= reg4 + 1'b1;
                        if(reg4 == 4'd9)
                        begin
                            reg4 <= 4'd0;
                            reg3 <= reg3 + 1'b1;
                            if(reg3 > 3'd5)
                                reg3 <= 3'd0;
                        end
                    end
                    else if(c_sub)//減
                        begin
                            reg4 <= reg4 - 1'b1;
                            if(reg4 == 4'd0)
                                begin
                                    reg4 <= 4'd9;
                                    reg3 <= reg3 - 3'd1;
                                    if(reg3 == 3'd0)
                                        reg3 <= 3'd5;
                                end
                        end
                end  
                //調(diào)時(shí)模式
                3'b010: 
                begin
                    if(c_add)//加
                    begin
                        if(flag == 2'd2)
                        begin
                            reg2 <= reg2 + 1'b1;
                            if(reg2 >= 4'd3)
                            begin
                                reg2 <= 4'd0;
                                reg1 <= 2'd0;
                                flag <= 2'd0;
                            end
                        end
                        else
                        begin
                            reg2 <= reg2 + 1'b1;
                            if(reg2 == 4'd9)
                            begin
                                flag <= flag + 1'b1;
                                reg2 <= 4'd0;
                                reg1 <= reg1 + 1'b1;         
                            end
                        end
                    end
                    else if(c_sub)//減
                        begin
                             if(flag == 2'd0)
                             begin
                                 reg2 <= reg2 - 1'b1;
                                 if(reg2 == 4'd0)
                                 begin
                                     reg2 <= 4'd3;
                                     reg1 <= 2'd2;
                                     flag <= 2'd2;
                                 end
                             end
                             else
                             begin
                                  reg2 <= reg2 - 1'b1;
                                  if(reg2 == 4'd0)
                                  begin
                                      flag <= flag - 1'b1;
                                      reg1 <= reg1 - 1'b1;   
                                      reg2 <= 4'd9;        
                             end
                       end
                  end
                end    
            endcase
     end       
    /************************************************/
    assign hour_h = reg1;
    assign hour_l = reg2;
    assign minute_h = reg3;
    assign minute_l = reg4;
    /************************************************/
endmodule

鬧鐘模塊(alarm)

輸入 功能說(shuō)明 輸出 功能說(shuō)明
a_hour 鬧鐘小時(shí)控制 a_hour_h 鬧鐘小時(shí)高位
a_minute 鬧鐘分鐘控制 a_hour_l 鬧鐘小時(shí)低位
clk 時(shí)鐘 a_minute_h 鬧鐘分鐘高位
rst_n 復(fù)位 a_minute_l 鬧鐘分鐘低位

細(xì)節(jié)講解

鬧鐘模塊與時(shí)鐘模塊的其實(shí)沒(méi)什么區(qū)別涉茧,就是在調(diào)鬧鐘時(shí),時(shí)鐘正常運(yùn)行疹娶,時(shí)鐘調(diào)分降瞳,調(diào)時(shí)都會(huì)停止運(yùn)行,也就是計(jì)數(shù)器不計(jì)數(shù)蚓胸,其他的區(qū)別不大挣饥。

代碼展示

<button class="testButton" onclick="document.all.child3.style.display=(document.all.child3.style.display =='none')?'':'none'">點(diǎn)擊顯\隱代碼</button>
<div id="child3" style="display:">

module alarm(
        input  clk, 
        input  rst_n,
        input  c_add,       //控制 加
        input  c_sub,       //控制 減
        input  [2:0]Time_model,

        output  [1:0]a_hour_h,     //鬧鐘小時(shí) 十位
        output  [3:0]a_hour_l,     //鬧鐘小時(shí) 個(gè)位
        output  [2:0]a_minute_h,   //鬧鐘分鐘 十位
        output  [3:0]a_minute_l    //鬧鐘分鐘 個(gè)位
    );
    //////////////////////////////////////////////////////////
 //                        功能控制                       //
 ////////////////////////////////////////////////////////
    reg [1:0]flag;//用來(lái)標(biāo)志reg1是否到了2,到了2,reg2只能加到4
    reg [1:0] reg1;//時(shí)的第一位:0~2
    reg [3:0] reg2;
  //時(shí)的第二位:當(dāng)?shù)谝晃粸?和1時(shí)沛膳,可以是0~9,當(dāng)?shù)谝晃粸?時(shí)扔枫,只能是0~9,
    reg [2:0] reg3;//分的第一位:只能是0~5
    reg [3:0] reg4;//分的第二位:是0~9
    
    always @(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
         begin
            reg1 <= 2'd0; //鬧鐘小時(shí) 高位
            reg2 <= 4'd0; //鬧鐘小時(shí) 低位
            reg3 <= 3'd0; //鬧鐘分鐘 高位
            reg4 <= 4'd0; //鬧鐘分鐘 低位
            flag <= 2'd0;
        end
        else
            case(Time_model)
                //鬧鐘調(diào)分模式            
                3'b011:
                begin 
                    if(c_add)//加
                    begin
                        reg4 <= reg4 + 1'b1;
                        if(reg4 == 4'd9)
                        begin
                            reg4 <= 4'd0;
                            reg3 <= reg3 + 1'b1;
                            if(reg3 > 3'd4)
                                reg3 <= 3'd0;
                        end
                    end
                    else if(c_sub)//減
                        begin
                            reg4 <= reg4 - 1'b1;
                            if(reg4 == 4'd0)
                                begin
                                    reg4 <= 4'd9;
                                    reg3 <= reg3 - 3'd1;
                                    if(reg3 == 3'd0)
                                        reg3 <= 3'd5;
                                end
                        end
                end  
                //鬧鐘調(diào)時(shí)模式
                3'b100: 
                begin
                    if(c_add)//加
                    begin
                        if(flag == 2'd2)
                        begin
                            reg2 <= reg2 + 1'b1;
                            if(reg2 >= 4'd3)
                            begin
                                reg2 <= 4'd0;
                                reg1 <= 2'd0;
                                flag <= 2'd0;
                            end
                        end
                        else
                        begin
                            reg2 <= reg2 + 1'b1;
                            if(reg2 == 4'd9)
                            begin
                                flag <= flag + 1'b1;
                                reg2 <= 4'd0;
                                reg1 <= reg1 + 1'b1;
                                
                            end
                        end
                    end
                    else if(c_sub)//減
                        begin
                             if(flag == 2'd0)
                             begin
                                 reg2 <= reg2 - 1'b1;
                                 if(reg2 == 4'd0)
                                 begin
                                     reg2 <= 4'd3;
                                     reg1 <= 2'd2;
                                     flag <= 2'd2;
                                 end
                             end
                             else
                             begin
                                  reg2 <= reg2 - 1'b1;
                                  if(reg2 == 4'd0)
                                  begin
                                      flag <= flag - 1'b1;
                                      reg1 <= reg1 - 1'b1;                              
                                      reg2 <= 4'd9;                                    
                             end
                       end
                  end
                end    
            endcase
     end       
    /************************************************/
    
    assign a_hour_h = reg1;
    assign a_hour_l = reg2;
    assign a_minute_h = reg3;
    assign a_minute_l = reg4;
    
    /************************************************/

endmodule

顯示模塊(display)

輸入 功能說(shuō)明 輸出 功能說(shuō)明
a_hour_h 鬧鐘小時(shí)高位 data 段選信號(hào)
a_hour_l 鬧鐘小時(shí)低位 select_wei 位選信號(hào)
a_minute_h 鬧鐘分鐘高位 beep 蜂鳴器
a_minute_l 鬧鐘分鐘低位
hour_h 時(shí)鐘小時(shí)高位
hour_l 時(shí)鐘小時(shí)低位
minute_h 時(shí)鐘分鐘高位
minute_l 時(shí)鐘分鐘低位
Display_Model 顯示模式控制
clk 時(shí)鐘
rst_n 復(fù)位

顯示模塊的輸入有三種類(lèi)型:

  1. 鬧鐘的數(shù)據(jù)
  2. 時(shí)鐘的數(shù)據(jù)
  3. 顯示模式控制信號(hào)

輸出也只有三個(gè)

  1. data是八段數(shù)碼管的段選信號(hào),由于我沒(méi)用小數(shù)點(diǎn)锹安,所以七根線(xiàn)
  2. select_wei數(shù)碼管位選短荐,四個(gè)數(shù)碼管,四根線(xiàn)
  3. beep鏈接蜂鳴器的叹哭,一根線(xiàn)忍宋。

細(xì)節(jié)講解

顯示模塊里用到的主要是數(shù)碼管動(dòng)態(tài)掃描的知識(shí),掃描頻率如何設(shè)置风罩,這些問(wèn)題糠排,查一下數(shù)碼管的是如何顯示就知道了,抓住段選和位選超升,還有動(dòng)態(tài)掃描的原理入宦,然后分清楚你使用的數(shù)碼管是共陰還是共陽(yáng),這個(gè)顯示模塊就很好理解了室琢。

代碼展示

module  display(
            input clk,
            input rst_n,
            
            //時(shí)鐘模式 雙段選數(shù)據(jù)
            input [1:0] hour_h,
            input [3:0] hour_l,
            input [2:0] minute_h,
            input [3:0] minute_l,
            
            //鬧鐘模式 段選數(shù)據(jù)
            input [1:0] a_hour_h,
            input [3:0] a_hour_l,
            input [2:0] a_minute_h,
            input [3:0] a_minute_l,
            
            input Display_Model,//0:時(shí)鐘模式乾闰,1:秒表模式
            
            output [6:0] data,//數(shù)碼管段選
            output reg[3:0] select_wei, //數(shù)碼管位選
            output reg alarm_out
                        );

/***********************************/
parameter     
            SEG_0     = 7'h7e,//c0,
            SEG_1     = 7'h30,//f9,
            SEG_2     = 7'h6d,//a4,
            SEG_3     = 7'h79,//b0,
            SEG_4     = 7'h33,//99,
            SEG_5     = 7'h5b,//92,
            SEG_6     = 7'h5f,//82,
            SEG_7     = 7'h70,//F8,
            SEG_8     = 7'h7f,//80,
            SEG_9     = 7'h7b;//90,
        
            /***********************************/
                        //時(shí)鐘數(shù)據(jù)編碼        
            /***********************************/
wire [6:0]c_data1;
wire [6:0]c_data2;
wire [6:0]c_data3;
wire [6:0]c_data4;

//數(shù)碼管一要顯示的列表數(shù)據(jù)(0~2)
reg [6:0] data1_temp;
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data1_temp <= SEG_0;
    else
        case(hour_h)
            2'd0:    data1_temp <= SEG_0;
            2'd1:    data1_temp <= SEG_1;
            2'd2:    data1_temp <= SEG_2;
            default: data1_temp <= SEG_0;
        endcase
/***********************************/
//數(shù)碼管二要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] data2_temp;
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data2_temp <= SEG_0;
    else
        case(hour_l)
            4'd0:    data2_temp <= SEG_0;
            4'd1:    data2_temp <= SEG_1;
            4'd2:    data2_temp <= SEG_2;
            4'd3:    data2_temp <= SEG_3;
            4'd4:    data2_temp <= SEG_4;
            4'd5:    data2_temp <= SEG_5;
            4'd6:    data2_temp <= SEG_6;
            4'd7:    data2_temp <= SEG_7;
            4'd8:    data2_temp <= SEG_8;
            4'd9:    data2_temp <= SEG_9;
            default: data2_temp <= SEG_0;
        endcase
/***********************************/
//數(shù)碼管三要顯示的列表數(shù)據(jù) (0~5)
reg [6:0] data3_temp;
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data3_temp <= SEG_0;
    else
        case(minute_h)
            3'd0:    data3_temp <= SEG_0;
            3'd1:    data3_temp <= SEG_1;
            3'd2:    data3_temp <= SEG_2;
            3'd3:    data3_temp <= SEG_3;
            3'd4:    data3_temp <= SEG_4;
            3'd5:    data3_temp <= SEG_5;
            default: data3_temp <= SEG_0;
        endcase
/***********************************/
//數(shù)碼管四要顯示的列表數(shù)據(jù)(1~9)
reg [6:0] data4_temp;
always @(posedge clk or negedge rst_n)
    if(!rst_n)
        data4_temp <= SEG_0;
    else
        case(minute_l)
            4'd0:    data4_temp <= SEG_0;
            4'd1:    data4_temp <= SEG_1;
            4'd2:    data4_temp <= SEG_2;
            4'd3:    data4_temp <= SEG_3;
            4'd4:    data4_temp <= SEG_4;
            4'd5:    data4_temp <= SEG_5;
            4'd6:    data4_temp <= SEG_6;
            4'd7:    data4_temp <= SEG_7;
            4'd8:    data4_temp <= SEG_8;
            4'd9:    data4_temp <= SEG_9;
            default: data4_temp <= SEG_0;
        endcase
/*****************************************/
assign c_data1 = data1_temp;
assign c_data2 = data2_temp;
assign c_data3 = data3_temp;
assign c_data4 = data4_temp;
/*****************************************/
        
            /***********************************/
                        //鬧鐘數(shù)據(jù)編碼        
            /***********************************/
wire [6:0]a_data1;
wire [6:0]a_data2;
wire [6:0]a_data3;
wire [6:0]a_data4;
//數(shù)碼管一要顯示的列表數(shù)據(jù)(0~5)
reg [6:0] a_data1_temp;
always @(posedge clk or negedge rst_n)
    if(!rst_n) 
        a_data1_temp <= SEG_0;
    else  
        case(a_hour_h)
            3'd0:    a_data1_temp <= SEG_0;
            3'd1:    a_data1_temp <= SEG_1;
            3'd2:    a_data1_temp <= SEG_2;
            3'd3:    a_data1_temp <= SEG_3;
            3'd4:    a_data1_temp <= SEG_4;
            3'd5:    a_data1_temp <= SEG_5;
            default: a_data1_temp <= SEG_0;
        endcase
/***********************************/
//數(shù)碼管二要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] a_data2_temp;
always @(posedge clk or negedge rst_n)
    if(!rst_n) 
        a_data2_temp <= SEG_0;
    else
        case(a_hour_l)
            4'd0:    a_data2_temp <= SEG_0;
            4'd1:    a_data2_temp <= SEG_1;
            4'd2:    a_data2_temp <= SEG_2;
            4'd3:    a_data2_temp <= SEG_3;
            4'd4:    a_data2_temp <= SEG_4;
            4'd5:    a_data2_temp <= SEG_5;
            4'd6:    a_data2_temp <= SEG_6;
            4'd7:    a_data2_temp <= SEG_7;
            4'd8:    a_data2_temp <= SEG_8;
            4'd9:    a_data2_temp <= SEG_9;
            default: a_data2_temp <= SEG_0;
        endcase
/*****************************************/
//數(shù)碼管三要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] a_data3_temp;        
always @(posedge clk or negedge rst_n)
    if(!rst_n) 
        a_data3_temp <= SEG_0;
    else 
        case(a_minute_h)
            4'd0:    a_data3_temp <= SEG_0;
            4'd1:    a_data3_temp <= SEG_1;
            4'd2:    a_data3_temp <= SEG_2;
            4'd3:    a_data3_temp <= SEG_3;
            4'd4:    a_data3_temp <= SEG_4;
            4'd5:    a_data3_temp <= SEG_5;
            4'd6:    a_data3_temp <= SEG_6;
            4'd7:    a_data3_temp <= SEG_7;
            4'd8:    a_data3_temp <= SEG_8;
            4'd9:    a_data3_temp <= SEG_9;
            default: a_data3_temp <= SEG_0;
        endcase
/***********************************/
//數(shù)碼管四要顯示的列表數(shù)據(jù)(0~9)
reg [6:0] a_data4_temp;
always @(posedge clk or negedge rst_n)
    if(!rst_n) 
        a_data4_temp <= SEG_0;
    else
        case(a_minute_l)
            4'd0:    a_data4_temp <= SEG_0;
            4'd1:    a_data4_temp <= SEG_1;
            4'd2:    a_data4_temp <= SEG_2;
            4'd3:    a_data4_temp <= SEG_3;
            4'd4:    a_data4_temp <= SEG_4;
            4'd5:    a_data4_temp <= SEG_5;
            4'd6:    a_data4_temp <= SEG_6;
            4'd7:    a_data4_temp <= SEG_7;
            4'd8:    a_data4_temp <= SEG_8;
            4'd9:    a_data4_temp <= SEG_9;
            default: a_data4_temp <= SEG_0;
        endcase
/*******************************************************/    
assign a_data1 = a_data1_temp;
assign a_data2 = a_data2_temp;
assign a_data3 = a_data3_temp;
assign a_data4 = a_data4_temp;
/***************************************************/

/******************************************/
parameter shuaxin = 17'h1ffff;
// 數(shù)碼管掃描頻率
reg [19:0] cnt;    
reg [1:0] num;//每隔5MS,num加1
always @(posedge clk or negedge rst_n)
    if(!rst_n) 
    begin
        select_wei <= 4'd8; // 1000
        cnt <= 18'd0;
        num <= 2'd0;
    end
    else if(cnt == shuaxin) 
            begin
                num <= num + 1'b1;
                cnt <= 18'd0;
                if(select_wei == 4'd1) //0001
                     select_wei <= 4'd8;
                 else
              select_wei <= {1'b0,select_wei[3:1]};   //右移
            end
         else
              cnt <= cnt + 1'b1;
/******************************************/
//通過(guò)Display_Model來(lái)確定是要送秒表數(shù)據(jù)還是鬧鐘的數(shù)據(jù)
reg [7:0] data_temp;
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        data_temp <= 7'h7e;
    else if(cnt == shuaxin) 
        case(num)
            2'd0:    data_temp <= Display_Model ? a_data1:c_data1;//給第一個(gè)數(shù)碼管送數(shù)據(jù)
            2'd1:    data_temp <= Display_Model ? a_data2:c_data2;//給第二個(gè)數(shù)碼管送數(shù)據(jù)
            2'd2:    data_temp <= Display_Model ? a_data3:c_data3;//給第二個(gè)數(shù)碼管送數(shù)據(jù)
            2'd3:    data_temp <= Display_Model ? a_data4:c_data4;//給第二個(gè)數(shù)碼管送數(shù)據(jù)
        endcase
end
assign data = data_temp;
/******************************************/   

  //////        比較器模塊             //////
always @(posedge clk or negedge rst_n)
begin
    if(!rst_n)
        alarm_out <= 0 ;
    else if(a_data1 == c_data1 && a_data2 == c_data2 && a_data3 == c_data3 && a_data4 == c_data4)
            alarm_out <=1;
            else
            alarm_out<=0;
end
endmodule

</div>

top層

主要是鏈接盈滴,直接上代碼吧涯肩。

代碼展示


module top(
            input clk,
            input rst_n,
           
            input add_in,
            input sub_in,
            input model_in,
            
            output [6:0] data,//數(shù)碼管段選數(shù)據(jù)
            output [3:0] select_wei, //數(shù)碼管位選
            output  alarm_out
            
            
           );

wire [1:0] hour_h;
wire [3:0] hour_l;
wire [2:0] minute_h;
wire [3:0] minute_l;

wire [1:0] a_hour_h;
wire [3:0] a_hour_l;
wire [2:0] a_minute_h;
wire [3:0] a_minute_l;

wire Display_Model;
wire [2:0]Time_model;

wire c_add;
wire c_sub;

wire a_add; 
wire a_sub;
wire cnt_control; //控制定時(shí)器


//
key       U1(
        //top的input
          .clk(clk),
          .rst_n(rst_n), 
          
          .add_in(add_in),
          .sub_in(sub_in),
          .model_in(model_in),
        
        //連clock的線(xiàn)
          .cnt_control(cnt_control),
          .c_add(c_add),
          .c_sub(c_sub),
          .Time_model(Time_model),
          
        //連alarm的線(xiàn)
           .a_add(a_add),
           .a_sub(a_sub),
        
        //連display的線(xiàn)
           .Display_Model(Display_Model)        
           );
                   
clock       U2(
        //input
              .clk(clk),
              .rst_n(rst_n),
              
        //從key來(lái)的線(xiàn)
              .c_add(c_add),
              .c_sub(c_sub),
              .cnt_control(cnt_control),
              .Time_model(Time_model),
         
        //output     
        //連display的線(xiàn)
        
              .hour_h(hour_h),
              .hour_l(hour_l),
              .minute_h(minute_h),
              .minute_l(minute_l)
                      
            );
alarm           U3(
                    //input
                          .clk(clk),
                          .rst_n(rst_n),
                          
                    //從key來(lái)的線(xiàn)
                          .c_add(a_add),
                          .c_sub(a_sub),              
                          .Time_model(Time_model),
                     
                    //output     
                    //連display的線(xiàn)
                    
                          .a_hour_h(a_hour_h),
                          .a_hour_l(a_hour_l),
                          .a_minute_h(a_minute_h),
                          .a_minute_l(a_minute_l)
                                  
                        );
    

                    
display             U4(
                        //input 
                        .clk(clk),
                        .rst_n(rst_n),
                        
                        //從clock 來(lái)的線(xiàn)
                        .hour_h(hour_h),
                        .hour_l(hour_l),
                        .minute_h(minute_h),
                        .minute_l(minute_l),
                        
                        //從alarm 來(lái)的線(xiàn)
                        .a_hour_h(a_hour_h),
                        .a_hour_l(a_hour_l),
                        .a_minute_h(a_minute_h),
                        .a_minute_l(a_minute_l),
                       
                        //從key 來(lái)的線(xiàn)
                        .Display_Model(Display_Model),
                        
                        //output 
                        .data(data),
                        .select_wei(select_wei),
                        .alarm_out(alarm_out)
                        );
                 
endmodule

細(xì)節(jié)講解

top層的作用是連接各個(gè)模塊,列出系統(tǒng)的輸入輸出,然后分清楚中間節(jié)點(diǎn)病苗,如果之前沒(méi)有寫(xiě)過(guò)top層疗垛,可以先從試著寫(xiě)個(gè)小系統(tǒng),比如:全加器(調(diào)用半加器實(shí)現(xiàn))铅乡,如果你已經(jīng)是老司機(jī)继谚,相信已經(jīng)駕輕就熟了烈菌,不多說(shuō)了阵幸。其實(shí),我這個(gè)例化寫(xiě)得有點(diǎn)煩了芽世,例化如果非要分寫(xiě)法可以分為兩種挚赊,我這是比較煩的,不過(guò)我也不改了济瓢,╭(╯^╰)╮

寫(xiě)在后面的話(huà)

數(shù)字鐘就講訴到這里荠割,整個(gè)系統(tǒng)不難理解,只是模塊之間的聯(lián)系必須弄清楚旺矾,我的觀(guān)點(diǎn)是:把需要的模塊列出來(lái)蔑鹦,分析模塊之間的聯(lián)系,再具體看各個(gè)模塊的內(nèi)容箕宙,單個(gè)驗(yàn)證嚎朽,自頂向下設(shè)計(jì),主要還是多琢磨吧柬帕,有耐心就好哟忍。

關(guān)于文章,如果有任何問(wèn)題都可以在評(píng)論區(qū)和我交流陷寝,如果有錯(cuò)誤锅很,歡迎斧正,謝謝了~~

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末凤跑,一起剝皮案震驚了整個(gè)濱河市爆安,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌仔引,老刑警劉巖鹏控,帶你破解...
    沈念sama閱讀 212,542評(píng)論 6 493
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異肤寝,居然都是意外死亡当辐,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,596評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門(mén)鲤看,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)缘揪,“玉大人,你說(shuō)我怎么就攤上這事≌殷荩” “怎么了蹈垢?”我有些...
    開(kāi)封第一講書(shū)人閱讀 158,021評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)袖裕。 經(jīng)常有香客問(wèn)我曹抬,道長(zhǎng),這世上最難降的妖魔是什么急鳄? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,682評(píng)論 1 284
  • 正文 為了忘掉前任谤民,我火速辦了婚禮,結(jié)果婚禮上疾宏,老公的妹妹穿的比我還像新娘张足。我一直安慰自己,他們只是感情好坎藐,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,792評(píng)論 6 386
  • 文/花漫 我一把揭開(kāi)白布为牍。 她就那樣靜靜地躺著,像睡著了一般岩馍。 火紅的嫁衣襯著肌膚如雪碉咆。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,985評(píng)論 1 291
  • 那天蛀恩,我揣著相機(jī)與錄音疫铜,去河邊找鬼。 笑死赦肋,一個(gè)胖子當(dāng)著我的面吹牛块攒,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播佃乘,決...
    沈念sama閱讀 39,107評(píng)論 3 410
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼囱井,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了趣避?” 一聲冷哼從身側(cè)響起庞呕,我...
    開(kāi)封第一講書(shū)人閱讀 37,845評(píng)論 0 268
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎程帕,沒(méi)想到半個(gè)月后住练,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,299評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡愁拭,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,612評(píng)論 2 327
  • 正文 我和宋清朗相戀三年讲逛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片岭埠。...
    茶點(diǎn)故事閱讀 38,747評(píng)論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡盏混,死狀恐怖蔚鸥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情许赃,我是刑警寧澤止喷,帶...
    沈念sama閱讀 34,441評(píng)論 4 333
  • 正文 年R本政府宣布,位于F島的核電站混聊,受9級(jí)特大地震影響弹谁,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜句喜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,072評(píng)論 3 317
  • 文/蒙蒙 一预愤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧藤滥,春花似錦鳖粟、人聲如沸社裆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,828評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)泳秀。三九已至标沪,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間嗜傅,已是汗流浹背金句。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,069評(píng)論 1 267
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留吕嘀,地道東北人违寞。 一個(gè)月前我還...
    沈念sama閱讀 46,545評(píng)論 2 362
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像偶房,于是被迫代替她去往敵國(guó)和親趁曼。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,658評(píng)論 2 350

推薦閱讀更多精彩內(nèi)容