【FPGA】数码管电子时钟(可设置时间和闹钟)

这篇具有很好参考价值的文章主要介绍了【FPGA】数码管电子时钟(可设置时间和闹钟)。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

本次实验内容承接上一篇文章数码管电子时钟,在此基础上新增两个功能:
1.设置时间
2.设置闹钟,到点响铃

一丶需求分析

模块:beep counter seg_driver top
其中:
1.设置时间
2.设置闹钟,到点响铃

这两个功能都整合在counter模块,里面设置的重要信号如下所示
【FPGA】数码管电子时钟(可设置时间和闹钟)

1.设置时间

我们需要利用开发板上的按键来设置时分秒HH:MM:SS

思路:
Counter:
rst_n:复位按键 【相当于开发板上的key1】
Key[0]:空闲状态—电子时钟 【相当于开发板上的key1】
Key[1]:设置时间 【相当于开发板上的key2】
Key[2]:设置闹钟 【相当于开发板上的key3】

按键切换三个状态:

1.空闲状态—就是一个时钟
输出dout_time给seg_driver模块显示时间

2.设置时间—设置当前的时分秒,改一下几个计时器里面的初值
修改counter里面的6个计时器的值,暂停计时
Key[0]:切换修改的时间位,切换到哪一位,哪一位闪烁 【相当于开发板上的key2】
Key[1]:加1 【相当于开发板上的key3】
Key[2]:确定–退出 【相当于开发板上的key4】

3.设置闹钟—设置个条件,到几时几分几秒蜂鸣器响
修改counter里面的6个计时器的值,暂停计时
Key[0]:切换修改的时间位,切换到哪一位,哪一位闪烁 【相当于开发板上的key2】
Key[1]:加1 【相当于开发板上的key3】
Key[2]:确定–退出(确定之后输出dout_time给beep模块作为响铃时间) 【相当于开发板上的key4】

2.设置闹钟

方式与设置时间基本完全一样,区别在设置闹钟的时间不给电子时钟,电子时钟保持设置的时间计时

二丶工程源码

1.counter

module counter (
    input  wire         clk             ,
    input  wire         rst_n           ,
    input  wire [2:0]   key             ,
    output reg  [19:0]  dout_time       ,  //输出时间 HH:MM:SS
    output wire         beep_r  
);
//计数器
reg  [25:0]    cnt    ;
wire           add_cnt;
wire           end_cnt; 
//S计时器

//个位 (0~9)
reg  [3:0]      cnt_s_bit;
wire            add_cnt_s_bit;
wire            end_cnt_s_bit;

reg  [3:0]      set_cnt_s_bit;
wire            add_set_cnt_s_bit;
wire            end_set_cnt_s_bit;

reg  [3:0]      clock_cnt_s_bit;
wire            add_clock_cnt_s_bit;
wire            end_clock_cnt_s_bit;
//十位 (0~5)
reg  [2:0]      cnt_s_ten;
wire            add_cnt_s_ten;
wire            end_cnt_s_ten;

reg  [2:0]      set_cnt_s_ten;
wire            add_set_cnt_s_ten;
wire            end_set_cnt_s_ten;

reg  [2:0]      clock_cnt_s_ten;
wire            add_clock_cnt_s_ten;
wire            end_clock_cnt_s_ten;


//M计时器

//个位 (0~9)
reg  [3:0]      cnt_m_bit;
wire            add_cnt_m_bit;
wire            end_cnt_m_bit;

reg  [3:0]      set_cnt_m_bit;
wire            add_set_cnt_m_bit;
wire            end_set_cnt_m_bit;

reg  [3:0]      clock_cnt_m_bit;
wire            add_clock_cnt_m_bit;
wire            end_clock_cnt_m_bit;
//十位 (0~5)
reg  [2:0]      cnt_m_ten;
wire            add_cnt_m_ten;
wire            end_cnt_m_ten;

reg  [2:0]      set_cnt_m_ten;
wire            add_set_cnt_m_ten;
wire            end_set_cnt_m_ten;

