目录
一、设计规格
1. 功能特性
(1)12小时制(1-12)的计数功能,在12:59:59时置数回01:00:00,并翻转AM/PM信号;
(2)AM/PM显示功能,0(灭灯)表示AM,1(亮灯)表示PM;
(3)数字钟复位功能,当复位后显示为01:00:00,状态为AM;
(4)数码管显示功能,只显示数字,不显示标点。
2. 硬件平台
该数字钟的实现平台是黑金(Alinx)的 Altera AX301B 开发板,如图1所示。该开发板采用的是Cyclone IV系列的芯片,具体型号为EP4CE6F17C8。AX301B搭载有源晶振,频率为50MHz。

图1 AX301B开发板
3. 数码管
AX301B使用的是共阳极八段数码管,其段结构如图2所示。对于共阳极数码管,其为低电平有效(当某段控制数据为低电平(0)时,对应字段亮起;反之,当某段控制数据为高电平(1)时,对应字段不亮)。

图2 八段数码管的段结构
4. 按键
AX301B拥有4个按键,分别为1个复位按键(RESET)和3个通用按键(KEY1~KEY3),其原理图如图3所示。可以看出,当按键松开时,为3.3V电源输入;而当按键按下时,导线接地。所以4个按键在松开状态下为高电平(1),在按压状态下为低电平(0)。

图3 按键的原理图
5. LED灯
AX301B拥有4个红色LED灯,其原理图如图4所示。可以看出,该结构为一个电阻和一个LED灯串联接地,当输出高电平时LED灯亮起,故4个LED灯为高电平有效。

