赞
踩
开发板:此款开发板使用的是 ALTERA 公司的 Cyclone IV 系列 FPGA,型号为 EP4CE6F17C8, 256 个引脚的 FBGA 封装。
题目:在EDA开发板上实现电子时钟功能
要求:实现电子时钟程序编写,实现在7段数码管显示时、分、秒,使用4x4矩阵按键模拟调节时钟指令输入按键,并实现整点报时功能。按键功能包括但不限以下功能:选择(时分秒选择按键、可以一一对应,也可以只用1个按键)、复位、+(时分秒加)、-(时分秒减)。
程序设计步骤:
1、七段数码管显示
1 | 2. | 4 | 6. | 5 | 7 |
图1 开机显示画面,其中.为时分秒的间隔
2、 数据输入:在图1所示的状态下,用4x4矩阵按键来进行时分秒的调节。
3、整点报时:到整点时,自动播放一段音乐。
4、一键复原:完成时间调节后,按“复原”按键,七段数码管显示最初的状态,回到图1所示状态。
以上既是该电子时钟的设计要求。
功能设计部分,分为以下7个模块。
EDA_clock | 顶层模块文件 | 将各个模块进行整合 |
clk1hz | 时钟频率 | 将50MHz晶振频率转化为1秒钟的频率,1Hz=1s |
cnt24 | 24计数器 | 时钟中 “时”的计数,并判断 |
cnt60 | 60计数器 | 时钟中“分”、“秒”的计数,并判断个位十位实时状态 |
key4x4_clock | 4x4矩阵键盘 | 矩阵键盘功能设置 |
seg_dynamic | 七段数码管 | 接收当前计数器值 |
buzzer | 蜂鸣器控制 | 当整点时播放音乐3秒钟 |
对于以下各个代码块有较为详细的标注,请自行对照理解,有疑惑的可以评论区,看到回复
创建工程后,该模块为顶层文件
代码如下:
- /**
- * @copyright: 2782978674@qq.com
- * @author: xietiancheng
- * @date: 2023.6.4
- *
- **/
-
- module EDA_clock(
- input wire sys_clk,
- input wire rst_n,
- input wire [3:0] key_in_y, // 输入矩阵键盘的列信号(KEY0~KEY3)
- output wire [3:0] key_out_x, // 输出矩阵键盘的行信号(KEY4~KEY7)
- output wire [5:0] sel , //数码管位选信号
- output wire [7:0] seg , //数码管段选信号
- output wire buzzer
- );
-
- wire clk_1hz;
- wire count_s;
- wire count_m;
- wire [6:0] Sec; //秒
- wire [6:0] Sec_out; //秒输出
- wire [6:0] Min; //分
- wire [6:0] Min_out; //分输出
- wire [6:0] Hour; //时
- wire [6:0] Hour_out; //时输出
- wire [4:0] Sec1; //秒的个位
- wire [4:0] Sec2; //秒的十位
- wire [4:0] Min1; //分的个位
- wire [4:0] Min2; //分的十位
- wire [4:0] Hour1; //时的个位
- wire [4:0] Hour2; //时的十位
-
- wire en_s; //秒的使能信号
- wire en_m; //分的使能信号
- wire en_h; //时的使能信号
- wire time_en;//当设置时间时,设置使能信号,当有效时时间停止,进行时钟各位赋值。
-
- // assign en_s=1'b1;
- assign en_m=count_s && en_s;
- assign en_h= (Min_out == 7'd59 && Sec_out == 7'd58)?1:0;
- //1hz代表一秒钟,时钟频率设置
- clk1hz
- #(
- .N (26'd25_000_000 ) //代表
- )
- clk1hz_inst
- (
- .clk(sys_clk),
- .rst_n(rst_n),
- .clk_out(clk_1hz)
- );
- /*********秒和分使用使能信号en_s和en_m来控制*********/
- //秒的代码
- cnt60 cnt60_inst1(
- .clk(clk_1hz),
- .rst_n(rst_n),
- .en(en_s),
- .time_en(time_en),
- .cnt0(Sec),
- .cnt_out(Sec_out),
- .cnt1(Sec1), //秒的个位
- .cnt2(Sec2), //秒的十位
- .flag(count_s) //秒的使能信号
- );
- //分的代码
- cnt60 cnt60_inst2(
- .clk(clk_1hz),
- .rst_n(rst_n),
- .en(en_m),
- .time_en(time_en),
- .cnt0(Min),
- .cnt_out(Min_out),
- .cnt1(Min1), //分的个位
- .cnt2(Min2), //分的十位
- .flag(count_m)
- );
- //时间的设置
- cnt24 cnt24_inst(
- .clk(clk_1hz),
- .rst_n(rst_n),
- .en(en_h),
- .time_en(time_en),
- .cnt0(Hour),
- .cnt_out(Hour_out),
- .cnt1(Hour1),
- .cnt2(Hour2)
- );
-
- //数码管控制显示模块
- seg_dynamic seg_dynamic_inst
- (
- .clk(sys_clk),
- .rst_n(rst_n),
- .Sec1(Sec1), //秒的个位
- .Sec2(Sec2), //秒的十位
- .Min1(Min1), //分的个位
- .Min2(Min2), //分的十位
- .Hour1(Hour1), //时的个位
- .Hour2(Hour2), //时的十位
- .sel (sel), //数码管位选信号
- .seg(seg) //数码管段选信号
- );
-
-
-
- //矩阵键盘设置调节时间
- key4x4_clock key4x4_clock_inst(
- .clk(sys_clk) ,
- .rst_n(rst_n) ,
- .Sec_out (Sec_out) ,
- .Min_out (Min_out) ,
- .Hour_out (Hour_out) ,
- .key_in_y(key_in_y) , // 输入矩阵键盘的列信号(KEY0~KEY3)
- .key_out_x(key_out_x) , // 输出矩阵键盘的行信号(KEY4~KEY7)
- .Sec(Sec) , //秒修改
- .Min(Min) , //分修改
- .Hour(Hour) , //时修改
- .en(en_s) , //时钟是否运行的使能信号
- .time_en(time_en)
- );
-
-
- buzzer buzzer_inst(
- .clk (sys_clk),
- .rst_n (rst_n ),
- .Sec_out(Sec_out),
- .Min_out(Min_out),
- .buzzer (buzzer)
-
- );
- endmodule
-
-
- /**********************************************************
-
- quartusII综合报错(Error (10028): Can't resolve multiple constant drivers for net "txd_cnt[3]")
- 出现这个错误的原因在于,在不同的always逻辑块中,对同一个reg变量进行了赋值。
- 在多个alwasy逻辑块同时并行工作的时候,会出现冲突。解决的办法就是,对于一个变量,只在一个always块中,进行赋值。
- ***********************************************************/