reg  [2:0]      clock_cnt_m_ten;
wire            add_clock_cnt_m_ten;
wire            end_clock_cnt_m_ten;

//H计时器

//个位 (0~9)
reg  [3:0]      cnt_h_bit;
wire            add_cnt_h_bit;
wire            end_cnt_h_bit;

reg  [3:0]      set_cnt_h_bit;
wire            add_set_cnt_h_bit;
wire            end_set_cnt_h_bit;

reg  [3:0]      clock_cnt_h_bit;
wire            add_clock_cnt_h_bit;
wire            end_clock_cnt_h_bit;
//十位 (0~2)
reg  [1:0]      cnt_h_ten;
wire            add_cnt_h_ten;
wire            end_cnt_h_ten;

reg  [1:0]      set_cnt_h_ten;
wire            add_set_cnt_h_ten;
wire            end_set_cnt_h_ten;

reg  [1:0]      clock_cnt_h_ten;
wire            add_clock_cnt_h_ten;
wire            end_clock_cnt_h_ten;

reg [3:0]       cnt_flag;
reg [3:0]       set_cnt_flag;
reg [3:0]       clock_cnt_flag;
reg [2:0]       state_c;  //现态
reg [2:0]       state_n;  //次态
reg [5:0]       select_seg;  //在设置时间和设置闹钟的时候切换位选
wire [19:0]     set_time_dout;
wire [19:0]     idel_dout;
wire [19:0]     clock_dout;

parameter   MAX_CNT=26'd50_000_000;
//定义状态
localparam      IDEL     =3'b001,  //空闲状态
                SET_TIME =3'b010,  //设置时间
                SET_CLOCK=3'b100;  //设置闹钟
//状态转移条件
wire            idel_TO_set_time;
wire            idel_TO_set_clock;
wire            set_time_TO_idel;
wire            set_clock_TO_idel;

//状态机第一段--状态转移
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        state_c<=IDEL;
    end
    else
        state_c<=state_n;
end

//状态机第二段--组合逻辑
always @(*) begin
    case (state_c)
        IDEL: begin
            if (idel_TO_set_time) begin
                state_n=SET_TIME;
            end
            else if(idel_TO_set_clock) begin
                state_n=SET_CLOCK;
            end
            else
                state_n=state_c;
        end
        SET_TIME: begin
            if (set_time_TO_idel) begin
                state_n=IDEL;
            end
            else
                state_n=state_c;
        end
        SET_CLOCK: begin
            if (set_clock_TO_idel) begin
                state_n=IDEL;
            end
            else
                state_n=state_c;
        end
        default :state_n=IDEL;
            
    endcase
end
assign idel_TO_set_time=state_c==IDEL&&key[0];
assign idel_TO_set_clock=state_c==IDEL&&key[1];
assign set_time_TO_idel=state_c==SET_TIME&&key[2];
assign set_clock_TO_idel=state_c==SET_CLOCK&&key[2];

//select_seg
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        select_seg<=6'b000_000;
    end
    else if(idel_TO_set_time||idel_TO_set_clock) begin
        select_seg<=6'b000_001;
    end
    else if((state_c==SET_TIME||state_c==SET_CLOCK)&&(key[0])) begin
        select_seg<={select_seg[4:0],select_seg[5]};
    end
end
//clock_cnt_s_bit   clock_cnt_s_ten   clock_cnt_m_bit   clock_cnt_m_ten   clock_cnt_h_bit   clock_cnt_h_ten

//秒计数器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clock_cnt_s_bit<=0;
    end
    else if (add_clock_cnt_s_bit) begin
        if (end_clock_cnt_s_bit) begin
            clock_cnt_s_bit<=0;
        end
        else
            clock_cnt_s_bit<=clock_cnt_s_bit+1;
    end

end

assign add_clock_cnt_s_bit=state_c==SET_CLOCK&&select_seg==6'b000_001&&key[1];
assign end_clock_cnt_s_bit=add_clock_cnt_s_bit&&clock_cnt_s_bit==9||idel_TO_set_clock;

