基于fpga的电子时钟

文章目录

  • 前言
  • 实验手册
  • 一、实验目的
  • 二、实验原理
    • 1.理论原理
    • 2.硬件原理
  • 三、系统架构设计
  • 四、模块说明
    • 1.模块端口信号列表
      • 按键消抖模块(key)
      • 计数器模块(counter)
      • 蜂鸣器乐谱模块(music)
      • 蜂鸣器发声模块(beep)
      • 数码管驱动模块(seg_driver)
      • 顶层模块(top)
    • 2.状态转移图
    • 3.时序图
  • 五、仿真波形图
  • 六、引脚分配
        • tcl引脚分配文件
  • 七、代码编写
      • 按键消抖模块(key)
      • 计数器模块(counter)
      • 蜂鸣器乐谱模块(music)
      • 蜂鸣器发声模块(beep)
      • 数码管驱动模块(seg_driver)
      • 顶层模块(top)
  • 八、总结

前言

本次实验是本人全部用状态机实现的,所以导致我的状态机空间有很多状态,有一部分状态可以进行修改,不过我认为全部写成状态机更有利于本人的理解,可能有人会觉得很绕,不过根据本人自身所画的状态图,就能较为清晰明了,本文结尾会附上所有代码,如有需要自取即可,但我希望不要一味的复制粘贴,理解之后手敲一遍更能提升自己,如需要工程文件私信我或者评论区找我,现写下此博客以便日后复习。

该开发板为EP4CE6F17C8

实验手册

一、实验目的

1、完成基本24时计数显示2、显示时间可调整
3、设置可调闹钟-闹钟触发时蜂鸣器响起

二、实验原理

1.理论原理

蜂鸣器原理输入一定频率的方波或者PWM信号,蜂鸣器就可以发出声音。输入不同频率的信号,蜂鸣器可以发出不同音色的声音
电子时钟原理是在数码管中由于有位选信号和段选信号的存在,我们无法做到将数码管同时进行变换,所以我们通过快速的切换和刷新,使得我们看到的是连续的多个数码管显示结果。通过控制位选信号和段选信号,可以实现不同的数字、字母或符号的动态显示。
将按键进行按键消抖获得稳定信号。
使用按键通过状态机切换状态控制位选信号,在相应的位选信号下,控制时位,分位,秒位的数值加一或减一。
利用相同原理使用状态机切换状态——闹钟设置状态和常规电子时钟状态,闹钟设置状态下对时分秒位的操作与电子时钟状态一致
闹钟状态中将设定的值与电子时钟的值比对,如果相等则传给蜂鸣器一个信号,并将该信号持续5s,是蜂鸣器发声五秒

2.硬件原理

我所用的板子自带的蜂鸣器是无源蜂鸣器——内部无振荡源,需要通以方波、PWM信号才能发出声音,以及是低电平有效
开发板上的数码管数码管位选和段选信号都是低电平有效。
位选信号根据需要的显示位数进行生成(该实验所用的开发板可用6个位选信号),它们用于选择要显示的数码管。
段选信号根据需要的显示内容进行生成,它们用于控制数码管的七段LED灯以及小数点LED灯的亮灭状态(该实验所用的开发板可用8个段选信号)。

三、系统架构设计

本次实验有按键消抖模块、计数器模块、蜂鸣器模块、音符模块、数码管驱动模块
按键消抖模块将按键信号转化为稳定的有效信号
计数器模块通过输入的有效按键信号,key3切换闹钟和电子时钟状态,以及key1加,key2减,时位、分位、秒位的加减,比对闹钟空间和电子时钟的时间数值,若相等则传出一个蜂鸣器信号给音符模块,再将hour、min、sec数值输入进数码管驱动模块进行显示。
数码管驱动模块,将计数器模块产生的时分秒显示出来,以及key0切换时位、分位、秒位、空闲状态的切换。
音符模块,接收到闹钟信号时将pwm波发给蜂鸣器发声模块,持续5s
蜂鸣器模块,接收到音符模块的pwm波,发声
顶层模块,统合所有模块。

四、模块说明

1.模块端口信号列表

按键消抖模块(key)

端口信号信号类型信号名称信号作用
inputwireclk时钟信号
inputwirerst_n复位信号
inputwirekey_in按键信号
outputregkey_flag稳定按键信号

计数器模块(counter)

端口信号信号类型信号名称信号作用
inputwireclk时钟信号
inputwirerst_n复位信号
inputwirekey_flag稳定按键信号
outputwirehour小时数
outputwiremin分钟数
outputwiresec秒钟数
outputwiremusic_flag闹钟信号

蜂鸣器乐谱模块(music)

端口信号信号类型信号名称信号作用
inputwireclk时钟信号
inputwirerst_n复位信号
inputwiremusic_flag闹钟到时信号
outputregflag蜂鸣器发声信号

蜂鸣器发声模块(beep)

端口信号信号类型信号名称信号作用
inputwireclk时钟信号
inputwirerst_n复位信号
inputwireflag控制蜂鸣器发声信号
outputregbeep蜂鸣器发声信号

数码管驱动模块(seg_driver)

