數碼管動態顯示


  數碼管顯示分為靜態顯示和動態顯示。靜態顯示沒什么卵用,和led燈沒差別。而動態顯示用處很大,基本上數碼管的使用都是動態顯示。其原理很簡單:視覺暫留效應。數碼管從右到左,一個接一個的亮起熄滅,讓其總的速度加快,人眼看上去就像是一直亮着一樣。掃描時間間隔建議為20ms以內,人眼才不會感到閃爍。一般來說一位數碼管掃描1ms就能得到不錯的效果了。

一、方法1

  第一種數碼管動態顯示:采用分頻時鍾掃描方法

  1 //======================================================================
  2 // --- 名稱 : seg_display
  3 // --- 作者 : xianyu_FPGA
  4 // --- 日期 : 2018-11-10
  5 // --- 描述 : 數碼管動態顯示模塊,改自小梅哥FPGA
  6 //======================================================================
  7 
  8 module seg_display
  9 //---------------------<端口聲明>---------------------------------------
 10 (
 11 input                   clk                 , //時鍾,50Mhz
 12 input                   rst_n               , //復位,低電平有效
 13 input                   en                  , //數碼管顯示使能
 14 input      [31:0]       data                , //輸入數據
 15 output     [ 7:0]       seg_sel             , //數碼管位選
 16 output reg [ 7:0]       seg_data              //數碼管段選,即內容顯示
 17 );
 18 //---------------------<信號定義>---------------------------------------
 19 reg  [14:0]             cnt                 ;
 20 wire                    add_cnt             ;
 21 wire                    end_cnt             ;
 22 reg                     clk_1k              ;
 23 reg  [ 7:0]             seg_sel_r           ;
 24 reg  [ 3:0]             data_tmp            ;
 25 
 26 //----------------------------------------------------------------------
 27 //--   1k分頻,掃描一個數目管時間為1ms
 28 //----------------------------------------------------------------------
 29 
 30 //計數
 31 always @(posedge clk or negedge rst_n)begin
 32     if(!rst_n)
 33         cnt <= 0;
 34     else if(add_cnt)begin
 35         if(end_cnt)
 36             cnt <= 0;
 37         else
 38             cnt <= cnt + 1;
 39     end
 40     else
 41         cnt <= cnt;
 42 end
 43 
 44 assign add_cnt = en;    //en為1才允許計數
 45 assign end_cnt = add_cnt && cnt==25000-1;
 46 
 47 //分頻
 48 always @(posedge clk or negedge rst_n)begin
 49     if(!rst_n)
 50         clk_1k <= 0;
 51     else if(end_cnt)
 52         clk_1k <= ~clk_1k;
 53     else
 54         clk_1k <= clk_1k;
 55 end
 56 
 57 //----------------------------------------------------------------------
 58 //--   數碼管掃描,8位循環掃描,頻率為1k
 59 //----------------------------------------------------------------------
 60 always @(posedge clk_1k or negedge rst_n)begin
 61     if(!rst_n)
 62         seg_sel_r <= 8'b0000_0001;
 63     else if(seg_sel==8'b1000_0000)
 64         seg_sel_r <= 8'b0000_0001;
 65     else
 66         seg_sel_r <= seg_sel << 1;
 67 end
 68 
 69 //----------------------------------------------------------------------
 70 //--   位選,不同計數對應不同位選編碼,也對應分割的不同數據
 71 //----------------------------------------------------------------------
 72 always @(*)begin
 73     case(seg_sel_r)
 74         8'b0000_0001: data_tmp = data[ 3: 0] ; // 位1
 75         8'b0000_0010: data_tmp = data[ 7: 4] ; // 位2
 76         8'b0000_0100: data_tmp = data[11: 8] ; // 位3
 77         8'b0000_1000: data_tmp = data[15:12] ; // 位4
 78         8'b0001_0000: data_tmp = data[19:16] ; // 位5
 79         8'b0010_0000: data_tmp = data[23:20] ; // 位6
 80         8'b0100_0000: data_tmp = data[27:24] ; // 位7
 81         8'b1000_0000: data_tmp = data[31:28] ; // 位8
 82         default:      data_tmp = 4'b0000     ;
 83     endcase
 84 end
 85 
 86 assign seg_sel = en ? seg_sel_r : 8'b0000_0000; // 位選使能
 87 
 88 //----------------------------------------------------------------------
 89 //--   段選,將不同分割數據進行段選編碼
 90 //----------------------------------------------------------------------
 91 always @(*)begin
 92     case(data_tmp)
 93         4'h0:   seg_data = 8'b1100_0000;
 94         4'h1:   seg_data = 8'b1111_1001;
 95         4'h2:   seg_data = 8'b1010_0100;
 96         4'h3:   seg_data = 8'b1011_0000;
 97         4'h4:   seg_data = 8'b1001_1001;
 98         4'h5:   seg_data = 8'b1001_0010;
 99         4'h6:   seg_data = 8'b1000_0010;
100         4'h7:   seg_data = 8'b1111_1000;
101         4'h8:   seg_data = 8'b1000_0000;
102         4'h9:   seg_data = 8'b1001_0000;
103         4'ha:   seg_data = 8'b1000_1000;
104         4'hb:   seg_data = 8'b1000_0011;
105         4'hc:   seg_data = 8'b1100_0110;
106         4'hd:   seg_data = 8'b1010_0001;
107         4'he:   seg_data = 8'b1000_0110;
108         4'hf:   seg_data = 8'b1011_1111;
109         default:seg_data = 8'b1111_1111;
110     endcase
111 end
112 
113 
114 endmodule

 

二、方法2

  第二種數碼管動態顯示方法:采用直接計數掃描方法

  1 //======================================================================
  2 // --- 名稱 : seg_display
  3 // --- 作者 : xianyu_FPGA
  4 // --- 日期 : 2018-11-10
  5 // --- 描述 : 數碼管動態顯示模塊
  6 //======================================================================
  7 
  8 module seg_display
  9 //---------------------<參數定義>---------------------------------------
 10 #(
 11 parameter SEG_SEL       = 8                 , //數碼管位數:8
 12 parameter SEG_DATA      = 8                 , //數碼管段數:8
 13 parameter TIME_1MS      = 50000             , //1ms時間
 14 parameter TIME_1MS_W    = 16                  //1ms時間位寬
 15 )
 16 //---------------------<端口聲明>---------------------------------------
 17 (
 18 input                       clk             , //時鍾,50Mhz
 19 input                       rst_n           , //復位,低電平有效
 20 input                       en              , //數碼管顯示使能
 21 input      [SEG_SEL*4-1:0]  data            , //輸入數據
 22 output     [SEG_SEL  -1:0]  seg_sel         , //數碼管位選
 23 output reg [SEG_DATA -1:0]  seg_data          //數碼管段選,即內容顯示
 24 );
 25 //---------------------<信號定義>---------------------------------------
 26 reg  [TIME_1MS_W-1:0]   cnt0                ;
 27 wire                    add_cnt0            ;
 28 wire                    end_cnt0            ;
 29 reg  [2:0]              cnt1                ;
 30 wire                    add_cnt1            ;
 31 wire                    end_cnt1            ;
 32 reg  [3:0]              data_tmp            ;
 33 reg  [SEG_SEL-1:0]      seg_sel_r           ;
 34 
 35 //----------------------------------------------------------------------
 36 //--   1個數碼管亮1ms
 37 //----------------------------------------------------------------------
 38 always @(posedge clk or negedge rst_n)begin
 39     if(!rst_n)
 40         cnt0 <= 0;
 41     else if(add_cnt0)begin
 42         if(end_cnt0)
 43             cnt0 <= 0;
 44         else
 45             cnt0 <= cnt0 + 1;
 46     end
 47     else
 48         cnt0 <= cnt0;
 49 end
 50 
 51 assign add_cnt0 = en; // 使能有效才計數
 52 assign end_cnt0 = add_cnt0 && cnt0==TIME_1MS-1;
 53 
 54 //----------------------------------------------------------------------
 55 //--   對各位數碼管不斷掃描
 56 //----------------------------------------------------------------------
 57 always @(posedge clk or negedge rst_n)begin 
 58     if(!rst_n)
 59         cnt1 <= 0;
 60     else if(add_cnt1)begin
 61         if(end_cnt1)
 62             cnt1 <= 0;
 63         else
 64             cnt1 <= cnt1 + 1;
 65     end
 66     else
 67         cnt1 <= cnt1;
 68 end
 69 
 70 assign add_cnt1 = end_cnt0;
 71 assign end_cnt1 = add_cnt1 && cnt1==SEG_SEL-1;
 72 
 73 //----------------------------------------------------------------------
 74 //--   位選,不同計數對應不同位選編碼,也對應分割的不同數據
 75 //----------------------------------------------------------------------
 76 always @(*)begin
 77     case(cnt1)
 78       3'd0  : begin seg_sel_r = 8'b0000_0001; data_tmp = data[ 3: 0]; end // 位1
 79       3'd1  : begin seg_sel_r = 8'b0000_0010; data_tmp = data[ 7: 4]; end // 位2
 80       3'd2  : begin seg_sel_r = 8'b0000_0100; data_tmp = data[11: 8]; end // 位3
 81       3'd3  : begin seg_sel_r = 8'b0000_1000; data_tmp = data[15:12]; end // 位4
 82       3'd4  : begin seg_sel_r = 8'b0001_0000; data_tmp = data[19:16]; end // 位5
 83       3'd5  : begin seg_sel_r = 8'b0010_0000; data_tmp = data[23:20]; end // 位6
 84       3'd6  : begin seg_sel_r = 8'b0100_0000; data_tmp = data[27:24]; end // 位7
 85       3'd7  : begin seg_sel_r = 8'b1000_0000; data_tmp = data[31:28]; end // 位8
 86     default : begin seg_sel_r = 8'b0000_0000; data_tmp = 4'b0000;     end
 87     endcase
 88 end
 89 
 90 assign seg_sel = en ? seg_sel_r : 8'b0000_0000; // 位選使能
 91 
 92 //----------------------------------------------------------------------
 93 //--   段選,將不同分割數據進行段選編碼
 94 //----------------------------------------------------------------------
 95 always @(*)begin
 96     case(data_tmp)
 97         4'h0:   seg_data = 8'b1100_0000;
 98         4'h1:   seg_data = 8'b1111_1001;
 99         4'h2:   seg_data = 8'b1010_0100;