图4 LED灯的原理图
二、设计划分
1. 设计分析
我们采用自顶向下的设计思路,将数字钟电路拆解成若干个小模块进行设计,然后再从顶层模块中进行例化实现上述功能。
(1)分钟和秒钟均为60进制,而4位二进制码是按16进制实现的,所以这里拆分成模10计数模块和模6计数模块两个模块来设计;
(2)由于时钟位比较特别,置数时需同时参考个位片与十位片的值,所以时钟位统计进行设计。时钟位满足12进制,设计为模12计数模块;
(3)AM/PM显示功能的设计也需要同时参考时钟个位片与十位片的值,故一同在模12计数模块中进行实现;
(4)复位功能在以上三个模块中均进行设计;
(5)数码管显示功能分为两部分:译码模块负责将上述模块输出的二进制码转换为对应的段控制码,以便能在数码管进行显示;数码管扫描显示模块负责顺序扫描每个数码管,并将段控制码输出到对应的数码管中。
综上,设计思路是将数字钟拆分为了5个部分:模10计数模块、模6计数模块、模12计数模块、译码模块、数码管扫描显示模块。
2. 模块设计细节
2.1 模10计数模块:充当个位片
该模块具有异步复位、使能计数、进位输出功能,计数范围0-9,并在等于9时进位。
表1 模10计数模块的信号
| 信号名称 | 方向 | 宽度(bit) | 说明 |
| clk | in | 1 | 系统时钟,50MHz |
| rst_n | in | 1 | 异步复位,低电平有效 |
| en | in | 1 | 计数使能 |
| q | out | 4 | 数据输出,范围0-9 |
| co | out | 1 | 进位输出,q等于9时置高 |
2.2 模6计数模块:充当十位片
该模块具有异步复位、使能计数、进位输出功能,计数范围0-5,并在等于5时进位。
表2 模6计数模块的信号
| 信号名称 | 方向 | 宽度(bit) | 说明 |
| clk | in | 1 | 系统时钟,50MHz |
| rst_n | in | 1 | 异步复位,低电平有效 |
| en | in | 1 | 计数使能 |
| q | out | 4 | 数据输出,范围0-5 |
| co | out | 1 | 进位输出,q等于5时置高 |
2.3 模12计数模块:充当小时的个位片与十位片,并带有AM/PM转换功能
该模块具有异步复位、同步置数、使能计数、进位输出功能。计数范围1-12,当等于12时复位为1,并对pm信号进行翻转。
表3 模12计数模块的信号
| 信号名称 | 方向 | 宽度(bit) | 说明 |
| clk | in | 1 | 系统时钟,50MHz |
| rst_n | in | 1 | 异步复位,低电平有效 |
| en | in | 1 | 计数使能 |
| q1 | out | 4 | 个位数据输出,范围0-9,在q2q1等于12时置数回1 |
| q2 | out | 4 | 十位数据输出,范围0-1,在q2q1等于12时置数回0 |
| pm | out | 1 | AM/PM信号,0表示AM,1表示PM |
2.4 译码模块
该模块的功能是将二进制码转换为对应的数码管段控制信号。
表4 译码模块的信号
| 信号名称 | 方向 | 宽度(bit) | 说明 |
| bin_data | in | 4 | 二进制数据,范围0-9 |
| seg_data | out | 8 | 共阳极数码管的段控制数据,共8段 |
表5 各数字和字符对应的段控制数据
| 字符 | 段控制码(1gfe_dcba) |
| 0 | 1100_0000 |
| 1 | 1111_1001 |
| 2 | 1010_0100 |
| 3 | 1011_0000 |
| 4 | 1001_1001 |
| 5 | 1001_0010 |
| 6 | 1000_0010 |
| 7 | 1111_1000 |
| 8 | 1000_0000 |
| 9 | 1001_0000 |
| a | 1000_1000 |
| b | 1000_0011 |
| c | 1100_0110 |
| d | 1010_0001 |
| e | 1000_0110 |
| f | 1000_1110 |
2.5 数码管扫描显示模块
该模块的功能是将多位数码管的段控制信号分别输出。
表6 数码管扫描显示模块的参数
| 参考名称 | 类型 | 说明 |
| CLK_FRE | parameter | 系统时钟频率,50MHz |
| SCAN_FRE | parameter | 单个数码管的扫描频率 |
| SCAN_CNT | parameter | 单次扫描的计数值 |
表7 数码管扫描显示模块的信号
| 信号名称 | 方向 | 宽度(bit) | 说明 |
| clk | in | 1 | 系统时钟,50MHz |
| rst_n | in | 1 | 异步复位,低电平有效 |
| data_0 | in | 8 | 第1位数码管的段控制信号,低电平亮 |
| data_1 | in | 8 | 第2位数码管的段控制信号,低电平亮 |
| data_2 | in | 8 | 第3位数码管的段控制信号,低电平亮 |
| data_3 | in | 8 | 第4位数码管的段控制信号,低电平亮 |
| data_4 | in | 8 | 第5位数码管的段控制信号,低电平亮 |
| data_5 | in | 8 | 第6位数码管的段控制信号,低电平亮 |
| seg_sel | out | 6 | 数码管选择信号,低电平有效 |
| seg_data | out | 8 | 数码管段控制信号,低电平亮 |
2.6 顶层模块
该模块的功能是例化前5个模块,以实现12小时制数字钟的功能。
表8 顶层模块的信号
| 信号名称 | 方向 | 宽度(bit) | 说明 |
| clk | in | 1 | 系统时钟,50MHz |
| rst_n | in | 1 | 异步复位,低电平有效 |
| seg_sel | out | 6 | 数码管选择信号,低电平有效 |
| seg_data | out | 8 | 数码管段控制信号,低电平亮 |
三、设计输入(代码)
1. 模10计数模块
module counter_10 (
// input
input clk, // 系统时钟,50MHz
input rst_n, // 系统复位,低电平有效
input en, // 使能信号
// output
output reg [3:0] q, // 数据输出
output reg co // 进位输出
);
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
co <= 1'b0;
q <= 4'd8; // 8用作测试,默认复位应设为0
end else if (en == 1'b1) begin
if (q == 4'd9) begin
co <= 1'b1;
q <= 4'd0;
end else begin
co <= 1'b0;
q <= q + 4'd1;
end
end else begin
co <= 1'b0;
end
end
endmodule
2. 模6计数模块
module counter_6 (
// input
input clk, // 系统时钟,50MHz
input rst_n, // 系统复位,低电平有效
input en, // 使能信号
// output
output reg [3:0] q, // 数据输出
output reg co // 进位输出
);
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
co <= 1'b0;
q <= 4'd5; // 5用作测试,默认复位应设为0
end else if (en == 1'b1) begin
if (q == 4'd5) begin
co <= 1'b1;
q <= 4'd0;
end else begin
co <= 1'b0;
q <= q + 4'd1;
end
end else begin
co <= 1'b0;
end
end
endmodule
3. 模12计数模块
module counter_12 (
// input
input clk, // 系统时钟,50MHz
input rst_n, // 系统复位,低电平有效
input en, // 使能信号
// output
output reg [3:0] q1, // 时钟 个位输出
output reg [3:0] q2, // 时钟 十位输出
output reg pm // AM/PM信号,0:AM,1:PM
);
// reg
reg co_hho; // 时钟个位 进位输出
// 时钟个位片
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
co_hho <= 1'b0;
q1 <= 4'd2; // 2用作测试,默认复位应设为1
end else if (en == 1'b1) begin
if ( q2 == 4'd1 && q1 == 4'd2 ) begin // 置数
co_hho <= 1'b0;
q1 <= 4'd1;
end else if (q1 == 4'd9) begin
co_hho <= 1'b1;
q1 <= 4'd0;
end else begin
co_hho <= 1'b0;
q1 <= q1 + 4'd1;
end
end else begin
co_hho <= 1'b0;
end
end
// 时钟十位片
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
q2 <= 4'd1; // 1用作测试,默认复位应设为0
end else if (en == 1'b1) begin
if ( q2 == 4'd1 && q1 == 4'd2 ) begin // 置数
q2 <= 4'd0;
end
end else if (co_hho == 1'b1) begin
q2 <= q2 + 4'd1;
end
end
// AM/PM信号
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
pm <= 1'b0;
end else if (en == 1'b1) begin
if ( q2 == 4'd1 && q1 == 4'd2 ) begin
pm <= ~pm;
end
end
end
endmodule
4. 译码模块
module seg_decoder (
// input
input [3:0] bin_data, // 二进制数据
// output
output reg [7:0] seg_data // 段控制数据
);
always @(*) begin
case (bin_data)
4'h0: seg_data = 8'b1100_0000; // 0
4'h1: seg_data = 8'b1111_1001; // 1
4'h2: seg_data = 8'b1010_0100; // 2
4'h3: seg_data = 8'b1011_0000; // 3
4'h4: seg_data = 8'b1001_1001; // 4
4'h5: seg_data = 8'b1001_0010; // 5
4'h6: seg_data = 8'b1000_0010; // 6
4'h7: seg_data = 8'b1111_1000; // 7
4'h8: seg_data = 8'b1000_0000; // 8
4'h9: seg_data = 8'b1001_0000; // 9
4'ha: seg_data = 8'b1000_1000;
4'hb: seg_data = 8'b1000_0011;
4'hc: seg_data = 8'b1100_0110;
4'hd: seg_data = 8'b1010_0001;
4'he: seg_data = 8'b1000_0110;
4'hf: seg_data = 8'b1000_1110;
default: seg_data = 8'hff; // 关闭
endcase
end
endmodule
5. 数码管扫描显示模块
module seg_scan
#(
// parameter
parameter CLK_FRE = 50_000_000, // 系统时钟频率
parameter SCAN_FRE = 200, // 单个数码管的扫描频率
parameter SCAN_CNT = CLK_FRE / (SCAN_FRE * 6) - 1 // 扫描计数值
)
(
// input
input clk, // 系统时钟,50MHz
input rst_n, // 系统复位,低电平有效
// 6个数码管的段控制数据
input [7:0] data_0,
input [7:0] data_1,
input [7:0] data_2,
input [7:0] data_3,
input [7:0] data_4,
input [7:0] data_5,
// output
output reg [5:0] seg_sel, // 数码管选择信号
output reg [7:0] seg_data // 段控制数据
);
// reg
reg [31:0] time_cnt; // 周期计数器
reg [3:0] scan_sel; // 数码管选择标志
// 设置 scan_sel
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
time_cnt <= 32'd0;
scan_sel <= 4'd0;
end else if (time_cnt == SCAN_CNT) begin
time_cnt <= 32'd0;
if (scan_sel == 4'd5) begin
scan_sel <= 4'd0;
end else begin
scan_sel <= scan_sel + 4'd1;
end
end else begin
time_cnt <= time_cnt + 32'd1;
end
end
// 数码管扫描显示
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
seg_sel <= 6'h3f;
seg_data <= 8'hff;
end else begin
case (scan_sel) // 根据scan_sel的值来选择显示对应的数码管
4'd0: begin
seg_sel <= 6'b011_111; // 右1管
seg_data <= data_0;
end
4'd1: begin
seg_sel <= 6'b101_111; // 右2管
seg_data <= data_1;
end
4'd2: begin
seg_sel <= 6'b110_111; // 右3管
seg_data <= data_2;
end
4'd3: begin
seg_sel <= 6'b111_011; // 右4管
seg_data <= data_3;
end
4'd4: begin
seg_sel <= 6'b111_101; // 右5管
seg_data <= data_4;
end
4'd5: begin
seg_sel <= 6'b111_110; // 右6管
seg_data <= data_5;
end
default: begin
seg_sel <= 6'h3f;
seg_data <= 8'hff;
end
endcase
end
end
endmodule
6. 顶层模块
module digital_clock (
// input
input clk, // 系统时钟,50MHz
input rst_n, // 系统复位,低电平有效
// output
output [5:0] seg_sel, // 数码管选择信号
output [7:0] seg_data, // 段控制数据
output pm // AM/PM信号,0:AM,1:PM
);
// -------------------- Variables -------------------------------
// reg
reg en_1hz; // 1Hz使能信号
reg [31:0] timer_cnt; // 周期计数器
// -------------------- Code ------------------------------------
// 设置 en_1hz
always @(posedge clk, negedge rst_n) begin
if (rst_n == 1'b0) begin
en_1hz <= 1'b0;
timer_cnt <= 32'd0;
end else if (timer_cnt == 32'd49_999_999) begin
en_1hz <= 1'b1;
timer_cnt <= 32'd0;
end else begin
en_1hz <= 1'b0;
timer_cnt <= timer_cnt + 32'd1;
end
end
// -------------------- Instantiate -----------------------------
// (1) 数字钟:
// 二进制数据信号
wire [3:0] b_hht; // hh ten digit
wire [3:0] b_hho; // hh one digit
wire [3:0] b_mmt; // mm ten digit
wire [3:0] b_mmo; // mm one digit
wire [3:0] b_sst; // ss ten digit
wire [3:0] b_sso; // ss one digit
// 进位信号
wire co_mmt;
wire co_mmo;
wire co_sst;
wire co_sso;
counter_12 M4 ( .clk(clk), .rst_n(rst_n), .en(co_mmt), .q1(b_hho), .q2(b_hht), .pm(pm) );
counter_6 M3 ( .clk(clk), .rst_n(rst_n), .en(co_mmo), .q(b_mmt), .co(co_mmt) );
counter_10 M2 ( .clk(clk), .rst_n(rst_n), .en(co_sst), .q(b_mmo), .co(co_mmo) );
counter_6 M1 ( .clk(clk), .rst_n(rst_n), .en(co_sso), .q(b_sst), .co(co_sst) );
counter_10 M0 ( .clk(clk), .rst_n(rst_n), .en(en_1hz), .q(b_sso), .co(co_sso) );
// (2) 译码器:
// 段控制数据
wire [7:0] s_hht;
wire [7:0] s_hho;
wire [7:0] s_mmt;
wire [7:0] s_mmo;
wire [7:0] s_sst;
wire [7:0] s_sso;
seg_decoder M10 ( .bin_data(b_hht), .seg_data(s_hht) );
seg_decoder M9 ( .bin_data(b_hho), .seg_data(s_hho) );
seg_decoder M8 ( .bin_data(b_mmt), .seg_data(s_mmt) );
seg_decoder M7 ( .bin_data(b_mmo), .seg_data(s_mmo) );
seg_decoder M6 ( .bin_data(b_sst), .seg_data(s_sst) );
seg_decoder M5 ( .bin_data(b_sso), .seg_data(s_sso) );
// (3) 数码管扫描显示:
seg_scan M11 (
.clk (clk ),
.rst_n (rst_n ),
.data_5 (s_hht ),
.data_4 (s_hho ),
.data_3 (s_mmt ),
.data_2 (s_mmo ),
.data_1 (s_sst ),
.data_0 (s_sso ),
.seg_sel (seg_sel ),
.seg_data (seg_data )
);
endmodule
四、引脚绑定

五、下载测试
数字钟从12:58:58开始进行测试,此时LED1为熄灭状态,表示当前为AM。

进行到12:59:59,当下一个1Hz使能触发时,数字钟置数回01:00:00,此时LED1为亮起状态,表示当前为PM。

&spm=1001.2101.3001.5002&articleId=134633414&d=1&t=3&u=1726ca493e9b4a1d8f7b9c6d7b93c8b8)
1064

被折叠的 条评论
为什么被折叠?