端口信号信号类型信号名称信号作用
inputwireclk时钟信号
inputwirerst_n复位信号
inputwirehour小时数
inputwiremin分钟数
inputwiresec秒钟数
inputwirekey_flag稳定按键信号
outputregseg数码管段选信号
outputregsel数码管位选信号

顶层模块(top)

端口信号信号类型信号名称信号作用
inputwireclk时钟信号
inputwirerst_n复位信号
inputwirekey_in按键信号
outputwiresel数码管位选信号
outputwirebeep蜂鸣器发声信号
outputwireseg数码管段选信号

2.状态转移图

请添加图片描述

闹钟空间时分秒位也有相同的加一减一,这里本人偷懒了没有画全。

3.时序图

请添加图片描述

五、仿真波形图

无仿真波形

六、引脚分配

请添加图片描述

tcl引脚分配文件

# Copyright (C) 2018  Intel Corporation. All rights reserved.
# Your use of Intel Corporation's design tools, logic functions 
# and other software and tools, and its AMPP partner logic 
# functions, and any output files from any of the foregoing 
# (including device programming or simulation files), and any 
# associated documentation or information are expressly subject 
# to the terms and conditions of the Intel Program License 
# Subscription Agreement, the Intel Quartus Prime License Agreement,
# the Intel FPGA IP License Agreement, or other applicable license
# agreement, including, without limitation, that your use is for
# the sole purpose of programming logic devices manufactured by
# Intel and sold by Intel or its authorized distributors.  Please
# refer to the applicable agreement for further details.# Quartus Prime Version 18.1.0 Build 625 09/12/2018 SJ Standard Edition
# File: D:\intelFPGA\code\dig_clock\tcl\dig_clock.tcl
# Generated on: Mon Aug 07 16:06:21 2023package require ::quartus::projectset_location_assignment PIN_A5 -to seg[7]
set_location_assignment PIN_B8 -to seg[6]
set_location_assignment PIN_A7 -to seg[5]
set_location_assignment PIN_B6 -to seg[4]
set_location_assignment PIN_B5 -to seg[3]
set_location_assignment PIN_A6 -to seg[2]
set_location_assignment PIN_A8 -to seg[1]
set_location_assignment PIN_B7 -to seg[0]
set_location_assignment PIN_E1 -to clk
set_location_assignment PIN_A4 -to sel[0]
set_location_assignment PIN_B4 -to sel[1]
set_location_assignment PIN_A3 -to sel[2]
set_location_assignment PIN_B3 -to sel[3]
set_location_assignment PIN_A2 -to sel[4]
set_location_assignment PIN_B1 -to sel[5]
set_location_assignment PIN_E15 -to key_in[0]
set_location_assignment PIN_E16 -to key_in[1]
set_location_assignment PIN_M16 -to key_in[2]
set_location_assignment PIN_M15 -to key_in[3]
set_location_assignment PIN_J1 -to beep

七、代码编写

按键消抖模块(key)

module key
(input wire clk,input wire rst_n,input wire key_in,output reg key_out,output reg key_flag
);parameter  CNT_MAX =20'd999_999; //20ms计数reg [19:0] cnt_20ms;
//reg key_flag;
//20ms消抖
always@(posedge clk or negedge rst_n)if(!rst_n)cnt_20ms<=20'b0;else if(key_in==1'b1)cnt_20ms<=20'd0;else if(cnt_20ms==CNT_MAX)cnt_20ms<=CNT_MAX;elsecnt_20ms<=cnt_20ms+20'd1;
//取单个脉冲信号
always@(posedge clk or negedge rst_n)if(!rst_n)key_flag<=1'b0;else if(cnt_20ms==(CNT_MAX-20'd1))key_flag<=1'b1;elsekey_flag<=1'b0;
//有效长信号
always @(posedge clk or negedge rst_n)beginif(!rst_n)beginkey_out <= 1'b0;endelse if(key_flag == 1'b1)key_out <= ~key_out;elsekey_out <= key_out;
endendmodule

计数器模块(counter)

