978|3

43

帖子

2

TA的资源

一粒金砂(高级)

【Tang Primer25K Dock】四——数码管的动态显示测试 [复制链接]

本帖最后由 Zhao_kar 于 2023-12-9 22:40 编辑

【Tang Primer25K Dock】四——数码管的动态显示测试

备注:

  • 前面讲过数码管原理了,本节就讲一下动态显示,然后本节有两个演示:
  • 第一个演示是数码管两个管一起显示,从0-9,同时低四位的led也跟着显示二进制值
  • 第二个演示是正常的00-99,然后因为演示问题,低位个位是用0.1s,也就是高位是1s,然后8个led用来显示值,高位四个显示十位,低位四个显示个位的值。
  • 下一节打算把按键混进来了,两个数码管显示0-99的数值范围,然后四个按键分别实现+1、2、4、8的加数,然后四个拨码开关,分别为rst,1s+1,1s-1,闪烁。
  • 后面真的打算画一个数码管模块,起码四个才能显示时钟吧,画完之后,就按照那个模块来实现,然后去做一个数字时钟,也就是测评计划的最后项目。目前我测试下来,感觉比预期想的快,然后我打算做完数字时钟后,有时间的话,移植一下那个软核,我看有人的计划有,暂时没有移植过,比较感兴趣。

一、动态显示的原理

  1. 前面说过数码管的原理了,先以最常见的多个位选单独控制的数码管分析,其工作状态应该为:假定我有一个四位的数码管,那么控制数码管的显示的信号是四条位选信号sel,如果我想让他全亮,那就是4‘b1111,如果只要第一位,那就是4’b1000,而又因为四个数码管的数值是同一个值,所以要想让四个数码管显示不同的值,我们要使用动态显示。
  2. 对于1,假如我想让四个数码管显示1234,那么数码管的显示流程应该如下,先让位选选择第一个,也就是第一个数码管亮,此时给的数值为1,然后让位选变成第二个,第二个数码管开始亮,此时给的是值2,以此类推,如果你给这个位选信号是1s,那么效果应该为每隔1s数码管亮一个,而且从第一个到第四个循环。
  3. 而在Verilog里面的话,那么我应该给一个reg,存1234这四个值,然后因为数码管译码是4位,所以应该用一个16进制,比如4‘h1234,也就是16’0001_0010_0011_0100,然后用一个高频的信号,一个100hz的信号,为什么用这个频率,是因为这个频率以上,四个位选的变化可以说是0.01s变一次,人是看不出来的,你看到的视觉效果会是四个连续的值,因为是四个位选,所以给一个2位的reg,做计数器,从00-11刚好四个状态,四个状态下,位选信号的值都会变化,而且同时给数码管的数据也跟着变,具体见代码。
  4. 说了那么多,不如直接上代码+注释直观,往下看吧

二、第一个测试的代码+注释+演示

1、代码+注释

module digital_cnt
#(
    parameter   CNT_1HZ=28'd24_999_999,
    parameter   CNT_100HZ=28'd49_999
)
(
    input clk,
    input rst,
    output[7:0]led,
    output reg [6:0]seg_n,
    output sel
);
/***************parameter*************/
localparam          P_0 = 7'b0000001    ;
localparam          P_1 = 7'b1111001    ;
localparam          P_2 = 7'b0010010    ;
localparam          P_3 = 7'b0110000    ;
localparam          P_4 = 7'b1101000    ;
localparam          P_5 = 7'b0100100    ;
localparam          P_6 = 7'b0000100    ;
localparam          P_7 = 7'b1110001    ;
localparam          P_8 = 7'b0000000    ;
localparam          P_9 = 7'b0100000    ;
localparam          P_X = 7'b1111111    ;
/***************reg*******************/

