【代码】Xilinx + Vivado + 数字时钟(时分秒) + LED指示

这篇具有很好参考价值的文章主要介绍了【代码】Xilinx + Vivado + 数字时钟(时分秒) + LED指示。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【代码】【Xilinx + Vivado + 数字时钟(时分秒) + LED指示】实践项目

最终效果(没图)

  • 每1秒sec计数累加1次,59次之后清零;
  • 每1分钟min计数累加1次,59次之后清零;
  • 每1小时hour计数累加1次,23次之后清零;
  • LED1交替翻转,1秒翻转1次,所以1亮1灭是2秒;
  • LED2交替翻转,1分钟翻转1次;

相关截图

fpga数码管显示小时和分钟,led 闪烁表示秒,# FPGA开发,嵌入式硬件开发,fpga开发,fpga

fpga数码管显示小时和分钟,led 闪烁表示秒,# FPGA开发,嵌入式硬件开发,fpga开发,fpga

fpga数码管显示小时和分钟,led 闪烁表示秒,# FPGA开发,嵌入式硬件开发,fpga开发,fpga

过程记录

首先要申明一点,目前入门FPGA的阶段属于非常非常,所有工程代码、工程逻辑都可能存在错误,希望各位同学老师能够指出,同时也参考了大量的互联网上优质内容,在这里一并感谢,基于这个原因也决定将核心逻辑进行共享。请勿做一切商业用途。

ok,let’s go

首先是搞清楚思路,我们设计一个时钟,是在我们这个现实世界里边的时钟,滴答滴答1秒就是1秒,而不是FPGA规定的1秒。如何将FPGA里边的1秒,对应上现实世界滴答滴答1秒,关键在于配合FPGA的时钟和计数值二者。假如我们现在FPGA的时钟是50MHz(6次方),那么FPGA计数一次就是20ns,我们需要计算50_000_000次,才能够达到现实世界滴答滴答1秒的效果。注意,到这里两个1秒就同步上了,因为现实世界、FPGA都消耗了1秒,不管你是从哪一帧开始的,从这一帧开始匹配上之后,往后的每个1秒(只要FPGA不要断电 and 世界不要毁灭)理论上都能一直匹配上,这就是数字时钟能够显示现实世界时间的原理。当然FPGA并不知道当前北京时间是多少(可以加上时间校正功能),也并不知道1小时有60分钟,1分钟有60秒,这些逻辑都是依靠我们自己去实现的。

设计模块1:分频部分,配合FPGA的时钟和计数值,实现1秒的计时;
设计模块2:秒钟部分,实现秒钟的累加,数值达到59自动清零;
设计模块3:分钟部分,实现分钟的累加,数值达到59自动清零;
设计模块4:时钟部分,实现时钟的累计,数值达到23自动清零;

由于我们定义secminhour都是全局的,所以我们不需要额外的标志位,再去判断是否技术满足1分钟,或者计数满足1小时。只需要判断是否等于59即可,因为下个时钟沿才会下一段判断,而刚好下个时钟沿不就正好60了吗(上一刻赋值,下一刻判断,注意使用非阻塞赋值)。所以我们要做的就是维护这些计数值达到59/23的时候自动清零即可。

在每次秒钟累加的时候,翻转LED1,而在累加59秒钟,自动清零那一块的代码里边,翻转LED2。具体不展开,可以结合代码边调边看。

// 秒钟部分
always @ ( posedge clk_div  or posedge rst)begin
       if(rst)begin
           sec <= 0;
           led_out1 <= 1'b0;
           led_out2 <= 1'b0;
       end
      else begin
        if ( sec == 59 )begin  
             sec <= 0 ;
             led_out2 <= ~led_out2;
            end
        else begin
            led_out1 <= ~led_out1;
            sec <= sec + 1 ;
        end   
    end
end

还需要讲一下这个分频部分,这一块比较重要。