module counter (input    wire         clk    ,input    wire         rst_n  ,input    wire [3:0]   key_flag,output   wire [4:0]   hour   ,output   wire [5:0]   min    ,output   wire [5:0]   sec    ,output   wire         music_flag    
);reg        [8:0]       cnt_min    ;//存放分钟加减
reg        [8:0]       cnt_sec    ;//存放秒钟加减
parameter MAXDAY = 17'd86400;//24小时 24*60*60
parameter SEC = 26'd50_000_000;//1s
reg        [5:0]       c_state;//现态,数码管选位加减
reg        [5:0]       n_state;//次态,数码管选位加减
parameter   IDLE = 6'd0,        //空闲状态S1   = 6'd1,        //数码管时位S2   = 6'd2,        //数码管分位S3   = 6'd3,        //数码管秒位A1   = 6'd4,        //时位加M1   = 6'd5,        //时位减A2   = 6'd6,        //分位加M2   = 6'd7,        //分位减A3   = 6'd8,        //秒位减M3   = 6'd9,        //秒位减R1   = 6'd10,       //闹钟功能空间      P1   = 6'd11,        //数码管时位P2   = 6'd12,        //数码管分位P3   = 6'd13,        //数码管秒位A4   = 6'd14,        //时位加M4   = 6'd15,        //时位减A5   = 6'd16,        //分位加M5   = 6'd17,        //分位减A6   = 6'd18,        //秒位减M6   = 6'd19;        //秒位减
reg        [25:0]      cnt_1s     ;
reg        [25:0]      cnt_1s_r   ;
reg        [16:0]      cnt_day    ;
reg        [16:0]      cnt_day_r  ;
reg        [31:0]      cnt_10ms   ;
wire [4:0]   hour_r  ;//存放时钟加减
wire [5:0]   min_r   ;
wire [5:0]   sec_r   ;
parameter MAX_10ms = 32'd499_999;
//10ms计数器
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_10ms <= 26'd0;endelse if (cnt_10ms == MAX_10ms) begincnt_10ms <= 26'd0;endelse begincnt_10ms <= cnt_10ms + 1'd1;end
end
//1秒计数器
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_1s <= 26'd0;endelse if (cnt_1s == SEC - 1'd1) begincnt_1s <= 26'd0;endelse begincnt_1s <= cnt_1s + 1'd1;end
end
//1天计时器_电子时钟
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_day <= 17'd0;end else if(cnt_day >= MAXDAY - 1'd1)begincnt_day <= 17'd0;end else if( cnt_1s == SEC -1'd1)begincnt_day <= cnt_day + 1'd1;endelse if(n_state == A1) begincnt_day <= cnt_day + 17'd3600;endelse if(n_state == M1) begincnt_day <= cnt_day - 17'd3600;endelse if (c_state== S1 &&key_flag[2] && (cnt_day / 3600)== 0) begincnt_day <= cnt_day + 17'd82800;endelse if(n_state == A2) begincnt_day <= cnt_day + 17'd60;endelse if(n_state == M2) begincnt_day <= cnt_day - 17'd60;endelse if(n_state == A3) begincnt_day <= cnt_day + 17'd1;endelse if(n_state == M3) begincnt_day <= cnt_day - 17'd1;endelse begincnt_day <= cnt_day;end 
end 
//1天计时器_r_闹钟空间
always@(posedge clk or negedge rst_n)beginif(!rst_n)begincnt_day_r <= 17'd0;end else if(cnt_day_r >= MAXDAY - 1'd1)begincnt_day_r <= 17'd0;end else if(n_state == A4) begincnt_day_r <= cnt_day_r + 17'd3600;endelse if(n_state == M4) begincnt_day_r <= cnt_day_r - 17'd3600;endelse if (key_flag[2] && (cnt_day_r / 3600)== 0) begincnt_day_r <= cnt_day_r + 17'd82800;endelse if(n_state == A5) begincnt_day_r <= cnt_day_r + 17'd60;endelse if(n_state == M5) begincnt_day_r <= cnt_day_r - 17'd60;endelse if(n_state == A6) begincnt_day_r <= cnt_day_r + 17'd10;endelse if(n_state == M6) begincnt_day_r <= cnt_day_r - 17'd10;endelse begincnt_day_r <= cnt_day_r;end 
end 
//如果处于闹钟空间则输出闹钟空间的值,否则输出电子时钟的值
assign hour = (c_state == R1||c_state == P1||c_state == P2||c_state == P3)?hour_r:cnt_day / 3600;
assign min = (c_state == R1||c_state == P1||c_state == P2||c_state == P3)?min_r:cnt_day % 3600 / 60;
assign sec = (c_state == R1||c_state == P1||c_state == P2||c_state == P3)?sec_r:cnt_day % 3600 % 60;assign hour_r = cnt_day_r /3600;
assign min_r = cnt_day_r % 3600 / 60;
assign sec_r = cnt_day_r % 3600 % 60;
//如果闹钟空间的值除了零以外的时候和电子时钟的值相等,则输出音乐信号给乐谱模块
assign music_flag = (cnt_day == cnt_day_r&&cnt_day_r != 0)?1:0;
//数码管选位状态机,第一段
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginc_state <= IDLE;endelse beginc_state <= n_state;end
end
//数码管选位状态机,第二段
always @(*) begincase (c_state)//空闲状态IDLE    :beginif (key_flag[0]) beginn_state = S1;endelse if (key_flag[3]) beginn_state = R1;endelse beginn_state = IDLE;endend//闹钟状态R1      :beginif (key_flag[0]) beginn_state = P1;endelse if (key_flag[3]) beginn_state = IDLE;endelse beginn_state = R1;endend//换位状态:时位S1      :beginif (key_flag[0]) beginn_state = S2;endelse if (key_flag[1]) beginn_state = A1;endelse if (key_flag[2]) beginn_state = M1;endelse beginn_state = S1;endend  //换位状态:分位S2      :beginif (key_flag[0]) beginn_state = S3;endelse if (key_flag[1]) beginn_state = A2;endelse if (key_flag[2]) beginn_state = M2;endelse beginn_state = S2;endend//换位状态:秒位  S3      :beginif (key_flag[0]) beginn_state = IDLE;endelse if (key_flag[1]) beginn_state = A3;endelse if (key_flag[2]) beginn_state = M3;endelse beginn_state = S3;endend//时位加一A1      :beginif (c_state == A1) beginn_state = S1;endelse beginn_state = A1;endend//时位减一  M1      :beginif (c_state == M1) beginn_state = S1;endelse beginn_state = M1;endend//分位加一A2      :beginif (c_state == A2) beginn_state = S2;endelse beginn_state = A2;endend//分位减一  M2      :beginif (c_state == M2) beginn_state = S2;endelse beginn_state = M2;endend//秒位加一A3      :beginif (c_state == A3) beginn_state = S3;endelse beginn_state = A3;endend//秒位减一  M3      :beginif (c_state == M3) beginn_state = S3;endelse beginn_state = M3;endend//闹钟空间:时位P1      :beginif (key_flag[0]) beginn_state = P2;endelse if (key_flag[1]) beginn_state = A4;endelse if (key_flag[2]) beginn_state = M4;endelse beginn_state = P1;endend//闹钟空间:分位  P2      :beginif (key_flag[0]) beginn_state = P3;endelse if (key_flag[1]) beginn_state = A5;endelse if (key_flag[2]) beginn_state = M5;endelse beginn_state = P2;endend//闹钟空间:秒位  P3      :beginif (key_flag[0]) beginn_state = R1;endelse if (key_flag[1]) beginn_state = A6;endelse if (key_flag[2]) beginn_state = M6;endelse beginn_state = P3;endend//闹钟空间:时位加一  A4      :beginif (c_state == A4) beginn_state = P1;endelse beginn_state = A4;endend//闹钟空间:时位减一    M4      :beginif (c_state == M4) beginn_state = P1;endelse beginn_state = M4;endend//闹钟空间:分位加一  A5      :beginif (c_state == A5) beginn_state = P2;endelse beginn_state = A5;endend//闹钟空间:分位减一    M5      :beginif (c_state == M5) beginn_state = P2;endelse beginn_state = M5;endend//闹钟空间:秒位加一  A6      :beginif (c_state == A6) beginn_state = P3;endelse beginn_state = A6;endend//闹钟空间:秒位减一    M6      :beginif (c_state == M6) beginn_state = P3;endelse beginn_state = M6;endenddefault:n_state = IDLE;endcase
end    
endmodule