//分1s时钟
reg [27:0] cnt_1hz;
reg clk_1hz=1'b0;
always @(posedge clk or negedge rst)
    if (rst == 1'b0) begin
        cnt_1hz <= 28'd0;
    end else if (cnt_1hz == CNT_1HZ) begin
        cnt_1hz <= 28'd0;
        clk_1hz = ~clk_1hz;
    end else begin
        cnt_1hz <= cnt_1hz + 1'b1;
    end


//分100hz的动态扫描时钟
reg [27:0] cnt_100hz;
reg clk_100hz=1'b0;
always @(posedge clk or negedge rst)
    if (rst == 1'b0) begin
        cnt_100hz <= 28'd0;
    end else if (cnt_100hz == CNT_100HZ) begin
        cnt_100hz <= 28'd0;
        clk_100hz = ~clk_100hz;
    end else begin
        cnt_100hz <= cnt_100hz + 1'b1;
    end


//数码管计数0-9
reg [3:0]   data_temp;//中间值
wire [3:0]  data;//值
assign data=data_temp;    
always@(posedge clk_1hz or negedge rst)
    if(rst==1'b0)
       data_temp<=4'b0000;
    else if(data_temp==4'b1001)begin//如果等于9
         data_temp<=4'b0000;
    end  else
        data_temp<=data_temp+1'b1;

//led的计数
reg [3:0] led_out;
assign led=~led_out;
always@(posedge clk_1hz or negedge rst)
    if(rst==1'b0)
       led_out<=4'b0000;
    else if(led_out==4'b1001)
        led_out<=4'b0000;
    else
       led_out<=led_out+1'b1;

//数码管数据选择
always @ (data)
        case(data)
            4'b0000: seg_n <= P_0;
            4'b0001: seg_n <= P_1;
            4'b0010: seg_n <= P_2;   
            4'b0011: seg_n <= P_3;
            4'b0100: seg_n <= P_4;
            4'b0101: seg_n <= P_5;
            4'b0110: seg_n <= P_6;
            4'b0111: seg_n <= P_7;
            4'b1000: seg_n <= P_8;
            4'b1001: seg_n <= P_9;
            default: seg_n <= P_X;      
        endcase

//动态扫描部分
reg sel_temp;
assign sel=sel_temp; 
//给一个100hz的时钟,然后因为这个数码管是通过sel的0和1选择左边和右边的值的
//所以把中间值当成计数器,就0、1计数,然后通过这个值控制数码管的左右显示
//然后因为这里没有对数值进行处理,所以效果为两个数码管一起显示一个值。
always@(posedge clk_100hz or negedge rst)
    if(rst==1'b0)
       sel_temp<=1'b0;
    else if(sel_temp==1'b1)
        sel_temp<=1'b0;
    else
       sel_temp<=sel_temp+1'b1;

endmodule

2、演示视频(如下)

测试1

 

三、第二个效果的代码

1、这一个是从00+到99,8个led的高位低位显示十位和个位的值

2、代码+注释

module digital_cnt
#(
    parameter   CNT_1HZ=28'd24_999_999,
    parameter   CNT_10HZ=28'd2_499_999,
    parameter   CNT_100HZ=28'd49_999
)
(
    input clk,
    input rst,
    output[7:0]led,
    output reg [6:0]seg_n,
    output reg sel
);
/***************parameter*************/
localparam          P_0 = 7'b0000001    ;
localparam          P_1 = 7'b1111001    ;
localparam          P_2 = 7'b0010010    ;
localparam          P_3 = 7'b0110000    ;
localparam          P_4 = 7'b1101000    ;
localparam          P_5 = 7'b0100100    ;
localparam          P_6 = 7'b0000100    ;
localparam          P_7 = 7'b1110001    ;
localparam          P_8 = 7'b0000000    ;
localparam          P_9 = 7'b0100000    ;
localparam          P_X = 7'b1111111    ;
/***************reg*******************/
/*分频0.1s部分*/
reg [27:0] cnt_10hz;
reg clk_10hz=1'b0;
always @(posedge clk or negedge rst)
    if (rst == 1'b0) begin
        cnt_10hz <= 28'd0;
    end else if (cnt_10hz == CNT_10HZ) begin
        cnt_10hz <= 28'd0;
        clk_10hz = ~clk_10hz;
    end else begin
        cnt_10hz <= cnt_10hz + 1'b1;
    end


/*分频1s部分*/
reg [27:0] cnt_1hz;
reg clk_1hz=1'b0;
always @(posedge clk or negedge rst)
    if (rst == 1'b0) begin
        cnt_1hz <= 28'd0;
    end else if (cnt_1hz == CNT_1HZ) begin
        cnt_1hz <= 28'd0;
        clk_1hz = ~clk_1hz;
    end else begin
        cnt_1hz <= cnt_1hz + 1'b1;
    end


/*分频100hz,动态扫描部分*/
reg [27:0] cnt_100hz;
reg clk_100hz=1'b0;
always @(posedge clk or negedge rst)
    if (rst == 1'b0) begin
        cnt_100hz <= 28'd0;
    end else if (cnt_100hz == CNT_100HZ) begin
        cnt_100hz <= 28'd0;
        clk_100hz = ~clk_100hz;
    end else begin
        cnt_100hz <= cnt_100hz + 1'b1;
    end


/*数码管计数0-9*/
reg [3:0]   data_temp_L,data_temp_H;
reg [3:0]  data;//值    
//下面为了显示效果,没有取1s的时钟,用的是10hz的,这样子高位就是1s的变化。
always@(posedge clk_10hz or negedge rst)
    if(rst==1'b0)begin
        data_temp_L <= 4'b0000;
        data_temp_H <= 4'b0000;
    end else if(data_temp_L == 4'b1001)begin//如果等于9
        data_temp_L <= 4'b0000;
        data_temp_H <= data_temp_H + 1'b1; //如果低位计满时,高位先加1
    end else if(data_temp_H == 4'b1010)begin
        data_temp_H <= 4'b0000;
    end else
        data_temp_L <= data_temp_L + 1'b1;//低位根据时钟的变化+1

//led的计数,以低四位表述个位的数值,高四位表述十位的值
wire [3:0] led_out_L;
wire [3:0] led_out_H;
assign led_out_H = data_temp_H;
assign led_out_L = data_temp_L;
assign led = ~{led_out_H,led_out_L};
//数码管数据选择
always @ (data)
        case(data)
            4'b0000: seg_n <= P_0;
            4'b0001: seg_n <= P_1;
            4'b0010: seg_n <= P_2;   
            4'b0011: seg_n <= P_3;
            4'b0100: seg_n <= P_4;
            4'b0101: seg_n <= P_5;
            4'b0110: seg_n <= P_6;
            4'b0111: seg_n <= P_7;
            4'b1000: seg_n <= P_8;
            4'b1001: seg_n <= P_9;
            default: seg_n <= P_X;      
        endcase
//动态扫描电路
wire cnt_digital;
reg cnt_digital_temp; 
assign cnt_digital = cnt_digital_temp;
//100hz的动态扫描时钟,然后使用一个计数器,因为这里只有一个位选,所以计数器是1位的,只能从0到1
always@(posedge clk_100hz or negedge rst)
    if(rst == 1'b0)
        cnt_digital_temp <= 1'b0;
    else if(cnt_digital_temp == 1'b1)
        cnt_digital_temp <= 1'b0;
    else
        cnt_digital_temp <= cnt_digital_temp + 1'b1;
//通过计数器的值,确定两个状态
//状态1选择第2个数码管,显示低位的数据
//状态2选择第一个数码管,显示高位的数据
//动态显示部分就两个,一个是动态扫描时钟,一个是case的处理
always@(cnt_digital)
    case(cnt_digital)
    1'b0:begin sel = 1'b0; data = data_temp_L; end
    1'b1:begin sel = 1'b1; data = data_temp_H; end
    default: begin sel = 1'b0; data = 4'b0000; end
    endcase

endmodule

3、视频演示

测试2

四、cst文件,约束文件,两个都是一模一样的

//Copyright (C)2014-2023 Gowin Semiconductor Corporation.
//All rights reserved. 
//File Title: Physical Constraints file
//GOWIN Version: V1.9.9 Beta-5
//Part Number: GW5A-LV25MG121NES
//Device: GW5A-25
//Device Version: A
//Created Time: Fri 12 08 18:00:14 2023

IO_LOC "sel" K5;
IO_PORT "sel" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "seg_n[6]" L11;
IO_PORT "seg_n[6]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "seg_n[5]" K11;
IO_PORT "seg_n[5]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "seg_n[4]" L5;
IO_PORT "seg_n[4]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "seg_n[3]" E10;
IO_PORT "seg_n[3]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "seg_n[2]" E11;
IO_PORT "seg_n[2]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "seg_n[1]" A11;
IO_PORT "seg_n[1]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "seg_n[0]" A10;
IO_PORT "seg_n[0]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[7]" C10;
IO_PORT "led[7]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[6]" C11;
IO_PORT "led[6]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[5]" B10;
IO_PORT "led[5]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[4]" B11;
IO_PORT "led[4]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[3]" D10;
IO_PORT "led[3]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[2]" D11;
IO_PORT "led[2]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[1]" G10;
IO_PORT "led[1]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "led[0]" G11;
IO_PORT "led[0]" PULL_MODE=NONE DRIVE=8 BANK_VCCIO=3.3;
IO_LOC "rst" F5;
IO_PORT "rst" PULL_MODE=NONE DRIVE=OFF BANK_VCCIO=3.3;
IO_LOC "clk" E2;
IO_PORT "clk" PULL_MODE=NONE DRIVE=OFF BANK_VCCIO=3.3;
约束.png

 

最新回复

第一段视频的配音很生动,给我吓到了   详情 回复 发表于 2024-4-20 18:43

回复
举报

55

帖子

0

TA的资源

一粒金砂(中级)

按键模块呢?这个板的按键模块怎么使用啊

点评

额,就四个拨码开关和四个按键正常用啊,约束引脚对就行了,这个模块上面是对称的,他一列,其中两个是开关两个是按键,第二列反过来,先按键后开关,然后具体使用就是正常按键,按下低电平,如果是板子上面的那两个  详情 回复 发表于 2024-1-27 23:10

回复

43

帖子

2

TA的资源

一粒金砂(高级)

学学学学学学学 发表于 2024-1-27 13:16 按键模块呢?这个板的按键模块怎么使用啊

额,就四个拨码开关和四个按键正常用啊,约束引脚对就行了,这个模块上面是对称的,他一列,其中两个是开关两个是按键,第二列反过来,先按键后开关,然后具体使用就是正常按键,按下低电平,如果是板子上面的那两个,可以去GitHub上看看,有人说过要怎么操作。

感谢提醒,我都忘记了更新这次活动的帖子了,还好还有时间更新


回复

113

帖子

1

TA的资源

一粒金砂(高级)

第一段视频的配音很生动,给我吓到了

个人签名

没用比没有强


回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/10 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2024 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表