//秒计数器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clock_cnt_s_ten<=0;
    end
    else if (add_clock_cnt_s_ten) begin
        if (end_clock_cnt_s_ten) begin
            clock_cnt_s_ten<=0;
        end
        else
            clock_cnt_s_ten<=clock_cnt_s_ten+1;
    end

end

assign add_clock_cnt_s_ten=state_c==SET_CLOCK&&select_seg==6'b000_010&&key[1];
assign end_clock_cnt_s_ten=add_clock_cnt_s_ten&&clock_cnt_s_ten==5||idel_TO_set_clock;

//分计数器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clock_cnt_m_bit<=0;
    end
    else if (add_clock_cnt_m_bit) begin
        if (end_clock_cnt_m_bit) begin
            clock_cnt_m_bit<=0;
        end
        else
            clock_cnt_m_bit<=clock_cnt_m_bit+1;
    end

end

assign add_clock_cnt_m_bit=state_c==SET_CLOCK&&select_seg==6'b000_100&&key[1];
assign end_clock_cnt_m_bit=add_clock_cnt_m_bit&&clock_cnt_m_bit==9||idel_TO_set_clock;

//分计数器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clock_cnt_m_ten<=0;
    end
    else if (add_clock_cnt_m_ten) begin
        if (end_clock_cnt_m_ten) begin
            clock_cnt_m_ten<=0;
        end
        else
            clock_cnt_m_ten<=clock_cnt_m_ten+1;
    end

end

assign add_clock_cnt_m_ten=state_c==SET_CLOCK&&select_seg==6'b001_000&&key[1];
assign end_clock_cnt_m_ten=add_clock_cnt_m_ten&&clock_cnt_m_ten==5||idel_TO_set_clock;

//时计数器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clock_cnt_h_bit<=0;
    end
    else if (add_clock_cnt_h_bit) begin
        if (end_clock_cnt_h_bit) begin
            clock_cnt_h_bit<=0;
        end
        else
            clock_cnt_h_bit<=clock_cnt_h_bit+1;
    end

end

assign add_clock_cnt_h_bit=state_c==SET_CLOCK&&select_seg==6'b010_000&&key[1];
assign end_clock_cnt_h_bit=add_clock_cnt_h_bit&&clock_cnt_h_bit==clock_cnt_flag||idel_TO_set_clock;


//时计数器---十位(0~2)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        clock_cnt_h_ten<=0;
    end
    else if (add_clock_cnt_h_ten) begin
        if (end_clock_cnt_h_ten) begin
            clock_cnt_h_ten<=0;
        end
        else
            clock_cnt_h_ten<=clock_cnt_h_ten+1;
    end

end

assign add_clock_cnt_h_ten=state_c==SET_CLOCK&&select_seg==6'b100_000&&key[1];
assign end_clock_cnt_h_ten=add_clock_cnt_h_ten&&clock_cnt_h_ten==2||idel_TO_set_clock;

//判断小时计时器十位是否记到 2
always @(*) begin
    if (clock_cnt_h_ten==2) begin
        clock_cnt_flag=4'd3;
    end
    else
        clock_cnt_flag=4'd9;
end

assign clock_dout={clock_cnt_h_ten,clock_cnt_h_bit,clock_cnt_m_ten,clock_cnt_m_bit,clock_cnt_s_ten,clock_cnt_s_bit};

///
///


//set_cnt_s_bit   set_cnt_s_ten   set_cnt_m_bit   set_cnt_m_ten   set_cnt_h_bit   set_cnt_h_ten

//秒计数器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        set_cnt_s_bit<=0;
    end
    else if (add_set_cnt_s_bit) begin
        if (end_set_cnt_s_bit) begin
            set_cnt_s_bit<=0;
        end
        else
            set_cnt_s_bit<=set_cnt_s_bit+1;
    end

end

assign add_set_cnt_s_bit=state_c==SET_TIME&&select_seg==6'b000_001&&key[1];
assign end_set_cnt_s_bit=add_set_cnt_s_bit&&set_cnt_s_bit==9||idel_TO_set_time;