蜂鸣器乐谱模块(music)

module music (input clk,input rst_n,input [3:0] key_out,input music_flag,output reg flag
);parameter MAX_0_3s = 25'd14_999_999;
reg [31:0] cnt_0_3s;
parameter MAX_1s = 32'd49_999_999;
reg        [31:0]      cnt_1s     ;//1秒计数器
parameter MAX_5s = 32'd5;
reg        [31:0]      cnt_5s     ;//1秒计数器parameter MAX_7    = 6'd33;//乐谱
reg [15:0]  cnt_7; //乐谱1寄存器
//parameter MAX_two_tiger = 6'd33;
//reg [15:0]  two_tiger;//乐谱2寄存器
//parameter MAX_300ms = 25'd14_999_999;
//reg [31:0] cnt_300ms;
reg [15:0] music_cnt;//音符音频计数器         
wire[15:0] duty;//占空比
reg [15:0] music;//音符数据寄存器
reg music_delay;parameter   DO  	= 16'd47750		;//1
parameter   RE  	= 16'd42250		;//2
parameter   MI  	= 16'd37900		;//3
parameter   FA  	= 16'd37550		;//4
parameter   SO  	= 16'd31850		;//5
parameter   LA      = 16'd28400		;//6
parameter   XI      = 16'd25400		;//7
//1s计数器
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_1s <= 1'd0;endelse if (cnt_1s == MAX_1s) begincnt_1s <= 1'd0;endelse begincnt_1s <= cnt_1s + 1;end
end
//5s计数器
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_5s <= 1'd0;endelse if (cnt_5s == MAX_5s) begincnt_5s <= 1'd0;endelse if (cnt_1s == MAX_1s)begincnt_5s <= cnt_5s + 1;end
end
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginmusic_delay <= 1'd0;endelse if (cnt_5s == MAX_5s) beginmusic_delay <= 1'd0;endelse if (music_flag)beginmusic_delay <= 1'd1;end
end
//0.3s计数器
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_0_3s <= 1'd0;endelse if (cnt_0_3s == MAX_0_3s) begincnt_0_3s <= 1'd0;endelse begincnt_0_3s <= cnt_0_3s + 1;end
end
//300ms计数器
//always @(posedge clk or negedge rst_n) begin
//    if (!rst_n) begin
//        cnt_300ms <= 1'd0;
//    end
//    else if (cnt_300ms == MAX_300ms) begin
//        cnt_300ms <= 1'd0;
//    end
//    else begin
//        cnt_300ms <= cnt_300ms + 1;
//    end
//end
//音符频率计数器
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginmusic_cnt <= 16'd0;end else if(music_cnt == music)beginmusic_cnt <= 16'd0;endelse beginmusic_cnt <= music_cnt + 1'd1;end 
end//乐谱1每隔0.5s音符切换
always @(posedge clk or negedge rst_n) beginif (!rst_n) begincnt_7 <= 1'd0;endelse if (cnt_7 == MAX_7 && cnt_0_3s == MAX_0_3s) begincnt_7 <= 1'd0;endelse if (cnt_0_3s == MAX_0_3s) begincnt_7 <= cnt_7 + 1'd1;endelse begincnt_7 <= cnt_7;end
end//乐谱2的切换间隔为300ms
//always @(posedge clk or negedge rst_n) begin
//    if (!rst_n) begin
//        two_tiger <= 1'd0;
//    end
//    else if (two_tiger == MAX_two_tiger && cnt_300ms == MAX_300ms) begin
//        two_tiger <= 1'd0;
//    end
//    else if (cnt_300ms == MAX_0_5s) begin
//        two_tiger <= two_tiger + 1'd1;
//    end
//    else begin
//        two_tiger <= two_tiger;
//    end
//end
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginmusic <= 1'd0;end//else if(key_out[1])begincase (cnt_7)6'd0:	music <= DO;6'd1:	music <= RE;6'd2:	music <= MI;						6'd3:	music <= DO;					6'd4:	music <= DO;					6'd5:	music <= RE;					6'd6:	music <= MI;					6'd7:	music <= DO;					6'd8:	music <= MI;					6'd9:	music <= FA;					6'd10:	music <= SO;6'd11:	music <= MI;6'd12:	music <= FA;6'd13:	music <= SO;6'd14:	music <= SO;6'd15:	music <= LA;6'd16:	music <= SO;6'd17:	music <= FA;6'd18:	music <= MI;6'd19:	music <= DO;6'd20:	music <= SO;6'd21:	music <= LA;6'd22:	music <= SO;6'd23:	music <= FA;6'd24:	music <= MI;6'd25:	music <= DO;6'd26:	music <= RE;6'd27:	music <= SO;6'd28:	music <= DO;6'd29:	music <= DO;6'd30:	music <= RE;6'd31:	music <= SO;6'd32:	music <= DO;6'd33:	music <= DO;default:music <= DO;endcase//end//else if(!key_out[1])begin//   case(cnt_7)//		10'd0: music <= DO  ;//        10'd1: music <= RE  ;//        10'd2: music <= MI  ;//        10'd3: music <= FA  ;//        10'd4: music <= SO  ;//        10'd5: music <= LA  ;//        10'd6: music <= XI  ;//        10'd7: music <= DO  ;//        10'd8: music <= RE  ;//        10'd9: music <= MI  ;//        10'd10: music <= FA  ;//        10'd11: music <= SO  ;//        10'd12: music <= LA  ;//        10'd13: music <= XI  ;//        10'd14: music <= DO  ;//        10'd15: music <= RE  ;//        10'd16: music <= MI  ;//        10'd17: music <= FA  ;//        10'd18: music <= SO  ;//        10'd19: music <= LA  ;//        10'd20: music <= XI  ;//        default: music <= DO;//    endcase//end
end
assign duty = music >> 1;//占空比50%
always@(posedge clk or negedge rst_n)beginif(!rst_n)beginflag <= 1'b0;end else if (music_delay)beginflag <= (music_cnt >= duty) ? 1'b1 : 1'b0; endelse beginflag <= 1'b0;end
endendmodule

