*一、设计题目* *数字电子钟Verilog设计*
*二、设计背景* 钟表的数字化给人们生产生活带来了极大的方便,而且大大地扩展了钟表原先的报时功能。诸如定时自动报警、按时自动打铃、时间程序自动控制、定时广播、定时启闭电路、定时开关烘箱、通断动力设备,甚至各种定时电气的自动启用等,所有这些,都是以钟表数字化为基础的。因此,研究数字钟及扩大其应用,有着非常现实的意义。
****三、设计内容及要求****设计内容: 设计一个电子钟,要求可以显示时、分、秒,用户可以设置时间 设计具体包含的模块内容如下:要求:1)根据系统设计要求,采用自顶向下的方法,划分系统主要模块,画出整体设计原理框图。2)根据工作原理、用硬件描述语言对设计内容实现,列出设计程序清单,给出仿真波形图和调试中存在问题及解决方法。3)设计内容下载至目标芯片,在EDA的AX301开发板上进行功能验证。4)谈谈该课题的课程设计中遇到的问题,获得哪些技能和体会,以及建设性意见。
四、****设计步骤和安排****:(1)题目安排;图书馆查相关资料;(2)设计原理研究,总体设计;(3)各主要模块的Verilog HDL设计。各模块的设计仿真分析。 (4) 完成系统顶层文件设计,系统总体功能的仿真分析。 (5) 将设计内容进行硬件配置,在AX301开发板上进行调试。 (6) 撰写课程设计报告、答辩并提交报告。

我的代码:

EDA_DESIGN.v

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
``module EDA_DESIGN(
input clk, // 外部时钟信号
input rst_n, // 复位信号
input set_mode, // 进入/退出设置模式
input increase, // 增加时间
input decrease, // 减少时间
output reg[5:0] seg_sel, // 数码管选择信号
output reg[7:0] seg_data, // 数码管数据
output led1, // LED 1
output led2, // LED 2
output led3, // LED 3
output led4 // LED 4
);

// 时间变量
reg[5:0] hour;
reg[5:0] minute;
reg[5:0] second;

// 中间信号
wire[5:0] hour_tc, minute_tc, second_tc;



// 7段显示变量
wire[6:0] seg_data_0, seg_data_1, seg_data_2, seg_data_3, seg_data_4, seg_data_5;

// 七段扫描模块的输出
wire[5:0] seg_sel_scan;
wire[7:0] seg_data_scan;

// 实例化计时模块
time_counter counter_module(
.clk(clk),
.rst_n(rst_n),
.set_mode(set_mode),
.increase(increase),
.decrease(decrease),
.hour(hour_tc),
.minute(minute_tc),
.second(second_tc),
.led1(led1),
.led2(led2),
.led3(led3),
.led4(led4)
);




// 使用合并的时间信号来控制显示
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
hour <= 6'd0;
minute <= 6'd0;
second <= 6'd0;
end else begin
hour <= hour_tc;
minute <= minute_tc;
second <= second_tc;
end
end




seg_decoder seg_decoder_h0(
.bin_data(hour / 10),
.seg_data(seg_data_0)
);

seg_decoder seg_decoder_h1(
.bin_data(hour % 10),
.seg_data(seg_data_1)
);

seg_decoder seg_decoder_m0(
.bin_data(minute / 10),
.seg_data(seg_data_2)
);

seg_decoder seg_decoder_m1(
.bin_data(minute % 10),
.seg_data(seg_data_3)
);

seg_decoder seg_decoder_s0(
.bin_data(second / 10),
.seg_data(seg_data_4)
);

seg_decoder seg_decoder_s1(
.bin_data(second % 10),
.seg_data(seg_data_5)
);


