数码管动态显示(三)——动态显示驱动模块


一、动态显示驱动模块示意图

在这里插入图片描述


二、动态显示驱动模块波形图

1.待显示数据data给其任意值9876;
2.小数点位point选中倒数第二个,数据为000-010,则显示的数据为987.6;
3.符号位sign首先给定低电平,当复位信号sys_rst_n无效(高)时,sign电平拉高,表示要显示负数,即-987.6;
4.使能信号seg_en给定初值低电平,复位信号无效给定高电平,表示数码管一直处于显示状态。
在这里插入图片描述data_reg变量只寄存符号位和数据位,不包含小数点位。(结果为X-9876,使用5个数码位,最高位不显示,用X表示)
每个数码位显示时间为1ms,为了对1ms进行记数,设置一个计数器变量cnt_1ms[15:0],初值为0,一个时钟周期20ns,1ms记数5*104个周期,则计数器最大值为49999(对应二进制为1100 0011 0100 1111),故计数器位宽16。
声明一个一毫秒标志信号flag_1ms用来控制数码位的选择,当计数器为最大值-1时保持高电平,其他时刻为低电平。
为了对扫描周期进行记数,声明cnt_sel变量,6个数码管,最大值为5(二进制101,三位宽)。在这里插入图片描述位选信号sel的000000表示一个数码位都不选中,000001表示选中第一个数码位。
定义一个变量表示即将要显示的数据data_disp,选中第一个数码位时显示6,第二个数码位显示7,第五个数码位显示负号,用10表示(也可以选择除了0-9的其他数值表示),最高位不显示,用11表示(二进制1011)。
声明变量小数点位dot_disp,高电平不显示,在第二个数码位拉低电平,其他时刻拉高。
输出段选信号seg,共阳数码管(段选时低电平点亮),初值全F表示不点亮,数字6对应的十六进制格式为82(查表);7表示f8,但由于小数点位要点亮,故7的dp应该为0,即0111_1000,对应十六进制的78,而不是f8;10表示负号,负号就是g位,即g为0(低有效),其他为1,也就是1011 1111,即bf;11不点亮就是全1,即ff。
在这里插入图片描述但段选信号和位选信号差一个时钟周期,为同步就要对信号进行打拍,将sel信号定义为一个变量sel_reg,使用时序逻辑对其进行打拍生成时序信号sel。
在这里插入图片描述

三、代码

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   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    ;   //当前数码管显示的小数点

//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_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        ;//其他情况赋值0
        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          ;    //显示负号,只点亮g,低电平
            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;

bcd bcd_inst
(    
    .sys_clk   (sys_clk   )  ,
    .sys_rst_n (sys_rst_n )  ,
    .data      (data      )  ,
    .unit  (unit ),
    .ten   (ten  ),
    .hun   (hun  ),
    .tho   (tho  ),
    .t_tho (t_tho),
    .h_hun (h_hun)
);

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'b0000_010;
        sign<=1'b1;
        seg_en<=1'b1;
    end

always #10 sys_clk=~sys_clk;

defparam seg_dynamic_inst.CNT_MAX=20'd5;//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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小年痴槑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值