蜂鸣器发声模块(beep)

module beep (input clk,input rst_n,input flag,output reg beep
);always @(posedge clk or negedge rst_n) beginif (!rst_n) beginbeep <= 1'b1; endelse if (flag) beginbeep <= 1'b0;endelse beginbeep <= 1'b1;end
endendmodule

数码管驱动模块(seg_driver)

module seg_driver (input   wire         clk     ,input   wire         rst_n   ,input   wire [4:0]   hour   ,input   wire [5:0]   min    ,input   wire [5:0]   sec    ,    input   wire [3:0]   key_flag,output   reg  [7:0]  seg    , //段选信号output   reg  [5:0]  sel      //位选信号);reg        [8:0]       cnt_num    ;
reg        [19:0]      cnt_delay  ;
reg        [7:0]       point      ;//小数点
reg        [5:0]       c_state;//现态,数码管选位加减
reg        [5:0]       n_state;//次态,数码管选位加减
parameter   IDLE = 6'd0,        //空闲状态S1   = 6'd1,        //数码管时位S2   = 6'd2,        //数码管分位S3   = 6'd3;        //数码管秒位parameter MAX_1s = 32'd24_999_999;
reg        [31:0]      cnt_1s     ;//1秒计数器parameter CNT_DELAY_MAX= 10'd1000   ;
parameter ZERO         = 8'b1100_0000    ,ONE          = 8'b1111_1001    ,TWO          = 8'b1010_0100    ,THREE        = 8'b1011_0000    ,FOUR         = 8'b1001_1001    ,FIVE         = 8'b1001_0010    ,SIX          = 8'b1000_0010    ,SEVEN        = 8'b1111_1000    ,EIGHT        = 8'b1000_0000    ,NINE         = 8'b1001_0000    ;//1s计数器
always @(posedge clk or negedge rst_n) beginif(!rst_n)begincnt_1s <= 10'd0;endelse if(cnt_1s == MAX_1s)begincnt_1s <= 10'd0;endelse begincnt_1s <= cnt_1s + 1'd1;end
end
//20us计数器
always @(posedge clk or negedge rst_n) beginif(!rst_n)begincnt_delay <= 10'd0;endelse if(cnt_delay == CNT_DELAY_MAX - 1'd1)begincnt_delay <= 10'd0;endelse begincnt_delay <= cnt_delay + 1'd1;end
end//该板块无法同时变化,只能依次闪烁,该方法为依次闪烁的间隔,人肉眼无法判断 20us
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginsel <= 6'b111_110;endelse if (cnt_delay == CNT_DELAY_MAX - 1'd1) beginsel <= {sel[4:0],sel[5]};endelse beginsel <= sel ;end
endalways @(*) begin//若处于时位,则相应的位选信号闪烁if (c_state == S1) begincase (sel)6'b111110:beginif (cnt_1s <= MAX_1s/2) begincnt_num = 9'd20;endelse cnt_num = hour / 10;end 6'b111101: beginif (cnt_1s <= MAX_1s/2) begincnt_num = 9'd20;endelse cnt_num = hour % 10 + 10;end 6'b111011: cnt_num = min / 10;6'b110111: cnt_num = min % 10 + 10;6'b101111: cnt_num = sec / 10;6'b011111: cnt_num = sec % 10;default: cnt_num = 4'd0;endcaseend//若处于分位,则相应的位选信号闪烁else if (c_state == S2) begincase (sel)6'b111110: cnt_num = hour / 10;6'b111101: cnt_num = hour % 10 + 10;6'b111011: beginif (cnt_1s <= MAX_1s/2) begincnt_num = 9'd20;endelse cnt_num = min / 10;end 6'b110111: beginif (cnt_1s <= MAX_1s/2) begincnt_num = 9'd20;endelse cnt_num = min % 10 + 10;end6'b101111: cnt_num = sec / 10;6'b011111: cnt_num = sec % 10;default: cnt_num = 4'd0;endcaseend//若处于秒位,则相应的位选信号闪烁else if (c_state == S3) begincase (sel)6'b111110: cnt_num = hour / 10;6'b111101: cnt_num = hour % 10 + 10;6'b111011: cnt_num = min / 10;6'b110111: cnt_num = min % 10 + 10;6'b101111: beginif (cnt_1s <= MAX_1s/2) begincnt_num = 9'd20;endelse cnt_num = sec / 10;end6'b011111: beginif (cnt_1s <= MAX_1s/2) begincnt_num = 9'd20;endelse cnt_num = sec % 10;enddefault: cnt_num = 4'd0;endcaseendelse begin //其他情况数码管正常显示   case (sel)6'b111110: cnt_num = hour / 10;6'b111101: cnt_num = hour % 10 + 10;6'b111011: cnt_num = min / 10;6'b110111: cnt_num = min % 10 + 10;6'b101111: cnt_num = sec / 10;6'b011111: cnt_num = sec % 10;default: cnt_num = 4'd0;endcaseend
end//通过数字num解析出seg值
always @(*) begincase (cnt_num)9'd0:begin    seg <=   ZERO  ;    end9'd1:begin    seg <=   ONE   ;    end9'd2:begin    seg <=   TWO   ;    end9'd3:begin    seg <=   THREE ;    end9'd4:begin    seg <=   FOUR  ;    end9'd5:begin    seg <=   FIVE  ;    end9'd6:begin    seg <=   SIX   ;    end9'd7:begin    seg <=   SEVEN ;    end9'd8:begin    seg <=   EIGHT ;    end9'd9:begin    seg <=   NINE  ;    end9'd10:begin    seg <=   {point[7],ZERO[6:0]} ;    end9'd11:begin    seg <=   {point[7],ONE[6:0]}   ;    end9'd12:begin    seg <=   {point[7],TWO[6:0]}   ;    end9'd13:begin    seg <=   {point[7],THREE[6:0]} ;    end9'd14:begin    seg <=   {point[7],FOUR[6:0]}  ;    end9'd15:begin    seg <=   {point[7],FIVE[6:0]}  ;    end9'd16:begin    seg <=   {point[7],SIX[6:0]}   ;    end9'd17:begin    seg <=   {point[7],SEVEN[6:0]} ;    end9'd18:begin    seg <=   {point[7],EIGHT[6:0]} ;    end9'd19:begin    seg <=   {point[7],NINE[6:0]}  ;    end9'd20:begin    seg <=   8'b11111111  ;    enddefault: seg <= ZERO;endcase
end//数码管选位状态机,第一段
always @(posedge clk or negedge rst_n) beginif (!rst_n) beginc_state <= IDLE;endelse beginc_state <= n_state;end
end
//数码管选位状态机,第二段
always @(*) begincase (c_state)//空闲状态IDLE    :beginif (key_flag[0]) beginn_state = S1;endelse beginn_state = IDLE;endend//数码管时位S1      :beginif (key_flag[0]) beginn_state = S2;endelse beginn_state = S1;endend //数码管分位 S2      :beginif (key_flag[0]) beginn_state = S3;endelse beginn_state = S2;endend//数码管秒位   S3      :beginif (key_flag[0]) beginn_state = IDLE;endelse beginn_state = S3;endenddefault:n_state = IDLE;endcase
endendmodule