//秒计数器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        set_cnt_s_ten<=0;
    end
    else if (add_set_cnt_s_ten) begin
        if (end_set_cnt_s_ten) begin
            set_cnt_s_ten<=0;
        end
        else
            set_cnt_s_ten<=set_cnt_s_ten+1;
    end

end

assign add_set_cnt_s_ten=state_c==SET_TIME&&select_seg==6'b000_010&&key[1];
assign end_set_cnt_s_ten=add_set_cnt_s_ten&&set_cnt_s_ten==5||idel_TO_set_time;

//分计数器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        set_cnt_m_bit<=0;
    end
    else if (add_set_cnt_m_bit) begin
        if (end_set_cnt_m_bit) begin
            set_cnt_m_bit<=0;
        end
        else
            set_cnt_m_bit<=set_cnt_m_bit+1;
    end

end

assign add_set_cnt_m_bit=state_c==SET_TIME&&select_seg==6'b000_100&&key[1];
assign end_set_cnt_m_bit=add_set_cnt_m_bit&&set_cnt_m_bit==9||idel_TO_set_time;

//分计数器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        set_cnt_m_ten<=0;
    end
    else if (add_set_cnt_m_ten) begin
        if (end_set_cnt_m_ten) begin
            set_cnt_m_ten<=0;
        end
        else
            set_cnt_m_ten<=set_cnt_m_ten+1;
    end

end

assign add_set_cnt_m_ten=state_c==SET_TIME&&select_seg==6'b001_000&&key[1];
assign end_set_cnt_m_ten=add_set_cnt_m_ten&&set_cnt_m_ten==5||idel_TO_set_time;

//时计数器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        set_cnt_h_bit<=0;
    end
    else if (add_set_cnt_h_bit) begin
        if (end_set_cnt_h_bit) begin
            set_cnt_h_bit<=0;
        end
        else
            set_cnt_h_bit<=set_cnt_h_bit+1;
    end

end

assign add_set_cnt_h_bit=state_c==SET_TIME&&select_seg==6'b010_000&&key[1];
assign end_set_cnt_h_bit=add_set_cnt_h_bit&&set_cnt_h_bit==set_cnt_flag||idel_TO_set_time;


//时计数器---十位(0~2)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        set_cnt_h_ten<=0;
    end
    else if (add_set_cnt_h_ten) begin
        if (end_set_cnt_h_ten) begin
            set_cnt_h_ten<=0;
        end
        else
            set_cnt_h_ten<=set_cnt_h_ten+1;
    end

end

assign add_set_cnt_h_ten=state_c==SET_TIME&&select_seg==6'b100_000&&key[1];
assign end_set_cnt_h_ten=add_set_cnt_h_ten&&set_cnt_h_ten==2||idel_TO_set_time;

//判断小时计时器十位是否记到 2
always @(*) begin
    if (set_cnt_h_ten==2) begin
        set_cnt_flag=4'd3;
    end
    else
        set_cnt_flag=4'd9;
end

assign set_time_dout={set_cnt_h_ten,set_cnt_h_bit,set_cnt_m_ten,set_cnt_m_bit,set_cnt_s_ten,set_cnt_s_bit};
///
///

//计数器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt<=0;
    end
    else if (add_cnt) begin
        if (end_cnt) begin
            cnt<=0;
        end
        else
            cnt<=cnt+1;
    end
end

assign add_cnt=state_c==IDEL||state_c==SET_CLOCK;    
assign end_cnt=add_cnt&&(cnt==MAX_CNT-1||set_time_TO_idel);

//秒计时器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_s_bit<=1;
    end
    else if(set_time_TO_idel) begin
        cnt_s_bit<=set_cnt_s_bit;           //在设置时间确定之后将设置的值赋给计时器
    end
    else if (add_cnt_s_bit) begin
        if (end_cnt_s_bit) begin
            cnt_s_bit<=0;
        end
        else
            cnt_s_bit<=cnt_s_bit+1;
    end

