• 数码管动态显示


      数码管显示分为静态显示和动态显示。静态显示没什么卵用,和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教程

  • 相关阅读:
    Day09 约束
    Day08 数据处理
    Day07 创建和管理表
    Day06 子查询
    Appium学习_01(连接、apppackage名查询、appactivity名查询)
    我的读书方法
    Python自动化学习记录
    FineReport帆软报表学习积累
    ERP企业资源管理 详解
    Centos7学习记录
  • 原文地址:https://www.cnblogs.com/xianyufpga/p/11006321.html
Copyright © 2020-2023  润新知