顶层模块(top)

module top(input wire clk,input wire rst_n,input wire [3:0] key_in,output wire [7:0] seg,output wire [5:0] sel,output wire beep    
);
wire [3:0] key_flag;
wire [4:0] hour;
wire [5:0] min;
wire [5:0] sec;
wire music_flag;
wire flag;key  u_key//key_fsm
(/* input wire */ .clk           (clk    )        ,              /* input wire */ .rst_n         (rst_n  )        ,            /* input wire */ .key_in        (key_in[0])        ,/* output reg */ .key_flag       (key_flag[0])              );key  u_key1
(/* input wire */ .clk           (clk    )        ,              /* input wire */ .rst_n         (rst_n  )        ,            /* input wire */ .key_in        (key_in[1])       ,     /* output reg */ .key_flag       (key_flag[1])                );key     u_key2
(/* input wire */ .clk           (clk    )        ,              /* input wire */ .rst_n         (rst_n  )        ,            /* input wire */ .key_in        (key_in[2])        , /* output reg */ .key_flag       (key_flag[2])                  );key     u_key3
(/* input wire */ .clk           (clk    )        ,              /* input wire */ .rst_n         (rst_n  )        ,            /* input wire */ .key_in        (key_in[3])       , /* output reg */ .key_flag      (key_flag[3])                        
);  
beep u_beep (/* input  */.clk  (clk  ),/* input  */.rst_n(rst_n),/* input  */.flag (flag ),/* output */.beep (beep )
);
music u_music(/* input  */.clk       (clk       )     ,/* input  */.rst_n     (rst_n     )     ,/* input  */.key_out   (key_out   )     ,/* input  */.music_flag(music_flag)     ,/* output */.flag(flag)
);
counter u_counter(.clk        (clk)   ,.rst_n      (rst_n) ,.hour       (hour)  ,.key_flag   (key_flag),.music_flag (music_flag),.min        (min)   ,.sec        (sec)   
);
seg_driver u_seg_driver(.clk        (clk)   ,.rst_n      (rst_n) ,.hour       (hour)   ,.key_flag   (key_flag),.min        (min)   ,.sec        (sec)   ,.seg        (seg)   ,.sel        (sel)   
);
endmodule

