模六十计数器(三)

文章目录

  • 前言
  • 一、代码模板
  • 二、Verilog程序
    • 1、顶层模块
    • 2、计数模块
    • 3、显示模块
  • 三、Testbench程序
  • 四、仿真波形
  • 五、实测结果
  • 总结


前言

又隔了将近一年,学习明德扬编程规范,重新编写模六十计数器程序,使其符合规范,并采用模板化与模块化编程,使程序思路更加清晰。与之前不同,此次编程在Quartus II 13.0中建立项目,在AX530开发板上下载调试,引脚定义与配置需要视情况更改,项目文件将上传到资源中。


一、代码模板

修改明德扬代码模板

:ab Zhushi /***************注释***************/
:ab Shixu always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)begin<Enter>end<Enter>else begin<Enter>end<Enter>end
:ab Zuhe always@(*)begin<Enter>end
:ab Module module module_name(<Enter>clk,<Enter>rst_n,<Enter>//<Enter>dout<Enter>);<Enter><Enter>//参数定义<Enter>parameter  LENGTH = 8;<Enter>//输入输出<Enter>input                clk;<Enter>input                rst_n;<Enter>output     [7:0]     dout;<Enter>reg        [7:0]     dout;<Enter>//中间信号<Enter>reg                  signal;<Enter><Enter><Enter>endmodule
:ab Unit module_name Unit(<Enter>.clk(clk),<Enter>.rst_n(rst_n),<Enter>.dout(dout)<Enter>);
:ab Ztj    /***************四段式状态机***************/<Enter>//状态更新<Enter>always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)<Enter>state_c <= IDLE;<Enter>else<Enter>state_c <= state_n;<Enter>end<Enter>//状态转移<Enter>always@(*)begin<Enter>case(state_c)<Enter>IDLE:begin<Enter>if(idle_s1)<Enter>state_n = S1;<Enter>else <Enter>state_n = state_c;<Enter>end<Enter>S1:begin<Enter>if(s1_s2)<Enter>state_n = S2;<Enter>else <Enter>state_n = state_c;<Enter>end<Enter>S2:begin<Enter>if(s2_s3)<Enter>state_n = S3;<Enter>else <Enter>state_n = state_c;<Enter>end<Enter>default:begin<Enter>state_n = IDLE;<Enter>end<Enter>endcase<Enter>end<Enter>//转移条件<Enter>assign idle_s1 = (state_c == IDLE) && ();<Enter>assign s1_s2 = (state_c == S1) && ();<Enter>assign s2_s3 = (state_c == S2) && ();<Enter>//(寄存器输出)<Enter>always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)begin<Enter>out1 <= 1'b0;endelse if(state_c == S1)beginout1 <= 1'b1;<Enter>end<Enter>else begin<Enter>out1 <= 1'b0;<Enter>end<Enter>end
:ab Jsq    reg [3:0] cnt;<Enter>wire en;<Enter>wire co;<Enter>always@(posedge clk or negedge rst_n)begin<Enter>if(!rst_n)begin<Enter>cnt <= 0;<Enter>end<Enter>else if(en)begin<Enter>if(co)<Enter>cnt <= 0;<Enter>else<Enter>cnt <= cnt + 1;<Enter>end<Enter>end<Enter>assign en = ;       <Enter>assign co = (en) && (cnt ==); 

二、Verilog程序

1、顶层模块

顶层模块尽量减少逻辑描述,只实现子模块之间的连接
计数模块实现间隔为1s的六十进制计数器
显示模块完成数码管的驱动,可作为基本模块使用

/***************模六十计数器顶层模块***************/
module Mo60(
    clk,
    rst_n,
    smg_sig,
    smg_loc
    );

    //输入输出
    input                clk;
    input                rst_n;
    output     [7:0]     smg_sig;
    output     [5:0]     smg_loc;
    wire       [7:0]     smg_sig;
    wire       [5:0]     smg_loc;
    //中间信号
    wire       [7:0]     cnt_val;
    wire       [23:0]    data;

    /***************计数模块***************/
    Count U_count(
        .clk(clk),
        .rst_n(rst_n),
        .cnt_val(cnt_val)
    );
    assign  data = {16'b0, cnt_val};
    /***************显示模块***************/
    Display U_display(
        .clk(clk),
        .rst_n(rst_n),
        .data(data),
        .smg_sig(smg_sig),
        .smg_loc(smg_loc)
    );

endmodule

2、计数模块

计数器模板额外包括了使能与进位信号,对应于加一条件与结束条件,虽然代码量上升,但思路更加清晰且不容易出错
进位信号需要在使能的条件下输出

/***************计数模块***************/
module Count(
    clk,
    rst_n,
    cnt_val
    );

    //参数定义
    parameter  CNT_1S = 26'd49_999_999;
    parameter  CNT_1US = 26'd49;
    //输入输出
    input                clk;
    input                rst_n;
    output     [7:0]     cnt_val;
    wire       [7:0]     cnt_val;
    
    /***************分频计数器***************/
    reg [25:0] cnt_div;
    wire en_div;
    wire co_div;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_div <= 0;
        end
        else if(en_div)begin
            if(co_div)
                cnt_div <= 0;
            else
                cnt_div <= cnt_div + 1;
        end
    end
    assign en_div = 1;       
    assign co_div = (en_div) && (cnt_div == CNT_1S);   
    /***************个位计数器***************/
    reg [3:0] cnt0;
    wire en0;
    wire co0;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt0 <= 0;
        end
        else if(en0)begin
            if(co0)
                cnt0 <= 0;
            else
                cnt0 <= cnt0 + 1;
        end
    end
    assign en0 = co_div;     
    assign co0 = (en0) && (cnt0 == 9);   
    /***************十位计数器***************/
    reg [3:0] cnt1;
    wire en1;
    wire co1;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt1 <= 0;
        end
        else if(en1)begin
            if(co1)
                cnt1 <= 0;
            else
                cnt1 <= cnt1 + 1;
        end
    end
    assign en1 = co0;       
    assign co1 = (en1) && (cnt1 == 5);   
    /***************输出计数***************/
    assign cnt_val = {cnt1, cnt0};

endmodule

3、显示模块

和之前一样,分频、扫描、译码、显示
在一个always中只对一个信号进行赋值

/***************显示模块***************/
module Display(
    clk,
    rst_n,
    data,
    smg_sig,
    smg_loc
    );

    //参数定义
    parameter  CNT_2MS = 17'd99_999;
    parameter  CNT_200NS = 17'd9;
    //输入输出
    input                clk;
    input                rst_n;
    input      [23:0]    data;
    output     [7:0]     smg_sig;
    output     [5:0]     smg_loc;
    reg        [7:0]     smg_sig;
    reg        [5:0]     smg_loc;
    
    /***************分频***************/
    reg [16:0] cnt_div;
    wire en_div;
    wire co_div;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_div <= 0;
        end
        else if(en_div)begin
            if(co_div)
                cnt_div <= 0;
            else
                cnt_div <= cnt_div + 1;
        end
    end
    assign en_div = 1;       
    assign co_div = (en_div) && (cnt_div == CNT_2MS);   
    /***************扫描***************/
    reg [3:0] cnt_scan;
    wire en_scan;
    wire co_scan;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            cnt_scan <= 0;
        end
        else if(en_scan)begin
            if(co_scan)
                cnt_scan <= 0;
            else
                cnt_scan <= cnt_scan + 1;
        end
    end
    assign en_scan = co_div;       
    assign co_scan = (en_scan) && (cnt_scan == 5);
    /***************取数***************/
    reg [3:0] smg_data;
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            smg_data <= 0;
        end
        else begin
            case(cnt_scan)
                0: smg_data <= data[3:0];
                1: smg_data <= data[7:4];
                2: smg_data <= data[11:8];
                3: smg_data <= data[15:12];
                4: smg_data <= data[19:16];
                5: smg_data <= data[23:20];
            endcase
        end
    end
    /***************显示***************/
    always@(posedge clk or negedge rst_n)begin
        if(!rst_n)begin
            smg_loc <= 6'b000000;
        end
        else begin
            case(cnt_scan)
                0: smg_loc <= 6'b111110;
                1: smg_loc <= 6'b111101;
                2: smg_loc <= 6'b111011;
                3: smg_loc <= 6'b110111;
                4: smg_loc <= 6'b101111;
                5: smg_loc <= 6'b011111;
            endcase
        end
    end
    /***************译码***************/
    always@(*)begin
        case(smg_data)
            0: smg_sig = 8'b00000011;
		    1: smg_sig = 8'b10011111;
		    2: smg_sig = 8'b00100101;
		    3: smg_sig = 8'b00001101;
		    4: smg_sig = 8'b10011001;
		    5: smg_sig = 8'b01001001;
		    6: smg_sig = 8'b01000001;
		    7: smg_sig = 8'b00011111;
		    8: smg_sig = 8'b00000001;
		    9: smg_sig = 8'b00001001;
		    default: smg_sig = 8'b01100001;//E
        endcase
    end

endmodule

三、Testbench程序

对Quartus生成的模板文件进行修改

`timescale 1 ns/ 1 ns
module Mo60_tb();

reg clk;
reg rst_n;
// wires                                               
wire [5:0]  smg_loc;
wire [7:0]  smg_sig;

// assign statements (if any)                          
Mo60 u1 (
// port map - connection between master ports and signals/registers   
	.clk(clk),
	.rst_n(rst_n),
	.smg_loc(smg_loc),
	.smg_sig(smg_sig)
);
initial begin
    clk = 0;
    rst_n = 1;
end

always begin
    #10 clk = ~clk;
end

initial begin
    #100 rst_n = 0;
    #100 rst_n = 1;
end

endmodule

四、仿真波形

在仿真时,将计数间隔设为CNT_1US,扫描间隔设为CNT_200NS,以加快仿真速度
模六十计数器(三)_第1张图片

五、实测结果

与之前不同,AX530开发板上有6个数码管
模六十计数器(三)_第2张图片


总结

使用模板可以提高编程速度,使逻辑更加清晰,特别是解决了计数器逻辑混乱的问题。

你可能感兴趣的:(Verilog,fpga开发,veriolg,模六十计数器)