end

assign add_cnt_s_bit=end_cnt;
assign end_cnt_s_bit=add_cnt_s_bit&&cnt_s_bit==9;

//秒计时器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_s_ten<=0;
    end
    else if(set_time_TO_idel) begin
        cnt_s_ten<=set_cnt_s_ten;
    end
    else if (add_cnt_s_ten) begin
        if (end_cnt_s_ten) begin
            cnt_s_ten<=0;
        end
        else
            cnt_s_ten<=cnt_s_ten+1;
    end

end

assign add_cnt_s_ten=end_cnt_s_bit;
assign end_cnt_s_ten=add_cnt_s_ten&&cnt_s_ten==5;

//分计时器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_m_bit<=0;
    end
    else if(set_time_TO_idel) begin
        cnt_m_bit<=set_cnt_m_bit;
    end
    else if (add_cnt_m_bit) begin
        if (end_cnt_m_bit) begin
            cnt_m_bit<=0;
        end
        else
            cnt_m_bit<=cnt_m_bit+1;
    end

end

assign add_cnt_m_bit=end_cnt_s_ten;
assign end_cnt_m_bit=add_cnt_m_bit&&cnt_m_bit==9;

//分计时器---十位(0~5)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_m_ten<=0;
    end
    else if(set_time_TO_idel) begin
        cnt_m_ten<=set_cnt_m_ten;
    end
    else if (add_cnt_m_ten) begin
        if (end_cnt_m_ten) begin
            cnt_m_ten<=0;
        end
        else
            cnt_m_ten<=cnt_m_ten+1;
    end

end

assign add_cnt_m_ten=end_cnt_m_bit;
assign end_cnt_m_ten=add_cnt_m_ten&&cnt_m_ten==5;

//时计时器---个位(0~9)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_h_bit<=0;
    end
    else if(set_time_TO_idel) begin
        cnt_h_bit<=set_cnt_h_bit;
    end
    else if (add_cnt_h_bit) begin
        if (end_cnt_h_bit) begin
            cnt_h_bit<=0;
        end
        else
            cnt_h_bit<=cnt_h_bit+1;
    end

end

assign add_cnt_h_bit=end_cnt_m_ten;
assign end_cnt_h_bit=add_cnt_h_bit&&cnt_h_bit==cnt_flag;


//时计时器---十位(0~2)
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt_h_ten<=0;
    end
    else if(set_time_TO_idel) begin
        cnt_h_ten<=set_cnt_h_ten;
    end
    else if (add_cnt_h_ten) begin
        if (end_cnt_h_ten) begin
            cnt_h_ten<=0;
        end
        else
            cnt_h_ten<=cnt_h_ten+1;
    end

end

assign add_cnt_h_ten=end_cnt_h_bit;
assign end_cnt_h_ten=add_cnt_h_ten&&cnt_h_ten==2;

//判断小时计时器十位是否记到 2
always @(*) begin
    if (cnt_h_ten==2) begin
        cnt_flag=4'd3;
    end
    else
        cnt_flag=4'd9;
end

assign idel_dout={cnt_h_ten,cnt_h_bit,cnt_m_ten,cnt_m_bit,cnt_s_ten,cnt_s_bit};  //拼接成 HH:MM:SS
///
///

//dout_time输出
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        dout_time<=20'b0;
    end
    else begin
        case (state_c)
            IDEL:dout_time<=idel_dout;    //控制数码管显示对应状态的值
            SET_TIME:dout_time<=set_time_dout;
            SET_CLOCK:dout_time<=clock_dout;
            default :dout_time<=IDEL;        
        endcase
    end
end

assign beep_r=clock_dout==idel_dout;  //比较设置的闹钟与现在的时间,结果输出给beep模块,到点闹铃
endmodule //counter

2.seg_driver

module seg_driver (
    input  wire          clk,
    input  wire          rst_n,
    input  wire [19:0]   dout_time,
    output reg  [5:0]    sel,
    output reg  [7:0]    seg
);
reg [3:0]       seg_flag;
reg             dot;  //小数点  用来显示  HH.MM.SS  这样的格式

