八段数码管动态显示(输入数据为BCD编码)

一、数码管概述

图1 八段共阴数码管内部等效原理图
图2 八段共阳数码管内部等效原理图

  上面两图分别是对应八段共阴、共阳的数码管内部等效图,共阴是将八个LED数码管的阴极连接在一起接低,阳极segment信号只需要输入高电平,相应的数码管就被点亮;将上面八个数码管按照下面形状排列,就构成了数码管。

图3 数码管示意图

如何让数码管显示出对应的数据?
  拿八段共阴数码管显示2举例,如上图显示2需要点亮a、b、g、e、d这五个LED,其余LED全部熄灭。所以segment信号应该输出的数据是0101_1011。显示其余数字也是类似的原理,而h一般是用作小数点处理,不需要的时候一般都不点亮这个LED。下面是不包括h段LED的数码管译码对应表。

表一 八段共阴共阳数码管译码数据

显示数字 共阳gfedcba 2进制 共阳gfedcba 16进制 共阴gfedcba 2进制 共阴gfedcba 16进制
0 8’b11000000 8’hC0 8’b00111111 8’h3f
1 8’b11111001 8’hF9 8’b00000110 8’h06
2 8’b10100100 8’hA2 8’b01011011 8’h5b
3 8’b10110000 8’bB0 8’b01001111 8’h4f
4 8’b10011001 8’h99 8’b01100110 8’b66
5 8’b10010010 8’h92 8’b01101101 8’h6d
6 8’b10000010 8’h82 8’b01111101 8’h7d
7 8’b11111000 8’hF8 8’b00000111 8’h07
8 8’b10000000 8’h80 8’b01111111 8’h7f
9 8’b10010000 8’h90 8’b01101111 8’h6f

  经过上面可知,想让数码管显示对应的数据,就必须给此数码管的八个数据线(八个LED输入端)输入对应的数据,将这8根数据线称为一组数据线。那如果需要同时使用两个数码管呢?此时就需要控制16个LED,所以就需要2组数据线。由此需要n个数码管显示n个数字,就需要n组数据线,这会极大消耗数据线资源,但是平常单片机或者FPGA这些开发板上面的数码管很多,却只有一组数据线,这是怎么做到的呢?

  为了解决上面问题,一般是将四个数码管制作成下图所示的三线制数码管,将四个独立数码管四组数据线接在一起,四个数码管共用一组数据线,同时每个数码管增加一个DIG片选信号,如下图当DIG1引脚为低电平时,此时数据线HEX的数据驱动第1个数码管显示对应的数字。通过控制4个DIG引脚实现一组数据线驱动多个数码管,比如20us点亮第一个数码管,之后每隔20us点亮下一个数码管,最后循环点亮四个数码管,在点亮不同数码管的时候控制数据线HEX输入不同的数据,就可以实现一组数据线驱动多个数码管显示不同的数据。

图3 4个八段数码管原理图

二、FPGA实现驱动数码管

1、信号列表

信号 位宽 输入/输出 描述
clk 1 I 系统时钟,1MHz
rst_n 1 I 系统复位,低电平有效
din 4*数码管个数 I 待显示的BCD码数据
segment 8 O 八段数码管的数据线
seg_sel 数码管个数 O 数码管片选信号,电平有效

2、设计思路

  通过参数实现该模块可以驱动任意个数码管,通过自动计算位宽函数自动计算寄存器的位宽。

  该设计实现FPGA可以驱动SEG_NUM个数码管,每个数码管显示的时间为TIME_20MS。所以本设计以20us计数器cnt_20us和点亮的第几个计数器sel为主体架构,其余信号对齐这两个计数器。计数器示意图如下,cnt_20us计数计数时,sel计数器加一,表示点亮下一个数码管。例如使用8个数码管同时显示12345678,则SEG_NUM=8,din=64‘h12345678,之后sel计数器为0时,segment译码显示4’d8,此时第0个数码管显示8,之后计数器cnt_20us计数结束,sel+1,此时点亮第一个数码管,则数据线segment应该将4’d7译码进行输出,之后各位显示类似。

图4 计数器架构

  参数设计以及自动计算位宽函数如下:

parameter       TIME_20US                   =   20              ,//数码管刷新时间,默认20us。
parameter       SEG_NUM                     =   6                //需要显示的数码管个数。
//参数定义
localparam              TIME_W    =     clogb2(TIME_20US);//计算数码管扫描时间的时钟数据位宽;
localparam              SEG_W     =     clogb2(SEG_NUM);
localparam              ZERO      =     8'hC0  ; //8'h3F;前面的数据是共阳数码管使用的,后面数据是共阴数码管使用的;
localparam              ONE       =     8'hF9  ; //8'h06;
localparam              TWO       =     8'hA4  ; //8'hB;
localparam              THREE     =     8'hB0  ; //8'hF;
localparam              FOUR      =     8'h99  ; //8'h66;
localparam              FIVE      =     8'h92  ; //8'h6D;
localparam              SIX       =     8'h82  ; //8'h7D;
localparam              SEVEN     =     8'hF8  ; //8'h07;
localparam              EIGHT     =     8'h80  ; //8'h7F;
localparam              NINE      =     8'h90  ; //8'h6F;
localparam              ERR       =     8'h86  ; //8'h79;//自动计算位宽的函数;function integer clogb2(input integer depth);beginif(depth==0)clogb2=1;else if(depth!=0)for(clogb2=0; depth>0;clogb2=clogb2+1)depth=depth>>1;endendfunction

计数器cnt_20us初始值为0,对系统时钟进行计数,计数到TIME_20US-1时结束,对应代码如下:

//20us计数器,用于对一个数码管点亮的持续时间进行计数,计数器初始值为0,对always @(posedge clk or negedge rst_n)beginif(!rst_n)begin//计数器初始值为0;cnt_20us <= 0;endelse if(end_cnt_20us)begin//当计数器计数到20us时,表示一个数码管已经被点亮20US了,将计数器清零;cnt_20us <= 0;endelse begin//否则,计数器加一;cnt_20us <= cnt_20us + 1'b1;endend//计数器结束条件,当计数器计数到TIME_20US-1时表示20US已经到了,将计数器清零;assign end_cnt_20us = cnt_20us == TIME_20US -

计数器sel初始值为0,表示最初点亮第0个数码管,当计数器cnt_20us计数计数结束时,表示一个数码管被点亮20us了,此时计数器sel加一,开始点亮下一个数码管,当计数器sel计数到SEG_NUM-1并且cnt_20us计数结束时,表示所有数码管都被点亮一次了,将计数器sel清零,从第一个数码管在此循环点亮;

综上:计数器sel初始值为0,加一条件add_sel=end_cnt_20us,结束条件end_sel=add_sel && sel==SEG_NUM-1,对应代码如下:

always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begin//初始值为0;sel <= 0;endelse if(add_sel) beginif(end_sel)//当计数器sel计数结束时,计数器清零;sel <= 0;elsesel <= sel + 1;endendassign add_sel = end_cnt_20us;//计数器sel的加一条件是,计数器cnt_20us计数器结束;assign end_sel = add_sel && sel == SEG_NUM - 1;//计数器sel计数到SEL_NUM-1时,计数器sel清零;

接下来还需要做两件事:

2.1、输入信号译码成数码管数据信号segment

  输入数据din是BCD码,所以只需要在计数器sel为0是将din[3:0]译码成segment输出给数码管即可。根据这个原理,sel_result信号先根据计数器sel的值从din取出对应的四位数据,代码如下:

//sel_result信号是当前被点亮数码管需要显示的数据,根据计数器sel的值确定此时应该将输入信号的哪几位数据译码输出给数码管进行显示;always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begin//初始值为0;sel_result <= 4'd0;endelse begin//取输入信号din[4*sel+3 : 4*sel]信号给译码部分进行译码,之后输出给数码管数据信号驱动数码管显示该数据;sel_result <= din[4*sel+3 -: 4];//{din[4*sel+3],din[4*sel+2],din[4*sel+1],din[4*sel]};endend

之后将sel_result译码成能驱动数码管显示对应数据信号segment,对应代码如下:

//译码器部分,将sel_result十进制信号译码成数码管显示该数字对应的八位数据信号;always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begin//初始上电时,所有数码管显示数据0;segment <= ZERO;endelse begincase(sel_result)//将sel_result译码成对应的segment数据,segment数据驱动数码管才能显示sel_result代表的数字;0: segment <= ZERO ;//想要数码管显示0,就要给数码管数据信号segment输入ZERO数据,其余类似;1: segment <= ONE  ;2: segment <= TWO  ;3: segment <= THREE;4: segment <= FOUR ;5: segment <= FIVE ;6: segment <= SIX  ;7: segment <= SEVEN;8: segment <= EIGHT;9: segment <= NINE ;default: segment <= ERR;endcaseendend

  对应仿真如下,六个数码管显示24’h044039,sel为0时,sel_result=4’d9,segment将sel_result通过译码表1译码成NINE对应的数据8’h90,则第一个数码管显示9,其余类推;

