资讯详情

基于Basys2的分秒计时器的设计

一、设计指标(都是坤坤指定的,我直接贴)

二、计时器原理:

三、Verilog实现

十进制计数器:

六进制计数器:

三、六十进制计数器:

4、计时器:

1Hz-toc" style="margin-left:40px;">6.时钟分频模块:50MHz->1Hz

7.数字管动态扫描模块:

8、BCD码译码模块:

显示模块:-toc" style="margin-left:40px;">9、LED显示模块:

10、顶层模块:

四、FPGA实现

1.管脚约束

2、实验效果


一、设计指标(同样的都是鲲鲲指定的,我直接贴过来)

在选择Basys 2/3型开发板,使用Verilog语言描述,计时器的设计,功能要求如下:

  1. 用Verilog语言描述,功能电路设计;
  2. 用数字管做计时器,四个数字管
  3. 开始计时和复位拨码开关(无约束)
  4. 两种工作模式
    1. 可从0开始计时,从00:00开始计时。
    2. 也可以自己设置倒数计时,比如从05:00到00:00的倒数计时。
  5. 假设输入晶振50MHz;
  6. 完成计时器的设计、前仿和后仿。

分(十位)

分(个位)

秒(十位)

秒(个位)

二、计时器原理:

笔者在网上找到了现有的方案,认为60进制计数器是由六进制计数器和十进制计数器建造的,然后两个60进制计数器在1Hz时钟下连接称为分秒计时器的思路比较清晰,所以作者的设计是按照这个思路来的。

系统框图如下:

具体来说,首先构建十进制计数器和六进制计数器,然后将十进制计数器作为六进制计数器的个位,六进制计数器作为十进制计数器。每个60进制计数器都有使能端和复位端。控制秒的60进制计数器的进位信号连接到控制分的60进制计数器的使能端。每个60进制计数器中的10进制计数器和6进制计数器输出的数字为4位BCD代码,这样我们就可以用我们之前解释的通用数字管显示模块显示,高两位显示0~59,低两位为秒显示0~59;

三、Verilog实现

十进制计数器:

常用的计数控制