100         4'h3:   seg_data = 8'b1011_0000;
101         4'h4:   seg_data = 8'b1001_1001;
102         4'h5:   seg_data = 8'b1001_0010;
103         4'h6:   seg_data = 8'b1000_0010;
104         4'h7:   seg_data = 8'b1111_1000;
105         4'h8:   seg_data = 8'b1000_0000;
106         4'h9:   seg_data = 8'b1001_0000;
107         4'ha:   seg_data = 8'b1000_1000;
108         4'hb:   seg_data = 8'b1000_0011;
109         4'hc:   seg_data = 8'b1100_0110;
110         4'hd:   seg_data = 8'b1010_0001;
111         4'he:   seg_data = 8'b1000_0110;
112         4'hf:   seg_data = 8'b1000_1110;
113         default:seg_data = 8'b1111_1111;
114     endcase
115 end
116 
117 
118 endmodule
119 
120 /*
121 //----------------------------------------------------------------------
122 //--   位選這樣寫也行,代碼變得很秀
123 //----------------------------------------------------------------------
124 always @(posedge clk or negedge rst_n)begin
125     if(!rst_n)
126         seg_sel <= {SEG_SEL{1'b0};
127     else if(en)
128         seg_sel <= ~(1'b1<<cnt1);
129     else
130         seg_sel <= {SEG_SEL{1'b0};
131 end
132 
133 always  @(*)begin
134     data_tmp = data[(cnt1+1)*4-1 -:4];
135 end
136 
137 */

 

  以上兩種方法實測均有效,數碼管足夠亮且不閃爍不重影,以后使用時可以直接拿來當數碼管的顯示模塊。使用時要注意你的數碼管器件的位數是幾位?段數是7段還是8段?低電平有效還是高電平有效?接口是直接連接還是通過HC595芯片連接?這幾個問題搞清楚了,數碼管顯示也就不是問題了。

 