图5 modelsim部分仿真结果

2.2、根据计数器sel控制数码管片选信号seg_sel

  计数器sel表示此时应该点亮第几个数码管,所以计数器sel=0时,应该将第一个数码管的片选拉低,其余数码管的片选拉高,此时数据线segment的数据用于驱动第一个数码管显示对应数据。segment信号滞后计数器sel变化两个时钟,所以seg_sel也需要滞后sel两个时钟,才能使得segment与seg_sel信号对齐。所以先将sel延迟一个时钟得到sel_ff0,代码如下:

//为了与段选动态扫描,保持同步,此时位选应该打一拍再赋给位选信号 seg_selalways  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)beginsel_ff0 <= 0;endelse beginsel_ff0 <= sel;endend

  之后根据sel_ff0得到数码管片选信号,将1左移sel_ff0之后取反,就可以将第sel_ff0位数码管片选拉低,其余数码管片选拉高,对应代码如下:

always  @(posedge clk or negedge rst_n)beginif(rst_n==1'b0)begin//初始值为0,全部数码管被点亮;seg_sel <= {{SEG_NUM}{1'b0}};endelse begin//将1左移sel_ff0位之后取反,seg_sel的第sel_ff0输出低电平,对应的第sel_ff0个数码管被点亮了,其余位输出高电平,对应的数码管熄灭;seg_sel <= ~({{{SEG_NUM-1}{1'b0}},1'b1} << sel_ff0);//~(6'h1<<sel_ff0);endend

三、源文件获取

  在公众号” 数字站 “回复“数码管fpga”获取下载链接。

  下载后解压得到源文件如下图:

图6 解压文件夹下的文件

  其中seg_disp.v是数码管驱动文件,test.v文件是仿真测试激励生成文件。可以直接使用modelsim打开该文件夹下的test.mpf文件进行仿真,如下图操作:

图7 modelsim打开工程

  一定要先修改查找的文件类型,不然很可能找不到该类型的文件,然后选择test.mpf文件打开即可,步骤如下所示:

图8 modelsim选择工程文件

  之后点击Library,然后选中work库里面的test右键选择Simulate即可。

图9 modelsim运行激励文件

  之后可以自己在sim选项卡里面添加文件,也可以加入我之前配置好的页面,下面是使用我之前配置好页面的方法。点击file,之后点击load,最后点击Macro File,如下图所示:

图10 modelsim打开已有波形页面配置文件

  首先还是选择打开文件夹显示所有类型的文件,之后选中wave.do文件打开,如下图所示:

图11 modelsim选择wave.do文件打开

  打开结果如下图所示:

图12 modelsim仿真结果

如果要重新仿真,进行如下图步骤操作即可:

图13 modelsim重新仿真

由于test.v文件有仿真结束设置,所以运行到时间后会自动停止仿真,回到该页面即可。

四、modelsim仿真6个数码管显示

图14 modelsim仿真结果

  仿真结果正确,在使用该模块时,例化时只需要更改SEG_NUM参数确定数码管个数以及是共阴数码管还是共阳数码管即可,其余信号可变位宽可以由自动计算位宽函数自动计算得出,不需要认为更改,该过程是在综合工具编译是完成的,不会消耗额外资源。

五、总结

  1、注意:主要是以两个数码管为主体架构,需要注意数码管数据信号要与片选信号对齐,如果没有对齐则会出现数码管显示数据奇怪的问题,原因在于一个数码管在某个别时钟显示了上一个数码管或者下一个数码管该显示的数据。
  2、扩展:后续可以加入小数点的控制电路,以及使用控制信号选择共阴还是共阳的数码管。

