开发板:此款开发板使用的是 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秒钟 |
对于以下各个代码块有较为详细的标注,请自行对照理解,有疑惑的可以评论区,看到回复
1. EDA_clock.v
创建工程后,该模块为顶层文件
代码如下:
/**
* @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块中,进行赋值。
***********************************************************/
2. clk1hz.v
将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
3. cnt24.v
代码如下:
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&