八、总结

虽然该代码仍有许多不足,但如果对各位有所帮助,还请各位不要吝啬手中的点赞和关注。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/26862.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

GD32F103VE侵入事件

GD32F103VE的TAMPER引脚(PC13)&#xff0c;当PC13输入低电平时&#xff0c;会产生一个侵入检测事件。它会将所有“数据备份寄存器”内容清除。 这个功能有什么用&#xff1f; 一是防止被人开壳&#xff0c;抄袭。二是自毁功能。 直奔主题&#xff0c;多一句就是浪费时间。测试…

flutter开发实战-flutter_spinkit实现多种风格进度指示器

flutter开发实战-flutter_spinkit实现多种风格进度指示器 最近开发过程中flutter_spinkit&#xff0c;这个拥有多种种风格加载指示器 一、flutter_spinkit 引入flutter_spinkit # 多种风格的模糊进度指示器flutter_spinkit: ^5.1.0效果示例 const spinkit SpinKitRotatingC…

如何找到死锁的线程?_java都学什么

在Java中&#xff0c;死锁是指两个或多个线程被无限地阻塞&#xff0c;等待彼此持有的资源&#xff0c;从而导致程序无法继续执行的情况。死锁通常是由于线程之间循环等待资源而产生的。要找到死锁的线程&#xff0c;可以采用以下方法&#xff1a; 1.线程转储(Thread Dump) 通过…

6.6 实现卷积神经网络LeNet训练并预测手写体数字

