首页 > 其他分享 >一个问题:六位八段数码管(Verilog)

一个问题:六位八段数码管(Verilog)

时间:2024-06-02 13:32:24浏览次数:10  
标签:cnt led clk seg 数码管 Verilog 八段 sel reg

【基本信息】

需求:verilog程序,显示任意六位字符或数值,包含点号,且能够按需点亮位数。(学习篇)

芯片型号:cyclone Ⅳ EP4CE10F17C8

数码管属性:六位、八段

【最终成果图】

image

经过多轮测试,最后代码程序满足设计要求,但结合仿真发现了一个问题,仿真和上机不匹配,当然还是要以上机为准。

【模块例化图】

image

这里就是简单地赋个初始值,来测试digital模块,最终是要seg_led和seg_sel的显示变化。

【verilog程序】

1、digital模块

模块化设计,六个位上的值直接拆开做处理,分析起来清晰。sel_cnt表示目前要显示的位数(从右往左),即sel_cnt = 6代表全亮。dp_cnt表示点号所在位数,若dp_cnt=0则代表没有点号。clk_2khz为数码管的刷新信号。

module digital
(
    input           sys_clk      ,
    input           sys_rst      ,
    input           clk_2khz     ,
    
    input [3:0]     num6,
    input [3:0]     num5,
    input [3:0]     num4,
    input [3:0]     num3,
    input [3:0]     num2,
    input [3:0]     num1,
    input [2:0]     sel_cnt     , 
    input [2:0]     dp_cnt      ,
   
    output reg[5:0] seg_sel     ,
    output reg[7:0] seg_led      
);
reg[2:0] sel_cnt_tran;
reg[3:0] num;
reg[2:0] tran1;
//endmodule

定义了几个变量,sel_cnt_tran用来根据数码管刷新信号更替数码管的位选,而num用来接引各位上的值,数码管根据num编号段选信号。tran1在过程讨论部分做解释。

always @(posedge sys_clk or negedge sys_rst)
begin
    if(!sys_rst)
        sel_cnt_tran = 3'd0;
    else 
    if(clk_2khz)begin 
        if(sel_cnt_tran < sel_cnt)begin
            tran1 = sel_cnt_tran;
            sel_cnt_tran = sel_cnt_tran + 1'b1;
        end
        else begin
            tran1 = sel_cnt_tran;
            sel_cnt_tran = 3'd0;
        end
    end
end

上述代码就是位选更替,可以直观得到,tran1比sel_cnt_tran要晚上一个数码管刷新周期。

always @(posedge sys_clk or negedge sys_rst)
begin
    if(!sys_rst)
        seg_sel <= 6'b111_111;
    else if(clk_2khz)begin
        case(sel_cnt_tran)
            3'd1:begin
                seg_sel <= 6'b111_110;
                num <= num1;
            end
            3'd2:begin
                seg_sel <= 6'b111_101;
                num <= num2;
            end
            3'd3:begin
                seg_sel <= 6'b111_011;
                num <= num3;
            end
            3'd4:begin
                seg_sel <= 6'b110_111;
                num <= num4;
            end
            3'd5:begin
                seg_sel <= 6'b101_111;
                num <= num5;
            end
            3'd6:begin
                seg_sel <= 6'b011_111;
                num <= num6;
            end
            default:begin
                seg_sel <= 6'b111_111;
            end
        endcase
    end
end

根据原理图,数码管是共阳极,并且位选拉低有效,这里测试是没有问题的。