//10ms计时器---用来切换数码管位选,以达到轮流显示时间的各位(肉眼可以看到动态的时间计数)
reg [15:0]      cnt;
wire            add_cnt;
wire            end_cnt;

parameter       MAX_CNT =50_000    ,
                ZERO    =7'b100_0000,
                ONE     =7'b111_1001,
                TWO     =7'b010_0100,
                THREE   =7'b011_0000,
                FOUR    =7'b001_1001,
                FIVE    =7'b001_0010,
                SIX     =7'b000_0010,
                SEVEN   =7'b111_1000,
                EIGHT   =7'b000_0000,
                NINE    =7'b001_0000;



//计时器
always @(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        cnt<=0;
    end
    else if(add_cnt) begin
        if (end_cnt) begin
            cnt<=0;
        end
        else
            cnt<=cnt+1;
    end
end
assign add_cnt=1'b1;
assign end_cnt=add_cnt&&cnt==MAX_CNT-1;

//切换数码管位选
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        sel<=6'b111_110;
    end
    else if(cnt==MAX_CNT-1) begin
        sel<={sel[4:0],sel[5]};
    end
end  

//切换数码管段选
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        seg_flag<=0;
    end
    else begin
        case (sel)
            6'b111_110: begin seg_flag<=dout_time[19:18]; dot<=1'b1;end  //小时 十位
            6'b111_101: begin seg_flag<=dout_time[17:14]; dot<=1'b0;end  //小时 个位
            6'b111_011: begin seg_flag<=dout_time[13:11]; dot<=1'b1;end  //分钟 十位
            6'b110_111: begin seg_flag<=dout_time[10:7];  dot<=1'b0;end  //分钟 个位
            6'b101_111: begin seg_flag<=dout_time[6:4];   dot<=1'b1;end  //秒   十位
            6'b011_111: begin seg_flag<=dout_time[3:0];   dot<=1'b1;end  //秒   个位
            default :seg_flag<=0;
        endcase
    end
end


//段选译码
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        seg<=8'b1111_1111;
    end
    else begin
        case (seg_flag)     
            0:  seg<={dot,ZERO}    ;
            1:  seg<={dot,ONE}     ;
            2:  seg<={dot,TWO}     ;
            3:  seg<={dot,THREE}   ;
            4:  seg<={dot,FOUR}    ;
            5:  seg<={dot,FIVE}    ;
            6:  seg<={dot,SIX}     ;
            7:  seg<={dot,SEVEN}   ;
            8:  seg<={dot,EIGHT}   ;
            9:  seg<={dot,NINE}    ;
            default: seg<=8'b1111_1111;
        endcase
    end
end

endmodule //seg_driver

3.key_debounce

module key_debounce (   
    input  wire     clk,     //系统时钟 50MHz
    input  wire     rst_n,   //复位信号
    input  wire     key,     //按键输入信号
    output reg      key_done //消抖之后的按键信号
);

reg                 key_r0;  //同步信号(滤波作用,滤除小于一个周期的抖动)
reg                 key_r1;  //打拍
reg                 flag;    //标志位
wire                nedge;   //下降沿检测(检测到下降沿代表开始抖动)

//计时器定义
reg [19:0]          cnt;
wire                add_cnt;  //计时器开启
wire                end_cnt;  //计时记满

parameter           MAX_CNT=20'd1_000_000;  //20ms延时

//同步
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        key_r0<=1'b1;
    end
    else
        key_r0<=key;
end

//打拍
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        key_r1<=1'b1;    
    end
    else
        key_r1<=key_r0;
end

assign nedge = ~key_r0 & key_r1;  //检测到下降沿拉高

//标志位
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        flag<=1'b0; 
    end
    else if (nedge) begin
        flag<=1'b1; 
    end
    else if (end_cnt) begin
        flag<=1'b0;
    end
end

//延时模块
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt<=20'b0;
    end
    else if (add_cnt) begin
        if (end_cnt) begin
            cnt<=20'b0;
        end
        else
            cnt<=cnt+1;
    end
end

assign add_cnt=flag;                    //计时器开启
assign end_cnt=add_cnt&&cnt==MAX_CNT-1; //计时器关闭

//key_done输出
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        key_done<=1'b0; 
    end
    else if (end_cnt) begin            //延时满20ms采样
        key_done<=~key_r0;
    end
    else
        key_done<=1'b0;
end

endmodule //key_debounce

4.beep

module beep (
    input  wire         clk,
    input  wire         rst_n,
    input  wire         beep_r,
    output reg          beep_out   
);
reg [25:0]      cnt;
wire            add_cnt;
wire            end_cnt;

parameter       MAX_CNT=26'd50_000_000;


//计时器
always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        cnt<=0;
    end
    else if(add_cnt) begin
        if (end_cnt) begin
            cnt<=0;
        end
        else
            cnt<=cnt+1;
    end
end
assign add_cnt=1;
assign end_cnt=add_cnt&&cnt==MAX_CNT-1;

always @(posedge clk or negedge rst_n) begin
    if (!rst_n) begin
        beep_out<=1;
    end
    else if(beep_r) begin
        beep_out<=0;
    end
    else if (end_cnt) begin
        beep_out<=1;
    end
    else
        beep_out<=beep_out;

end

endmodule //beep

5.顶层模块

module top (
    input  wire       clk         ,  //系统时钟
    input  wire       rst_n       ,  //复位信号
    input  wire [2:0] key         ,  //三个按键
    output wire [5:0] sel         ,  //数码管位选
    output wire [7:0] seg         ,  //数码管段选
    output wire       beep_out
);
wire [19:0]     dout_time;
wire [2:0]      key_done;
wire            beep_r;
//例化计时模块
counter u_counter(
    .clk        (clk)       ,
    .rst_n      (rst_n)     ,
    .key        (key_done)     ,
    .dout_time  (dout_time) , //输出时间 HH:MM:SS
    .beep_r     (beep_r)
);

//例化数码管驱动
seg_driver u_seg_driver(
    .clk            (clk)   ,
    .rst_n          (rst_n) ,
    .sel            (sel)   ,
    .seg            (seg)   ,
    .dout_time      (dout_time)
);

//例化按键消抖
key_debounce key_debounce2(   
    .clk            (clk),     //系统时钟 50MHz
    .rst_n          (rst_n),   //复位信号
    .key            (key[0]),     //按键输入信号
    .key_done       (key_done[0]) //消抖之后的按键信号
);
key_debounce key_debounce3(   
    .clk            (clk),     //系统时钟 50MHz
    .rst_n          (rst_n),   //复位信号
    .key            (key[1]),     //按键输入信号
    .key_done       (key_done[1]) //消抖之后的按键信号
);
key_debounce key_debounce4(   
    .clk            (clk),     //系统时钟 50MHz
    .rst_n          (rst_n),   //复位信号
    .key            (key[2]),     //按键输入信号
    .key_done       (key_done[2]) //消抖之后的按键信号
);

//例化闹钟模块
beep u_beep(
    .clk                (clk),
    .rst_n              (rst_n),
    .beep_r             (beep_r),
    .beep_out           (beep_out)   
);
endmodule //top

三丶模块原理图

【FPGA】数码管电子时钟(可设置时间和闹钟)

四丶管脚信息

【FPGA】数码管电子时钟(可设置时间和闹钟)

五丶上板验证

数码管电子时钟(设置时间+设置闹钟)

六丶源码

https://github.com/xuranww/update_digital_clock.git文章来源地址https://www.toymoban.com/news/detail-403323.html

到了这里,关于【FPGA】数码管电子时钟(可设置时间和闹钟)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 数码管电子时钟

            本人用的FPGA板子用的是Cyclone IV ,这个板子的数码管是共阳极的,即当给的信号为0时,才会点亮它,而且数码管的段选信号是六个位置共用的,意味着它不能在同一时间两个位置显示不同的内容,而要想达到同时看到时分秒,只能不断将每个位置的数码管赋予不同

    2024年02月05日
    浏览(40)
  • 51单片机简易时钟闹钟八位数码管显示仿真( proteus仿真+程序+原理图+报告+讲解视频)

    51单片机简易时钟闹钟八位数码管显示仿真( proteus仿真+程序+原理图+报告+讲解视频) 仿真图proteus7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0046 本设计旨在设计一个基于51单片机的多功能数字时钟闹钟proteus仿真设计,可以显示时、分、秒,并且可以设置时

    2024年02月09日
    浏览(45)
  • C51单片机的电子时钟(数码管显示)

    普中科技51单片机开发板STC89C52 查看这两个原理图,我们可以发现控制这8个数码管由P22、P23、P24这三个控制,就相当于三个二进制数来控制数码管,三个二进制数(000-111)总共有8个,每一个二进制代表控制一个数码管。而控制数码管的发光二极管P0-P7控制,例如要想数码管显

    2024年02月11日
    浏览(51)
  • FPGA学习—通过数码管实现电子秒表模拟

    请参阅博主以前写过的一篇电子时钟模拟,在此不再赘述。 https://blog.csdn.net/qq_54347584/article/details/130402287 项目说明:本次项目是为了通过数码管实现秒表模拟。其中,六位数码管分别显示秒表的分位,秒位,毫秒位(由于毫秒有三位,在此只取百位和十位),其中分位和秒位

    2024年02月14日
    浏览(47)
  • 基于RASC的keil电子时钟制作(瑞萨RA)(6)----定时器驱动数码管

    要想让每个数码管显示不同的数字,但是数码管必须依次地被持续驱动,数码管之间的刷新速度应该足够快,这样就看不出来数码管之间在闪烁。刷新频率可以设置为2ms刷新一次,这样人眼就看不出闪烁了。 首先需要准备一个开发板,这里我准备的是芯片型号R7FA2E1A72DFL的开

    2024年02月15日
    浏览(44)
  • Arduino UNO驱动TM1637四位时钟数码管显示时间

    TM1637 是一种带键盘扫描接口的LED(发光二极管显示器)驱动控制专用电路,内部集成有MCU 数字接口、数据锁存器、LED 高压驱动、键盘扫描等电路。  显示模式(8 段×6 位),支持共阳数码管输出  键扫描(8×2bit),增强型抗干扰按键识别电路  辉度调节电路(占空比

    2024年02月12日
    浏览(42)
  • 51单片机实验三:数码管显示时钟 按键调节时间时闪烁提示

    功能效果:1.时分秒的动态显示。2.用三个按键实现时分秒的修改,调节的数字闪烁提示。  

    2024年02月11日
    浏览(42)
  • FPGA学习之数码管时间显示模块

    在学习完小梅哥的串口通信以及数码管显示教程后,他留下了一个课后作业,也就是本次的数码管时间显示模块。作为一个FPGA新人,这也算是第一个比较完整的练手小项目了,也推荐和我一样的新人花时间去完成一下。总体功能虽然比较简单,但是我也花了小两天的时间去编

    2024年03月10日
    浏览(63)
  • 基于51单片机的数码管闹钟设计

    系统功能:利用定时器实现时钟,时钟可以通过独立按键设置,设有一个闹钟,闹钟时间可通过按键进行设置,时钟界面和闹钟界面可通过按键切换,当时钟和闹钟时间相同,蜂鸣器响,提示闹钟时间到等。 此系统重点在于:数码管动态驱动的使用方法,单片机内部定时器的

    2024年02月11日
    浏览(45)
  • 51单片机(数码管可调时钟)

    1.数码管(共阴极)如何显示数字:位选+段选(单个) 位选:138译码器通过P22、P23、P24三个端口输入二进制数(011、000等)来选择连同译码器右边的哪一条线,而这些线又分别连着数码管的LED12345678、决定选择哪一个来显示数字 段选:决定输出什么数字,数码管下方又连着一

    2024年02月05日
    浏览(50)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包