seg_scan seg_scan_module(
.clk(clk),
.rst_n(rst_n),
.seg_sel(seg_sel_scan),
.seg_data(seg_data_scan),
.seg_data_0({1'b1, seg_data_0}),
.seg_data_1({1'b1, seg_data_1}),
.seg_data_2({1'b1, seg_data_2}),
.seg_data_3({1'b1, seg_data_3}),
.seg_data_4({1'b1, seg_data_4}),
.seg_data_5({1'b1, seg_data_5})
);

// 更新 seg_sel 和 seg_data
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
seg_sel <= 6'b0;
seg_data <= 8'b0;
end else begin
seg_sel <= seg_sel_scan; // 从中间信号更新 seg_sel
seg_data <= seg_data_scan; // 从中间信号更新 seg_data
end
end

endmodule

seg_decoder.v

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
module seg_decoder
(
input[3:0] bin_data, // bin data input
output reg[6:0] seg_data // seven segments LED output
);

always@(*)
begin
case(bin_data)
4'd0:seg_data <= 7'b100_0000;
4'd1:seg_data <= 7'b111_1001;
4'd2:seg_data <= 7'b010_0100;
4'd3:seg_data <= 7'b011_0000;
4'd4:seg_data <= 7'b001_1001;
4'd5:seg_data <= 7'b001_0010;
4'd6:seg_data <= 7'b000_0010;
4'd7:seg_data <= 7'b111_1000;
4'd8:seg_data <= 7'b000_0000;
4'd9:seg_data <= 7'b001_0000;
4'ha:seg_data <= 7'b000_1000;
4'hb:seg_data <= 7'b000_0011;
4'hc:seg_data <= 7'b100_0110;
4'hd:seg_data <= 7'b010_0001;
4'he:seg_data <= 7'b000_0110;
4'hf:seg_data <= 7'b000_1110;
default:seg_data <= 7'b111_1111;
endcase
end
endmodule

seg_scan.v

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
module seg_scan(
input clk,
input rst_n,
output reg[5:0] seg_sel, //digital led chip select
output reg[7:0] seg_data, //eight segment digital tube output,MSB is the decimal point
input[7:0] seg_data_0,
input[7:0] seg_data_1,
input[7:0] seg_data_2,
input[7:0] seg_data_3,
input[7:0] seg_data_4,
input[7:0] seg_data_5
);
parameter SCAN_FREQ = 200; //scan frequency
parameter CLK_FREQ = 50000000; //clock frequency

parameter SCAN_COUNT = CLK_FREQ /(SCAN_FREQ * 6) - 1;

reg[31:0] scan_timer; //scan time counter
reg[3:0] scan_sel; //Scan select counter
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
scan_timer <= 32'd0;
scan_sel <= 4'd0;
end
else if(scan_timer >= SCAN_COUNT)
begin
scan_timer <= 32'd0;
if(scan_sel == 4'd5)
scan_sel <= 4'd0;
else
scan_sel <= scan_sel + 4'd1;
end
else
begin
scan_timer <= scan_timer + 32'd1;
end
end
always@(posedge clk or negedge rst_n)
begin
if(rst_n == 1'b0)
begin
seg_sel <= 6'b111111;
seg_data <= 8'hff;
end
else
begin
case(scan_sel)
//first digital led
4'd0:
begin
seg_sel <= 6'b11_1110;
seg_data <= seg_data_0;
end
//second digital led
4'd1:
begin
seg_sel <= 6'b11_1101;
seg_data <= seg_data_1;
end
//...
4'd2:
begin
seg_sel <= 6'b11_1011;
seg_data <= seg_data_2;
end
4'd3:
begin
seg_sel <= 6'b11_0111;
seg_data <= seg_data_3;
end
4'd4:
begin
seg_sel <= 6'b10_1111;
seg_data <= seg_data_4;
end
4'd5:
begin
seg_sel <= 6'b01_1111;
seg_data <= seg_data_5;
end
default:
begin
seg_sel <= 6'b11_1111;
seg_data <= 8'hff;
end
endcase
end
end

endmodule

time_counter.v

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
module time_counter(
input clk, // 外部提供的时钟信号
input rst_n, // 复位信号
input set_mode, // 进入/退出设置模式
input increase, // 增加当前设置的时间单位
input decrease, // 减少当前设置的时间单位
output reg[5:0] hour, // 小时
output reg[5:0] minute, // 分钟
output reg[5:0] second, // 秒
output reg led1,
output reg led2,
output reg led3,
output reg led4
);

// 定义状态
parameter NORMAL = 2'b00, SET_HOUR = 2'b01, SET_MINUTE = 2'b10, SET_SECOND = 2'b11;
reg[1:0] current_state;

// 定义一个足够大的计数器来存储从上次增加秒数以来的时钟周期数
reg[31:0] counter;
parameter SECOND_TICK = 32'd50_000_000; // 50MHz时钟下每秒的时钟周期数

// 用于防抖动的辅助变量
reg set_mode_prev;
reg increase_prev, decrease_prev;

// 防抖动逻辑:检测按钮的边沿
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
set_mode_prev <= 1'b0;
increase_prev <= 1'b0;
decrease_prev <= 1'b0;
end else begin
set_mode_prev <= set_mode;
increase_prev <= increase;
decrease_prev <= decrease;
end
end

// 边沿检测
wire set_mode_edge = set_mode & ~set_mode_prev;
wire increase_edge = increase & ~increase_prev;
wire decrease_edge = decrease & ~decrease_prev;

// 状态机和时间控制逻辑
always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// 复位逻辑
current_state <= NORMAL;
hour <= 6'd0;
minute <= 6'd0;
second <= 6'd0;
counter <= 32'd0;
// Reset LEDs
end else begin
// 状态机逻辑
if (set_mode_edge) begin
case (current_state)
NORMAL: current_state <= SET_HOUR;
SET_HOUR: current_state <= SET_MINUTE;
SET_MINUTE: current_state <= SET_SECOND;
SET_SECOND: current_state <= NORMAL;
default: current_state <= NORMAL;
endcase
end

// 时间和模式控制逻辑
case (current_state)
NORMAL: begin

if (counter >= SECOND_TICK - 1) begin
// 每秒更新一次
counter <= 32'd0;
if (second < 59) second <= second + 1'b1;
else begin
second <= 6'd0;
if (minute < 59) minute <= minute + 1'b1;
else begin
minute <= 6'd0;
if (hour < 23) hour <= hour + 1'b1;
else hour <= 6'd0;
end
end
end else counter <= counter + 1'b1;
end
SET_HOUR: begin
if (increase_edge && hour < 23) hour <= hour + 1'b1;
else if (decrease_edge && hour > 0) hour <= hour - 1'b1;
end
SET_MINUTE: begin
if (increase_edge && minute < 59) minute <= minute + 1'b1;
else if (decrease_edge && minute > 0) minute <= minute - 1'b1;
end
SET_SECOND: begin
if (increase_edge && second < 59) second <= second + 1'b1;
else if (decrease_edge && second > 0) second <= second - 1'b1;
end
endcase
end
end


always @(posedge clk or negedge rst_n) begin
if (!rst_n) begin
// 所有LED熄灭
led1 <= 1'b0;
led2 <= 1'b0;
led3 <= 1'b0;
led4 <= 1'b0;
end else begin
case (current_state)
NORMAL: begin
led1 <= 1'b0;
led2 <= 1'b0;
led3 <= 1'b0;
led4 <= 1'b0;
end
SET_HOUR: begin
// 使第一个LED闪烁
led1 <= ~led1;
led2 <= 1'b0;
led3 <= 1'b0;
led4 <= 1'b0;
end
SET_MINUTE: begin
led1 <= 1'b0;
// 使第二个LED闪烁
led2 <= ~led2;
led3 <= 1'b0;
led4 <= 1'b0;
end
SET_SECOND: begin
led1 <= 1'b0;
led2 <= 1'b0;
// 使第三个LED闪烁
led3 <= ~led3;
led4 <= 1'b0;
end
endcase
end
end


endmodule

1.前言

钟表的数字化给人们生产生活带来了极大的方便,而且大大地扩展了钟表原先的报时功能。诸如定时自动报警、按时自动打铃、时间程序自动控制、定时广播、定时启闭电路、定时开关烘箱、通断动力设备,甚至各种定时电气的自动启用等,所有这些,都是以钟表数字化为基础的。因此,研究数字钟及扩大其应用,有着非常现实的意义。

2.设计内容

本设计旨在开发一个能够显示时、分、秒的数字电子钟。用户可以通过按钮设置时间,设备通过数码管显示当前时间。项目使用硬件描述语言Verilog进行开发,并在EDA的AX301开发板上进行功能验证。

3.系统的主要功能及使用方法

3.1 功能描述

时间显示:数码管显示当前的时、分、秒。

时间设置:用户可以通过按钮进入设置模式,对时、分、秒进行调整。

自动计时:系统能够自动计算时间的流逝。

3.2 使用方法

设置时间:通过特定按钮进入设置模式,使用增加和减少按钮来调整时间。

查看时间:在正常模式下,数码管显示当前时间。

4.数字电子钟的Verilog设计

4.1设计思想

在本设计中,采用了自顶向下的设计方法。系统由多个模块组成,包括时间计数模块(time_counter.v)、七段解码模块(seg_decoder.v)和数码管扫描模块(seg_scan.v)。每个模块负责特定的功能,通过模块间的相互协作实现整个系统的功能。

4.2设计流程图

4.3模块说明*

4.3.1 计时器

该模块负责计时功能。根据外部时钟信号,维护当前的时、分、秒,并支持设置模式以调整时间。

4.3.2 七段数码管选择器

七段解码模块,负责将二进制时间数据转换为七段显示码,用于数码管显示。

4.3.3 数码管扫描模块

数码管扫描模块,负责控制数码管的显示,实现动态扫描以显示完整的时间信息。

4.3.6 顶层文件