module counter_10(     input clk,     input rst_n,     input en,//使能     output reg [3:0]dout,     output co//进位     );     //输出BCD码     always@(posedge clk or negedge rst_n)     begin         if(!rst_n)             dout <= 4'd0;         else if(en)         begin             if(dout == 4'd9)                 dout <= 4'd0;             else                 dout <= dout   4'd1;         end         else             dout <= dout;     end     //当dout = 1001时产生进位     assign co = dout[0] & dout[3]; endmodule 

六进制计数器:

同十进制计数器的思路

module counter_6(     input clk,     input rst_n,     input en,//使能     output reg [3:0]dout,     output co//进位     );     //输出BCD码     always@(posedge clk or negedge rst_n)     begin         if(!rst_n)             dout <= 4'd0;         else if(en)         begin             if(dout == 4'd5)                 dout <= 4'd0;             ele
                dout <= dout + 4'd1;
        end
        else
            dout <= dout;
    end
    //当dout = 0101时产生进位
    assign co = dout[0] & dout[2];
endmodule

3、六十进制计数器:

例化十进制计数器和六进制计数器,其中的进位控制逻辑需要主义

module counter_60(
    input clk,
    input rst_n,
    input en,//使能
    output [7:0]dout,
    output co//进位
    );
    //用一个十进制计数器和一个六进制计数器来构成60进制计数器
    //声明内部信号线
    wire co_10_1;//模10计数器的进位输出信号
    wire co_10;//模6计数器的选通信号
    wire co_6;//模6计数器的进位输出信号
    wire [3:0]dout_10,dout_6;
    //模块实例化
    //个位模十
    counter_10 c_10(
        .clk(clk),
        .rst_n(rst_n),
        .en(en),
        .dout(dout_10),
        .co(co_10_1));
    //十位模六
    counter_6 c_6(
        .clk(clk),
        .rst_n(rst_n),
        .en(co_10),
        .dout(dout_6),
        .co(co_6));
    //产生进位信号与八位输出
    assign co_10 = co_10_1 & en;
    assign co = co_10 & co_6;
    assign dout = {dout_6,dout_10};
endmodule

4、计时器:

在计时器中例化两个六十进制计数器

module Timer(
    input clk,
    input rst_n,
    input en,
    output [7:0]min_out,
    output [7:0]sec_out
    );
    //用两个模60计数器作为分、秒的信号
    //声明内部信号线
    wire co_sec_1,co_sec;
    //模块实例化
    counter_60 c_60_sec(
        .clk(clk),
        .rst_n(rst_n),
        .en(en),
        .dout(sec_out),
        .co(co_sec_1));
    counter_60 c_60_min(
        .clk(clk),
        .rst_n(rst_n),
        .en(co_sec),
        .dout(min_out));
    //产生进位
    assign co_sec = co_sec_1 & en;

endmodule

5、时钟分频:50MHz->1KHz

将板子50MHz时钟分频称为1KHz时钟,用于数码管动态扫描

module clk_divider_1KHz(
    input clk,
    input rst_n,
    output reg clk_div
    );
    //输入板子50MHz时钟,输出1KHz时钟
    //计数分频:50000次
    reg [15:0]cnt = 16'd0;
    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            cnt <= 16'd0;
        end
        else if(cnt == 16'd50000)
        begin
            cnt <= 16'd0;
        end
        else
        begin
            cnt <= cnt + 16'd1;
        end
    end
    //输出时钟控制
    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            clk_div <= 1'b0;
        end
        else if(cnt <= 16'd24999)
        begin
            clk_div <= 1'b1;
        end
        else
        begin
            clk_div <= 1'b0;
        end
    end
endmodule

6、时钟分频模块:50MHz->1Hz

将板子50MHz时钟分频为1Hz时钟,用于计时器计数

module clk_divider_1Hz(
    input clk,
    input rst_n,
    output reg clk_div
    );
    //输入板子50MHz时钟,输出1KHz时钟
    //计数分频:50000次
    reg [25:0]cnt = 26'd0;
    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            cnt <= 26'd0;
        end
        else if(cnt == 26'd50_000_000)
        begin
            cnt <= 26'd0;
        end
        else
        begin
            cnt <= cnt + 26'd1;
        end
    end
    //输出时钟控制
    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
        begin
            clk_div <= 1'b0;
        end
        else if(cnt <= 26'd24_999_999)
        begin
            clk_div <= 1'b1;
        end
        else
        begin
            clk_div <= 1'b0;
        end
    end
endmodule

7、数码管动态扫描模块:

输入1KHz时钟进行动态扫描,通过扫描计数器的状态选择相应的位并输出相应的段选码

module Display(
    input clk_div,
    input rst_n,
    input [7:0]Out_number_1,
    input [7:0]Out_number_2,
    input [7:0]Out_number_3,
    input [7:0]Out_number_4,
    output reg [7:0]duan_code,
    output reg [3:0]wei_code
    );
    //将输入的十六进制代码转换为共阳极数码管段选码动态扫描输出
    reg [2:0]sel_cnt;//扫描计数器
    //动态扫描
    //扫描计数器控制位选
    always@(posedge clk_div or negedge rst_n)
    begin
        if(!rst_n)
        begin
            sel_cnt <= 3'd0; 
        end
        else if(sel_cnt == 3'd4)
        begin
            sel_cnt <= 3'd0;
        end
        else
        begin
            sel_cnt <= sel_cnt + 3'd1;
        end
    end
    //位选与段选对应
    always@(posedge clk_div or negedge rst_n)
    begin
        if(!rst_n)
        begin
            wei_code <= 4'b0000;
            duan_code <= 8'hff;
        end
        else
        begin
            case(sel_cnt)
                3'd0:
                begin
                    wei_code <= 4'b0001;
                    duan_code <= Out_number_1;
                end
                3'd1:
                begin
                    wei_code <= 4'b0010;
                    duan_code <= Out_number_2;
                end
                3'd2:
                begin
                    wei_code <= 4'b0100;
                    duan_code <= Out_number_3;
                end
                3'd3:
                begin
                    wei_code <= 4'b1000;
                    duan_code <= Out_number_4;
                end
                default:
                begin
                    wei_code <= 4'b0000;
                    duan_code <= 8'hff;
                end
            endcase
        end
    end

endmodule

8、BCD码译码模块:

将计数器输出的BCD码转化为共阳极数码管的段选码,用于动态扫描显示

module wei_encoder(
   input [3:0]hex_number,
    output reg [7:0]display_code
    );
    //将输入的十六进制代码转换为共阳极数码管段选编码并输出
    always@(*)
    begin
        case(hex_number)
            4'b0000:display_code = 8'hc0;//0
            4'b0001:display_code = 8'hf9;//1
            4'b0010:display_code = 8'ha4;//2
            4'b0011:display_code = 8'hb0;//3
            4'b0100:display_code = 8'h99;//4
            4'b0101:display_code = 8'h92;//5
            4'b0110:display_code = 8'h82;//6
            4'b0111:display_code = 8'hf8;//7
            4'b1000:display_code = 8'h80;//8
            4'b1001:display_code = 8'h90;//9
            4'b1010:display_code = 8'h88;//A
            4'b1011:display_code = 8'h83;//B
            4'b1100:display_code = 8'hc6;//C
            4'b1101:display_code = 8'ha1;//D
            4'b1110:display_code = 8'h86;//E
            4'b1111:display_code = 8'h8e;//F
            default:display_code = 8'hff;//无
        endcase
    end
endmodule

9、LED显示模块:

突发奇想想用8个LED实现一个流水灯,计时一秒灯位移一次

module led_light(
    input clk,//1Hz时钟
    input rst_n,
    output reg [7:0]led
    );
    //初始化
    initial
    begin
        led = 8'b0000_0001;
    end
    //循环位移
    always@(posedge clk or negedge rst_n)
    begin
        if(!rst_n)
            led <= 8'h00;
        else
        begin
            led[7:0] <= {led[6:0],led[7]};
        end
    end
endmodule

10、顶层模块:

module top(
    input clk,
    input rst_n,
    input en,
    output [3:0]wei_code,
    output [7:0]duan_code,
    output [7:0]led_display
    );
    //声明内部信号
    wire [7:0]sec_out;//八位BCD数:秒
    wire [7:0]min_out;//八位BCD数:分
    wire clk_div_1000;//系统50MHz时钟->1KHz
    wire clk_div_1;//系统50MHz时钟->1Hz
    wire [7:0]output_number_1;//数码管右一段选码
    wire [7:0]output_number_2;//数码管右二段选码
    wire [7:0]output_number_3;//数码管右三段选码
    wire [7:0]output_number_4;//数码管右四段选码
    
    //模块实例化
    //时钟分频,用于数码管扫描
    clk_divider_1KHz div_1(
        .clk(clk),
        .rst_n(rst_n),
        .clk_div(clk_div_1000)
    );
    //时钟分频,用于计数器计数
    clk_divider_1Hz div_2(
        .clk(clk),
        .rst_n(rst_n),
        .clk_div(clk_div_1)
    );
    //计时器:用于产生分、秒的压缩BCD码用于数码管扫描输出
    Timer timer(
        .clk(clk_div_1),
        .rst_n(rst_n),
        .en(en),
        .min_out(min_out),
        .sec_out(sec_out)
    );
    //将二进制数转换位段选码,用于数码管扫描输出
    wei_encoder encoder_1(
        .hex_number(sec_out[3:0]),
        .display_code(output_number_1)
    );
    wei_encoder encoder_2(
        .hex_number(sec_out[7:4]),
        .display_code(output_number_2)
    );
    wei_encoder encoder_3(
        .hex_number(min_out[3:0]),
        .display_code(output_number_3)
    );
    wei_encoder encoder_4(
        .hex_number(min_out[7:4]),
        .display_code(output_number_4)
    );
    //数码管动态扫描模块,将段选码输出
    Display display(
        .clk_div(clk_div_1000),
        .rst_n(rst_n),
        .Out_number_1(output_number_1),
        .Out_number_2(output_number_2),
        .Out_number_3(output_number_3),
        .Out_number_4(output_number_4),
        .duan_code(duan_code),
        .wei_code(wei_code)
    );
    //led流水灯,每一秒移动一次
    led_light led(
        .clk(clk_div_1),//1Hz时钟
        .rst_n(rst_n),
        .led(led_display)
    );
endmodule

四、FPGA实现

1.管脚约束

根据开发板手册绑定管脚,管脚约束如下:

NET "led_display[7]" LOC = G1;
NET "led_display[6]" LOC = P4;
NET "led_display[5]" LOC = N4;
NET "led_display[4]" LOC = N5;
NET "led_display[3]" LOC = P6;
NET "led_display[2]" LOC = P7;
NET "led_display[1]" LOC = M11;
NET "led_display[0]" LOC = M5;
NET "wei_code[0]" LOC = F12;
NET "wei_code[1]" LOC = J12;
NET "wei_code[2]" LOC = M13;
NET "wei_code[3]" LOC = K14;
NET "duan_code[7]" LOC = N13;
NET "duan_code[6]" LOC = M12;
NET "duan_code[5]" LOC = L13;
NET "duan_code[4]" LOC = P12;
NET "duan_code[3]" LOC = N11;
NET "duan_code[2]" LOC = N14;
NET "duan_code[1]" LOC = H12;
NET "duan_code[0]" LOC = L14;
NET "clk" LOC = B8;
NET "en" LOC = P11;
NET "rst_n" LOC = N3;

2、实验效果

见视频(后续上传)

FPGA计时器

标签: 用于m12连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台