FPGA 学习小组
直播中

陈丽霞

7年用户 192经验值
私信 关注

数码管的工作原理

数码管在我们的整个设计中,我们输入的数据与计算的结果都需要用数码管来显示,所以说数码管还是扮演着很重要的角色的。
1.1简析数码管的工作原理关于数码管的工作原理,为了照顾零基础的朋友,Kevin还是再进行下简单的介绍,如果是已经了解了数码管工作原理的朋友可以直接跳过这一节。
下面我们先来一张数码管的图片:

数码管是由多个发光二极管封装在一起组成的“8”字型器件,各发光二极管已经在器件内部完成连线。
对于数码管,有共阴极和共阳极之分,共阳极及共阴极数码管内部间的连线可以简化成下图:
图中的“COM”相当于是一个片选信号,例如,共阳极的位选“COM”为高时,即选中了该数码管,此时数码管才能工作起来。当“COM”选通之后,我们就可以选通相应的段选信号使数码管显示我们想要的字符了。比如说,我们想让数码管显示一个“0”(假设数码管是共阳极的),那我们相应的h~a的十六进制代码应为0xc0。
以下是共阴极与共阳极数码管的0~f编码(顺序是为h~a):
共阳:
0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
共阴:
0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f,0x77,0x7c,0x39,0x5e,0x79,0x71
1.2让数码管走起来在这一节中,我们来做这样的一个小练习,Kevin也是想通过这样的一个小练习来让大家基本掌握数码管的工作原理,同时也了解如何使用FPGA来驱动数码管。
先说一下实验要求:数码管从0~9循环计数,变化时间的间隔为1S。
首先,咱们先画一个该设计的简单的逻辑框图:

图中“Div_cnt”模块在1s计时到了之后,就让div_flag这个信号拉高一个时钟周期。“Seg_ctrl”为数码管控制模块,产生位选sel信号及数码管的显示字符信号seg,显然我们的seg信号的变化需要根据div_flag这个信号来控制。
下面可以根据我们的这个逻辑图框图来写代码了。
首先来写div_cnt这个模块:
  • /********************************************************************
  • *        Module            Name:        div_cnt
  • *        Engineer          :        Kevin
  • *        Function        :        1s计数模块
  • *        Blog        Website        :        http://dengkanwen.com
  • *        Version                     :        v1.0
  • ********************************************************************/
  • module        div_cnt(
  •                 input        wire                sclk,                        //系统时钟为50MHz,即周期为20ns
  •                 input        wire                s_rst_n,
  •                
  •                 output        reg                    div_flag
  •                 );
  •                
  •         parameter                CNT_END        =        26'd4999_9999;        //1s计时结束
  •       
  •         reg        [25:0]        cnt;                //计数器
  •       
  •         always        @(posedge sclk or negedge s_rst_n)
  •                 if(s_rst_n == 1'b0)
  •                         cnt        <=        26'd0;
  •                 else if(cnt == CNT_END)
  •                         cnt        <=        26'd0;
  •                 else
  •                         cnt        <=        cnt + 1'b1;
  •                        
  •         always        @(posedge sclk or negedge s_rst_n)
  •                 if(s_rst_n == 1'b0)
  •                         div_flag        <=        1'b0;
  •                 else if(cnt == CNT_END)
  •                         div_flag        <=        1'b1;
  •                 else
  •                         div_flag        <=        1'b0;
  • endmodule

接下来,我们来写数码管的控制模块,在写控制模块之前,我们需要来看一下我们的电路原理图:

咱们先来简单的说一下这个数码管电路。电路图中总共有6位数码管,所以呢就有6个位选控制端,而这6个位选控制端是和三极管连在一块的,看着三极管的连法,应该知道,数码管是属于共阳极的。然而这6个数码管的位选是由3-8译码器来控制的,下面咱们再看一下3-8译码器与数码管位选端的连线图:

连线图已经出来了,可能有些朋友还不太清楚3-8译码器的原理,那咱们再来一张3-8译码器的真值表:

结合电路图及真值表,咱们可以看出,我们可以控制译码器的A、B、C这三个引脚来控制输出端Y电平的高低,从而就可以来控制我们数码管的位选端。例如,我们想让位选信号为S1的那个数码管工作起来,那我们就必须要先使之位选端有效,则需要使Y0的输出为低,所以我们ABC的信号应该为000.
在Kevin讲完之后,相信大家对咱们这个数码管电路的工作原理应该了解的差不多了。
我们只是让一个数码管亮起来,那我们索性也就只让位选信号为s1的那个数码管工作,其余数码管不工作。下面咱们就动手来写数码管控制模块的代码:
  • /********************************************************************
  • *        Module        Name        :        seg_ctrl
  • *        Engineer        :        Kevin
  • *        Function           :        数码管显示控制模块
  • *        Blog        Website        :        http://dengkanwen.com
  • *        Version                :        v1.0
  • *********************************************************************/
  • module        seg_ctrl(
  •                 input        wire                sclk,
  •                 input        wire                s_rst_n,
  •                 input        wire                div_flag,
  •                
  •                 output        wire        [2:0        sel,                //位选控制,连3-8译码器
  •                 output        reg        [7:0        seg                //段选信号
  •                 );
  •                
  • //========================共阳极数码管编码=========================================
  • //0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e
  • //=================================================================================
  •                
  •         parameter        ZERO        =        8'hc0,
  •                         ONE        =        8'hf9,
  •                         TWO        =        8'ha4,
  •                         THREE        =        8'hb0,
  •                         FOUR        =        8'h99,
  •                         FIVE        =        8'h92,
  •                         SIX        =        8'h82,
  •                         SEVEN        =        8'hf8,
  •                         EIGHT        =        8'h80,
  •                         NINE        =        8'h90;
  •       
  •         reg        [3:0        num_cnt;                //用于寄存当前数码管应显示的值
  • //num_cnt      
  •         always        @(posedge sclk or negedge s_rst_n)
  •                 if(s_rst_n == 1'b0)
  •                         num_cnt        <=        4'd0;
  •                 else if(num_cnt == 4'd9 && div_flag == 1'b1)
  •                         num_cnt        <=        4'd0;
  •                 else if(div_flag == 1'b1)
  •                         num_cnt        <=        num_cnt + 1'b1;
  • //seg               
  •         always        @*
  •                 case(num_cnt)
  •                         4'd0:
  •                                 seg        <=        ZERO;
  •                         4'd1:
  •                                 seg        <=        ONE;
  •                         4'd2:
  •                                 seg        <=        TWO;
  •                         4'd3:
  •                                 seg        <=        THREE;
  •                         4'd4:
  •                                 seg        <=        FOUR;
  •                         4'd5:
  •                                 seg        <=        FIVE;
  •                         4'd6:
  •                                 seg        <=        SIX;
  •                         4'd7:
  •                                 seg        <=        SEVEN;
  •                         4'd8:      
  •                                 seg        <=        EIGHT;
  •                         4'd9:
  •                                 seg        <=        NINE;               
  •                 endcase
  • //sel
  •         assign        sel        =        3'b000;
  • endmodule

这两个模块写好了之后,下面咱们再写一个顶层模块,用于连接两个模块之间的连线。
  • /********************************************************************
  • *        Module        Name        :        seg_top
  • *        Eneigneer        :        Kevin
  • *        Function        :        数码管0~9变换顶层模块
  • *        Blog        Website        :        http://dengkanwen.com
  • *        Version                :        v1.0
  • *********************************************************************/
  • module        seg_top(
  •                 input        wire                sclk,
  •                 input        wire                s_rst_n,
  •                
  •                 output        wire        [2:0        sel,
  •                 output        wire        [7:0        seg
  •                 );
  •         wire                div_flag;
  •                
  •         div_cnt                div_cnt_inst(
  •                 .sclk                        (sclk),                //系统时钟为50MHz,即周期为20ns
  •                 .s_rst_n                (s_rst_n),
  •                 .div_flag                (div_flag)
  •                 );
  •                
  •         seg_ctrl        seg_ctrl_inst(
  •                 .sclk                        (sclk),
  •                 .s_rst_n                (s_rst_n),
  •                 .div_flag                (div_flag),
  •                 .sel                        (sel),                //位选控制,连3-8译码器
  •                 .seg                        (seg)                //段选信号
  •                 );
  • endmodule

虽然Kevin对于这种简单的设计还是比较有自信的,但是为了教给大家一个良好的设计习惯,咱们还是进行仿真,所以接下来咱们来写一个仿真文件。 当然在仿真的时候,我们可以将div_cnt中的cnt计满的值写小一点。
  • `timescale        1ns/1ns
  • module        tb_seg_top;
  •         reg                sclk;
  •         reg                s_rst_n;
  •       
  •         wire        [2:0]        sel;
  •         wire        [7:0]        seg;
  •       
  •         initial        begin
  •                 sclk        =        1;
  •                 s_rst_n        <=        0;
  •                 #20
  •                 s_rst_n        <=        1;      
  •         end
  •       
  •         always        #5        sclk        =        ~sclk;
  •       
  •         seg_top                seg_top_inst(
  •                 .sclk                (sclk),
  •                 .s_rst_n        (s_rst_n),
  •                 .sel                (sel),
  •                 .seg                (seg)
  •                 );
  • endmodule

下面是咱们的仿真波形:

根据咱们的波形,可以说暂时是没有发现错误的,当然,Kevin下板子后也是板子也能正常工作。
本章剩余部分,请看评论哦
(备注:如果有发现内容错误,请大家及时指出,Kevin的QQ:1024726016)
转载请注明:邓堪文博客 » 【Kevin原创】《基于FPGA的简易计算器设计》第一章:玩转数码管

更多回帖

发帖
×
20
完善资料,
赚取积分