三、HC595

  附上小梅哥FPGA的HC595模塊的代碼,可以直接搭配數碼管動態顯示模塊使用,在頂層例化連接一下就行了。

  1 //======================================================================
  2 // --- 名稱 : HC595
  3 // --- 作者 : xianyu_FPGA
  4 // --- 日期 : 2018-11-10
  5 // --- 描述 : HC595驅動
  6 //======================================================================
  7 
  8 module HC595
  9 //---------------------<參數定義>---------------------------------------
 10 #(
 11 parameter SEG_SEL       = 8                 , //8位
 12 parameter SEG_DATA      = 8                   //8段
 13 )
 14 //---------------------<端口聲明>---------------------------------------
 15 (
 16 input                   clk                 , //時鍾,50Mhz
 17 input                   rst_n               , //復位,低電平有效
 18 input                   en                  , //數碼管使能信號
 19 input  [SEG_SEL -1:0]   seg_sel             , //數碼管位選
 20 input  [SEG_DATA-1:0]   seg_data            , //數碼管段選
 21 output reg              ST_CP               , //存儲寄存器時鍾輸出
 22 output reg              SH_CP               , //移位寄存器時鍾輸出
 23 output reg              DS                    //串行數據輸入
 24 );
 25 //---------------------<信號定義>---------------------------------------
 26 reg  [ 1:0]             cnt0                ;
 27 wire                    add_cnt0            ;
 28 wire                    end_cnt0            ;
 29 reg  [ 5:0]             cnt1                ;
 30 wire                    add_cnt1            ;
 31 wire                    end_cnt1            ;
 32 wire                    sclk                ; //分頻時鍾信號
 33 wire [ 5:0]             sclk_cnt            ; //序列機計數器
 34 
 35 //----------------------------------------------------------------------
 36 //--   4分頻計數器
 37 //----------------------------------------------------------------------
 38 always @(posedge clk or negedge rst_n)begin
 39     if(!rst_n)
 40         cnt0 <= 0;
 41     else if(add_cnt0)begin
 42         if(end_cnt0)
 43             cnt0 <= 0;
 44         else
 45             cnt0 <= cnt0 + 1;
 46     end
 47     else
 48         cnt0 <= cnt0;
 49 end
 50 
 51 assign add_cnt0 = en;
 52 assign end_cnt0 = add_cnt0 && cnt0==4-1;
 53 
 54 assign sclk = end_cnt0;
 55 
 56 //----------------------------------------------------------------------
 57 //--   序列機計數器
 58 //----------------------------------------------------------------------
 59 always @(posedge clk or negedge rst_n)begin 
 60     if(!rst_n)
 61         cnt1 <= 0;
 62     else if(add_cnt1)begin
 63         if(end_cnt1)
 64             cnt1 <= 0;
 65         else
 66             cnt1 <= cnt1 + 1;
 67     end
 68     else
 69         cnt1 <= cnt1;
 70 end
 71 
 72 assign add_cnt1 = sclk;
 73 assign end_cnt1 = add_cnt1 && cnt1==35-1;
 74 
 75 assign sclk_cnt = cnt1;
 76 
 77 //-------------------------------------------------------------------------------
 78 //--   SHCP:移位寄存器的時鍾輸入,上升沿時移位寄存器中的數據依次移動一位
 79 //--   STCP:存儲寄存器的時鍾輸入,上升沿時移位寄存器中的數據進入存儲寄存器
 80 //--   通常STCP置為低電平,移位結束后再在ST_CP端產生一個正脈沖更新顯示數據
 81 //-------------------------------------------------------------------------------
 82 always @(posedge clk or negedge rst_n)begin
 83     if(!rst_n)begin
 84         ST_CP <= 0;
 85         SH_CP <= 0;
 86         DS    <= 0;
 87     end 
 88     else begin
 89         case(sclk_cnt)
 90              0: begin             SH_CP <= 0;                    end 
 91              1: begin ST_CP <= 0; SH_CP <= 1;                    end 
 92              2: begin             SH_CP <= 0; DS <= seg_data[7]; end
 93              3: begin             SH_CP <= 1;                    end
 94              4: begin             SH_CP <= 0; DS <= seg_data[6]; end
 95              5: begin             SH_CP <= 1;                    end
 96              6: begin             SH_CP <= 0; DS <= seg_data[5]; end
 97              7: begin             SH_CP <= 1;                    end
 98              8: begin             SH_CP <= 0; DS <= seg_data[4]; end
 99              9: begin             SH_CP <= 1;                    end