变量 含义
clk_out1 经过PLL分频得到的50MHz时钟信号
cnt FPGA自加计数的值
clk_div FPGA累计满1秒给的信号(上升沿)
sec 秒钟计数值(59后清零)
min 分钟计数值(59后清零)
hour 时钟计数值(23后清零)
parameter TIME_2HZ = 25_000_000 ; 
parameter TIME_1HZ= 50_000_000  ; 

//分频部分  50MHz - 1Hz/2Hz
always @ ( posedge clk_out1 or posedge rst)begin
       if(rst)begin
           cnt <= 0;
           clk_div <= 0;
        end
       else begin
        if ( cnt < TIME_2HZ  - 1 )
           begin
               clk_div <= 0;
               cnt <= cnt + 1;
           end
        else if ( cnt < TIME_1HZ - 1 )
           begin
               clk_div <= 1;
               cnt <= cnt + 1 ;
           end
        else
           cnt <=0 ;
       end
end

另外由于板载自带的晶振源是200MHz,所以我们需要PLL分频把晶振源降低到50MHz,这一部分参考之前的那篇博客。如果你的晶振已经是50MHz,那么直接把clk_out1换成sys_clk(50MHz)即可。

上述博客地址:【已解决】FPGA系列Xilinx Artix7找不到SYS_CLK在哪里,如何输出50MHZ频率方波

逻辑是这样的,系统时钟现在是50MHz,计数一次就是20ns,我们可以计数累计50_000_000就翻转一次clk_div的状态;而这里用的方法稍微有些不同,相当于是一个500ms高电平,一个500ms低电平,当两个高电平之间相隔还是1秒整。但如果我们1秒翻转1次翻转一次clk_div的状态,那么两次上升沿的间隔就是2秒(1秒高电平1秒低电平)而不是1秒。

fpga数码管显示小时和分钟,led 闪烁表示秒,# FPGA开发,嵌入式硬件开发,fpga开发,fpga

集合图像来看,假设我涂阴影的部分是1秒的自然时间,那么方案1就是维持500ms的低电平,维持500ms的高电平。而方案2就是维持1_000ms也就是1秒的高电平,再维持1_000ms的低电平。上述两种方案,哪种更加贴近我们的需求呢?显然是第一种方案,因为它能够维持每隔1秒,传递一个有效上升沿clk_div ,而方案2需要每隔2秒才能传递一个有效的高电平。

另外需要注意的一点是,每个1秒产生一个clk_div信号,并且在秒钟、分钟、时钟的计时处理函数中,都将clk_div的上升沿作为触发条件。看似没有什么问题,但其实也有更好的写法。理论上应该使用系统时钟(50MHz)作为触发条件,而不是自己分频的时钟,并且在系统时钟触发之后,再去判断clk_div上升沿完成一系列操作。虽然目前看工程暂时没有什么问题,这里先mark一下看看有没有其他大佬指点一下。

搞定这几个主要逻辑之后,读后边的代码,应该就比较顺畅了。具体还有问题的话可以评论区留言一下。

代码工程

首先要申明一点,目前入门FPGA的阶段属于非常非常,所有工程代码、工程逻辑都可能存在错误,希望各位同学老师能够指出,同时也参考了大量的互联网上优质内容,在这里一并感谢,基于这个原因也决定将核心逻辑进行共享。请勿做一切商业用途。

另外本次工程项目也继续产用了层次化的设计,具体什么是层次化(仅个人理解),代码复用带来什么好处请看我另一篇博客,这里不再赘述。以下代码包含三个部分,第一部分是核心clock module的实现。第二部分是Top.v,也就是最后下载到板子上的逻辑,这部分调用了clock module并且申明了一些端口的输出。第三部分是Testbench,同样是调用了clock module,并且申明了相应端口的输出,不同的是这里也申明了secminhour三个端口的输出,毕竟我们要看的就是这三个呀!?!

我的另一篇博客:FPGA基于Vivado开发,设计顶层文件Top.v

完整的clock module代码,主要实现功能是在50MHz的晶振源下,通过时钟+计数值的配合,每隔1秒输出一个有效的上升沿clk_div,并且进入具体逻辑的判断,包含计数值累加、计数值清零等操作。具体可以结合代码+仿真再看看。

