• 【FPGA】时序逻辑电路——基于计数器实现一个以1秒频率闪烁的LED灯


    时序逻辑电路 计数器的实现

    1 D触发器

    image-20221112094647196

    分析:

    特性:输出端Q只在CK处于上升沿的时候变化

    图中波形的形成过程:

    • 当D处于高电平时,CK未处于上升沿时,Q仍处于低电平

    • 当CK来到上升沿,Q需要根据D发生变化,由于D是高电平,所以Q要从低电平变化成高电平

    • D从高电平变化成低电平,但是此时CK未来到上升沿,所以Q不随着D变化(虽然D变了,Q仍保持刚刚的状态——存储功能)

    • CK来到上升沿,此时D又恢复了高电平,所以Q不变

    2 计数器

    原理:加法器基本结构图

    image-20221112095528426

    这样就能实现 每一个时序上升沿,计数器结果都加1

    今天我们的任务是
    设计一个以1秒频率闪烁的LED灯(亮灭各500ms)

    怎么知道500ms亮,500ms灭呢?

    • 我们就需要一个计数器,计数到什么时候到了500ms

    • 时钟的频率我们设置为50MHz 20ns,也就是两个上升沿(一个周期)的时间是20ns

    • 每到一个上升沿,计数器的值加一次

    • 由于500ms亮和灭,所以我们需要计数器计数 500ms/20ns = 25000000次

    • 而一个四位计数器肯定计数不了这么多的值,那么需要多少位呢?

    image-20221112104038009

    • 源代码
    module led_flash(
        clk,
        reset_n,//reset是复位信号,  _n 表示低电平有效,也就是低电平时复位
        led
        );
        
       input clk;
       input reset_n;
       output reg led;
       
       reg [24:0] counter;//25位计数器
       
       always@(posedge clk or negedge reset_n)  //当clk处于上升沿或者reset处于下降沿的时候下面的代码就生效
       if(!reset_n) // if(reset_n == 0)
            counter <= 0;  // <= 是非阻塞赋值的意思
        else if (counter == 2500_0000) //-1)
            counter <= 0;
       else
            counter <= counter + 1'd1;
            
            
      //需要让 led 灯每500ms翻转一次
       always@(posedge clk or negedge reset_n)  
       if(!reset_n) 
            led <= 0;
        else if (counter == 2500_0000) //-1)  要减1
            led <= !led; //翻转
    
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    仿真代码

    `timescale 1ns / 1ps
    
    module led_flash_tb(
    
        );
        reg clk;
        reg reset_n;
        wire led;
        
        led_flash UUT(
            .clk(clk),
            .reset_n(reset_n),
            .led(led)
            );
        
        initial clk = 1;
        always #10 clk =! clk; 
        
        initial begin 
            reset_n = 0;
            #201; //避开上升沿 
            reset_n = 1;
            #20_0000_0000;   // 2s
        end
        
    endmodule
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 仿真

    从仿真的结果看

    image-20221112114920018

    比预想的500ms 多了 20ns

    原因是这里如果想计数2500_0000次,应该写2499_9999

    image-20221112115216247

    这里以计数到4为例,如果要计数到4的话,实际上不是计数了4次,而是5次

    • 0-1
    • 1-2
    • 2-3
    • 3-4
    • 4-0

    所以应该改为 2500_0000-1

    改过之后 就可以了

    image-20221112120351268

    改过之后 就可以了

    image-20221112120351268
  • 相关阅读:
    评论组件--uniapp textarea focus,string.replace
    报错的解决 sqlite3.OperationalError: unrecognized token: “630008.OF“
    天宇优配|GDR海外发行热情高 资本市场互联互通提速
    超大规模的产业实用语义分割数据集PSSL与预训练模型开源啦!
    4、两个栈实现一个队列
    选择「程序员」职业的8个理由
    【Unity实战】实现强大通用易扩展的对话系统(附项目源码)
    【Java编程进阶之路--数组】
    Python用27行代码绘制一幅满天星
    C++ if 语句
  • 原文地址:https://blog.csdn.net/Living_Amethyst/article/details/127821308