简介:这份资源是电工电子基础实验B的计数与分频电路实验报告,面向具备电工电子基础的大专院校学生与初学者,尤其适合计算机学院相关专业同学,用于掌握计数器、分频电路与序列信号发生器的设计与仿真方法。报告完整记录了用CB4CLE计数器以置零法和置最大数法设计M=7计数器、设计N=5整数分频电路,以及用数据选择器产生“1110010”序列信号的全过程,并配有状态转移表、反馈函数推导、原理图与ISE仿真波形、手绘波形和示波器波形对照。资源包共1个PDF文件,约7.87MB,内容涵盖实验目的、仪器设备、设计过程、电路图、结果分析与实验小结,便于读者对照电路图逐步理解反馈逻辑与时序特性,验证设计正确性。目前已有259人学习,适合作为数字电路实验参考与查漏补缺之用。
1. 计数与分频电路:一张从模值到波形的知识地图
数字电路实验里,计数与分频这一块是最容易被低估的。很多人以为把计数器接上时钟、把模值算对就完事了,结果一上仿真,波形和手绘的对不上,或者分频出来的周期差了一个时钟节拍,回头查半天才发现是反馈逻辑取错了位。这份实验报告记录的东西,恰好是这条链路上最关键的几个环节:用 CB4CLE 计数器做 M=7 的计数、用置零法做 N=5 的整数分频、再用数据选择器拼出“1110010”序列。它适合已经学过触发器、编码器、数据选择器,正在把零散知识点往一张图上收的人。梳理下来会发现,这个方向的知识地图其实只有三层:模值与状态转移是骨架,反馈函数是关节,波形是唯一的验收标准。三层任何一层断了,电路就只是“看起来接对了”。
2. 计数器设计:置零法与置最大数的分岔口
2.1 模值、状态数与反馈函数的关系
计数器设计的起点不是画图,而是把“模几”翻译成“用几个状态、跳过哪个状态”。M=7 意味着有效状态是 7 个,而 CB4CLE 是 4 位二进制计数器,天然有 16 个状态,所以必须人为截断。置零法的思路是:让计数器从 0 开始正常往上数,数到第 7 个状态时产生一个反馈信号,把计数器拉回 0。状态转移表就是把这个过程逐行列出来:
| 时钟沿 | Q3 Q2 Q1 Q0 | 说明 |
|---|---|---|
| 0 | 0000 | 初始清零 |
| 1 | 0001 | 正常计数 |
| 2 | 0010 | 正常计数 |
| 3 | 0011 | 正常计数 |
| 4 | 0100 | 正常计数 |
| 5 | 0101 | 正常计数 |
| 6 | 0110 | 最后一个有效状态 |
| 7 | 0000 | 反馈置零,回到起点 |
反馈函数从表里读:第 6 个状态是 0110,也就是 Q2=1、Q1=1,其余为 0,所以反馈项取 Q2·Q1。这里最容易犯的错是把“第 7 个状态”理解成二进制 0111,然后拿 Q2·Q1·Q0 去做反馈,结果模值变成 8。模 7 的“7”是状态个数,不是最大状态值,这个区别在状态转移表上看得最清楚,但脱离表格纯靠脑算时翻车率极高。
置最大数法是另一条路:让计数器数到某个值后,通过置数端把计数器直接置成最大值(全 1),再自然溢出回 0。两种方法在功能上等价,但资源占用和时序行为不同。置零法反馈逻辑通常更简单,因为只需要检测一个中间状态;置最大数法需要用到置数端 D3~D0,连线多一组,但对某些计数器芯片来说,置数端的建立时间比异步清零更可控。
提示:判断用哪种方法,先看手头计数器芯片的清零和置数哪个是同步的。同步清零的芯片用置零法,反馈信号不会产生毛刺;异步清零的芯片用置零法要格外小心,因为清零动作和时钟沿之间没有保护。
2.2 置零法的完整设计流程
把置零法拆成可复现的步骤,顺序不能乱:
第一步,确定有效状态集合。M=7 就是 {0,1,2,3,4,5,6},共 7 个。
第二步,找“最后一个有效状态”的二进制编码。6 的编码是 0110,对应 Q3=0、Q2=1、Q1=1、Q0=0。
第三步,写反馈函数。只取该状态中为 1 的位做与运算,得到 F = Q2·Q1。如果最后一个有效状态是 0101(5),反馈就是 Q2·Q0;如果是 0011(3),反馈就是 Q1·Q0。规律很死:编码里哪些位是 1,就把哪些位乘起来。
第四步,把反馈接到计数器的清零端(或同步清零端)。注意极性:多数芯片的清零端低电平有效,所以反馈信号可能需要取反,或者用与非门实现。
第五步,仿真验证。看波形里 Q0 的频率是不是时钟的 1/2,Q1 是不是 1/4,Q2 是不是 1/8 再被截断。模 7 计数器的 Q2 波形不是标准方波,因为它在第 7 个节拍被强制拉低,这个“不完整周期”正是模值不是 2 的幂时的典型特征。
// 模7计数器核心逻辑(置零法,同步清零) // 反馈项 F = Q2 & Q1,检测状态 0110 module counter_mod7( input clk, input rst_n, output reg [3:0] q ); wire feedback = q[2] & q[1]; // 状态6的检测项 always @(posedge clk or negedge rst_n) begin if (!rst_n) q <= 4'b0000; else if (feedback) q <= 4'b0000; // 同步清零,回到起点 else q <= q + 1'b1; end endmodule这段代码里feedback只用了两位,不是偷懒,而是状态 0110 的 Q3 和 Q0 本来就是 0,写进去也不影响逻辑,但会多占一个与门输入。实际搭电路时,反馈项越少,门延迟越小,时序余量越大。参数上唯一需要改的是q[2] & q[1]这两个下标——换模值就换下标,换置最大数法就把清零分支改成置数分支。
2.3 置最大数法的差异点
置最大数法的状态转移表和置零法长得不一样:它不是数到 6 就回 0,而是数到某个值后跳到 15,再靠 4 位计数器的自然溢出回到 0。所以有效状态集合可能变成 {9,10,11,12,13,14,15} 这种“高位段”,具体取决于置数端接什么值。反馈函数的写法也跟着变:检测的是“置数触发状态”,而不是“最后一个有效状态”。
两种方法对比:
| 对比项 | 置零法 | 置最大数法 |
|---|---|---|
| 反馈检测对象 | 最后一个有效状态 | 置数触发状态 |
| 用到的端口 | 清零端 | 置数端 D3~D0 |
| 有效状态段 | 从 0 开始 | 通常在高位段 |
| 波形特征 | 低位有完整方波,高位截断 | 高位有完整方波,低位截断 |
| 常见误用 | 把模值当最大状态值 | 置数端接错导致跳过有效状态 |
置最大数法最容易错的地方是置数端的值。如果置数端接 1111,计数器从 15 往下溢出,有效状态是 15 到某个值;如果置数端接 1001,有效状态段整体平移。这个“平移量”直接决定反馈函数取哪几位,接错一位,模值就偏。
3. 分频电路:N=5 整数分频的模值映射
3.1 分频比与模值的等价关系
分频和计数在电路层面是同一件事,区别只在观察角度。N=5 的整数分频,意思是输出信号周期是输入时钟周期的 5 倍,等价于设计一个模 5 的计数器,然后取某一位输出作为分频结果。实验报告里写“分频比 N=5 可知周期为原来的 5 倍,即设计模 5 的电路”,这句话是整个分频设计的枢纽。
模 5 的状态转移表:
| 时钟沿 | Q2 Q1 Q0 | 说明 |
|---|---|---|
| 0 | 000 | 初始 |
| 1 | 001 | |
| 2 | 010 | |
| 3 | 011 | |
| 4 | 100 | 最后一个有效状态 |
| 5 | 000 | 反馈置零 |
最后一个有效状态是 100,只有 Q2 为 1,所以反馈函数 F = Q2。这个结果比模 7 还简单,但简单不等于不会错。常见的错误有两个:一是把模 5 写成模 4(状态 000 到 011),反馈取 Q1·Q0,分频比变成 4;二是反馈取了 Q2·Q1,但状态 100 里 Q1 是 0,反馈永远不触发,计数器数到 111 才溢出,分频比变成 8。
3.2 从反馈函数到分频输出的取法
反馈函数只保证计数器按模 5 循环,但“哪个引脚当分频输出”是另一个决策。取 Q2 输出,得到的是占空比 2/5 的波形(状态 0、1 时 Q2=0,状态 2、3、4 时 Q2=1,等等——具体占空比取决于编码顺序)。取 Q0 输出,频率是时钟的 1/2,不是 1/5。所以分频输出必须取最高位 Q2,因为只有最高位的翻转周期等于整个模值周期。
// N=5 整数分频,输出取最高位 module divider_n5( input clk, input rst_n, output clk_out ); reg [2:0] cnt; always @(posedge clk or negedge rst_n) begin if (!rst_n) cnt <= 3'b000; else if (cnt == 3'b100) // 检测状态4 cnt <= 3'b000; // 回零,模5循环 else cnt <= cnt + 1'b1; end assign clk_out = cnt[2]; // 最高位即分频输出 endmodulecnt == 3'b100这个判断条件是整个分频器的命门。写成cnt[2]作为条件也行,因为模 5 范围内只有状态 4 的 Q2 为 1,但显式写全三位更不容易在改模值时漏改。clk_out取cnt[2]而不是cnt[0],是因为 Q0 每个时钟沿都翻转,频率是时钟的一半,和分频比 5 无关。
3.3 波形验证的三个观察点
分频电路做完,波形要看三件事。第一,clk_out的一个完整周期是否正好包含 5 个输入时钟周期,数上升沿个数最直接。第二,clk_out的占空比是否稳定,模 5 分频的占空比通常不是 50%,如果看到占空比在周期之间跳变,说明反馈逻辑有竞争。第三,复位后的第一个周期是否完整,异步复位释放时刻如果靠近时钟沿,第一个周期可能被截短,这是仿真和实测都容易忽略的“第零周期”问题。
注意:手绘波形和仿真波形对不上时,先核对时钟沿的触发方向。ISE 仿真里默认的时钟初始值是 0,第一个上升沿出现在半个周期之后;手绘时如果从 0 时刻画上升沿,整体会错开半拍,看起来像分频比错了,其实只是相位基准不同。
4. 序列信号产生:数据选择器与计数器的协同
4.1 序列长度决定模值
“1110010”是 7 位序列,所以需要一个模 7 的计数器来提供 7 个地址,再用八选一数据选择器按地址输出对应位。这里模 7 计数器和第 2 章的 M=7 计数器是同一个东西,但用途不同:第 2 章用它验证计数功能,这里用它当“地址发生器”。序列长度和计数器模值的对应关系是硬约束——7 位序列配模 7,8 位序列配模 8,少一位或多一位,序列就会循环错位。
状态转移表把地址和输出绑在一起:
| 计数器状态 | 选择器地址 | 数据输入 | 序列输出 |
|---|---|---|---|
| 000 | A2A1A0=000 | D0 | 1 |
| 001 | 001 | D1 | 1 |
| 010 | 010 | D2 | 1 |
| 011 | 011 | D3 | 0 |
| 100 | 100 | D4 | 0 |
| 101 | 101 | D5 | 1 |
| 110 | 110 | D6 | 0 |
| 111 | — | — | 不用(模7跳过) |
数据输入端 D0~D6 分别接序列的 7 个位,D7 随意(因为模 7 计数器不会停在 111)。这个“随意”是很多人的翻车点:仿真时 D7 悬空或接错,恰好计数器因为毛刺短暂经过 111,输出就冒出一个不该有的脉冲。
4.2 卡诺图降维的实际操作
实验报告提到“画出卡诺图后降维”,这一步是把“地址→输出”的真值表化简成选择器的连线方案。7 个有效状态对应 7 个输出值,卡诺图上会有 7 个格被填,剩下 1 个格是无关项。降维的意思是:不直接把 7 个数据端各接一个固定电平,而是利用选择器的使能端或地址高位,把两组数据合并到更少的输入端上。
具体做法是:以 A2 为分组依据,A2=0 时地址是 000~011,对应序列前 4 位“1110”;A2=1 时地址是 100~110,对应序列后 3 位“010”。如果选择器有使能端,可以用 A2 控制两组数据分时送入,数据端数量从 7 降到 4。降维的收益是连线少、改序列方便,代价是使能端的时序要和控制信号对齐,否则切换瞬间会出毛刺。
// 用8选1数据选择器产生"1110010" // 计数器提供地址,选择器按地址输出 module seq_gen( input clk, input rst_n, output seq_out ); reg [2:0] addr; always @(posedge clk or negedge rst_n) begin if (!rst_n) addr <= 3'b000; else if (addr == 3'b110) // 模7,状态6后回零 addr <= 3'b000; else addr <= addr + 1'b1; end // 数据端按序列"1110010"配置,D7为无关项 reg [7:0] data_in = 8'b0_1110010; assign seq_out = data_in[addr]; endmoduledata_in的位序要和地址对应:data_in[0]是序列第 1 位,data_in[6]是第 7 位,data_in[7]填 0 只是占位。如果位序接反,输出序列会变成“0100111”,波形上看起来“有信号但不对”,这种错误比完全没输出更难查,因为示波器上确实有跳变。
4.3 协同工作的时序边界
计数器和数据选择器协同,关键在“地址稳定”和“数据建立”之间的时间窗。计数器在时钟沿翻转地址,选择器的输出会跟着地址变化,如果选择器的传播延迟大于半个时钟周期,输出会在地址切换瞬间出现窄脉冲。仿真时把时钟频率设低一点(比如 1 MHz)不容易暴露这个问题,一旦上板跑高频,毛刺就出来了。
处理办法有两个:一是选择传播延迟小的选择器型号,二是在选择器输出后加一级寄存器,用时钟沿把输出打一拍。加寄存器会引入一个时钟周期的延迟,序列整体后移一拍,但波形干净。实验报告里的仿真波形如果和手绘波形在相位上差一拍,很可能就是手绘时按“组合输出”画的,而实际电路里加了寄存级。
5. 易错点排查:反馈逻辑、波形基准与端口极性
5.1 易错点一:反馈项取多了或取少了
为什么漏:写反馈函数时习惯性把“最后一个有效状态”的所有为 1 的位都乘进去,但有些位在化简后是冗余的,多乘一个位不会改变逻辑功能,却会改变门延迟;反过来,漏掉一个为 1 的位,反馈永远不触发,计数器直接数满溢出。模 7 取 Q2·Q1 是对的,取 Q2·Q1·Q0 功能上也对(因为状态 0110 的 Q0 是 0,乘进去恒为 0),但取 Q2 就错了,因为状态 0100 也会触发。
怎么补:写完反馈函数,拿状态转移表逐行代入验算。只有“最后一个有效状态”那一行能让反馈为 1,其余行必须为 0。这一步手算五分钟,能省掉仿真跑一遍再回头改的两小时。
5.2 易错点二:把模值当成最大状态值
为什么漏:M=7 的“7”在口语里和“数到 7”混在一起,脑算时容易把状态 0111 当成终点。实际上模 7 的终点是 0110(状态 6),因为从 0 开始数 7 个数是 0~6。这个 off-by-one 在计数器设计里是血泪经验级别的坑,模 5、模 7、模 10 全都会遇到。
怎么补:养成先列状态转移表再写反馈的习惯,表的第一列写时钟沿序号,第二列写编码,最后一行明确标“反馈触发”。表列完,模值就不会错。
5.3 易错点三:清零端/置数端极性接反
为什么漏:不同芯片的清零端有效电平不一样,有的低有效(带 n 后缀),有的高有效。原理图上画一个反相器圆圈不代表实际连线时也加了反相器,仿真模型和实物封装的极性偶尔不一致。
怎么补:在代码或原理图里把极性显式写出来,比如if (!rst_n)而不是if (rst_n == 0),让读的人一眼看到低有效。上板前用万用表量一下清零端的静态电平,确认复位释放后它处于无效状态。
5.4 易错点四:波形观察的相位基准不统一
为什么漏:仿真工具的时钟从 0 时刻开始,第一个上升沿在半个周期后;手绘波形时人习惯从 0 时刻画第一个上升沿。两者差半拍,对比时看起来像分频比错了或反馈延迟了,其实只是基准不同。
怎么补:对比波形前先对齐“第一个复位释放后的时钟沿”,以那个沿为 t=0 重新数周期。ISE 仿真里可以把光标拖到复位信号上升沿,读此时各输出的值作为初始状态。
5.5 易错点五:序列发生器的无关项没处理
为什么漏:模 7 计数器理论上不会停在 111,所以 D7 被当成无关项随便接。但实际电路上电瞬间、复位释放瞬间、或者毛刺导致的状态跳变,都可能让地址短暂经过 111,D7 接错就冒出一个错误脉冲。
怎么补:D7 接一个确定电平(通常接 0),不要悬空。如果选择器有使能端,用计数器的有效状态范围做使能,把 111 彻底屏蔽掉。
6. 复习清单:从模值口算到波形自查的落地方法
复习这一块,最有效的方式不是重读报告,而是拿一张白纸做“模值口算—反馈默写—波形预判”三连。具体做法:随机写一个模值(比如 M=6、M=9、M=5),三十秒内写出状态转移表的最后一行和反馈函数,然后预判最高位的波形周期是时钟的几倍、占空比大概多少。写不出来就回去翻第 2 章的表,翻完再默一遍。这个练习做五组,比看十遍原理图管用。
下面这张自查表可以贴在实验台旁边,每次搭完电路逐项打勾:
| 检查项 | 通过标准 | 不通过时先看哪 |
|---|---|---|
| 模值 | 状态转移表行数 = 模值 | 最后一行编码是否 off-by-one |
| 反馈函数 | 只有最后一行代入结果为 1 | 是否多乘或漏乘了位 |
| 清零/置数极性 | 复位释放后端口处于无效电平 | 芯片手册的有效电平定义 |
| 分频输出取位 | 取最高位,周期 = N 倍时钟 | 是否误取了 Q0 |
| 序列位序 | data_in[0] 对应序列第 1 位 | 位序是否接反 |
| 无关项 | D7 接确定电平 | 是否悬空 |
| 波形基准 | 以复位释放后第一个时钟沿为 t=0 | 仿真与手绘的起点是否一致 |
代码层面的自查可以更机械:把反馈条件单独拎出来,用穷举的方式跑一遍所有状态,看是不是只有目标状态触发。下面这段 Python 片段就是干这个的,改mod_value和feedback_mask两个参数就能验任何模值:
# 穷举验证反馈函数:只有最后一个有效状态应触发反馈 mod_value = 7 feedback_mask = 0b0110 # 模7的最后一个有效状态编码 for state in range(16): # 反馈项只取 mask 中为1的位 triggered = (state & feedback_mask) == feedback_mask should_trigger = (state == mod_value - 1) if triggered != should_trigger: print(f"状态 {state:04b} 反馈={triggered},应为 {should_trigger}")跑出来没有输出,说明反馈函数在 0~15 全范围内都正确;有输出就按提示的状态号回去改 mask。这个脚本的好处是把“我觉得对了”变成“穷举过了”,尤其适合改模值之后快速回归。
我自己的习惯是:每次改完模值或反馈项,先跑一遍这个穷举,再开仿真看波形。有一次做模 6 计数器,反馈项手滑写成了 Q2·Q0,穷举脚本直接报状态 0101 误触发,省掉了仿真跑完发现波形少一个状态再回头查的来回。从那以后我每次动反馈逻辑都强制走一遍“穷举—仿真—手绘”三步,顺序不乱。希望这份梳理帮到你,复习时少走一点弯路。
本文还有配套的精品资源,点击获取