将50MHz转化为1Hz的频率,可通过parameter参数N进行更改转化为其他频率
代码如下:
- module clk1hz
- #(parameter N = 26'd25_000_000)
- (
- input clk,
- input rst_n,
- output reg clk_out
- );
- reg [32:0] tmp;
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n) begin
- tmp <= 0;
- clk_out<=0;
- end
- else if (tmp == N-1)
- begin
- clk_out<= ~clk_out;
- tmp <= 0;
- end
- else
- begin
- tmp <= tmp+1;
- clk_out <=clk_out;
- end
- end
- endmodule

代码如下:
- module cnt24
- // #(parameter CNT = 5'd0)
- (
- input wire clk ,
- input wire rst_n ,
- input wire en ,
- input wire time_en ,
- input wire [6:0] cnt0,
- output reg [6:0] cnt_out, //控制cnt的传入传出
- output reg [4:0] cnt1,
- output reg [4:0] cnt2
- );
- reg [6:0] cnt;
-
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n) begin
- cnt<=cnt0;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- else
- begin
- if(en==1)
- begin
- if(cnt<23)
- begin
- cnt<=cnt+1;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- else begin
- cnt<=0;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- end
- else if(time_en==1'b1)begin
- cnt <=cnt0;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- else begin //if(en_m==0 &&en == 0)begin
- cnt<=cnt;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- end
- end
- endmodule
- /*
- if(cnt1<10)
- begin
- cnt1 <= cnt1+1;
- end
- else
- begin
- cnt1<= 0;
- cnt2<=cnt2+1;
- end
- */

代码如下:
- module cnt60
- (
- input wire clk,
- input wire rst_n,
- input wire en,
- input wire time_en, //修改时钟值的使能信号
- input wire [6:0] cnt0, //控制cnt的传入传出
- output reg [6:0] cnt_out, //控制cnt的传入传出
- output reg [4:0] cnt1,
- output reg [4:0] cnt2,
- output reg flag
- );
- reg [6:0] cnt; //时钟始终变化着运行着的值
-
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- begin
- cnt<=cnt0;
- //控制个位和十位的变化
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- else
- begin
- if(en==1)
- begin
- if(cnt<59)
- begin
- cnt <=cnt +1;
- //控制个位和十位的变化
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- else begin
- cnt <= 0;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- end
- else if(time_en==1'b1)begin
- cnt <=cnt0 ;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- else begin
- cnt <=cnt;
- cnt1<=cnt%10;
- cnt2<=cnt/10;
- cnt_out<=cnt;
- end
- end
- end
- //当cnt到达58时flag的变化
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)
- flag<=0;
- else if(cnt <58)
- flag <=0;
- else if(cnt == 58)
- flag <= 1;
- else flag <= 0;
- end
- endmodule

代码如下:
- `timescale 1ns / 1ps //精度 可不用
- module key4x4_clock(
- input wire clk,
- input wire rst_n,
- input wire [6:0] Sec_out,
- input wire [6:0] Min_out,
- input wire [6:0] Hour_out,
- input wire [3:0] key_in_y, // 输入矩阵键盘的列信号(KEY0~KEY3)
- output reg [3:0] key_out_x, // 输出矩阵键盘的行信号(KEY4~KEY7)
- output reg [6:0] Sec, //秒修改
- output reg [6:0] Min, //分修改
- output reg [6:0] Hour, //时修改
- output reg en , //时钟是否运行的使能信号
- output reg time_en //时钟是否运行的使能信号
- );
-
- //寄存器定义
- reg [19:0] count;
- reg [1:0] count1; //时钟修改的时候,在修改时它的值等于当前已经变化后的值,count1作为该修改值的使能信号
-
-
- //==============================================
- // 输出矩阵键盘的行信号,20ms 扫描矩阵键盘一次,采样频率小于按键毛刺频率,相当于滤除掉了高频毛刺信号。
- //==============================================
- always @(posedge clk or negedge rst_n) //检测时钟的上升沿和复位的下降沿
- begin
- if(!rst_n) begin //复位信号低有效
- count <= 20'd0; //计数器清 0
- key_out_x <= 4'b1111;
- end
- else begin
- if(count == 20'd0) //0ms 扫描第一行矩阵键盘
- begin
- key_out_x <= 4'b1110; //开始扫描第一行矩阵键盘,第一行输出0
- count <= count + 20'b1; //计数器加1
- end
- else if(count == 20'd249_999) //5ms 扫描第二行矩阵键盘,5ms 计数(50M/200-1=249_999)
- begin
- key_out_x <= 4'b1101; //开始扫描第二行矩阵键盘,第二行输出 0
- count <= count + 20'b1; //计数器加 1
- end
- else if(count ==20'd499_999) //10ms扫描第三行矩阵键盘 ,10ms计数(50M/100-1=499_999)
- begin
- key_out_x <= 4'b1011; //扫描第三行矩阵键盘,第三行输出0
- count <= count + 20'b1; //计数器加1
- end
- else if(count ==20'd749_999) //15ms扫描第四行矩阵键盘 ,15ms 计 数(50M/67.7-1=749_999)
- begin
- key_out_x <= 4'b0111; //扫描第四行矩阵键盘,第四行输出0
- count <= count + 20'b1; //计数器加 1
- end
- else if(count ==20'd999_999) //20ms 计数(50M/50-1=999_999)
- begin
- count <= 0; //计数器为 0
- end
- else
- count <= count + 20'b1; //计数器加 1
- end
- end
- //====================================================
- // 采样列的按键信号
- //====================================================
- reg [3:0] key_h1_scan; //第一行按键扫描值 KEY
- reg [3:0] key_h1_scan_r; //第一行按键扫描值寄存器 KEY
- reg [3:0] key_h2_scan; //第二行按键扫描值 KEY
- reg [3:0] key_h2_scan_r; //第二行按键扫描值寄存器 KEY
- reg [3:0] key_h3_scan; //第三行按键扫描值 KEY
- reg [3:0] key_h3_scan_r; //第三行按键扫描值寄存器 KEY
- reg [3:0] key_h4_scan; //第四行按键扫描值 KEY
- reg [3:0] key_h4_scan_r; //第四行按键扫描值寄存器 KEY
- always @(posedge clk)
- begin
- if(!rst_n) begin //复位信号低有效
- key_h1_scan <= 4'b1111;
- key_h2_scan <= 4'b1111;
- key_h3_scan <= 4'b1111;
- key_h4_scan <= 4'b1111;
- end
- else begin
- if(count == 20'd124_999) //2.5ms 扫描第一行矩阵键盘值
- key_h1_scan<=key_in_y; //扫描第一行的矩阵键盘值
- else if(count == 20'd374_999) //7.5ms 扫描第二行矩阵键盘值
- key_h2_scan<=key_in_y; //扫描第二行的矩阵键盘值
- else if(count == 20'd624_999) //12.5ms 扫描第三行矩阵键盘值
- key_h3_scan<=key_in_y; //扫描第三行的矩阵键盘值
- else if(count == 20'd874_999) //17.5ms 扫描第四行矩阵键盘值
- key_h4_scan<=key_in_y; //扫描第四行的矩阵键盘值
- end
- end
-
- //====================================================
- // 按键信号锁存一个时钟节拍
- //====================================================
- always @(posedge clk)
- begin
- key_h1_scan_r <= key_h1_scan;
- key_h2_scan_r <= key_h2_scan;
- key_h3_scan_r <= key_h3_scan;
- key_h4_scan_r <= key_h4_scan;
- end
-
-
- wire [3:0] flag_h1_key = key_h1_scan_r[3:0] & (~key_h1_scan[3:0]); //当检测到按键有下降沿变化时,代表该按键被按下,按键有效
- wire [3:0] flag_h2_key = key_h2_scan_r[3:0] & (~key_h2_scan[3:0]); //当检测到按键有下降沿变化时,代表该按键被按下,按键有效
- wire [3:0] flag_h3_key = key_h3_scan_r[3:0] & (~key_h3_scan[3:0]); //当检测到按键有下降沿变化时,代表该按键被按下,按键有效
- wire [3:0] flag_h4_key = key_h4_scan_r[3:0] & (~key_h4_scan[3:0]); //当检测到按键有下降沿变化时,代表该按键被按下,按键有效
-
-
-
-
-
- /* 状态参数的定义 --- 可以使用独热码 */
- parameter IDLE = 5'b00001, //初始状态(也是终态) 使能信号正常,可以初次进行时钟正常运行
- ONE = 5'b00010, //设置秒的个十位
- TWO = 5'b00100, //设置分
- THREE = 5'b01000, //设置时
- SETTING = 5'b10000; //时间设置键 使能信号失效
- /**************按键排列******************
- K1设置键 K2设置秒 K3设置分 K4设置时
- K5确认键
- K9时间加 K10时间减
- *****************************************/
- reg [4:0] state ; //状态跳变
- //状态跳转
- always@ (posedge clk or negedge rst_n)
- begin
- if(rst_n == 1'b0)
- state <=IDLE;
- else
- case(state)
- IDLE: if(flag_h1_key[0]==1'b1)
- state <= SETTING;
- else
- state <= IDLE;
- SETTING:if(flag_h1_key[1]==1'b1)
- state <= ONE;
- else if(flag_h1_key[2]==1'b1)
- state <= TWO;
- else if(flag_h1_key[3]==1'b1)
- state <= THREE;
- else if(flag_h2_key[0]==1'b1)
- state <= IDLE;
- else
- state <= SETTING;
-
- ONE: if(flag_h1_key[2])
- state <= TWO;
- else if(flag_h1_key[3]==1'b1)
- state <= THREE;
- else if(flag_h2_key[0]==1'b1)
- state <= IDLE;
- else
- state <= ONE;
- TWO: if(flag_h1_key[1])
- state <= ONE;
- else if(flag_h1_key[3]==1'b1)
- state <= THREE;
- else if(flag_h2_key[0]==1'b1)
- state <= IDLE;
- else
- state <= TWO;
- THREE: if(flag_h1_key[1]==1'b1)
- state <= ONE;
- else if(flag_h1_key[2]==1'b1)
- state <= TWO;
- else if(flag_h2_key[0]==1'b1)
- state <= IDLE;
- else
- state <= THREE;
- default:state <=IDLE;
- endcase
- end
-
- /* 描述状态IDLE和SETTING的输出 */
- always@(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)begin
- en <= 1'b0;
- time_en <= 1'b0;
- count1 <=1'b0;
- end
- else if(state <= IDLE) begin //相当于确认按键,按下以后使能信号有效,时钟继续运行
- en <= 1'b1;
- time_en <= 1'b0;
- end
- else if(state <= SETTING)begin
- en <= 1'b0;
- time_en <= 1'b1;
- count1 <= 1'b1;
- end
- else if(flag_h2_key[0]==1'b1)
- count1 <= 1'b0;
- else begin
- en <= en;
- end
- end
- /* 描述ONE状态的输出 */
- always@(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)begin
- Sec <= 7'd57;
- end
- else if(state==SETTING && count1 ==1'b0)begin
- Sec <= Sec_out;
- end
- else if (state == ONE && flag_h3_key[0] == 1'b1 && Sec < 59)
- Sec <=Sec + 1'b1;
- else if (state == ONE && flag_h3_key[1] == 1'b1 && Sec >0)
- Sec <=Sec - 1'b1;
- else if(state == ONE && flag_h3_key[0] == 1'b1 && Sec == 7'd59)
- Sec<= 7'd0;
- else if(state == ONE && flag_h3_key[1] == 1'b1 && Sec == 7'd0)
- Sec<=7'd59;
- else
- Sec <=Sec;
- end
-
- /* 描述TWO状态的输出 */
- always@(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)begin
- Min <= 7'd46;
- end
- else if(state==SETTING && count1 ==1'b0)begin
- Min <= Min_out;
- end
- else if (state == TWO && flag_h3_key[0] == 1'b1 && Min < 59)
- Min <= Min + 1'b1;
- else if (state == TWO && flag_h3_key[1] == 1'b1 && Min >0)
- Min <= Min - 1'b1;
- else if(state == TWO && flag_h3_key[0] == 1'b1 && Min == 7'd59)
- Min<= 7'd0;
- else if(state == TWO && flag_h3_key[1] == 1'b1 && Min == 7'd0)
- Min<=7'd59;
- else
- Min <= Min;
- end
- /* 描述THREE状态的输出 */
- always@(posedge clk or negedge rst_n)
- begin
- if(rst_n==1'b0)begin
- Hour<= 7'd12;
- end
- else if(state==SETTING && count1 ==1'b0)begin
- Hour <= Hour_out;
- end
- else if (state == THREE && flag_h3_key[0] == 1'b1 && Hour < 7'd23)
- Hour <=Hour + 1'b1;
- else if (state == THREE && flag_h3_key[1] == 1'b1 && Hour > 7'd0)
- Hour <=Hour - 1'b1;
- else if(state == THREE && flag_h3_key[0] == 1'b1 && Hour == 7'd23)
- Hour<= 7'd0;
- else if(state == THREE && flag_h3_key[1] == 1'b1 && Hour == 7'd0)
- Hour<=7'd23;
- else
- Hour <=Hour;
- end
-
- endmodule

代码如下:
- module seg_dynamic
- (
- input wire clk,
- input wire rst_n,
- input wire [4:0] Sec1, //秒的个位
- input wire [4:0] Sec2, //秒的十位
- input wire [4:0] Min1, //分的个位
- input wire [4:0] Min2, //分的十位
- input wire [4:0] Hour1, //时的个位
- input wire [4:0] Hour2, //时的十位
- output reg [5:0] sel , //数码管位选信号
- output reg [7:0] seg //数码管段选信号
- );
- //十六进制数显示编码
- parameter
- SEG_0 = 8'b1100_0000,
- SEG_1 = 8'b1111_1001,
- SEG_2 = 8'b1010_0100,
- SEG_3 = 8'b1011_0000,
- SEG_4 = 8'b1001_1001,
- SEG_5 = 8'b1001_0010,
- SEG_6 = 8'b1000_0010,
- SEG_7 = 8'b1111_1000,
- SEG_8 = 8'b1000_0000,
- SEG_9 = 8'b1001_0000,
- SEG_A = 8'b1000_1000, SEG_B = 8'b1000_0011,
- SEG_C = 8'b1100_0110, SEG_D = 8'b1010_0001,
- SEG_E = 8'b1000_0110, SEG_F = 8'b1000_1110;
- parameter IDLE = 8'b1111_1111; //不显示状态
- //reg define
- reg [23:0] data_reg ; //待显示数据寄存器
- reg [15:0] cnt_1ms ; //1ms计数器
- reg flag_1ms ; //1ms标志信号
- reg [2:0] cnt_sel ; //数码管位选计数器
- reg [5:0] sel_reg ; //位选信号
- reg [3:0] data_disp ; //当前数码管显示的数据
- parameter CNT_MAX = 16'd49_999; //数码管刷新时间计数最大值
-
- reg [7:0] led_SG ; //秒的个位
- reg [7:0] led_SS ; //秒的十位
- reg [7:0] led_MG ; //分的个位
- reg [7:0] led_MS ; //分的十位
- reg [7:0] led_HG ; //时的个位
- reg [7:0] led_HS ; //时的十位
-
- /****************************************************
- *****************数码管段选信号**********************
- ******************************************************/
-
- //七段数码管显示秒的个位
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)
- led_SG<=IDLE;
- else begin
- case(Sec1)
- 0: led_SG<=SEG_0;
- 1: led_SG<=SEG_1;
- 2: led_SG<=SEG_2;
- 3: led_SG<=SEG_3;
- 4: led_SG<=SEG_4;
- 5: led_SG<=SEG_5;
- 6: led_SG<=SEG_6;
- 7: led_SG<=SEG_7;
- 8: led_SG<=SEG_8;
- 9: led_SG<=SEG_9;
- default led_SG<=IDLE;
- endcase
- end
- end
- //七段数码管显示秒的十位
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)
- led_SS<=IDLE;
- else begin
- case(Sec2)
- 0: led_SS<=SEG_0;
- 1: led_SS<=SEG_1;
- 2: led_SS<=SEG_2;
- 3: led_SS<=SEG_3;
- 4: led_SS<=SEG_4;
- 5: led_SS<=SEG_5;
- 6: led_SS<=SEG_6;
- 7: led_SS<=SEG_7;
- 8: led_SS<=SEG_8;
- 9: led_SS<=SEG_9;
- default led_SS<=IDLE;
- endcase
- end
- end
-
- //七段数码管显示分的个位
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)
- led_MG<=IDLE;
- else begin
- case(Min1)
- 0: led_MG<=8'b0100_0000;
- 1: led_MG<=8'b0111_1001;
- 2: led_MG<=8'b0010_0100;
- 3: led_MG<=8'b0011_0000;
- 4: led_MG<=8'b0001_1001;
- 5: led_MG<=8'b0001_0010;
- 6: led_MG<=8'b0000_0010;
- 7: led_MG<=8'b0111_1000;
- 8: led_MG<=8'b0000_0000;
- 9: led_MG<=8'b0001_0000;
- default led_MG<=8'b0111_1111;
- endcase
- end
- end
-
- //七段数码管显示分的十位
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)
- led_MS<=IDLE;
- else begin
- case(Min2)
- 0: led_MS<=SEG_0;
- 1: led_MS<=SEG_1;
- 2: led_MS<=SEG_2;
- 3: led_MS<=SEG_3;
- 4: led_MS<=SEG_4;
- 5: led_MS<=SEG_5;
- 6: led_MS<=SEG_6;
- 7: led_MS<=SEG_7;
- 8: led_MS<=SEG_8;
- 9: led_MS<=SEG_9;
- default led_MS<=IDLE;
- endcase
- end
- end
- //七段数码管显示时的个位
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)
- led_HG <= IDLE;
- else begin
- case(Hour1)
- 0: led_HG <= 8'b0100_0000;
- 1: led_HG <= 8'b0111_1001;
- 2: led_HG <= 8'b0010_0100;
- 3: led_HG <= 8'b0011_0000;
- 4: led_HG <= 8'b0001_1001;
- 5: led_HG <= 8'b0001_0010;
- 6: led_HG <= 8'b0000_0010;
- 7: led_HG <= 8'b0111_1000;
- 8: led_HG <= 8'b0000_0000;
- 9: led_HG <= 8'b0001_0000;
- default led_HG <= 8'b0111_1111;
- endcase
- end
- end
- //七段数码管显示时的十位
- always @(posedge clk or negedge rst_n)begin
- if(rst_n==1'b0)
- led_HS<=IDLE;
- else begin
- case(Hour2)
- 0: led_HS<=SEG_0;
- 1: led_HS<=SEG_1;
- 2: led_HS<=SEG_2;
- 3: led_HS<=SEG_3;
- // 4: led_HS<=SEG_4;
- // 5: led_HS<=SEG_5;
- // 6: led_HS<=SEG_6;
- // 7: led_HS<=SEG_7;
- // 8: led_HS<=SEG_8;
- // 9: led_HS<=SEG_9;
- default led_HS<=IDLE;
- endcase
- end
- end
-
-
-
- /****************************************************
- *****************数码管位选信号**********************
- ******************************************************/
-
-
- //cnt_1ms:1ms循环计数
- always@(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- cnt_1ms <= 16'd0;
- else if(cnt_1ms == CNT_MAX)
- cnt_1ms <= 16'd0;
- else
- cnt_1ms <= cnt_1ms + 1'b1;
- //flag_1ms:1ms标志信号
- always@(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- flag_1ms <= 1'b0;
- else if(cnt_1ms == CNT_MAX - 1'b1)
- flag_1ms <= 1'b1;
- else
- flag_1ms <= 1'b0;
-
- //cnt_sel:从0到5循环数,用于选择当前显示的数码管
- always@(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- cnt_sel <= 3'd0;
- else if((cnt_sel == 3'd5) && (flag_1ms == 1'b1))
- cnt_sel <= 3'd0;
- else if(flag_1ms == 1'b1)
- cnt_sel <= cnt_sel + 1'b1;
- else
- cnt_sel <= cnt_sel;
-
- //数码管位选信号寄存器
- always@(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- sel_reg <= 6'b000_000;
- else if((cnt_sel == 3'd0) && (flag_1ms == 1'b1))
- sel_reg <= 6'b000_001;
- else if(flag_1ms == 1'b1)
- sel_reg <= sel_reg << 1;
- else
- sel_reg <= sel_reg;
- //控制数码管的位选信号,使六个数码管轮流显示
- always@(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- seg <= 8'hff;
- else if( flag_1ms == 1'b1)
- case(cnt_sel)
- 3'd0: seg <= led_HS; //给第6个数码管赋十万位值
- 3'd1: seg <= led_HG; //给第5个数码管赋万位值
- 3'd2: seg <= led_MS; //给第4个数码管赋千位值
- 3'd3: seg <= led_MG ; //给第3个数码管赋百位值
- 3'd4: seg <= led_SS ; //给第2个数码管赋十位值
- 3'd5: seg <= led_SG ; //给第1个数码管赋个位值
- default:seg <= 8'hff;
- endcase
- else
- seg <= seg;
-
- //sel:数码管位选信号赋值
- always@(posedge clk or negedge rst_n)
- if(rst_n == 1'b0)
- sel <= 6'b111_111;
- else
- sel <= ~sel_reg;
-
- endmodule

buzzer==0响否则=1不响,歌曲放了两首,都能使用,自行选择,但意义不大。
代码如下:
-
- module buzzer(
- input wire clk , //系统时钟50MHz
- input wire rst_n ,
- input wire [6:0] Sec_out ,
- input wire [6:0] Min_out ,
- // input wire Min1 ,
- // input wire Min2 ,
- output reg buzzer //蜂鸣器输出端
-
- );
- // assign buzzer =( Sec_out==1'b0 && Min_out==1'b0 )?0:1; //只响一秒钟
-
-
- /**********--------------森林狂想曲-----------------************************/
- //模块名称song
- reg beep_r; //寄存器
- reg[7:0] state; //乐谱状态机
- reg[16:0]count,count_end;
- reg[23:0]count1;
-
- //乐谱参数:D=F/2K (D:参数,F:时钟频率,K:音高频率)
- parameter L_3 = 17'd75850, //低音3
- L_5 = 17'd63776, //低音5
- L_6 = 17'd56818, //低音6
- L_7 = 17'd50618, //低音7
- M_1 = 17'd47774, //中音1
- M_2 = 17'd42568, //中音2
- M_3 = 17'd37919, //中音3
- M_5 = 17'd31888, //中音5
- M_6 = 17'd28409, //中音6
- H_1 = 17'd23889; //高音1
- parameter TIME = 12000000; //控制每一个音的长短(250ms)
- // assign buzzer = beep_r; //输出音乐
-
- //★★★以下两个时序逻辑模块较为重点关注
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)begin
- buzzer <= 1'b1;
- end
- else if(Min_out==1'b0 && Sec_out<=7'd3) //整点报时并3s后停止
- buzzer <= beep_r;
- else
- buzzer <=1'b1;
- end
-
-
- always@(posedge clk) begin
- count <= count + 1'b1; //计数器加1
- if(count == count_end) begin
- count <= 17'h0; //计数器清零
- beep_r <= !beep_r; //输出取反
- end
- end
-
- //曲谱 产生分频的系数并描述出曲谱
- always @(posedge clk) begin
- if(count1 < TIME) //一个节拍250mS
- count1 = count1 + 1'b1;
- else begin
- count1 = 24'd0;
- if(state == 8'd63)
- state = 8'd0;
- else
- state = state + 1'b1;
- case(state)
- 8'd0:count_end = L_6;
- 8'd1:count_end=M_1;
- 8'd2:count_end=M_3;
- 8'D3:count_end=M_5;
- 8'D4,8'D5:count_end=M_3;
- 8'D6:count_end=M_3;
- 8'D7:count_end=M_2;
-
- 8'D8,8'D9:count_end=M_3;
- 8'D10:count_end=M_3;
- 8'D11:count_end=M_2;
- 8'D12,8'D13:count_end=M_3;
- 8'D14:count_end=L_6;
- 8'D15:count_end=L_7;
-
- 8'D16:count_end=M_1;
- 8'D17:count_end=M_3;
- 8'D18:count_end=M_2;
- 8'D19:count_end=M_1;
- 8'D20,8'D21:count_end=L_6;
- 8'D22,8'D23:count_end=L_5;
-
- 8'D24,8'D25,8'D26,8'D27,8'D28,8'D29,8'D30,8'D31:count_end=L_3;
-
- 8'd32:count_end = L_6;
- 8'd33:count_end=M_1;
- 8'd34:count_end=M_3;
- 8'D35:count_end=M_5;
- 8'D36,8'D37:count_end=M_3;
- 8'D38:count_end=M_3;
- 8'D39:count_end=M_2;
-
- 8'D40,8'D41:count_end=M_3;
- 8'D42:count_end=M_3;
- 8'D43:count_end=M_2;
- 8'D44,8'D45:count_end=M_3;
- 8'D46:count_end=L_6;
- 8'D47:count_end=L_7;
-
- 8'D48:count_end=M_1;
- 8'D49:count_end=M_3;
- 8'D50:count_end=M_2;
- 8'D51:count_end=M_1;
- 8'D52,8'D53:count_end=L_6;
- 8'D54,8'D55:count_end=L_5;
-
- 8'D56,8'D57,8'D58,8'D59,8'D60,8'D61:count_end=L_6;
- 8'D62:count_end=L_6;
- 8'D63:count_end=L_7;
- default: count_end = 16'h0;
- endcase
- end
- end
-
-
- /************************************************************************
- -------------------------两只老虎----------------------------------------
-
- //中间信号定义
- reg [16:0] cnt0 ; //产生PWM的计数器
- wire add_cnt0;
- wire end_cnt0;
-
- reg [7:0] cnt1 ; //每个音符持续时间的计数器
- wire add_cnt1;
- wire end_cnt1;
-
- reg [5:0] cnt2 ; //《两只老虎》共32个音节
- wire add_cnt2;
- wire end_cnt2;
-
- reg [16:0] pre_set ; //存放每个音节的频率在系统中的时钟个数
-
- //每个音符对应的系统周期计数,中音
- localparam M1=95602, //音符1do
- M2=85178, //音符rui
- M3=75872, //音符mi
- M4=71633, //音符fa
- M5=63775, //音符so
- M6=56818, //音符la
- M7=50607; //音符xi
-
- //每个音符对应的系统周期计数,低音音符so,频率392
- //周期是1/392s,换算成ns是2551020ns,每个
- //系统时钟周期是20ns,所以上述是2551020/20个系统周期个数127,551
- localparam D5=127551; //音符so,低音
-
-
- //每个音节的频率在系统时钟周期下对应的系统周期个数
- //--------------------------------------------
- //比如:音符1的频率是523HZ,它的周期是1/523s,换算成ns是1912045ns,每个
- //系统时钟周期是20ns,所以上述是1912045/20个系统周期个数,即cnt0的计数
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt0<=0;
- end
- else if(add_cnt0)begin
- if(end_cnt0)
- cnt0<=0;
- else
- cnt0<=cnt0+1;
- end
- end
- assign add_cnt0=1'b1;
- assign end_cnt0=add_cnt0 && cnt0==pre_set-1;
- // assign buzzer=(cnt0>=(pre_set/2) && Min_out==1'b0)?1:0; //每个音符的占空比为50%
-
- //每个音符持续一段时间
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)begin
- buzzer <= 1'b1;
- end
- else if(cnt0>=(pre_set/2) && Min_out==1'b0 && Sec_out<=7'd3)
- buzzer <= 1'b0;
- else
- buzzer <=1'b1;
- end
- //每个音符持续一段时间
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt1<=0;
- end
- else if(add_cnt1)begin
- if(end_cnt1)
- cnt1<=0;
- else
- cnt1<=cnt1+1;
- end
- end
- assign add_cnt1=end_cnt0;
- assign end_cnt1=add_cnt1 && cnt1==150-1;
- //计32个音符(两只老虎共32音节)
- always @(posedge clk or negedge rst_n)begin
- if(!rst_n)begin
- cnt2<=0;
- end
- else if(add_cnt2)begin
- if(end_cnt2)
- cnt2<=0;
- else
- cnt2<=cnt2+1;
- end
- end
- assign add_cnt2=end_cnt1;
- assign end_cnt2=add_cnt2 && cnt2==32-1;
- //存放歌曲的简谱
- always @(posedge clk or negedge rst_n)
- begin
- if(!rst_n)begin
- pre_set<=0;
- end
- else begin
- case(cnt2)
- 0:pre_set<=M1;
- 1:pre_set<=M2;
- 2:pre_set<=M3;
- 3:pre_set<=M1;
- 4:pre_set<=M1;
- 5:pre_set<=M2;
- 6:pre_set<=M3;
- 7:pre_set<=M1;
- 8:pre_set<=M3;
- 9:pre_set<=M4;
- 10:pre_set<=M5;
- 11:pre_set<=M3;
- 12:pre_set<=M4;
- 13:pre_set<=M5;
- 14:pre_set<=M5;
- 15:pre_set<=M6;
- 16:pre_set<=M5;
- 17:pre_set<=M4;
- 18:pre_set<=M3;
- 19:pre_set<=M1;
- 20:pre_set<=M5;
- 21:pre_set<=M6;
- 22:pre_set<=M5;
- 23:pre_set<=M4;
- 24:pre_set<=M3;
- 25:pre_set<=M1;
- 26:pre_set<=M2;
- 27:pre_set<=D5;
- 28:pre_set<=M1;
- 29:pre_set<=M2;
- 30:pre_set<=D5;
- 31:pre_set<=M1;
- default:pre_set<=0;
- endcase
- end
- end
- */
- endmodule
-

对于以上各个模块内,进行了非常清晰的层次化设计,大部分都有了较为详细的标注,并通过了基础测试验证。从顶层文件开始,对照各个参数寄存器等依次往下进行理解比较,最后得出自己的设计结果。
对于各个引脚配置如下:
对于引脚的配置,可直接将如下配置直接复制到EDA_clock.qsf文件中,然后进行综合即可直接配置完成。
set_location_assignment PIN_E1 -to sys_clk set_location_assignment PIN_N13 -to rst_n set_location_assignment PIN_R14 -to seg[0] set_location_assignment PIN_N9 -to sel[0] set_location_assignment PIN_P9 -to sel[1] set_location_assignment PIN_M10 -to sel[2] set_location_assignment PIN_N11 -to sel[3] set_location_assignment PIN_P11 -to sel[4] set_location_assignment PIN_M11 -to sel[5] set_location_assignment PIN_N16 -to seg[1] set_location_assignment PIN_P16 -to seg[2] set_location_assignment PIN_T15 -to seg[3] set_location_assignment PIN_P15 -to seg[4] set_location_assignment PIN_N12 -to seg[5] set_location_assignment PIN_N15 -to seg[6] set_location_assignment PIN_R16 -to seg[7] set_location_assignment PIN_B5 -to key_in_y[3] set_location_assignment PIN_A4 -to key_in_y[2] set_location_assignment PIN_B4 -to key_in_y[1] set_location_assignment PIN_A3 -to key_in_y[0] set_location_assignment PIN_B3 -to key_out_x[3] set_location_assignment PIN_A2 -to key_out_x[2] set_location_assignment PIN_B1 -to key_out_x[1] set_location_assignment PIN_C2 -to key_out_x[0] set_location_assignment PIN_C11 -to buzzer
运行成功:
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。