19 数码管动态显示 三 ( 动态显示驱动)_数码管动态驱动_guo-1228的博客-程序员秘密

技术标签: fpga  FPGA学习  verilog  嵌入式  

一、设计思路
假设要显示的-987.6
则要显示的个、十、百、千、万、十万分别为6、7、8、9其中万和十万为0;

需要注意的是,bcd_8421模块完成二进制到bcd编码所用的时间在21个周期,所以需要一段时间的延迟。
data_reg[23:0]用作变量的寄存,但是只是对符号位和数据位进行寄存,不包含小数点位

二、实现
1.visio波形图分析
在这里插入图片描述在这里插入图片描述

2.程序

module  seg_dynamic
(
    input   wire            sys_clk     , //系统时钟,频率50MHz
    input   wire            sys_rst_n   , //复位信号,低有效
    input   wire    [19:0]  data        , //数码管要显示的值
    input   wire    [5:0]   point       , //小数点显示,高电平有效
    input   wire            seg_en      , //数码管使能信号,高电平有效
    input   wire            sign        , //符号位,高电平显示负号

    output  reg     [5:0]   sel         , //数码管位选信号
    output  reg     [7:0]   seg           //数码管段选信号
);


//parameter define
parameter   CNT_MAX =   16'd49_999;  //数码管刷新时间计数最大值

//wire  define
wire    [3:0]   unit        ;   //个位数
wire    [3:0]   ten         ;   //十位数
wire    [3:0]   hun         ;   //百位数
wire    [3:0]   tho         ;   //千位数
wire    [3:0]   t_tho       ;   //万位数
wire    [3:0]   h_hun       ;   //十万位数

//reg   define
reg     [23:0]  data_reg    ;   //待显示数据寄存器
reg     [15:0]  cnt_1ms     ;   //1ms计数器
reg             flag_1ms    ;   //1ms标志信号
reg     [2:0]   cnt_sel     ;   //数码管位选计数器
reg     [5:0]   sel_reg     ;   //位选信号
reg     [3:0]   data_disp   ;   //当前数码管显示的数据
reg             dot_disp    ;   //当前数码管显示的小数点

//********************************************************************//
//***************************** Main Code ****************************//
//********************************************************************//

//data_reg:控制数码管显示数据
 always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_reg    <=  24'b0;
//若显示的十进制数的十万位为非零数据或需显示小数点,则六个数码管全显示
    else    if((h_hun) || (point[5])) 
        data_reg    <=  {
    h_hun,t_tho,tho,hun,ten,unit};
//若显示的十进制数的万位为非零数据或需显示小数点,则值显示在5个数码管上
//打比方我们输入的十进制数据为20’d12345,我们就让数码管显示12345而不是012345
    else    if(((t_tho) || (point[4])) && (sign == 1'b1))//显示负号
        data_reg <= {
    4'd10,t_tho,tho,hun,ten,unit};//4'd10我们定义为显示负号
    else    if(((t_tho) || (point[4])) && (sign == 1'b0))
        data_reg <= {
    4'd11,t_tho,tho,hun,ten,unit};//4'd11我们定义为不显示
//若显示的十进制数的千位为非零数据或需显示小数点,则值显示4个数码管
    else    if(((tho) || (point[3])) && (sign == 1'b1))
        data_reg <= {
    4'd11,4'd10,tho,hun,ten,unit};
    else    if(((tho) || (point[3])) && (sign == 1'b0))
        data_reg <= {
    4'd11,4'd11,tho,hun,ten,unit};
//若显示的十进制数的百位为非零数据或需显示小数点,则值显示3个数码管
    else    if(((hun) || (point[2])) && (sign == 1'b1))
        data_reg <= {
    4'd11,4'd11,4'd10,hun,ten,unit};
    else    if(((hun) || (point[2])) && (sign == 1'b0))
        data_reg <= {
    4'd11,4'd11,4'd11,hun,ten,unit};
//若显示的十进制数的十位为非零数据或需显示小数点,则值显示2个数码管
    else    if(((ten) || (point[1])) && (sign == 1'b1))
        data_reg <= {
    4'd11,4'd11,4'd11,4'd10,ten,unit};
    else    if(((ten) || (point[1])) && (sign == 1'b0))
        data_reg <= {
    4'd11,4'd11,4'd11,4'd11,ten,unit};
//若显示的十进制数的个位且需显示负号
    else    if(((unit) || (point[0])) && (sign == 1'b1))
        data_reg <= {
    4'd11,4'd11,4'd11,4'd11,4'd10,unit};
//若上面都不满足都只显示一位数码管
    else
        data_reg <= {
    4'd11,4'd11,4'd11,4'd11,4'd11,unit};

//cnt_1ms:1ms循环计数
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_1ms <=  16'd0;
    else    if(cnt_1ms == CNT_MAX)
        cnt_1ms <=  16'd0;
    else
        cnt_1ms <=  cnt_1ms + 1'b1;

//flag_1ms:1ms标志信号
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        flag_1ms    <=  1'b0;
    else    if(cnt_1ms == CNT_MAX - 1'b1)
        flag_1ms    <=  1'b1;
    else
        flag_1ms    <=  1'b0;

//cnt_sel:从0到5循环数,用于选择当前显示的数码管
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        cnt_sel <=  3'd0;
    else    if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
        cnt_sel <=  3'd0;
    else    if(flag_1ms == 1'b1)
        cnt_sel <=  cnt_sel + 1'b1;
    else
        cnt_sel <=  cnt_sel;

//数码管位选信号寄存器
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        sel_reg <=  6'b000_000;
    else    if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
        sel_reg <=  6'b000_001;
    else    if(flag_1ms == 1'b1)
        sel_reg <=  sel_reg << 1;
    else
        sel_reg <=  sel_reg;

//控制数码管的位选信号,使六个数码管轮流显示
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        data_disp    <=  4'b0;
    else    if((seg_en == 1'b1) && (flag_1ms == 1'b1))
        case(cnt_sel)
        3'd0:   data_disp    <=  data_reg[3:0]  ;  //给第1个数码管赋个位值
        3'd1:   data_disp    <=  data_reg[7:4]  ;  //给第2个数码管赋十位值
        3'd2:   data_disp    <=  data_reg[11:8] ;  //给第3个数码管赋百位值
        3'd3:   data_disp    <=  data_reg[15:12];  //给第4个数码管赋千位值
        3'd4:   data_disp    <=  data_reg[19:16];  //给第5个数码管赋万位值
        3'd5:   data_disp    <=  data_reg[23:20];  //给第6个数码管赋十万位值
        default:data_disp    <=  4'b0        ;
        endcase
    else
        data_disp   <=  data_disp;

//dot_disp:小数点低电平点亮,需对小数点有效信号取反
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        dot_disp    <=  1'b1; 
    else    if(flag_1ms == 1'b1)
        dot_disp    <=  ~point[cnt_sel];
    else
        dot_disp    <=  dot_disp;

//控制数码管段选信号,显示数字
always@(posedge sys_clk or  negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        seg <=  8'b1111_1111;
    else    
        case(data_disp)
            4'd0  : seg  <=  {dot_disp,7'b100_0000};    //显示数字0
            4'd1  : seg  <=  {dot_disp,7'b111_1001};    //显示数字1
            4'd2  : seg  <=  {dot_disp,7'b010_0100};    //显示数字2
            4'd3  : seg  <=  {dot_disp,7'b011_0000};    //显示数字3
            4'd4  : seg  <=  {dot_disp,7'b001_1001};    //显示数字4
            4'd5  : seg  <=  {dot_disp,7'b001_0010};    //显示数字5
            4'd6  : seg  <=  {dot_disp,7'b000_0010};    //显示数字6
            4'd7  : seg  <=  {dot_disp,7'b111_1000};    //显示数字7
            4'd8  : seg  <=  {dot_disp,7'b000_0000};    //显示数字8
            4'd9  : seg  <=  {dot_disp,7'b001_0000};    //显示数字9
            4'd10 : seg  <=  8'b1011_1111          ;    //显示负号
            4'd11 : seg  <=  8'b1111_1111          ;    //不显示任何字符
            default:seg  <=  8'b1100_0000;
        endcase

//sel:数码管位选信号赋值
always@(posedge sys_clk or negedge sys_rst_n)
    if(sys_rst_n == 1'b0)
        sel <=  6'b000_000;
    else
        sel <=  sel_reg;

//********************************************************************//
//*************************** Instantiation **************************//
//********************************************************************//

//---------- bsd_8421_inst ----------
bcd_8421    bcd_8421_inst
(
    .sys_clk     (sys_clk  ),   //系统时钟,频率50MHz
    .sys_rst_n   (sys_rst_n),   //复位信号,低电平有效
    .data        (data     ),   //输入需要转换的数据

    .unit        (unit     ),   //个位BCD码
    .ten         (ten      ),   //十位BCD码
    .hun         (hun      ),   //百位BCD码
    .tho         (tho      ),   //千位BCD码
    .t_tho       (t_tho    ),   //万位BCD码
    .h_hun       (h_hun    )    //十万位BCD码
);

endmodule

仿真程序

`timescale 1ns/1ns
module tb_seg_dynamic();


reg         sys_clk         ;
reg         sys_rst_n       ;
reg [19:0]  data            ;
reg [5:0]   point           ;
reg         seg_en          ;
reg         sign            ;
                       
wire    [5:0]   sel         ;
wire    [7:0]   seg         ;

initial
    begin
        sys_clk = 1'b1;
        sys_rst_n <= 1'b0;
        data <= 20'd0;
        point <= 6'b0;
        sign <= 1'b0;
        seg_en <= 1'b0;
        #30
        sys_rst_n <= 1'b1;
        data <= 20'd9876;
        point <= 6'b000010;
        sign <= 1'b1;
        seg_en <= 1'b1;
    end 
    
always #10 sys_clk = ~sys_clk;
defparam  seg_dynamic_inst.CNT_MAX = 20'd5 ; 
//对seg_dynamic_inst模块中的CNT_MAX进行重新定义
seg_dynamic seg_dynamic_inst
(
    .sys_clk   (sys_clk  ) , 
    .sys_rst_n (sys_rst_n) , 
    .data      (data     ) , 
    .point     (point    ) , 
    .seg_en    (seg_en   ) , 
    .sign      (sign     ) , 
                
    .sel       (sel      ) , 
    .seg       (seg      )   
);

endmodule



版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_48564372/article/details/113387642

智能推荐

【资源下载】JM 的H.264/AVC编解码(附YUVPlayer和YUV文件下载)_一条余弦Cos的博客-程序员秘密

整理不易,冲冲冲……后期继续更YUVPlayer下载地址:http://www.yuvplayer.com/YUV 文件下载地址:http://trace.eas.asu.edu/yuv/index.html注意:用YUVPlayer播放时请记住下载视频对应的长和宽的数值,播放时需要自己手动填入,否则会出现播放不正确的情况。...

编辑器VSCode使用心得_weixin_33810006的博客-程序员秘密

工欲善其事必先利其器,趁手的工具会使我们开发事半功倍。市面上的编辑器我用过许多,编辑器使用经历Notepad++,(开源)这个应该是最轻量级的吧,查看代码还好,编辑代码就算了官网地址:https://notepad-plus-plus.org/Brackets,(开源)这个也不错,github-star:30k了,上次发布版本是6月...

设计模式 -- 工厂模式_工厂设计模式csdn_赵不酷的博客-程序员秘密

所有工厂模式都通过减少应用程序和具体类之间的依赖促进松耦合。工厂是很有威力的技巧,帮助我们针对抽象编程,而不要针对具体类编程。理论介绍工厂方法模式:定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个。工厂方法让类把实例化推迟到子类。抽象工厂模式:提供一个接口,用于创建相关或者依赖对象的家族,而不需要明确指定具体类。应用场景工厂方法模式:可以将你的客户代码从需要实例化的具...

Fortran入门教程(二)——数据类型_fortran character_Sumbrella_的博客-程序员秘密

数据类型数据类型是指在计算机中能够记录文本、数值等的数据单位。算法处理的对象是数据,而数据是以某种特定的形式(如整数、实数、字符等形式)存在的。不同的数据之间往往还存在某些联系,例如由若干个整数组成一个整数数组。1. 变量声明隐式声明(不再使用)隐式声明是传统 Fortran 语言预先定义且无须通过类型声明语句对变量类型进行定义,习惯称为I-N规则。Fortran 规定,凡以字母I、J、K、L、M、N(无论大写还是 小写)6个字母开头的变量名,如无另外说明则为整型变量。以其他字母开头的变量被默认为

beeline软件_Beeline_weixin_39938269的博客-程序员秘密

Beeline是一个转为优化国服游戏打造的多功能网络加速应用。可以快速解决手游网络卡顿、延迟、掉线、丢包、跳红跳蓝、加载缓慢等问题。并且有着多个线路可以选择,能智能选择线路、降低延迟、断线重连、防止卡顿,提高网络稳定性。同时还支持一些锁国区的手机应用,让你可以看国内的视频和听音乐。Beeline软件特色【国服手游,一键加速】Beeline游戏加速器支持:王者荣耀、和平精英、第五人格、阴阳师、梦幻西...

Flink on yarn_Amos_Mu的博客-程序员秘密

1.Flink on yarn执行方式和提交命令第一种:是先开辟资源然后在进行资源的调度使用,开辟的资源是供所有的flink进程来使用的,如果某一时刻没有flink程序执行开辟的资源会空转等待新的flink进程。第二种:是一边开辟资源一边进行使用,一个资源供一个flink进程使用,flink进程执行完毕之后就释放资源。 flink的提交命令: ...

随便推点

sap进阶系列(5):第一篇:财务总览之基金管理(资金预算)_ctyg7349的博客-程序员秘密

2.4; s+ v0 B. B. W1 P' ]( j基金管理(资金预算)上一章介绍的是资金管理中的资金头寸管理,流动性预测和公司总部资金平衡。本章介绍的模块是管理资金预算的。由于本模块在公共部门(如政府等)是特别重要的模块,...

从服务器下载&&OTA升级&&JSON文件解析_ota json_hejunw的博客-程序员秘密

mainActivity :package com.example.he.toby.otademo;import android.content.pm.PackageInfo;import android.content.pm.PackageManager;import android.support.v7.app.AppCompatActivity;import android

CodeForces 963A - Alternating Sum 等比数列求和 逆元 数论_MasterAn的博客-程序员秘密

题目链接题意 求等比数列的和并对1e9+91e9+91e9+9取模。分析 S=a1(qlen−1)q−1S=a1(qlen−1)q−1S=\frac{a1(q^len -1)}{q-1},q=bk∗(inv(a))k(mod1e9+9),其中len=(n+1)/k,inv(a)为a的逆元q=bk∗(inv(a))k(mod1e9+9),其中len=(n+1)/k,inv(a)为a的逆元...

高并发详细讲解以实现_如何实现高并发_gua_niu123的博客-程序员秘密

一、什么是高并发高并发(High Concurrency)是互联网分布式系统架构设计中必须考虑的因素之一,它通常是指,通过设计保证系统能够同时并行处理很多请求。高并发相关常用的一些指标有响应时间(Response Time),吞吐量(Throughput),每秒查询率QPS(Query Per Second),并发用户数等。响应时间:系统对请求做出响应的时间。例如系统处理一个HTTP请求需要200ms,这个200ms就是系统的响应时间。吞吐量:单位时间内处理的请求数量。QPS:每秒响应请求数。在互

HDU - 1045 Fire Net 【DFS】_牧心.的博客-程序员秘密

DescriptionSuppose that we have a square city with straight streets. A map of a city is a square board with n rows and n columns, each representing a street or a piece of wall.A blockhouse is a sm...

【企业框架源码】 SpringMVC mybatis 多数据源 代码生成器 SSM java redis shiro ehcache_weixin_34318272的博客-程序员秘密

获取【下载地址】 QQ: 313596790官网 http://www.fhadmin.org/A代码编辑器,在线模版编辑,仿开发工具编辑器,pdf在线预览,文件转换编码B 集成代码生成器 [正反双向](单表、主表、明细表、树形表,快速开发利器)+快速表单构建器freemaker模版技术 ,0个代码不用写,生成完整的一个模块,带页面、建表sql脚本,处理类,service等完整模块C...