模型架构 代码实现 import torch from torch import nn from d2l import torch as d2lnet nn.Sequential(nn.Conv2d(1,6,kernel_size5,padding2),nn.Sigmoid(),#padding2补偿5x5卷积核导致的特征减少。nn.AvgPool2d(kernel_size2,stride2),nn.Conv2d(6,16,kernel_size5),nn.S…

OpenStreetMap数据转3D场景【Python + PostgreSQL】

很长一段时间以来&#xff0c;我对 GIS 和渲染感兴趣&#xff0c;在分别尝试这两者之后&#xff0c;我决定最终尝试以 3D 方式渲染 OpenStreetMap 中的地理数据&#xff0c;重点关注不超过城市的小规模。 在本文中&#xff0c;我将介绍从建筑形状生成三角形网格、以适合 Blend…

iperf3-性能测试

iperf3-性能测试 安装1.apt安装2.源码安装 使用方法iperf原理测试参考文档性能测试客户端服务端 官方文档&#xff1a;https://iperf.fr/iperf-doc.php 安装 1.apt安装 sudo apt-get install iperf32.源码安装 # 按照官方说明安装 ./configure make sudo make install执行编…

GATK ApplyBQSRSpark 过程中因No space left on device终止

Error&#xff1a; GATK ApplyBQSRSpark 过程中因No space left on device终止 执行命令&#xff1a; nohup time ./gatk --java-options "-Xmx128G" ApplyBQSRSpark --spark-master local[20] -R ../../alignment/hg38/hg38.fa -I ../../alignment/bam/P368T.s…

微信小程序nodejs+vue+uniapp高校食堂线上预约点餐系统

本次设计任务是要设计一个食堂线上预约点餐系统&#xff0c;通过这个系统能够满足管理员及学生的食堂线上预约点餐分享功能。系统的主要包括首页、个人中心、学生管理、菜品分类管理、菜品管理、关于我们管理、意见反馈、系统管理、订单管理等功能。 开发语言 node.js 框架&am…

【论文阅读】对抗溯源图主机入侵检测系统的模仿攻击(NDSS-2023)

作者&#xff1a;伊利诺伊大学芝加哥分校-Akul Goyal、Gang Wang、Adam Bates&#xff1b;维克森林大学-Xueyuan Han、 引用&#xff1a;Goyal A, Han X, Wang G, et al. Sometimes, You Aren’t What You Do: Mimicry Attacks against Provenance Graph Host Intrusion Detect…

BenchmarkSQL 支持 TiDB 驱动以及 tidb-loadbalance

作者&#xff1a; GangShen 原文来源&#xff1a; https://tidb.net/blog/3c274180 使用 BenchmarkSQL 对 TiDB 进行 TPC-C 测试 众所周知 TiDB 是一个兼容 MySQL 协议的分布式关系型数据库&#xff0c;用户可以使用 MySQL 的驱动以及连接方式连接 TiDB 进行使用&#xff0…

Git从远程仓库中删除文件,并上传新文件

目录 删除&#xff1a; 拉取远程分支的更新&#xff1a; ​编辑 首先查看git状态&#xff1a; ​编辑 删除文件并提交版本库&#xff1a; 提交&#xff1a; 上传新文件&#xff1a; 首先查看git状态&#xff1a; 提交到暂存区&#xff1a; 提交到版本库&#xff1a; 上…

基于Spring Boot的在线视频教育培训网站设计与实现(Java+spring boot+MySQL)

获取源码或者论文请私信博主 演示视频&#xff1a; 基于Spring Boot的在线视频教育培训网站设计与实现&#xff08;Javaspring bootMySQL&#xff09; 使用技术&#xff1a; 前端&#xff1a;html css javascript jQuery ajax thymeleaf 微信小程序 后端&#xff1a;Java sp…

skywalking日志收集

文章目录 一、介绍二、添加依赖三、修改日志配置1. 添加链路表示traceId2. 添加链路上下文3. 异步日志 四、收集链路日志 一、介绍 在上一篇文章skywalking全链路追踪中我们介绍了在微服务项目中使用skywalking进行服务调用链路的追踪。 本文在全链路追踪的基础上&#xff0c…

gradle项目Connection timed out,build时先下载gradle问题download gradle-x.x-bin.zip

IDEA 导入 Gradle 项目&#xff0c;编译的时候会默认下载 配置版本的Gradle.zip问题&#xff0c;一般会下载失败&#xff0c;提示Connection timed out&#xff0c;连接超时。 解决办法&#xff1a; 修改项目根目录下gradle目录下的gradle-wrapper.properties文件&#xff0c;…

LLM as Co-pilot:AutoDev 1.0 发布,开源全流程 AI 辅助编程

四月&#xff0c;在那篇《AutoDev&#xff1a;AI 突破研发效能&#xff0c;探索平台工程新机遇》&#xff0c;我们初步拟定了 AI 对于研发的影响。我们有了几个基本的假设&#xff1a; 中大型企业将至少拥有一个私有化的大语言模型。只有构建端到端工具才能借助 AI 实现增质提效…

STM32入门——定时器

内容为江科大STM32标准库学习记录 TIM简介 TIM&#xff08;Timer&#xff09;定时器定时器可以对输入的时钟进行计数&#xff0c;并在计数值达到设定值时触发中断16位计数器、预分频器、自动重装寄存器的时基单元&#xff0c;在72MHz计数时钟下可以实现最大59.65s的定时&…

【Docker】性能测试监控平台搭建:InfluxDB+Grafana+Jmeter+cAdvisor

前言 在做性能测试时&#xff0c;如果有一个性能测试结果实时展示的页面&#xff0c;可以极大的提高我们对系统性能表现的掌握程度&#xff0c;进而提高我们的测试效率。但是我们每次打开Jmeter都会有几个硕大的字提示别用GUI模式进行负载测试&#xff0c;而且它自带的监视器效…

系统架构设计师-软件架构设计(7)

目录 大型网站系统架构演化 一、第一阶段&#xff1a;单体架构 到 第二阶段&#xff1a;垂直架构 二、第三阶段&#xff1a;使用缓存改善网站性能 1、缓存与数据库的数据一致性问题 2、缓存技术对比【MemCache与Redis】 3、Redis分布式存储方案 4、Redis集群切片的常见方式 …

c++ boost circular_buffer

boost库中的 circular_buffer顾名思义是一个循环缓冲器&#xff0c;其 capcity是固定的当容量满了以后&#xff0c;插入一个元素时&#xff0c;会在容器的开头或结尾处删除一个元素。 circular_buffer为了效率考虑&#xff0c;使用了连续内存块保存元素 使用固定内存&#x…

为什么要选择文件传输软件?有哪些最佳高速文件传输软件?

是否经历过这样的场景&#xff0c;正在努力地完成工作任务&#xff0c;但是由于制作的数据无法及时传送给合作伙伴&#xff0c;工作流程被打断了&#xff1f;这听起来很令人沮丧&#xff0c;对吧&#xff1f;可是&#xff0c;这种情况在现实中并不罕见。 因此&#xff0c;需要…