1. 程式人生 > >verilog實現的毫秒級計時器

verilog實現的毫秒級計時器

使用開發板完成毫秒級的計時器。範圍從0.000s ~ 9.999s, 之後自動溢位回到0.000s。用4位7段數碼管顯示計時時間,秒單位要有小數點。用1個開關控制計時開始和停止。停止時,觸發inc的button一次,對應時間增加1ms。Reset按鈕點選後,時間恢復到0.000s。

原理

     1 狀態轉換圖

計時器加1計算顯示數字的電路邏輯:

`timescale 1ns / 1ps
//////////////////////////////////////////////////////////////////////////////////
// Company: 
// Engineer: 
// 
// Create Date:    16:35:38 11/30/2014 
// Design Name: 
// Module Name:    ms_timer 
// Project Name: 
// Target Devices: 
// Tool versions: 
// Description: 
//
// Dependencies: 
//
// Revision: 
// Revision 0.01 - File Created
// Additional Comments: 
//
//////////////////////////////////////////////////////////////////////////////////
 
module ms_timer(
input clk,
input inc,
input wire switch, // 1 為start, 0 為stop
input rst, // 復位,上升沿觸發,非同步
output reg [7:0] num, // 選擇顯示的資料,用parameter引數賦值
output reg [3:0] loc// 選擇哪一個數碼管位輸出
    );
parameter  SEG_NUM0 = 8'b00000011,  // abcdefg dp
           SEG_NUM1 = 8'b10011111,
              SEG_NUM2 = 8'b00100101,
              SEG_NUM3 = 8'b00001101,
              SEG_NUM4 = 8'b10011001,
              SEG_NUM5 = 8'b01001001,
              SEG_NUM6 = 8'b01000001,
              SEG_NUM7 = 8'b00011111,
              SEG_NUM8 = 8'b00000001,
              SEG_NUM9 = 8'b00001001,
              SEGD_NUM0 = 8'b00000010,  // 秒單位,需要小數點 abcdefg dp
           SEGD_NUM1 = 8'b10011110,
              SEGD_NUM2 = 8'b00100100,
              SEGD_NUM3 = 8'b00001100,
              SEGD_NUM4 = 8'b10011000,
              SEGD_NUM5 = 8'b01001000,
              SEGD_NUM6 = 8'b01000000,
              SEGD_NUM7 = 8'b00011110,
              SEGD_NUM8 = 8'b00000000,
              SEGD_NUM9 = 8'b00001000;
 
// 位選        
parameter  DUAN_3 = 4'b0111,              
              DUAN_2 = 4'b1011,
              DUAN_1 = 4'b1101,
              DUAN_0 = 4'b1110;
               
reg [20:0] count = 0;
reg [3:0] ms1 = 0;   // 毫秒單位
reg [3:0] ms10 = 0; // 10毫秒單位
reg [3:0] ms100 = 0; // 100毫秒單位
reg [3:0] s1 = 0; // 1秒單位
 
reg [17:0] fenpin = 0;
reg clk_1ms = 0;
reg cen = 0;
integer fsm = 1; //判斷狀態,一開始為停止狀態
always @(posedge clk) begin
       if(fenpin == 100000)
           fenpin <= 0;
        else 
           fenpin <= fenpin + 1'b1;
end
 
always @ (posedge clk) begin
   if(fenpin < 50000)
        clk_1ms  <= 0;
    else
        clk_1ms  <= 1;
end
// 掃描位選
always @ (posedge clk) begin
   count <= count + 1'b1; 
end
 
always @ (posedge clk_1ms or posedge rst) begin
if (rst) begin
fsm = 1;
cen = 0;
end
else begin
 case(fsm)
    0: begin // 在start的自加狀態下   
        cen = 1;
        if(!switch)// 觸發stop
         fsm = 1;
         else 
          fsm = 0;
        end
     1: begin  // stop狀態
        cen = 0;
        if(switch) //觸發start
         fsm = 0;
       else if(inc) 
         fsm = 2;
         else
         fsm = 1;
       end        
     2: begin    // inc函式
        cen = 1;
        fsm = 3;
         end
     3: begin
        cen = 0;
         if(inc)
         fsm = 3;
         else
         fsm = 1;
       end
 endcase
end
 
end
 
// 計時器加1,實現4個數字的加法
always @ (posedge clk_1ms) begin 
if(!rst) begin
if(cen) begin
case(ms1)
     4'b1001: ms1 <= 4'b0000;
     default:  ms1 <= ms1 + 1'b1;
     endcase
      
     case(ms10)
     4'b1001: begin
               if(ms1 == 4'b1001)
                 ms10 <= 4'b0000;
                 end
     default: begin
               if(ms1 == 4'b1001)
                 ms10 <= ms10 + 1'b1;
                 end
     endcase
      
     case(ms100)
     4'b1001: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001)
                 ms100 <= 4'b0000;
                 end
     default: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001)
                 ms100 <= ms100 + 1'b1;
                 end
     endcase
      
     case(s1)
     4'b1001: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001 && ms100 == 4'b1001)
                 s1 <= 4'b0000;
                 end
     default: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001 && ms100 == 4'b1001)
                 s1 <= s1 + 1'b1;
                 end
     endcase
end
end
//復位清零
else begin
ms1 <= 0;
ms100 <= 0;
ms10 <= 0;
s1 <= 0;
end
end
 
// 掃描顯示,位選訊號。掃描到對應數碼管位就顯示那一位數字
always @ (posedge clk) begin
  case(count[19:18])
  2'b00: begin
          loc <= DUAN_3;
             case(s1)
             4'b0000: num <= SEGD_NUM0;
             4'b0001: num <= SEGD_NUM1;
             4'b0010: num <= SEGD_NUM2;
             4'b0011: num <= SEGD_NUM3;
             4'b0100: num <= SEGD_NUM4;
             4'b0101: num <= SEGD_NUM5;
             4'b0110: num <= SEGD_NUM6;
             4'b0111: num <= SEGD_NUM7;
             4'b1000: num <= SEGD_NUM8;
             4'b1001: num <= SEGD_NUM9;
             endcase
            end
     
  2'b01: begin
          loc <= DUAN_2;
             case(ms100)
             4'b0000: num <= SEG_NUM0;
             4'b0001: num <= SEG_NUM1;
             4'b0010: num <= SEG_NUM2;
             4'b0011: num <= SEG_NUM3;
             4'b0100: num <= SEG_NUM4;
             4'b0101: num <= SEG_NUM5;
             4'b0110: num <= SEG_NUM6;
             4'b0111: num <= SEG_NUM7;
             4'b1000: num <= SEG_NUM8;
             4'b1001: num <= SEG_NUM9;
             endcase
            end
  2'b10: begin
          loc <= DUAN_1;
             case(ms10)
             4'b0000: num <= SEG_NUM0;
             4'b0001: num <= SEG_NUM1;
             4'b0010: num <= SEG_NUM2;
             4'b0011: num <= SEG_NUM3;
             4'b0100: num <= SEG_NUM4;
             4'b0101: num <= SEG_NUM5;
             4'b0110: num <= SEG_NUM6;
             4'b0111: num <= SEG_NUM7;
             4'b1000: num <= SEG_NUM8;
             4'b1001: num <= SEG_NUM9;
             endcase
            end
  2'b11: begin
          loc <= DUAN_0;
             case(ms1)
             4'b0000: num <= SEG_NUM0;
             4'b0001: num <= SEG_NUM1;
             4'b0010: num <= SEG_NUM2;
             4'b0011: num <= SEG_NUM3;
             4'b0100: num <= SEG_NUM4;
             4'b0101: num <= SEG_NUM5;
             4'b0110: num <= SEG_NUM6;
             4'b0111: num <= SEG_NUM7;
             4'b1000: num <= SEG_NUM8;
             4'b1001: num <= SEG_NUM9;
             endcase
            end
  endcase
 
end
    
endmodule
 
 
 
//test 使用程式碼
/*
module ms_timer(
input clk,
input inc,
input wire switch, // 1 為start, 0 為stop
input rst, // 復位,上升沿觸發,非同步
output reg [7:0] num, // 選擇顯示的資料,用parameter引數賦值
output reg [3:0] loc// 選擇哪一個數碼管位輸出
    );
parameter  SEG_NUM0 = 8'b00000011,  // abcdefg dp
           SEG_NUM1 = 8'b10011111,
              SEG_NUM2 = 8'b00100101,
              SEG_NUM3 = 8'b00001101,
              SEG_NUM4 = 8'b10011001,
              SEG_NUM5 = 8'b01001001,
              SEG_NUM6 = 8'b01000001,
              SEG_NUM7 = 8'b00011111,
              SEG_NUM8 = 8'b00000001,
              SEG_NUM9 = 8'b00001001,
              SEGD_NUM0 = 8'b00000010,  // 秒單位,需要小數點 abcdefg dp
           SEGD_NUM1 = 8'b10011110,
              SEGD_NUM2 = 8'b00100100,
              SEGD_NUM3 = 8'b00001100,
              SEGD_NUM4 = 8'b10011000,
              SEGD_NUM5 = 8'b01001000,
              SEGD_NUM6 = 8'b01000000,
              SEGD_NUM7 = 8'b00011110,
              SEGD_NUM8 = 8'b00000000,
              SEGD_NUM9 = 8'b00001000;
 
// 位選        
parameter  DUAN_3 = 4'b0111,              
              DUAN_2 = 4'b1011,
              DUAN_1 = 4'b1101,
              DUAN_0 = 4'b1110;
               
reg [20:0] count = 0;
reg [3:0] ms1 = 0;   // 毫秒單位
reg [3:0] ms10 = 0; // 10毫秒單位
reg [3:0] ms100 = 0; // 100毫秒單位
reg [3:0] s1 = 0; // 1秒單位
 
reg cen = 0;
integer fsm = 1; //判斷狀態,一開始為停止狀態
 
// 掃描位選
always @ (posedge clk) begin
   count <= count + 1'b1; 
end
 
always @ (posedge clk or posedge rst) begin
if (rst) begin
fsm = 1;
cen = 0;
end
else begin
 case(fsm)
    0: begin // 在start的自加狀態下   
        cen = 1;
        if(!switch)// 觸發stop
         fsm = 1;
         else  
          fsm = 0;
        end
     1: begin  // stop狀態
        cen = 0;
        if(switch) //觸發start
         fsm = 0;
       else if(inc) 
         fsm = 2;
         else
         fsm = 1;
       end        
     2: begin
        cen = 1;
        fsm = 3;
         end
      3: begin
        cen = 0;
         if(inc)
         fsm = 3;
         else
         fsm = 1;
       end
 endcase
end
 
end
 
always @ (posedge clk) begin 
if(!rst) begin
if(cen) begin
case(ms1)
     4'b1001: ms1 <= 4'b0000;
     default:  ms1 <= ms1 + 1'b1;
     endcase
      
     case(ms10)
     4'b1001: begin
               if(ms1 == 4'b1001)
                 ms10 <= 4'b0000;
                 end
     default: begin
               if(ms1 == 4'b1001)
                 ms10 <= ms10 + 1'b1;
                 end
     endcase
      
     case(ms100)
     4'b1001: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001)
                 ms100 <= 4'b0000;
                 end
     default: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001)
                 ms100 <= ms100 + 1'b1;
                 end
     endcase
      
     case(s1)
     4'b1001: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001 && ms100 == 4'b1001)
                 s1 <= 4'b0000;
                 end
     default: begin
               if(ms1 == 4'b1001 && ms10 == 4'b1001 && ms100 == 4'b1001)
                 s1 <= s1 + 1'b1;
                 end
     endcase
end
end
 
else begin
ms1 <= 0;
ms100 <= 0;
ms10 <= 0;
s1 <= 0;
end
end
 
// 掃描顯示
always @ (posedge clk) begin
  case(count[2:1])
  2'b00: begin
          loc <= DUAN_3;
             case(s1)
             4'b0000: num <= SEGD_NUM0;
             4'b0001: num <= SEGD_NUM1;
             4'b0010: num <= SEGD_NUM2;
             4'b0011: num <= SEGD_NUM3;
             4'b0100: num <= SEGD_NUM4;
             4'b0101: num <= SEGD_NUM5;
             4'b0110: num <= SEGD_NUM6;
             4'b0111: num <= SEGD_NUM7;
             4'b1000: num <= SEGD_NUM8;
             4'b1001: num <= SEGD_NUM9;
             endcase
            end
     
  2'b01: begin
          loc <= DUAN_2;
             case(ms100)
             4'b0000: num <= SEG_NUM0;
             4'b0001: num <= SEG_NUM1;
             4'b0010: num <= SEG_NUM2;
             4'b0011: num <= SEG_NUM3;
             4'b0100: num <= SEG_NUM4;
             4'b0101: num <= SEG_NUM5;
             4'b0110: num <= SEG_NUM6;
             4'b0111: num <= SEG_NUM7;
             4'b1000: num <= SEG_NUM8;
             4'b1001: num <= SEG_NUM9;
             endcase
            end
  2'b10: begin
          loc <= DUAN_1;
             case(ms10)
             4'b0000: num <= SEG_NUM0;
             4'b0001: num <= SEG_NUM1;
             4'b0010: num <= SEG_NUM2;
             4'b0011: num <= SEG_NUM3;
             4'b0100: num <= SEG_NUM4;
             4'b0101: num <= SEG_NUM5;
             4'b0110: num <= SEG_NUM6;
             4'b0111: num <= SEG_NUM7;
             4'b1000: num <= SEG_NUM8;
             4'b1001: num <= SEG_NUM9;
             endcase
            end
  2'b11: begin
          loc <= DUAN_0;
             case(ms1)
             4'b0000: num <= SEG_NUM0;
             4'b0001: num <= SEG_NUM1;
             4'b0010: num <= SEG_NUM2;
             4'b0011: num <= SEG_NUM3;
             4'b0100: num <= SEG_NUM4;
             4'b0101: num <= SEG_NUM5;
             4'b0110: num <= SEG_NUM6;
             4'b0111: num <= SEG_NUM7;
             4'b1000: num <= SEG_NUM8;
             4'b1001: num <= SEG_NUM9;
             endcase
            end
  endcase
 
end
    
endmodule
*/

.v