`timescale 1ns / 1ns

//数字时钟模块
module clock1(
    sec,
    min,
    hour,
    rst,
    sys_clk_p,
    sys_clk_n,
    clk_out1,
    led_out1,
    led_out2
    );
       
input      rst;
input      sys_clk_p;            // Differential input clock 200Mhz
input      sys_clk_n;            // Differential input clock 200Mhz
output     clk_out1;  
output [7:0]  sec,min;
output [7:0]  hour;
output    led_out1;
output    led_out2;
reg    [7:0]  sec=0;
reg    [7:0]  min=0;
reg    [7:0]  hour=0;
reg    [32:0] cnt;
reg    clk_div;
reg    led_out1;
reg    led_out2;

//parameter TIME_2HZ = 25 ;  // 测试仿真使用
//parameter TIME_1HZ= 50  ; 
parameter TIME_2HZ = 25_000_000 ; 
parameter TIME_1HZ= 50_000_000  ; 


//分频部分  50MHz - 1Hz
always @ ( posedge clk_out1 or posedge rst)begin
       if(rst)begin
           cnt <= 0;
           clk_div <= 0;
        end
       else begin
        if ( cnt < TIME_2HZ  - 1 )
           begin
               clk_div <= 0;
               cnt <= cnt + 1;
           end
        else if ( cnt < TIME_1HZ - 1 )
           begin
               clk_div <= 1;
               cnt <= cnt + 1 ;
           end
        else
           cnt <=0 ;
       end
end

// 秒钟部分
always @ ( posedge clk_div  or posedge rst)begin
       if(rst)begin
           sec <= 0;
           led_out1 <= 1'b0;
           led_out2 <= 1'b0;
       end
      else begin
        if ( sec == 59 )begin  
             sec <= 0 ;
             led_out2 <= ~led_out2;
            end
        else begin
            led_out1 <= ~led_out1;
            sec <= sec + 1 ;
        end   
    end
end

//分钟部分
always @ ( posedge clk_div or posedge rst)begin
   if(rst)begin
        min <= 0;
   end 
   else begin
     if ( sec == 59 )begin
         if (min ==59 )
            min <= 0;
         else
            min <= min + 1 ;
     end
   end
end

// 时钟部分
always @ ( posedge clk_div or posedge rst)
    begin
       if(rst)begin
           hour <= 0;
       end
       else begin
            if ( sec == 59 && min ==59 )begin
                if (hour == 23)
                    hour <= 0 ;
                else
                    hour <= hour + 1;
            end
       end
end

endmodule

完整的顶层Top.v文件代码,常规的clock module初始化,PLL分频是因为我的板子是200MHz的,通过PLL分频为50MHz(之前的博客写了)。

`timescale 1ns / 1ps


module TOP(
    input rst,
    input sys_clk_p,
    input sys_clk_n,
    output clk_out1,
    output led_out1,
    output led_out2
    );

//***********差分时钟50MHz *****************************************
wire   sys_clk_p;
wire   sys_clk_n;
wire   rst;
wire   clk_out1; 

//***********数字时钟****************************************
wire   led_out1;
wire   led_out2;


//时钟模块初始化
clock1 clock(
    .led_out1(led_out1),
    .led_out2(led_out2),
    .rst(rst),
    .sys_clk_p(sys_clk_p        ),
    .sys_clk_n(sys_clk_n        ),
    .clk_out1(clk_out1        )
    );

//PLL分频的代码
clk_wiz_0 clk_wiz_0
(
// Clock out ports
.clk_out1(clk_out1),     // output clk_out1
// Status and control signals
.reset(rst), 
//.locked(locked),       // output locked
// Clock in ports
.clk_in1_p(sys_clk_p),   
.clk_in1_n(sys_clk_n));    // input clk_in1_n

endmodule

然后就是仿真文件,也都比较常规,注意的是这里还申明了sec、min、hour三个输出,方便我们看他的波形。另外值得注意的点是,这里的数字时钟计数方式是十六进制,也就是说09、0a、0b、0c ……这样的计数方式,具体原因我也还没搞清楚。后续我将这个clock制作成为数字时钟并且显示的时候,另外做了一些处理,最终也能够正常显示成09、10、11、12……这种形式,感兴趣的话可以翻翻那一篇博客。

`timescale 1ns / 1ns


module clock1_tb();

//***********??????*****************************************
reg   sys_clk_p;
wire  sys_clk_n;
reg     rst;
wire    clk_out1; 
//***********??????*****************************************
wire [7:0]   sec;
wire [7:0]   min;
wire [7:0]   hour;
wire   led_out1;
wire   led_out2;


//初始化系统时钟
initial begin
    sys_clk_p = 1'b0;
    rst <= 1'b0; 
    #2000
    rst <= 1'b1;
    #20000
    rst <= 1'b0;  
    #2000000
    rst <= 1'b1;
    #20000
    rst <= 1'b0;  
end


parameter T = 5; //200MHz时钟周期为5ns
always #(T/2) sys_clk_p = ~ sys_clk_p;   
assign sys_clk_n = ~ sys_clk_p;


//数字时钟初始化
clock1 clock(
    .led_out1(led_out1),
    .led_out2(led_out2),
    .sec(sec),
    .min(min),
    .hour(hour),
    .rst(rst),
    .sys_clk_p          (sys_clk_p        ),
    .sys_clk_n          (sys_clk_n        ),
    .clk_out1         (clk_out1        )
    );    

//PLL时钟分频
clk_wiz_0 clk_wiz_0
(
// Clock out ports
.clk_out1(clk_out1),     // output clk_out1
// Status and control signals
.reset(rst), 
//.locked(locked),       // output locked
// Clock in ports
.clk_in1_p(sys_clk_p),   
.clk_in1_n(sys_clk_n));    // input clk_in1_n

endmodule

fpga数码管显示小时和分钟,led 闪烁表示秒,# FPGA开发,嵌入式硬件开发,fpga开发,fpga

后续可以烧录板子具体看一看现象,引脚图上边已经给出了,但我们的引脚不会是一样的。另外因为我的时钟200MHz,所以会有sys_clk_p、sys_clk_n(二者差分)、clk_out1(最终的50MHz,其实可以不输出)。板子的复位是高电平有效,这一点也和传统复位可能有些区别,这一点大家注意一下。如果你是低电平复位建议写成rst_n,我是高电平复位所以是rst

总结

  • 通过时钟+计数值的配合,在FPGA环境下产生周期为1秒的上升沿clk_div
  • 在此上升沿的基础之上,实现了秒钟、分钟、时钟的计时逻辑;
  • 最终展示效果是LED1每隔1秒翻转一次(2秒完成一次闪烁),LED2每隔1分钟翻转一次。

参考

  • FPGA Verilog 开发实战指南 – 基于 Xilinx Artix7,野火(非常推荐这本书和他们家的白嫖资料);
  • 基于FPGA的数字时钟(使用vivado)
  • 基于FPGA的简易时钟(含verilog源码)

以上。

如果你觉得这篇文章对你有帮助,请为我点个赞谢谢🌹🌹
如果有遇到其他问题,也请在评论区留言🌹🌹文章来源地址https://www.toymoban.com/news/detail-767088.html

到了这里,关于【代码】Xilinx + Vivado + 数字时钟(时分秒) + LED指示的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • FPGA数字时钟(可暂停调数,含代码)

    前段时间刚刚开始初步学习FPGA相关知识,在学习了一段时间后,利用前面所学知识,写了一个数字时钟,顺便在这里写下总结,方便理解。 (本人小白一名,有错欢迎指出,欢迎探讨) 我使用的FPGA芯片型号是Cyclone IV的EP4CE6F17C8,如有想测试实现效果的同学,可以把后面3-

    2024年02月02日
    浏览(43)
  • Xilinx FPGA开发环境vivado使用流程

    第一步:点击Add Sources按钮 第二步:选择add or create design sources按钮,即添加设计文件 第三步:选择create file 文件新建完成后: 此时可以定义I/O端口,我们选择自己在程序中编写。 第四步:在编辑器中编写verilog程序 XDC文件里主要是完成管脚的约束,时钟的约束,以及组的约

    2024年02月03日
    浏览(58)
  • Xilinx 7系列FPGA的时钟管理

    在7系列FPGA中,时钟管理单元(CMT)包含了混合模式时钟管理器(MMCM)和锁相环(PLL)。PLL是包含了MMCM功能的一个子集。CMT骨干网可用于链接CMT的时钟功能。CMT图(图3-1)展示了各种时钟输入源与MMCM/PLL之间连接的高级视图,时钟输入连接允许多个资源为MMCM/PLL提供参考时钟

    2024年04月26日
    浏览(39)
  • Xilinx 7系列FPGA局部时钟资源

    局部时钟网络是玩去哪独立于全局时钟网络的。与全局时钟不同,局部时钟信号(BUFR)的覆盖范围仅限于一个时钟区域。一个I/O时钟信号驱动单个时钟区域。这些网络对于源同步接口设计特别有用。在7系列器件中,I/O bank与局部时钟域的大小相同。 在7系列器件中,局部时钟

    2024年04月29日
    浏览(52)
  • xilinx 7系列FPGA时钟布线资源

    7系列FPGA拥有多种时钟路由资源,以支持各种时钟方案和需求,包括高扇出、短传播延迟以及极低的偏斜。为了最佳地利用时钟路由资源,需要了解如何将用户时钟从PCB传递到FPGA,确定哪种时钟路由资源最优,然后通过利用适当的I/O和时钟缓冲器来访问这些时钟路由资源。

    2024年04月22日
    浏览(57)
  • Vivado | FPGA开发工具(Xilinx系列芯片)

    官网下载地址 最详细的Vivado安装教程 Vivado的安装以及使用_入门

    2024年02月12日
    浏览(59)
  • 【FPGA】Xilinx vivado生成.dcp文件的方法

    DCP文件是vivado软件生成的网表文件,主要起到加密的作用,在不需要提供源代码的情况下运行工程。 首先,需要新建工程,工程顶层文件就是生成后dcp文件的名称,然后在vivado-Tool-setting-project-setting-synthesis路径下,在More options中输入-mode out_of_context(综合时不产生IO buffer),

    2024年04月12日
    浏览(46)
  • FPGA小脚丫开发板实现数字时钟,具备调时、整点报时、闹钟功能(含verilog代码)

    一、实现功能 1. 能正常完成时钟的时、分、秒走时; 2. 使用 LED 闪烁或者改变颜色等方式实现秒的指示,要求闪烁频率或者颜色切换频率为 1Hz ; 3. 使用两位七段数码管显示时和分,其切换方式为:默认显示“分钟”,按住 K4 键显示“小时”,按下 K3 显示秒针; 4. 关上开关

    2024年02月11日
    浏览(56)
  • 【FPGA】 xilinx vivado中AXI4通信协议详解

    AXI是ARM 1996年提出的微控制器总线家族AMBA中的一部分。AXI的第一个版本出现在AMBA3.0,发布于2003年。当前的最新的版本发布于2010年。AXI 4总线和别的总线一样,都用来传输bits信息 (包含了数据或者地址) 。AXI4总线有三种类型,分别是AXI4、AXI4-Lite、AXI4-Stream AXI4:主要面向高性能

    2024年04月28日
    浏览(41)
  • Xilinx 7系列FPGA全局时钟缓冲器基本单元

    Global Clock Buffer Primitives(全局时钟缓冲器基本单元)在FPGA(现场可编程门阵列)和其他数字系统中扮演着至关重要的角色。这些基本单元被设计用于处理、分配和增强时钟信号,以确保系统中的各个组件都能以精确和同步的方式工作。 表2-2中的基本单元代表了全局时钟缓冲

    2024年04月23日
    浏览(59)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包