【牛客网刷题系列 之 Verilog进阶挑战】~ 计数器专题

本文详细介绍了三种Verilog计数器的设计:简易秒表、可置位计数器和加减计数器。通过题目描述、解题思路、代码实现和波形分析,展示了如何利用Verilog实现不同功能的计数器,包括秒表计时、置位操作和模式切换计数。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

0. 前言

本次更新注意是针对于计数器而言,怎么评价计数器呢?其实我觉得,计数器不难,但是你还离不开计数器这个东西,包括实现一些任意占空比的任意分频啊,这些都得用得着计数器的。所以说,有必要单独拿出来和大家分享一下下呢!!!

1. VL50 简易秒表

1.1 题目描述

请编写一个模块,实现简易秒表的功能:具有两个输出,当输出端口second从1-60循环计数,每当second计数到60,输出端口minute加一,一直到minute=60,暂停计数。

1.1.1 信号示意图

在这里插入图片描述

1.1.2 波形示意图

在这里插入图片描述

1.1.3 输入描述

clk:系统时钟信号
rst_n:异步复位信号,低电平有效

1.1.4 输出描述

second:6比特位宽,秒表的秒读数
minute:6比特位宽,秒表的分读数

1.2 解题思路

该题的思路类似于生活中的时钟,就是 秒 计时从1开始(注意复位是从0开始的哦!!!);分从0开始,秒 每满60个数,分自动加一,秒自动置1,依次类推,直到分为60,停止计数。

1.3 代码实现

`timescale 1ns/1ns

module count_module(
	input clk,
	input rst_n,

    output reg [5:0]second,
    output reg [5:0]minute
	);
	
	//second
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
           second <= 6'd0; 
        end
        else begin
            if(second == 6'd60) begin //second从1-60循环计数
               second <= 6'd1;
            end
            else if (minute == 6'd60) begin //一直到minute=60,暂停计数
               second <= 6'd0; 
            end
            else begin
                second <= second + 1'b1; 
            end
        end
    end
	
    //minute
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
           minute <= 6'd0; 
        end
        else begin
            if(second == 6'd60) begin   //每当second计数到60,输出端口minute加一
               minute <= minute + 6'd1;
            end
            else begin
                minute <= minute;  //一直到minute=60,暂停计数
            end
        end
    end
endmodule

1.4 测试文件

待更。。。

1.5 仿真波形

待更。。。

2. VL51 可置位计数器

2.1 题目描述

请编写一个十六进制计数器模块,计数器输出信号递增每次到达0,给出指示信号zero,当置位信号set 有效时,将当前输出置为输入的数值set_num。

2.1.1 信号示意图

在这里插入图片描述

2.1.2 波形示意图

在这里插入图片描述

2.1.3 输入描述

clk:时钟信号
rst_n:复位信号,低电平有效
set:置位指示信号,当该信号有效时,表示将输出信号强制置为set_num
set_num:4比特信号,当set信号有效时,将该信号的数字赋予输出信号number

2.1.4 输出描述

zero:过零指示信号,当number计数到0时,该信号为1,其余时刻为0
number:4比特位宽,表示计数器的当前读数

2.2 解题思路

该题相比于之前多了一个置位功能,实现起来也比较简单,正常情况下,有如下代码便可实现一个可置位的计数器!!!但这个题有点小小的不一样(不知道是出题人故意这么设定的呢?还是这是一个巧合呢?哈哈哈)!!!

`timescale 1ns/1ns