100             10: begin             SH_CP <= 0; DS <= seg_data[3]; end
101             11: begin             SH_CP <= 1;                    end
102             12: begin             SH_CP <= 0; DS <= seg_data[2]; end
103             13: begin             SH_CP <= 1;                    end
104             14: begin             SH_CP <= 0; DS <= seg_data[1]; end
105             15: begin             SH_CP <= 1;                    end
106             16: begin             SH_CP <= 0; DS <= seg_data[0]; end
107             17: begin             SH_CP <= 1;                    end
108             18: begin             SH_CP <= 0; DS <= seg_sel[7];  end
109             19: begin             SH_CP <= 1;                    end
110             20: begin             SH_CP <= 0; DS <= seg_sel[6];  end
111             21: begin             SH_CP <= 1;                    end
112             22: begin             SH_CP <= 0; DS <= seg_sel[5];  end
113             23: begin             SH_CP <= 1;                    end
114             24: begin             SH_CP <= 0; DS <= seg_sel[4];  end
115             25: begin             SH_CP <= 1;                    end
116             26: begin             SH_CP <= 0; DS <= seg_sel[3];  end
117             27: begin             SH_CP <= 1;                    end
118             28: begin             SH_CP <= 0; DS <= seg_sel[2];  end
119             29: begin             SH_CP <= 1;                    end
120             30: begin             SH_CP <= 0; DS <= seg_sel[1];  end
121             31: begin             SH_CP <= 1;                    end
122             32: begin             SH_CP <= 0; DS <= seg_sel[0];  end
123             33: begin             SH_CP <= 1;                    end
124             34: begin ST_CP <= 1;                                end
125             default:
126                 begin ST_CP <= 0; SH_CP <= 0; DS <= 0          ; end
127         endcase
128     end
129 end
130 
131 endmodule

 

  ok,數碼管的學習就到這里,以后遇到問題再補充進來。

 

參考資料:

[1]小梅哥FPGA教程

[2]鋯石科技FPGA教程


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM