找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 5927|回复: 2
打印 上一主题 下一主题
收起左侧

FPGA学习-计数器设计与验证

[复制链接]
跳转到指定楼层
楼主
ID:108531 发表于 2016-3-12 22:45 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式

1、源程序(源码注释与源码对应是最好的解释)【时序逻辑】

/* 实验名称:计数器验证

 * 程序功能:每 500ms ,LED 状态亮或灭一次

 * 时钟计算:50MHz 的时钟频率,那么时钟周期就是 1/50Mhz = 0.02us == 20ns

 *                500ms = 500_000_000ns = 500_000_000ns/20ns = 25_000_000次

 *                也就是说在 50MHz 的时钟频率下,累加 25000000 次就等于 500ms 的时间

 */

module mytest(clk_50M, rst_n, led);

    input clk_50M;        // 系统时钟 50MHz

    input rst_n;            // 全局复位,低电平复位

    output reg led;       // led 指示灯输出

   

    // 25000_000 => 0x17D7840 => 4*6+1 = 25位

    reg[24:0] cnt;     // 定义计数器寄存器

 

    // 计数器程序块

    // always :对某些信号变化感兴趣

    // posedge:  表示 clk_50m   上升沿时会进入该程序块

    // negedge:    表示 rst_n    下降沿时会进入该程序块

    always@(posedge clk_50M or negedge rst_n)

       

        if(1'b0 == rst_n)                    // 当 rst_n 引脚为低电平时表示复位

            cnt <= 25'd0;                    // 复位计数器的值

        else if(25'd24_999_999 == cnt)         // 由于 cnt 是从 0 开始计数,所以需要-1

            cnt <= 25'd0;                    // 避免溢出

        else

            cnt <= cnt + 1'b1;                // 计数器计数(累加)

           

    // led 输出程序块

    always@(posedge clk_50M or negedge rst_n)

       

        if(1'b0 == rst_n)                // rst_n 复位时,点亮 led 不做其他事情

            led <= 1'b1;

        else if(25'd24_999_999 == cnt)    // 当计数器达到 500ms 时则翻转一次 led 状态

            led <= ~led;

        else

            ;                // rst_n 不是复位,同时计数器未满,空语句,不做其他事情

endmodule 

2、仿真程序

/* 实验名称:计数器验证 */

 `timescale 1ns/1ns

`define clock_period 20 // 时钟周期 系统时钟是50M/s 时钟周期是1/50Mhz = 0.02us == 20ns

 

module mytest_tb;            // 由于是简单的仿真测试,所以可以不跟端口列表

 

    reg clk, rst_n;        // 激励信号源

    wire led;

 

    mytest counter0(.clk_50M(clk), .rst_n(rst_n), .led(led));

   

    initial clk = 1;// 激励输出 小梅哥说这里 clk = 1 仿真时有一定的好处,建议保持这个习惯

    // "`" 表示调用宏定义参数   10ns 高电平 10ns 低电平形成一个时钟周期

    always #(`clock_period/2) clk = ~clk;    // 产生时钟信号 20ns一个周期   

    initial begin

        rst_n = 1'b0;                // 复位

        #(`clock_period * 200);         // 延时200个时钟周期

        rst_n = 1'b1;

        #2000000000;                // 延时 2秒钟

        $stop;

    end

 

endmodule

 

 

3、程序生成的波形

        由于时间太长,所以将比较值25'd24_999_999 修改为25'd24_999 时间原先为500ms变0.5ms

 

 

4、程序生成的电路图

 

电路图理解:

 

这个原理图我一开始也看不太懂,后来经过视频的讲解以及结合代码来看,总算是看明白了。

 

首先,从25为寄存器(cnt[24..0])开始看:

    情况1:寄存器为0~0x17D783E时,Q会输出该值,传给加法器进行累加,同时传给25位比较器(Equal0)

的A端口,比较器会将该值(A端口)与B端口值(0x17D783F)比较,A与B不等则输出0到翻转器的ENA.同时也输入到25位二路选择器的 SEL 端,翻转器那边不会触发,而二路选择器的SEL等于0,所以会选择DATAA的数据输出给寄存器。而DATAA的数据是由加法器累加(0x17D783E+1),由再传给寄存器,进入情况2。

    情况2:寄存器为0x17D783F时,Q会输出该值,传给加法器进行累加,同时传给比较器的A端口,比较器判断A与B端口相等,则输出1到翻转器的ENA端口,同时输出1给选择器的 SEL端口。翻转器会翻转电平输出,而选择器则会选择 DATAB 端口的数据(0)传给寄存器,此时寄存器的值为0.

 

本来想画流程图的,由于项目比较紧,既然已经理解了,就不画了,抓紧时间学下一个知识点。

 

分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

沙发
ID:305020 发表于 2018-4-10 11:10 | 只看该作者
您好  ,想请教您一些问题 ,我现在想做100mhz的计数器  周期是10ns应该怎么去做呢?
回复

使用道具 举报

板凳
ID:310716 发表于 2018-4-21 10:05 | 只看该作者
KUNH3266 发表于 2018-4-10 11:10
您好  ,想请教您一些问题 ,我现在想做100mhz的计数器  周期是10ns应该怎么去做呢?

比如系统时钟是50Mhz,那只需要二分频就可以了。
回复

使用道具 举报

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

本版积分规则

手机版|小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表