module count_module(
	input clk,
	input rst_n,
	input set,
	input [3:0] set_num,
	output reg [3:0]number,
	output reg zero
	);

    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            number <= 4'd0;
        end
        else begin
            if(set) begin
               number <= set_num; 
            end
            else begin
                number <= number + 1'b1;
            end
        end
    end
    //zero
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            zero <= 1'b0;
        end
        else begin
            if(number == 1'b0) begin
               zero <= 1'b1; 
            end
            else begin
               zero <= 1'b0; 
            end
        end
    end
endmodule

为什么会有number_reg呢?

如果只是实现一个可置位的计数器,很简单,不用临时寄存但是,该题的标准答案不行呢,必须实现的是number和zero同时拉起来,这就要求有一个变量可以提前为0,来指示number和zero的信号。这就有了如下答案:

2.3 代码实现

`timescale 1ns/1ns

module count_module(
	input clk,
	input rst_n,
	input set,
	input [3:0] set_num,
	output reg [3:0]number,
	output reg zero
	);
    
    /* 
    为什么会有number_reg呢?
    如果只是实现一个可置位的计数器,很简单,不用临时寄存
    但是,该题的标准答案不行呢,必须实现的是number和zero同时拉起来
    这就要求有一个变量可以提前为0,来指示number和zero的信号。
    */
    reg [3:0] number_reg;
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            number_reg <= 4'd0;
        end
        else begin
            if(set) begin
               number_reg <= set_num; 
            end
            else begin
                number_reg <= number_reg + 1'b1;
            end
        end
    end
    // number
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            number <= 4'd0;
        end
        else begin
           number <=  number_reg;
        end
    end
    //zero
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            zero <= 1'b0;
        end
        else begin
            if(number_reg == 1'b0) begin
               zero <= 1'b1; 
            end
            else begin
               zero <= 1'b0; 
            end
        end
    end
endmodule

2.4 测试文件

待更。。。

2.5 仿真波形

待更。。。

3. VL52 加减计数器

3.1 题目描述

请编写一个十进制计数器模块,当mode信号为1,计数器输出信号递增,当mode信号为0,计数器输出信号递减。每次到达0,给出指示信号zero。

3.1.1 信号示意图

在这里插入图片描述

3.1.2 波形示意图

在这里插入图片描述

3.1.3 输入描述

clk:系统时钟信号
rst_n:复位信号,低电平有效
mode:模式选择信号,当该信号为1,计数器每个时钟加一;为0,则每个时钟减一。

3.1.4 输出描述

number:4比特位宽,计数器当前输出读数。
zero:过零指示信号,当number为0时,该信号为1,其他时刻为0.

3.2 解题思路

该题的思路类似于上一个题,也是需要输出同步拉高的,所以也需要一个寄存器暂存起来,话不多说,开干!!!

3.3 代码实现

`timescale 1ns/1ns

module count_module(
	input clk,
	input rst_n,
	input mode,
	output reg [3:0]number,
	output reg zero
	);

    /*
    和 51题,可置位计数器极其类似啊!!!
    */
    reg [3:0] number_temp;
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            number_temp <= 4'd0;
        end
        else begin
            if(mode) begin
                if(number_temp == 4'd9) begin
                    number_temp <= 4'd0;
                end
                else begin
                    number_temp <= number_temp + 1'b1;
                end
            end
            else begin
                if(number_temp == 4'd0) begin
                    number_temp <= 4'd9;
                end
                else begin
                    number_temp <= number_temp - 1'b1;
                end
            end
        end
    end
    // number
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            number <= 4'd0;
        end
        else begin
            number <= number_temp;
        end
    end
    
    //zero
    always @ (posedge clk or negedge rst_n) begin
        if(!rst_n) begin
            zero <= 1'd0;
        end
        else begin
            if(number_temp == 1'd0) begin
               zero <= 1'd1; 
            end
            else begin
                zero <= 1'd0;
            end
        end
    end
endmodule

3.4 测试文件

待更。。。

3.5 仿真波形

待更。。。

声明

本人所有系列的文章,仅供学习,不可商用,如有侵权,请告知,立删!!!

本人主要是记录学习过程,以供自己回头复习,再就是提供给后人参考,不喜勿喷!!!

如果觉得对你有用的话,记得收藏+评论!!!

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值