always @(posedge sys_clk or negedge sys_rst)begin
    if (!sys_rst)
        seg_led = 8'b0;
    else begin
        case (num)
            4'h0 :    seg_led = 8'b1100_0000;
            4'h1 :    seg_led = 8'b1111_1001;
            4'h2 :    seg_led = 8'b1010_0100;
            4'h3 :    seg_led = 8'b1011_0000;
            4'h4 :    seg_led = 8'b1001_1001;
            4'h5 :    seg_led = 8'b1001_0010;
            4'h6 :    seg_led = 8'b1000_0010;
            4'h7 :    seg_led = 8'b1111_1000;
            4'h8 :    seg_led = 8'b1000_0000;
            4'h9 :    seg_led = 8'b1001_0000;
            4'ha :    seg_led = 8'b1000_1000;
            4'hb :    seg_led = 8'b1000_0011;
            4'hc :    seg_led = 8'b1100_0110;
            4'hd :    seg_led = 8'b1010_0001;
            4'he :    seg_led = 8'b1000_0110;
            4'hf :    seg_led = 8'b1000_1110;
            default : seg_led = 8'b1100_0000;//多余
        endcase
        if(dp_cnt == (tran1))begin	//确定点号,这里不是sel_cnt_tran
            seg_led = seg_led & 8'b0111_1111;
        end 
    end
end

2、clk_2khz模块

module clk_2khz
(
    input               sys_clk      ,
    input               sys_rst      ,
    
    output reg          clk_out 
);
parameter   cnt_2khz_max = 25_000;
reg[14:0]   cnt;

clk_2khz时钟产生很简单,cnt_2khz_max = 1/2_000x50_000_000,在这就放下代码。注意两个问题:一个是不要直接posedge clk_2khz方式来读上升沿,另外尽量不要采用取反方式产生分频时钟信号,如果是取反,可以采用wire en;assign en = d1 & d0来读边沿信号。

always @(posedge sys_clk or negedge sys_rst)begin
    if(!sys_rst)begin
        cnt <= 15'd0;
        clk_out <= 1'b0;
    end
    else if(cnt <(cnt_2khz_max-1'b1))begin
        cnt <= cnt + 1'b1;
        clk_out <= 1'b0;
    end
    else begin
        cnt <= 15'd0;verilog
        clk_out <= 1'b1;
    end
end
endmodule

3、顶部例化测试

module digital_top  (  
    input           sys_clk ,  
    input           sys_rst ,  
    output [5:0] seg_sel ,  
    output [7:0] seg_led   
);  
wire clk_2khz_tran;
reg[3:0] num1       = 4'd2;
reg[3:0] num2       = 4'h1;
reg[3:0] num3       = 4'd5;
reg[2:0] sel_cnt    = 3'd6;
reg[2:0] dp_cnt     = 3'd6;
digital digital_inst();  //例化省略
clk_2khz clk_generator1(); 
endmodule

4、Modelsim仿真

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

parameter   T1 =20 ;
parameter   T2 =200;
parameter max = 14;
reg sys_clk;
reg clk_2khz;
reg sys_rst;
reg[3:0] num1       = 4'h1;
reg[3:0] num2       = 4'h1;
reg[3:0] num3       = 4'h1;
reg[2:0] sel_cnt    = 3'd6;
reg[2:0] dp_cnt     = 3'd6;
reg[3:0] cnt;
wire[7:0] seg_led;
wire[5:0] seg_sel;

always # (T1/2) sys_clk <= ~sys_clk;

always @(posedge sys_clk or negedge sys_rst)begin
    if(!sys_rst)
        cnt <= 4'd0;
    else begin 
        if(cnt < max)begin
            cnt <= cnt + 1'b1;
            clk_2khz <= 1'b0;
        end
        else begin 
            cnt <= 4'd0;
            clk_2khz <= 1'b1;
        end
    end
end

initial begin
    sys_clk              <=1'b0;
    sys_rst              <=1'b0;
    #50 sys_rst          <=1'b1;  
end
    digital digital_inst();//例化省略  
endmodule

【过程讨论】

首先由于自己疏忽,数码管位选刷新位置采用的是非阻塞赋值的方法,通过用sel_cnt_tran判断为真的话,通过仿真(下图)观察到,位选和段选不匹配,就是说,点号的位置不正确,现象是位选落后了。

image

然后想着将赋值方法改为阻塞赋值,还是有问题。强制更改,设定判断条件为if(dp_cnt == (sel_cnt_tran-1’b1))看看,显然,这样虽然有效(图在下面),但只能保证最终的点号位置有限,比如dp_cnt = 6就有问题,因为sel_cnt_tran在6后赋值是0,达不到条件。后面借助变量tran1在sel_cnt_tran刷新处赋值使其落后一个周期,仿真显示不正确,但上机测试有效。

image

标签:cnt,led,clk,seg,数码管,Verilog,八段,sel,reg
From: https://www.cnblogs.com/handat/p/18227025

相关文章

  • Verilog设计实现七段数码管译码器的设计
    七段数码管常用于计时器、拨码开关输入、班级和学号等信息的显示,通过控制不同的段亮灭,可以实现各种数字和字符的显示。七段数码管通常由a-g七个段组成,每一段对应一个LED。为了显示不同的数字,需要控制这些LED的亮灭。图1七段数码管为了控制这些LED的亮灭,需要设计一个显示译......
  • Verilog设计实现7人投票表决器
    使用verilog实现七人投票表决器。要求若超过四人含四人投票赞成,则表决通过。设计模块://定义模块test6,声明输出端口pass和输入端口votemoduletest6(outputpass,//输出端口,表示投票结果是否通过inputvote//输入端口,一个7位的向量,每位表示......
  • Verilog设计实现两个8位二进制数相乘
    乘法器的基本原理可以通过多种方法实现,例如移位相加法、查找表法等。在Verilog中,我们可以使用内建的乘法运算符“*”来实现乘法功能。首先明确计算的范围。8位2进制1111_1111=255,所以两个8位二进制数的取值范围是0-255。考虑最大值255*255=65025=(1111_1110_0000_0001)2。所......
  • Verilog HDL中如何控制模块的调用与否
    VerilogHDL中如何控制模块的调用与否(实用)语言:VerilgHDLEDA工具:ISE、Vivado、QuartusIIVerilogHDL中如何控制模块的调用与否(实用)一、引言二、模块调用与否的几种方法1.注释2.使用预处理指令`ifdef3.使用generate语句三、结尾关键词:调用,VerilogHDL......
  • 基于51单片机的超声波测距(汽车倒车雷达)—数码管显示
    基于51单片机的超声波测距(仿真+程序+原理图+PCB+设计报告)功能介绍具体功能:1.HC-SR04超声波模块测距;2.数码管显示测量的距离,74hc573和三极管驱动数码管;3.本设计可用作汽车的倒车雷达;4.三个按键可设置报警距离;​演示视频:基于51单片机的超声波测距(汽车倒车雷达)—数码......
  • 基于FPGA的NC图像质量评估verilog实现,包含testbench和MATLAB辅助验证程序
    1.算法运行效果图预览vivado2019.2和matlab2022a测试,结果如下:    2.算法运行软件版本vivado2019.2 matlab2022a 3.算法理论概述​      图像质量的含义包括图像的逼真度和图像的可读懂性。所谓图像的逼真度是指被评价图像与标准图像的偏离程度,偏差越......
  • Verilog入门篇,带你了解Verilog
    前言 学习资源推荐:学习书目推荐《Verilog数字系统教程》第四版,夏宇闻,韩彬编著。         Verilog刷题网站:HDLBits。                                           ......
  • 【转载】Verilog对数据进行四舍五入(round)与饱和(saturation)截位
    jgliu</div><!--end:blogTitle博客的标题和副标题--><divid="navigator">博客园首页新随笔联系订阅管理 <divclass="blogStats"> <spanid="stats_post_count">随笔-19&nbsp;</span>文......
  • SystemVerilog -- 3.2 SystemVerilog Threads --> fork join_any
    forkjoin_any在一个简单的SystemVerilog中,mainthread会等到所有childthread都完成执行。这意味着如果任何childthread永远运行并且永远不会完成,则fork将挂起模拟。SystemVerilog还提供了带有forkjoin和forkjoin_any的原始版和变体。如果任何一个childthread完成,则允许ma......
  • SystemVerilog -- 3.1 SystemVerilog Threads --> fork join
    forkjoinSystemVerilog通过构造提供对并行或并发threads的支持。可以使用fork和join同时生成多个proceduralblocks。有一些变体允许mainthread根据childthread何时完成继续执行其余语句。Syntaxfork//Thread1//Thread2//...//Thread3joinforkjoin......