简介:这份多功能数字钟实验报告来自南京理工大学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 分频得到,具体看实验箱时钟资源和手头芯片。分频链一旦顺序接错,后面计时和报时都会偏。
| 目标频率 | 来源 | 主要用途 | 分频实现 |
|---|---|---|---|
| 1MHz | 48MHz / 48 | 中间时钟 | 两片 74160 置数到 0 |
| 1kHz | 1MHz / 1000 | 动态扫描、报时 | 三片 74160 级联 |
| 500Hz | 1kHz / 2 | 整点报时低音 | D 触发器二分频 |
| 2Hz | 1kHz / 500 或 1MHz 分频 | 快速校时校分 | 74160 模 500 |
| 1Hz | 1kHz / 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 |
|---|---|---|---|
| 58 | 0101 | 1000 | 1 |
| 59 | 0101 | 1001 | 0 |
| 00 | 0000 | 0000 | 1 |
行为级 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 endmoduleen是计数使能,接 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 电平 | 计时器状态 |
|---|---|---|---|
| 0 | 1 | 1 | 正常计时 |
| 1 | 0 | 0 | 时、分、秒全清零 |
// 异步清零与正常计时的切换 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 endclrn_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; // 保持时使能为 0k_key_sync2是打两拍后的稳定信号,en_counter控制计数器的ENT或时钟使能端。用 74160 时,可以把en_counter接到ENT和ENP,这样时钟还在走,但计数器不翻。保持期间数码管仍然动态扫描,显示当前冻结的时间。如果实验箱上按键是机械开关,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'53 | 5 | 9 | 5 | 3 | 500Hz |
| 59'55 | 5 | 9 | 5 | 5 | 500Hz |
| 59'57 | 5 | 9 | 5 | 7 | 500Hz |
| 59'59 | 5 | 9 | 5 | 9 | 1kHz |
// 整点报时触发与频率选择 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_tens、min_ones、sec_tens、sec_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 输出 | 点亮数码管 | 显示内容 |
|---|---|---|---|---|
| 0 | 0 | Y0 | 秒个位 | 秒的个位 BCD |
| 1 | 1 | Y1 | 秒十位 | 秒的十位 BCD |
| 2 | 2 | Y2 | 分个位 | 分的个位 BCD |
| 3 | 3 | Y3 | 分十位 | 分的十位 BCD |
| 4 | 4 | Y4 | 时个位 | 时的个位 BCD |
| 5 | 5 | Y5 | 时十位 | 时的十位 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(低有效) |
|---|---|---|
| 0000 | 0 | 0000001 |
| 0001 | 1 | 1001111 |
| 0010 | 2 | 0010010 |
| 0011 | 3 | 0000110 |
| 0100 | 4 | 1001100 |
| 0101 | 5 | 0100100 |
| 0110 | 6 | 0100000 |
| 0111 | 7 | 0001111 |
| 1000 | 8 | 0000000 |
| 1001 | 9 | 0000100 |
实验里如果某一段常亮或不亮,先量 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,边缘能看到轻微闪烁,用这个办法可以快速判断视觉暂留的边界。
本文还有配套的精品资源,点击获取