SMART SOPC实验箱多功能数字钟:分频、74160计时与动态扫描
2026/9/18 19:29:49 网站建设 项目流程

简介:这份多功能数字钟实验报告来自南京理工大学EDA(2)课程设计,面向电子信息、电子工程等专业学习数字电路与EDA技术的学生,可用于课程实验报告参考、Quartus II设计流程学习及SMART SOPC实验箱验证对照。报告围绕24小时计时、保持、清零、快速校时校分、整点报时与动态显示等功能展开,完整记录了脉冲发生、计时、清零、校时校分、保持、报时及译码显示等子模块的设计方案、编辑与波形图仿真过程,并说明各模块如何合并为总电路。作者还整理了实验中遇到的问题、解决思路以及收获与感受,对初学者梳理设计脉络、规避常见错误较有借鉴意义。资源包共1个doc文档,约688KB,结构含摘要、目录、设计要求、实验原理、模块电路设计、总电路图与参考文献等章节;目前已有302人浏览学习,适合需要动手完成同类数字钟设计的读者参考。

1. 从一块 SMART SOPC 实验箱说起:多功能数字钟到底练什么

南京理工大学 EDA(2) 实验里,多功能数字钟是很多人第一次把数字逻辑课上的 74160、74151、7447 真正连成系统的地方。Quartus II 7.0 画原理图、仿真波形、再下载到 SMART SOPC 实验箱,这套流程看起来只是做一个 24 小时计时器,但实际卡人的地方往往不是“钟”本身,而是 48MHz 怎么分到 1Hz、模 60 怎么无毛刺回零、动态扫描为什么会有重影。它适合正在做 EDA 课程设计的学生,也适合想借这个题目把分频链、模计数、总线复用和按键防抖串一遍的工程师。下面按我拆这个实验的顺序,从脉冲发生到顶层下载,把能抄的参数和容易翻车的点都摊开。

2. 脉冲发生与计时核心:48MHz 分频链和 74160 模 60/模 24 计数器

2.1 分频链的级联顺序与 74160 置数法

SMART SOPC 实验箱一般只给一个 48MHz 有源晶振,而秒计数器要的是 1Hz。常见做法是先用两片 74160 做 48 分频得到 1MHz,再用三片 74160 级联做 1000 分频得到 1kHz,接着用 D 触发器二分频得到 500Hz,最后再走一遍 1000 分频得到 1Hz。2Hz 用于快速校时校分,可以从 1kHz 继续做 500 分频,也可以从 1MHz 分频得到,具体看实验箱时钟资源和手头芯片。分频链一旦顺序接错,后面计时和报时都会偏。

目标频率来源主要用途分频实现
1MHz48MHz / 48中间时钟两片 74160 置数到 0
1kHz1MHz / 1000动态扫描、报时三片 74160 级联
500Hz1kHz / 2整点报时低音D 触发器二分频
2Hz1kHz / 500 或 1MHz 分频快速校时校分74160 模 500
1Hz1kHz / 1000秒计数三片 74160 级联

用 Verilog 描述 48 分频的等效逻辑,比直接画原理图更容易检查边界:

// 48 分频:计数 0~47,到 47 时下一拍回 0 module div48( input wire clk_48m, input wire rst_n, output reg clk_1m ); reg [5:0] cnt; always @(posedge clk_48m or negedge rst_n) begin if (!rst_n) begin cnt <= 6'd0; clk_1m <= 1'b0; end else if (cnt == 6'd47) begin cnt <= 6'd0; clk_1m <= ~clk_1m; // 每 48 个输入周期翻转一次 end else begin cnt <= cnt + 1'b1; end end endmodule

这里cnt是 6 位,因为 47 需要 6 位二进制;clk_1m在计数到 47 时翻转,保证输出是输入时钟的 48 分频。实际用 74160 时,两片级联成 0~47 计数器,最高位进位输出作为下一级时钟。注意 74160 的置数端LDN是低有效,到 47 时给LDN=0,下一个脉冲把两片同时置 0。如果只接一片,模值会变成 10 或 16,后面全错。

