verilog数字钟实验总结

本文部分代码参考的b站教学,记录下来仅方便期末考试的时候复习。

要想实现数字时钟,我们首先要明确几个问题:1.怎么形成以秒为单位的“输入”(这里并非输入,其实是一秒钟产生一次响应);2.处理时分秒的进位问题;3.将其显示在数码管上。理清这三个需求其实verilog的编写也就很明确了,即三个问题各对应三个模块。

首先解决第一个问题。为了模拟现实中的1s我们可以采用对周期信号进行计数的方式来实现,很容易就想到clk信号,而时钟信号是周期激励,显然我们不可能手动对它完成输入,那这时候我们就需要接到FPGA开发板上自带的时钟信号激励源上。以我手上的BASYS 3为例,自带100MHz的clk激励,也就是1ns产生一次clk信号,那我们就可以通过对clk计数,当counter达到100_000_000次时,时长就达到了1s。输出就用0和1区分

代码如下:

module clk_1s(
  input clk,
  input rstn,
  output flag_1s
);
parameter num_1s = 100_000_000;
reg [26:0]cnt_1s;
always@(posedge clk or negedge rstn)
  begin
    if(!rstn) begin
      cnt_1s <= 0;
    end 
    else 
      begin
        if(cnt_1s == num_1s) cnt_1s <= 0;
        else cnt_1s <= cnt_1s+1;
      end
   end
assign flag_1s = (cnt_1s == num_1s) ? 1 : 0;
endmodule

第二个问题,处理时分秒进位问题其实和C语言是一样的用if else语句一一处理不同的情况就行了

输出是6个三位位宽的二进制数分别对应时分秒的十位和个位

代码如下:

module clock(
  input clk,
  input rstn,
  input flag_1s,
  output reg[3:0] data0,
  output reg[3:0] data1,
  output reg[3:0] data2,
  output reg[3:0] data3,
  output reg[3:0] data4,
  output reg[3:0] data5
);
reg [5:0] second;
reg [5:0] minute;
reg [4:0] hour;
always@(posedge clk or negedge rstn)
  begin
    if(!rstn) begin
      second <= 0;
    end else begin
       if(second==59&&flag_1s)begin
         second <= 0;
       end else if(flag_1s)begin
         second = second + 1;
       end else begin
         second <= second;
       end
     end
  end
always@(posedge clk or negedge rstn)
  begin
    if(!rstn) minute <= 0;
    else 
      begin
       if(minute==59&&second==59&&flag_1s) minute <= 0;
       else if(second==59&&flag_1s) minute <= minute + 1;
       else minute <= minute;
      end
   end
always@(posedge clk or negedge rstn)
  begin
    if(!rstn) hour <= 0;
    else 
      begin
        if(hour==23&&minute==59&&second==59&&flag_1s) hour<=0;
        else if(minute==59&&second==59&&flag_1s) hour <= hour + 1;
        else hour <= hour;
      end
  end
always@(posedge clk or negedge rstn)
  begin
    if(!rstn) begin
      data0 <= 0;
      data1 <= 0;
      data2 <= 0;
      data3 <= 0;
      data4 <= 0;
      data5 <= 0;
    end else begin
      data0 <= hour/10;
      data1 <= hour%10;
      data2 <= minute/10;
      data3 <= minute%10;
      data4 <= second/10;
      data5 <= second%10;
    end
  end
endmodule

第三个问题:数码管的输出。要想解决这个问题首先要明确数码管点亮的逻辑是什么。

需要控制数码管的时间在人眼可滞留范围的同时保证数据不会更新,否则就会出现显示误差

直接贴图了

简而言之,就是一次性只能点亮一个数码管,而且是低电平点亮。想呈现出四个数码管同时亮的情况就得对clk信号进行分频,太快会让数码管扫描过快,出现显示上的出错,比如混亮,过亮,来不及变化等情况;太慢又会出现灯光过暗或者只有一个灯光在亮的情况。我把频率分到了1kHz

分频的代码如下:
reg[15:0]cnl;
reg clk1k;
always@(posedge clk or negedge rstn)
  begin
    if(!rstn)
    begin
      cnl<=0;
      clk1k<=0;
    end
    else if(cnl>=49999)
    begin
      clk1k<=!clk1k;
      cnl<=0;
    end
    else cnl<=cnl+1;
  end

接下来就是具体数码管的显示处理,因为我们前面提到了有六个数字需要显示,再结合同时只能点亮一个数码管(只有四个数码管,所以其中有两个数据显示在led上),就想到需要六个状态去一一对应,改变状态就改变了数码管的选择。同时一个中间变量去承接每个状态需要输出的数字,再将数字用译码器变化成对应的编码去数码管上显示就好了,注意区别这里的数码管选择和数码管显示。

代码如下:

module digital(
  input clk,
  input rstn,
  input [3:0]data0,
  input [3:0]data1,
  input [3:0]data2,
  input [3:0]data3,
  input [3:0]data4,
  input [3:0]data5,
  output reg[7:0]seg,
  output reg[3:0]sel,
  output reg[2:0]hours1,
  output reg[2:0]hours2
);
reg[15:0]cnl;
reg clk1k;
always@(posedge clk or negedge rstn)//分频
  begin
    if(!rstn)
    begin
      cnl<=0;
      clk1k<=0;
    end
    else if(cnl>=24999)
    begin
      clk1k<=!clk1k;
      cnl<=0;
    end
    else cnl<=cnl+1;
  end
reg [3:0]tub;//中间变量
reg [2:0]state;//状态变量
always@(posedge clk1k or negedge rstn)
  begin
    if(!rstn)
    begin
      tub<=0;
      state<=0;
      sel<=0;
      hours1<=0;
      hours2<=0;
    end
    else
    begin
      case(state)//每种状态的数码管选择,0111即第四个数码管,hours1和2显示在led上,并且在状态转换的同时,数据也更新一次
        0:begin hours1<=data0;sel<=4'b1111;state<=1;end
        1:begin hours2<=data1;sel<=4'b1111;state<=2;end
        2:begin tub<=data2;sel<=4'b0111;state<=3;end
        3:begin tub<=data3;sel<=4'b1011;state<=4;end
        4:begin tub<=data4;sel<=4'b1101;state<=5;end
        5:begin tub<=data5;sel<=4'b1110;state<=0;end
        default:state<=0;
      endcase
    end
  end
always@(*)//数码管数字显示
  if(!rstn)
    seg<=8'b1100_0000;
  else
    case(tub)
      0:seg<=8'b1100_0000;
      1:seg<=8'b1111_1001;
      2:seg<=8'b1010_0100;
      3:seg<=8'b1011_0000;
      4:seg<=8'b1001_1001;
      5:seg<=8'b1001_0010;
      6:seg<=8'b1000_0010;
      7:seg<=8'b1111_1000;
      8:seg<=8'b1000_0000;
      9:seg<=8'b1001_0000;
      default:seg<=8'b1100_0000;
    endcase
endmodule

最后的流程就是用一个顶层模块把三个模块穿起来就行了:

module top(
  input clk,
  input rstn,
  output [7:0]seg,//输出用于数码管数字的显示
  output [3:0]sel,//输出控制六个数码管的显示
  output [2:0]hours1,//输出时的
  output [2:0]hours2
    );
  wire flag_1s;
  wire [3:0]data0;
  wire [3:0]data1;
  wire [3:0]data2;
  wire [3:0]data3;
  wire [3:0]data4;
  wire [3:0]data5;
clk_1s clk_1s_u(
  .clk(clk),
  .rstn(rstn),
  .flag_1s(flag_1s)
);
clock clock_u(
  .clk(clk),
  .rstn(rstn),
  .flag_1s(flag_1s),
  .data0(data0),
  .data1(data1),
  .data2(data2),
  .data3(data3),
  .data4(data4),
  .data5(data5)
);
digital digital_u(
  .clk(clk),
  .rstn(rstn),
   .data0(data0),
  .data1(data1),
  .data2(data2),
  .data3(data3),
  .data4(data4),
  .data5(data5),
  .seg(seg),
  .sel(sel),
  .hours1(hours1),
  .hours2(hours2)
);
endmodule

下面贴上具体的电路图

 约束文件的编写因为有数码管所以需要去查表进行约束,采用图像化约束会简单一些

这个是约束后的代码

set_property IOSTANDARD LVCMOS33 [get_ports {seg[7]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[6]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {seg[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[5]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[4]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[3]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {sel[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports clk]
set_property IOSTANDARD LVCMOS33 [get_ports rstn]
set_property PACKAGE_PIN W5 [get_ports clk]
set_property PACKAGE_PIN R2 [get_ports rstn]
set_property PACKAGE_PIN U2 [get_ports {sel[0]}]
set_property PACKAGE_PIN U4 [get_ports {sel[1]}]
set_property PACKAGE_PIN V4 [get_ports {sel[2]}]
set_property PACKAGE_PIN W4 [get_ports {sel[3]}]
set_property PACKAGE_PIN V7 [get_ports {seg[7]}]
set_property PACKAGE_PIN W7 [get_ports {seg[0]}]
set_property PACKAGE_PIN W6 [get_ports {seg[1]}]
set_property PACKAGE_PIN U8 [get_ports {seg[2]}]
set_property PACKAGE_PIN V8 [get_ports {seg[3]}]
set_property PACKAGE_PIN U5 [get_ports {seg[4]}]
set_property PACKAGE_PIN V5 [get_ports {seg[5]}]
set_property PACKAGE_PIN U7 [get_ports {seg[6]}]

set_property PACKAGE_PIN P3 [get_ports {hours1[2]}]
set_property PACKAGE_PIN U3 [get_ports {hours1[1]}]
set_property PACKAGE_PIN W3 [get_ports {hours1[0]}]
set_property PACKAGE_PIN V3 [get_ports {hours2[2]}]
set_property PACKAGE_PIN V13 [get_ports {hours2[1]}]
set_property PACKAGE_PIN V14 [get_ports {hours2[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hours1[2]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hours1[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hours1[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hours2[0]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hours2[1]}]
set_property IOSTANDARD LVCMOS33 [get_ports {hours2[2]}]

  • 8
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 5
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值