八段数码管动态显示(输入数据为BCD编码)相关推荐

  1. 让51单片机八段数码管亮起来(静态显示和动态显示、共阴极和共阳极、位码和段码)

    51单片机数码管的显示 一.八段数码管基础部分 1.八段数码管的共阴极和共阳极 2.八段数码管的位码和段码 二.八段数码管动态显示 1.八个八段数码管动态扫描0到7流水显示 2.八个八段数码管动态扫描 ...

  2. 51矩阵键盘数码管动态显示

    一.实验目的 1.了解矩阵键盘扫描方法. 2.了解数码管动态显示方法. 二.实验内容 1.完成读取矩阵键盘并静态显示. 2.完成完成读取矩阵键盘并动态显示. 三.实验原理 四.实验电路与程序 1.软件 ...

  3. 蓝桥杯单片机数码管动态显示_单片机静态动态数码管

    单片机系统中常用的显示器有: 发光二极管LED(Light Emitting Diode)显示器.液晶LCD(Liquid Crystal Display)显示器.TFT液晶显示器等.LED显示器有两 ...

  4. 正点原子FPGA开发指南——数码管动态显示

    数码管是将若干发光二极管按一定图形排列并封装在一起的一种数码显示器件.常见的数码管如下图所示: 这种数码管主要被称为八段数码管或8字形数码管,可用来显示小数点.数字0~9,和英文字母A~F. 我们的目 ...

  5. BCD编码(8421编码)

    用4位二进制数来表示1位十进制数中的0~9这10个数码,简称BCD码,即BCD代码.Binary-Coded Decimal‎,简称BCD,称BCD码或二-十进制代码,亦称二进码十进数.是一种二进制的 ...

  6. 8086与8255实现数码管动态显示

    微机原理8086与8255实现数码管动态显示 效果 汇编代码(汇编软件用的是emu8086) DATAS SEGMENT;此处输入数据段代码 TABLE DB 40H,79H,24H,30H,19H, ...

  7. FPGA 驱动数码管动态显示(VerilogVivado)

    FPGA 驱动数码管动态显示 前言 一.数码管驱动原理 二.设计思路 三.实现代码 四.hex8_tb文件 五.上板测试 1.74HC595时序图 2. HC595_Driver设计 3.HC595_ ...

  8. 用 定时计数器中断 和 动态八段数码管 做一个秒表

    用 定时/计数器中断 和 动态八段数码管做一个秒表 目录 用 定时/计数器中断 和 动态八段数码管做一个秒表 1.思路 定时器 数码管 2.主要代码讲解 3.全部代码参考(代码写的很烂,欢迎提出建议) ...

  9. .net 对日期格式转BCD编码

    项目背景 与C语言的相关加密做对接,遇到一个没见过的编码,对日期YYYYMMDDHHMMSS进行转BCD编码 编码原理 BCD码(Binary-Coded Decimal‎),用4位二进制数来表示1位 ...

  10. java转BCD_关于BCD编码 BCD与十进制转换

    BCD码(Binary-Coded Decimal‎)亦称二进码十进数或二-十进制代码.用4位二进制数来表示1位十进制数中的0~9这10个数码.是一种二进制的数字编码形式,用二进制编码的十进制代码.B ...

最新文章

  1. JVM:StringTable
  2. 卫星数据现已加入 Azure 豪华套餐,在太空向女神表个白?
  3. EasyUI表单验证,自定义插件验证,自定义js插件验证,远程验证,常见手机号,中英文,qq等验证规则验证...
  4. python3模块文档_Python3模块-Python入门到精通
  5. 【项目管理】绩效域-工件裁剪对照(工件维度)
  6. 大道至简第六章读后感
  7. HTML如何添加锚点,论程序员成长的正确姿势
  8. linux 安装rpm包时遇到error:Failed dependencies解法方法
  9. VMLite 安装linux系统,VMlite安装XPMode及xp、win7、linux的虚拟磁盘到D盘的方法(15页)-原创力文档...
  10. Latex中定义、定理、引理、证明 设置方法总结
  11. TeeChart Pro VCL/FMX教程(六):使用系列(二)
  12. python简单代码示例-python3简单代码示例
  13. php短信验证码的前台代码怎么写,php短信验证码接口代码示例
  14. Pyecharts 猎聘招聘数据可视化
  15. 2018.6清北学堂day6上午
  16. 打工宣言“我选择打工”走红,网友:言之有理,不得不赞同!
  17. Echars柱状图嵌套 居中对齐 柱子占比宽度由大到小嵌套包含 并用小箭头标记当前产出位置
  18. 量子计算机的研究进展,量子计算原理及研究进展.pdf
  19. 线性代数matlab求一个正交矩阵,线性代数求一个正交矩阵P,是P^-1AP= – 手机爱问...
  20. MAC如何安装pfx

热门文章

  1. centos mysql mariadb_centos7 mysql和mariadb的资料 - 菜鸟头头
  2. Mybatis001_JDBC
  3. java web安全框架_7.1 SpringSecurity安全框架
  4. CSS设置字间距、行间距、首行缩进
  5. 46岁微软:从盖茨缔造帝国到纳德拉复兴
  6. 智商测试图片素材软件,智商测试图片 测试你智商的图片[100P]
  7. 问题记录之---nginx temp文件夹
  8. 计算机考试网页制作演示视频教程,一级计算机考试网页制作怎么办!求操作步骤!...
  9. mybatis插入大于号小于号到oracle
  10. 回溯算法-数独(计算器)