2.2 模 60 计数器:两片 74160 的置数端与毛刺抑制

秒和分都是 0~59,用两片 74160 级联:个位片计 0~9,十位片计 0~5。到 59 时,十位是 5、个位是 9,此时给两片LDN低电平,下一拍整体回 0。原理图里常把高电平信号直接参与置数,但实际芯片引脚有电平偏移,低电平信号如果直接进与门,可能因为毛刺提前置数。我一般会把低有效的输出端先取非,再和有效的高电平一起送进置数逻辑,这样波形干净很多。

状态十位 QD QC QB QA个位 QD QC QB QA置数条件 LDN
58010110001
59010110010
00000000001

行为级 Verilog 可以这样写:

// 模 60 计数器:0~59,进位输出 carry module counter60( input wire clk, input wire rst_n, input wire en, output reg [3:0] ones, output reg [3:0] tens, output reg carry ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin ones <= 4'd0; tens <= 4'd0; carry <= 1'b0; end else if (en) begin if (ones == 4'd9) begin ones <= 4'd0; if (tens == 4'd5) begin tens <= 4'd0; carry <= 1'b1; // 59 到 00 时产生进位 end else begin tens <= tens + 1'b1; carry <= 1'b0; end end else begin ones <= ones + 1'b1; carry <= 1'b0; end end end endmodule

en是计数使能,接 1Hz 时钟或者校分时的 2Hz;carry在 59 到 00 那一拍拉高,正好给下一级分或时计数器当时钟。用 74160 实现时,个位片的RCO接十位片的ENT,十位片到 5 且个位到 9 时组合出LDN=0。仿真波形要重点看 59 之后是不是干净地回到 00,中间不能出现 60 或 6A 之类的瞬态。

2.3 模 24 计数器与进位链

时计数器是 0~23,同样两片 74160:个位 0~9,十位 0~2。到 23 时置 0。注意 23 的十位是 2、个位是 3,不是 24。如果置数逻辑写成十位 2 且个位 4,就会多计一个数。进位链上,秒计数器的carry接分计数器的时钟使能,分计数器的carry接时计数器的时钟使能。这样 23:59:59 之后回到 00:00:00。

module counter24( input wire clk, input wire rst_n, input wire en, output reg [3:0] ones, output reg [3:0] tens ); always @(posedge clk or negedge rst_n) begin if (!rst_n) begin ones <= 4'd0; tens <= 4'd0; end else if (en) begin if (ones == 4'd9) begin ones <= 4'd0; if (tens == 4'd2) tens <= 4'd0; else tens <= tens + 1'b1; end else if (tens == 4'd2 && ones == 4'd3) begin ones <= 4'd0; tens <= 4'd0; end else begin ones <= ones + 1'b1; end end end endmodule

这里把 23 的判断放在ones分支之前,避免 23 时先加一变成 24 再回零。实际原理图里 74160 的置数端是同步还是异步要看具体型号,74160 是同步置数,所以置数信号要在时钟沿之前稳定。仿真时给一个 1Hz 时钟,跑 24 小时太慢,我一般把使能端接 1kHz 快速跑一遍,看进位边界。

2.4 仿真波形与常见错误

Quartus II 7.0 的波形仿真文件里,把clk_48m周期设为 20.833ns,仿真时间至少 2ms 才能看到 1kHz 输出;想看 1Hz 回零,直接把分频链输出clk_1hz接到计时器,仿真时间设到 70s 以上。常见错误有三个:一是 48 分频的输出接错到 1000 分频的时钟端,导致频率除以 48 又除以 1000 变成 1Hz 而不是 1kHz;二是 74160 的CLRN悬空,芯片一直清零,计数器不动;三是置数端直接接低电平信号,仿真出现窄脉冲,计数器偶尔跳两个数。遇到计数跳变,先看置数逻辑有没有取非,再看时钟线上有没有门控毛刺。

3. 清零、校时校分与保持:控制通路里的异步信号和防抖

3.1 异步清零:CLRN 低有效与开关映射

74160 的CLRN是异步清零,低电平有效,不管时钟有没有沿,只要CLRN=0就回零。所以把六个数码管对应的所有 74160 的CLRN并联,接到一个开关RDN上。设计要求RDN=1时清零,但CLRN是低有效,中间必须加一个非门。开关拨到 1,非门输出 0,计数器全清;拨回 0,非门输出 1,正常计时。

RDN 开关非门输出CLRN 电平计时器状态
011正常计时
100时、分、秒全清零
// 异步清零与正常计时的切换 wire clrn_all; assign clrn_all = ~rdn_key; // rdn_key=1 时清零 always @(posedge clk or negedge clrn_all) begin if (!clrn_all) begin ones <= 4'd0; tens <= 4'd0; end else begin // 正常计数逻辑 end end

clrn_all直接进 always 的异步复位端,综合工具会映射到 74160 的CLRN引脚。注意按键抖动会让CLRN产生毛刺,虽然异步清零对毛刺敏感,但一般拨动开关抖动时间在毫秒级,清零效果肉眼看不出来。如果要求严格,可以在开关后加一个 D 触发器做同步。

3.2 2Hz 快速校时校分的实现

校分开关M_KEY=1时,分计数器时钟从 1Hz 切到 2Hz,秒计数器仍然走 1Hz;校时开关H_KEY=1时,时计数器时钟从 1Hz 切到 2Hz,分、秒正常。这里关键是时钟切换不能有毛刺,常见做法是用一个二选一多路器,选择端接按键,两路输入分别是 1Hz 和 2Hz。如果直接用一个与门把 2Hz 和按键相与,再和 1Hz 或起来,切换瞬间可能出现窄脉冲,计数器多走一格。

// 校分时钟选择:m_key=1 时选 2Hz,否则选 1Hz wire clk_minute; assign clk_minute = m_key ? clk_2hz : clk_1hz; // 校时时钟选择:h_key=1 时选 2Hz,否则选 1Hz wire clk_hour; assign clk_hour = h_key ? clk_2hz : clk_1hz;

clk_2hz周期 0.5s,按一秒两次的速度校分,一分钟能走 120 个分,够用。校时和校分不建议同时打开,否则分和时都快速走,很难对准。原理图上可以在两个按键后加互斥逻辑,或者干脆在操作时只拨一个。校时校分时秒计数器照常走,所以校到 59 秒附近要快一点,不然校完分又被秒进位顶掉。

3.3 保持电路的门控时钟与 D 触发器防抖

保持开关K_KEY=1时,计时器保持当前时间不变。最直接的做法是不给计数器时钟脉冲,即门控时钟:clk_gated = clk_1hz & ~k_key。但组合逻辑门控时钟在按键切换时容易产生毛刺,毛刺会被 74160 当成一个时钟沿,时间跳一下。更稳的做法是用 D 触发器把k_key同步到时钟域,再用同步后的信号去控制时钟使能。

// 同步门控:用 D 触发器对 k_key 打拍,避免毛刺 reg k_key_sync1, k_key_sync2; always @(posedge clk_1hz or negedge rst_n) begin if (!rst_n) begin k_key_sync1 <= 1'b0; k_key_sync2 <= 1'b0; end else begin k_key_sync1 <= k_key; k_key_sync2 <= k_key_sync1; end end wire en_counter; assign en_counter = ~k_key_sync2; // 保持时使能为 0

k_key_sync2是打两拍后的稳定信号,en_counter控制计数器的ENT或时钟使能端。用 74160 时,可以把en_counter接到ENTENP,这样时钟还在走,但计数器不翻。保持期间数码管仍然动态扫描,显示当前冻结的时间。如果实验箱上按键是机械开关,k_key本身抖动可能几十毫秒,打两拍同步能滤掉大部分。

3.4 防抖电路与实验现象

校时校分按键同样需要防抖。原文提到用 D 触发器锁存实现防颤,具体接法是把按键信号接到 D 端,时钟接一个低频信号比如 100Hz,Q 输出作为稳定的控制信号。这样只有按键稳定超过一个时钟周期,输出才变化。实验时如果发现按一下校分,分位跳了两三个数,基本就是抖动没处理。用示波器看按键波形,能看到上升沿和下降沿有一串毛刺;加上 D 触发器后,毛刺被滤掉,波形变成干净的单次跳变。

4. 整点报时与动态扫描显示:卡诺图化简和 74151/74138 联调

4.1 整点报时逻辑:59'53、55、57 与 59'59 的频率选择

整点报时要求在 59 分 53 秒、55 秒、57 秒输出 500Hz 低音,59 分 59 秒输出 1kHz 高音。触发信号来自分计数器和秒计数器的输出。把分十位、分个位、秒十位、秒个位的 BCD 码展开成二进制,对 53、55、57、59 四个时刻做卡诺图化简,能得到一个较简的与门网络。常见做法是分别判断分计数器等于 59,再判断秒计数器等于 53/55/57/59,最后把 500Hz 或 1kHz 送到蜂鸣器。

时刻分十位分个位秒十位秒个位输出频率
59'535953500Hz
59'555955500Hz
59'575957500Hz
59'5959591kHz
// 整点报时触发与频率选择 wire min_59 = (min_tens == 4'd5) && (min_ones == 4'd9); wire sec_53 = (sec_tens == 4'd5) && (sec_ones == 4'd3); wire sec_55 = (sec_tens == 4'd5) && (sec_ones == 4'd5); wire sec_57 = (sec_tens == 4'd5) && (sec_ones == 4'd7); wire sec_59 = (sec_tens == 4'd5) && (sec_ones == 4'd9); wire beep_low = min_59 && (sec_53 || sec_55 || sec_57); wire beep_high = min_59 && sec_59; wire beep = beep_low ? clk_500hz : (beep_high ? clk_1khz : 1'b0);

min_tensmin_onessec_tenssec_ones是计时器输出的 BCD 码;beep直接驱动蜂鸣器,低音时选 500Hz,高音时选 1kHz,其余时间静音。卡诺图化简后如果有多余项,仿真时可能在其他秒数误响,跑一次 59 分 50 秒到 59 分 59 秒的波形就能看出来。

4.2 动态显示:6 位 BCD 数据的 74151 多路复用

六个数码管如果都用静态译码,需要六片 7447 和大量连线。实验里只用一个译码显示单元,所以采用动态扫描:用一片 74151 八选一多路器轮流选择时、分、秒的个位和十位 BCD 数据,送到一片 7447 译码,再用 74138 三-八译码器控制六个共阳数码管的位选端。扫描计数器用模 6 计数器,输出三位二进制,低三位接 74138 的 A、B、C,同时接 74151 的地址端。扫描频率选 1kHz,即每位数码管每 6ms 点亮一次,人眼看不到闪烁。

扫描计数74151 通道74138 输出点亮数码管显示内容
00Y0秒个位秒的个位 BCD
11Y1秒十位秒的十位 BCD
22Y2分个位分的个位 BCD
33Y3分十位分的十位 BCD
44Y4时个位时的个位 BCD
55Y5时十位时的十位 BCD
// 模 6 扫描计数器与动态选择 reg [2:0] scan_cnt; always @(posedge clk_1khz or negedge rst_n) begin if (!rst_n) scan_cnt <= 3'd0; else if (scan_cnt == 3'd5) scan_cnt <= 3'd0; else scan_cnt <= scan_cnt + 1'b1; end reg [3:0] bcd_out; always @(*) begin case (scan_cnt) 3'd0: bcd_out = sec_ones; 3'd1: bcd_out = sec_tens; 3'd2: bcd_out = min_ones; 3'd3: bcd_out = min_tens; 3'd4: bcd_out = hour_ones; 3'd5: bcd_out = hour_tens; default: bcd_out = 4'd0; endcase end // 74138 位选:低有效,对应扫描计数值 wire [5:0] dig_en; assign dig_en = ~(6'b000001 << scan_cnt);

scan_cnt每 1ms 加一,bcd_out随地址切换,7447 译码后输出段码。dig_en的移位写法在综合后就是 74138 的译码逻辑,低有效选通对应数码管。实际 74138 只有三个地址输入和八个输出,用其中六个即可。注意 74151 的地址和 74138 的地址要接同一个scan_cnt,否则数据位和显示位会错位,出现“秒个位显示在分十位”的现象。

4.3 7447 译码与数码管段码

7447 是 BCD 到共阳七段译码器,输出低有效。共阳数码管的公共端接高电平,段码低电平点亮。如果实验箱是共阴数码管,需要换 7448 或者加反相器。段码限流电阻一般 220Ω 到 470Ω,太小会烧段,太大会暗。动态扫描时每位数码管只亮 1/6 时间,亮度比静态低,可以把限流电阻取小一点,但不要低于 150Ω。

BCD 输入显示数字7447 段输出 abcdefg(低有效)
000000000001
000111001111
001020010010
001130000110
010041001100
010150100100
011060100000
011170001111
100080000000
100190000100

实验里如果某一段常亮或不亮,先量 7447 对应输出脚电压,再查数码管公共端有没有接对。动态扫描时如果所有位同时亮但显示内容错,多半是 74151 的地址线接反了;如果某一位特别暗,查 74138 对应输出有没有接限流电阻或三极管驱动。

5. 顶层整合与下载验证:从 Quartus II 7.0 到 SMART SOPC 实验箱的最后几公里

顶层整合时,把分频模块、计时模块、控制模块、报时模块和显示模块例化到一个.bdf或 Verilog 顶层里。Quartus II 7.0 对 Verilog-2001 支持够用,但引脚分配最好用 Tcl 脚本或.qsf文件,比在图形界面一个个点快。下面是一个引脚分配片段,把 48MHz 时钟、按键和数码管段位选映射到实验箱的对应引脚:

# Quartus II 7.0 引脚分配示例,实际引脚号以实验箱手册为准 set_location_assignment PIN_23 -to clk_48m set_location_assignment PIN_45 -to rdn_key set_location_assignment PIN_46 -to m_key set_location_assignment PIN_47 -to h_key set_location_assignment PIN_48 -to k_key set_location_assignment PIN_100 -to seg_a set_location_assignment PIN_101 -to seg_b set_location_assignment PIN_102 -to seg_c set_location_assignment PIN_103 -to seg_d set_location_assignment PIN_104 -to seg_e set_location_assignment PIN_105 -to seg_f set_location_assignment PIN_106 -to seg_g set_location_assignment PIN_110 -to dig_en[0] set_location_assignment PIN_111 -to dig_en[1] set_location_assignment PIN_112 -to dig_en[2] set_location_assignment PIN_113 -to dig_en[3] set_location_assignment PIN_114 -to dig_en[4] set_location_assignment PIN_115 -to dig_en[5] set_location_assignment PIN_120 -to beep

分配完先跑一次编译,看 Fitter 报告里的引脚冲突和时序违规。48MHz 输入如果没接专用时钟脚,Quartus 会报警告,但实验箱一般有固定时钟脚。下载时用 JTAG 模式,把.sof文件烧到 FPGA 里,拨动 RDN 看六个数码管是否全灭,再松开看是否从 00:00:00 开始走。校分时按住 M_KEY,分位应该以 2Hz 快速走,秒位仍然正常。整点报时不好等,可以把分计数器预置到 59 分 50 秒,或者用仿真先验证。附加功能里,星期显示可以借用时的进位信号,每当时从 23 到 00 时给星期计数器加一;秒表功能则用另一个模 100 计数器和模 60 计数器,通过界面切换信号选择显示数据源。动态扫描频率如果降到 500Hz,六个数码管轮流点亮周期变成 12ms,边缘能看到轻微闪烁,用这个办法可以快速判断视觉暂留的边界。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询