数字电子技术里,编码器和译码器是我见过最容易被低估的两块芯片。很多同学学到这里,看一眼真值表就说“哦,就是查表嘛”,然后直接翻过去学触发器。等到做实验、做课程设计,要用74LS138给单片机扩一个片选,或者用74LS148做键盘编码,才发现到处都是坑:输出低电平有效反来反去、级联信号接错、按键按一下乱跳好几下,甚至两片芯片一接就冒烟。这篇文章就是来陪你把这些坑一个个填上的。
这篇内容围绕“编码器与译码器”展开,面向三类人:正在复习《数字电子技术基础》准备考试或考研的电子/自动化学生,刚入门单片机、在地址译码和编码器测速上卡壳的嵌入式初学者,以及像我一样经常要回去查带使能端级联逻辑的“老油条”。我会从芯片内部逻辑一路讲到旋转编码器、伺服驱动器和STM32的编码器模式,把你在热搜词里看到的各种“编码器”串成一条线。
1. 先搞清楚:编码器和译码器到底在“编”什么
1.1 一个类比:编码器和译码器是互为镜像的“翻译官”
很多人第一次接触编码器和译码器,总把它们当成两种完全独立的器件。其实它们就是一对互为反操作的“翻译官”:编码器把人能看懂的“含义”(比如按键编号、数字量、状态)翻译成机器能处理的二进制代码;译码器则反过来,把二进制代码还原成某种“含义”,比如点亮某一位数码管、选中某一片存储器、给某个外设发送脉冲。
我用一个生活化的例子解释过很多遍:想象你去一栋酒店,需要找房间号。编码器的任务是把“客人住在哪一间”这种自然语言转换成保安能懂的编号;译码器的任务是看到编号后,准确找到对应的房间并按响门铃。数字电路里,编码器输入是一组互斥信号,输出是二进制码;译码器输入是二进制码,输出是一组互斥的选通信号。两者组合在一起,就构成了一条从“事件”到“代码”再到“动作”的链路。
这个“互逆”关系不仅是考试重点,也是工程中排查问题的基本框架。我见过不少同学,编码器和译码器分开学都会,一旦让它们组合工作就犯迷糊,根本原因就是没有把这条链路串起来看。先把“输入是什么、输出是什么、谁在翻译谁”想清楚,后面的电路才能谈得上调试。
1.2 没有这两种芯片,数字系统会怎么样
你可能会想:不就是多引几根线吗?计算机为什么非要把信息编码成二进制再传输?算一笔账你就明白了。假如一个系统里有16个按键需要检测,如果不编码,每一路都要单独接到处理器,占用16个IO口;用编码器之后,只需要4根二进制输出线。至于为什么是4根,因为2的4次方等于16,这正是二进制对数的威力。
译码器这边同样如此。4根地址线最多可以表示0到15十六个地址,如果要把这十六个地址分别“点亮”成十六个存储芯片的片选信号,就必须用译码器把二进制代码展开成16根独立信号线。换句话说,编码器解决的是“数量压缩”的问题,译码器解决的是“选路展开”的问题。没有它们,数字系统要么引脚爆炸,要么布线复杂到没法做PCB。
从更深一层看,编码器和译码器其实就是“硬件化了的查表过程”。真值表里每一行怎么写,硬件上就用门电路把对应的与或逻辑搭起来。这个过程本身没有蕴含什么高深算法,但它是你建立“数字电路=输入到输出的确定性映射”这一观念最好的起点。
1.3 别被同名词带偏:电机编码器、音视频编码器和AI自编码器
如果你经常在网上搜“编码器”,会搜出来一堆看似完全不相关的东西:ffmpeg编码器、3D卷积自编码器、磁编码器、伺服电机默认编码器线数、STM32定时器编码器模式……这些确实是“编码器”在不同领域的含义,但它们和数字电子技术里讲的组合逻辑编码器并不是一回事,我在这里先帮你把词义理清,后面才不会互相混淆。
数字电路里的编码器/译码器,是一种组合逻辑器件,输入输出之间是“同时刻、无记忆”的映射关系,核心是为了信号压缩与地址展开。电机控制领域的旋转编码器,是把机械角度/位置转换成电脉冲或数字量的一种传感器,核心是测量位置与速度。音视频压缩领域的编码器,是把原始媒体流压缩成H.264、H.265等码流的算法软件,核心是数据压缩。深度学习中的自编码器,则是一种用于特征提取与重建的神经网络结构,核心是学习数据表示。
搜索热词里出现的“fiash”这个词虽然写法有些特别,但你把它和“ffmpeg”“播放器需要新的编码器”放一起看,就知道指的是音视频编解码器,而不是数电课本里的74LS148。这篇文章的主体还是讲数字电子技术里的编码器和译码器,但在第5章我会专门延伸讲旋转编码器和伺服编码器,因为它们和嵌入式工程的关系最紧密,也是线上线下被问得最多的话题。
2. 编码器原理拆解:从硬接线真值表到优先编码
2.1 最朴素的编码器就是“一张真值表按引脚连死”
先看最简单的情况:8线-3线编码器,8个输入I0到I7,3个输出Y2、Y1、Y0(高电平有效),含义是“当某一个输入为1时,输出该输入编号的二进制代码”。比如I4为1时,输出100(4),I6为1时输出110(6)。这种编码器的设计思路非常直白:把真值表抄下来,写逻辑表达式,再用门电路实现。
拿Y2这一路来说,只有I4、I5、I6、I7当中任意一个为1时,Y2才需要为1(因为这四个编号的二进制最高位都是1)。所以逻辑表达式就是 Y2 = I4 + I5 + I6 + I7。同理,Y1 = I2 + I3 + I6 + I7,Y0 = I1 + I3 + I5 + I7。整个电路只需要三个(或门组),输入直接接进去,输出直接接出来,没有任何时钟,这就是“组合逻辑”。
这个设计有一个隐含前提:任何时刻最多只有一个输入为1。如果两个输入同时为1,输出就会变成一个乱七八糟的“混合码”。实际系统中这种“独热”约束往往并不成立,比如两个按键同时被按下,于是才有了下面要说的优先编码器。所以我说,最朴素的编码器是“理想化”的,它帮你理解原理,但不适合直接拿到工程里用。
2.2 优先级:多路同时有效时到底听谁的
工程里更实用的是优先编码器,典型代表是74LS148(8线-3线优先编码器)。它和刚才讲的朴素编码器最大的区别在于:即使有多个输入同时有效,输出也只认优先级最高的那一路。74LS148约定I7优先级最高,I0最低,所以当I5和I2同时为1时,输出对应编号5,不会出现“局部或”的乱码。
74LS148的输入输出都是低电平有效,这背后有工程考虑:TTL电路吸收电流的能力比输出电流强,信号线悬空时容易被干扰拉成低电平,所以很多工业芯片习惯把“有效”定义成低电平,利用下拉电阻和“或门”逻辑天然配合。使用这类芯片时,必须养成“带反相看真值表”的习惯,否则非常容易把输入输出理解反。
此外,74LS148还有三个“配角”引脚:使能输入EI、使能输出EO和优先标志GS。EI=1时芯片不工作,所有输出为高阻或无效;EI=0时芯片进入工作状态。当芯片工作但没有有效输入时,EO输出低电平,GS输出高电平;当芯片工作且有输入被编码时,EO输出高电平,GS输出低电平。这个GS和EO在很多教科书上会被一句话带过,但级联时它们就是命根子。
2.3 两片74LS148拼成16线-4线编码器
实验中经常有把8路编码扩展到16路的需求,比如16个按键要编码成4位二进制编号。用两片74LS148就能实现,接法非常经典:高位片(处理I8到I15)的EI直接接地,让它始终工作;高位片的EO接到低位片(处理I0到I7)的EI;OR两片对应的Y0/Y1/Y2输出,得到低三位;高位片的GS作为输出最高位。
这个接法的原理是优先级贯穿:高位片的优先级天然高于低位片。只要高位片有任何一路输入,GS就变低并完成编码,同时EO变高,把低位片禁掉,低位片的输出作废。只有高位片完全无输入时,EO才变低,低位片才被允许工作,此时用高位片GS输出“0”,代表编号落在0到7之间。这样一来,16路输入就变成了4位二进制输出,优先级顺序也保持了连续性。
我在实验课上看到很多人第一次搭这个电路时,最常犯的错是把EO接到另一片同样功能的引脚上,却忘了用GS做最高位,结果输出始终只有0到7。这里给大家一个建议:调级联电路时,先用“单路测试法”——只接通某一输入,比如I13,顺着信号查一遍哪一级被禁止、哪一级在编码。只要中间某级偏离了预期,立刻就能定位。这个排查方法,比我当年拿万用表乱戳半个下午不知道强多少倍。
3. 译码器原理拆解:74LS138的常用玩法和进阶偷懒技巧
3.1 3线-8线译码器内部到底怎么搭出来的
74LS138是3线-8线译码器里的“人民代表”。三个输入A、B、C,三个使能端G1、G2A、G2B,八个低电平有效的输出Y0到Y7。它内部相当于是三输入变量的“最小项发生器”:八个与门,每个与门对应唯一一种输入组合,输出低电平表示该组合被选中。
为什么输出要设计成低电平有效?因为译码器的主要用途是片选和选通,而TTL电路低电平“灌电流”能力强,用低电平驱动负载更可靠;另外,多个译码器输出做“线与”时,低电平有效用起来也更符合“有任一选中即拉低”的逻辑。记住这一点,后面调片选信号时你会感谢当年记笔记的自己。
74LS138的使能逻辑是:G1为高,同时G2A和G2B都为低,芯片才工作并译码;否则不管A、B、C是什么,所有输出全部为高(无效)。这个“多使能端”设计不是白给的,它让你可以非常方便地做级联扩展。比如要搞4线-16线译码器,用两片74LS138:第一片的G1接高位地址A3的反相,第二片的G1直接接A3,A0到A2同时接两片的A、B、C。A3=0时第一片工作,A3=1时第二片工作,16个输出就被展开成两排了。
3.2 地址译码与数据分配器:单片机外扩的两种典型玩法
在实际单片机系统里,74LS138最常见的任务是地址译码。比如8086或51单片机要扩展多片存储器或IO接口,地址线的高位经过译码后产生各个芯片的片选CS。以51单片机为例,P2口的高位地址A15、A14、A13接到74LS138的A、B、C,译码输出Y0到Y7分别“管辖”不同的8KB空间。只要程序访问对应地址范围,对应片选就会自动拉低,硬件上不用CPU管任何事。
另一种玩法是当数据分配器(Demultiplexer)。把G2A当作数据输入端D,A、B、C当作选择地址,那么D的电平就会“原样传送”到对应的输出端。比如A、B、C=011时,D会被送到Y3。这就像是一个“单刀八掷开关”,常用于在多个外设之间分发同一个数据/控制信号。注意这里的D是高还是低有效,取决于你接到哪个使能端,接法不同路由输出的极性也不同,这是一个容易绕晕的点。
当年我帮一个学弟查他做的“八路流水灯”,逻辑明明是对的一上电就全灭。后来才发现他把G2A和G2B当成了“或非”逻辑中的两个输入,一个接地一个接数据,但手册上要求两个都必须是低,他给的却是高电平有效的数据。这类错误用万用表很难察觉,建议把芯片手册里使能端的表格抄在实验报告第一页,调不出来时反复对照。
3.3 进阶技巧:用译码器当逻辑函数发生器
除了做片选和分配,74LS138还有一个经常被忽视的本领——当组合逻辑函数发生器。因为译码器每个输出对应一个最小项的反相,理论上任何一个三变量逻辑函数都能用它加一个或门/与非门实现。这比用一堆与门或门搭起来简洁得多,尤其是在实验板上只剩几个芯片、又不想多插芯片的时候。
拿1位全加器举例。全加器有三个输入:A、B和低位进位Ci,输出是和S与进位Co。真值表展开后,S对应最小项编号1、2、4、7,Co对应3、5、6、7。如果输入接到74LS138的A、B、C,则Y1到Y7分别就是这些最小项的低有效输出。因为Y_i = (m_i)非,所以S的表达式可以写成 S = Y1非 + Y2非 + Y4非 + Y7非,取一次反就能得到 Y1·Y2·Y4·Y7 的与非形式。把Y1、Y2、Y4、Y7接到一个四输入与非门,输出就是S;Co同理,接Y3、Y5、Y6、Y7到一个四输入与非门即可。
这个技巧在教材上叫“MSI实现组合逻辑”,考试爱考,工程里偶尔也会救命。核心思想是:译码器是“最小项发生器”,你有N个变量,就找一片2的N次方输出的译码器,再配合一个或门/与非门,任何这个变量个数以内的逻辑函数都能拼出来。熟练使用这套思路,你对“中规模集成电路”的理解会顺势上一个大台阶。
4. 从芯片到真实系统:七段数码管显示与编码器实战
4.1 七段译码驱动芯片:为什么说它是“半译码半驱动”
如果你做过带数码管的课设,一定用过74LS47或74LS48这类芯片。它们输入的是BCD码(0-9的二进制编码),输出的是七段数码管需要的a到g段信号,所以叫BCD-七段译码器/驱动器。和74LS138这种纯译码器相比,它除了做逻辑翻译,还能直接输出一定的驱动电流,所以我说它是“半译码半驱动”。
74LS48输出高电平有效,适合共阴极数码管;74LS47输出低电平有效,适合共阳极数码管。用之前一定先确认你的数码管是共阴还是共阳,接反了要么全暗要么全亮,那种“所有段一起亮但不听控制”的现象基本就是共阴共阳选反了。另外,芯片输出端一般都需要串限流电阻,阻值取220欧姆到1千欧之间,具体看电源电压和数码管压降,不会算的优先用1k先试亮,再逐渐减小。
这类芯片还附带了几个非常有用的控制脚:灯测试LT、灭灯输入BI/RBO、灭零输入RBI。LT拉低时所有段强制亮,用来检测数码管有没有坏段;RBI和RBO配合可以把小数点前或后无意义的“0”熄灭,让显示更自然。很多书把这几个脚当作“扩展知识”忽略掉,但实际产品面板上那个“数值前面不显示多余0”的效果,就是靠它们实现的。
4.2 动态扫描显示的时序控制
直接让每位数码管都占一组译码驱动,电路会很臃肿。所以多位数码管通常采用“动态扫描”:所有位的段选线(a-g等)并联,位选线单独控制,单片机轮流让某一位点亮,利用视觉暂留让肉眼“看到”所有位同时在亮。这本质上是把“静态空间并行”换成了“动态时间复用”,用速度换IO口数量。
扫描频率要超过人眼的闪烁融合阈值,一般每人眼融合频率在50Hz左右,实际工程里4位扫描周期做到4到10ms比较稳。如果4位数码管扫描周期是8ms,那么每位置就只能亮2ms左右,占空比只有1/4。占空比太低会导致亮度明显下降,所以动态扫描显示器的段选限流电阻通常要比静态显示取得小一些,否则看起来会很暗。
写代码时要注意消隐:每一位切到下一位置前,先把段选全部清零,再切换位选,否则下一位会短暂显示上一位的残影。这个“先关段,再换位,再开段”的时序,是动态扫描最常见的调试点。很多人显示乱跳第一反应是“硬件虚焊”,其实多半是代码里没有消隐。我习惯把这段专门封装成一个函数,注释里写清十六字口诀:先灭段、再换位、后送码、必消隐。
4.3 编码器/译码器在现代FPGA设计中的“还魂”
如果你将来接触FPGA或Verilog/VHDL,可能会以为74LS138这种中规模芯片已经“退出历史舞台”。实际上恰恰相反,编码器和译码器的行为定义已经“融化”成了硬件描述语言里的基本语句。你写一个case语句,综合器会自动把它翻译成类似译码器结构的选择逻辑;你写一段if-elseif,综合器也会自动生成带优先级的编码逻辑——这本质上就是把74LS148内部结构重新描述了一遍。
比如你想在FPGA里实现一个3线-8线译码器,直接这样写就能得到和74LS138行为几乎一致的功能:
module decoder3to8 ( input wire [2:0] a, input wire en, output reg [7:0] y ); always @(*) begin y = 8'b11111111; // 默认全无效,对应低电平有效 if (en) begin case (a) 3'b000 : y = 8'b11111110; 3'b001 : y = 8'b11111101; 3'b010 : y = 8'b11111011; 3'b011 : y = 8'b11110111; 3'b100 : y = 8'b11101111; 3'b101 : y = 8'b11011111; 3'b110 : y = 8'b10111111; 3'b111 : y = 8'b01111111; default: y = 8'b11111111; endcase end end endmodule这段代码的重点是默认值先给“全1”,再用case覆盖选中路为0,正好模拟了74LS138低电平有效、未选中路全部为高的行为。有了这样的映射能力,你在纸上推导过的所有使能、级联、最小项技巧,在FPGA里依然是有效的底层心智模型。很多初学者直接学RTL发现逻辑“悬”,就是因为缺了数电芯片这一层硬件直觉的支撑。
5. 跳出芯片看工程:旋转编码器、伺服编码器与STM32中的“编码器”
5.1 编码器这个词到了电机控制里,指的是什么
第5章要彻底把话题从“数电课本”拉开,因为它已经到了嵌入式工程的实际场景。旋转编码器本质上是一个传感器,把电机或机械轴的转角、位置、速度转换成数字脉冲或数字量。它的“编码”方式和74LS148完全不是一个层级的,但底层思想有共通之处:码盘上的码道、刻线、光电/磁感应单元,组合起来就是一张“转角和二进制码”的真值表。
增量式旋转编码器输出三路信号:A、B、Z。A和B相位相差90度,称为正交信号,用来判断方向和计数;Z每转一圈输出一个脉冲,作为绝对零位参考。绝对值编码器则直接输出位置码,可以是二进制码、格雷码,也可以是串行协议(如SSI、BiSS、CANopen)里的数据帧。它的优点是断电后位置不丢失,不需要“找零”,在伺服电机、机器人和数控机床里几乎是标配。
如果你在网上搜“磁编码器AS5047P”“双磁编码器测电机位置”“码盘式编码器”,都属于旋转编码器的范畴。它们之间只是“用什么方式感知”的区别:光电式用码盘挡光,磁式用磁铁加霍尔/磁阻传感器,但都要解决一个问题——把连续的机械角度离散化成数字量,分辨率越高,码道越多,信号处理越复杂。
5.2 正交信号、倍频计数与STM32定时器编码器模式
增量式编码器测方向靠的是A、B两路相位关系。假设编码器正转时A超前B,反装时B超前A。判断方法:在每个边沿查看另一路电平,比如A上升沿时若B为低,判定为正转;若B为高,判定为反转。用“边沿+状态”组合查表,就能实时知道方向和步进。
这里有个关键工程点:倍频。编码器输出A/B每转各N个脉冲,如果只在A的上升沿计数,一转发N个脉冲,叫1倍频;在A的上升沿和下降沿都计数,是2倍频;A和B的上升沿、下降沿都计数,就是4倍频。4倍频后每转计数值变成4N,分辨率在数值上提高了4倍。注意,这个提升只是“计数细分”,不会改变码盘刻线的物理精度,所以它提高的是测量分辨率,不是绝对精度。
STM32的定时器有一个专门的编码器模式,就是把定时器的两个输入TI1、TI2接A、B,硬件自动完成“哪个边沿该不该计数、该加还是该减”的判断。用STM32CubeMX配置时,只需要选一个定时器,把模式设为Encoder Mode,决定是TI1计数、TI2计数还是TI1+TI2都计数,再设置预分频和自动重载值就行。代码上,初始化和普通PWM捕获几乎一样,区别是把计数方向标志位读出来就能得到转向:
// 假设TIM3已经通过CubeMX配置为Encoder Mode int16_t position; uint8_t direction; position = (int16_t)__HAL_TIM_GET_COUNTER(&htim3); if (__HAL_TIM_IS_TIM_COUNTING_DOWN(&htim3)) { direction = 1; // 反转 } else { direction = 0; // 正转 }配置方面的坑一般集中在:编码器信号没接对TI1/TI2对应的GPIO、定时器重载值小于单圈计数值导致计数溢出、没有开启上拉或下拉导致悬空抖动。切记,编码器输出是开漏还是推挽,会影响GPIO是否要配置上拉,这往往是“明明信号对接了就是计数乱”的元凶。
5.3 伺服驱动器中“编码器线数262144”到底能不能改
搜索热词里有一条很典型:“汇川伺服ms1h4在驱动器里查看到默认编码器线数是262144,这个数值可以改吗?”但凡你做过伺服电机调试,一定会遇到这个问题。先把这个数字拆开看:262144正好是2的18次方,说明这颗电机配的编码器是18位分辨率,也就是单圈能区分262144个位置。它对应的要么是17位增量+1位多圈,要么是18位绝对值编码器,具体以电机铭牌为准。
驱动器中显示的“编码器线数”本质上不是你可以随便改的“电子齿轮比”,而是编码器硬件本身上报给驱动器的分辨率参数。驱动器只是把这个值读出来,用来换算转速和位置。如果你强行去改这一项,哪怕只差一个数量级,驱动器换算出的实际位置、速度都会完全错乱:轻则电机原地抖动自检报错,重则运行时飞车报警。很多伺服驱动器在修改编码器相关参数后,会强制要求重新上电或重新识别编码器,就是这个原因。
那“这个数值可以改吗”这个问题,正确的理解应该是:可以改的是控制侧的电子齿轮比、每转脉冲数设定、分频输出参数,而不是编码器物理分辨率。你如果想要“少脉冲跑完整圈”,事情应该在驱动器电子齿轮里做,而不是编辑编码器线数。我见过有人为了省事直接把线数改成10000,结果电机转一下驱动器直接报位置超差,折腾半天又改回来,纯属白忙一场。
关于伺服这类问题,我一般建议的处理步骤是:先核对电机铭牌上的编码器类型和位数,再对照驱动器手册确认参数含义,最后用驱动器自带的“编码器识别/初始化”功能重新读取。如果显示值与铭牌不符,优先检查编码器线缆、屏蔽层接地和供电电压,而不是立刻怀疑软件参数。调试表格见下:
| 现象 | 可能原因 | 处理方案 |
|---|---|---|
| 驱动器显示编码器线数和铭牌不一致 | 编码器线缆接触不良、型号混淆 | 重新插拔并固定线缆,按铭牌重新识别 |
| 修改线数后电机报位置超差 | 参数含义理解错误 | 恢复默认参数,在电子齿轮比处做调整 |
| 电机上电后自检异响、编码器报警 | 编码器供电异常、屏蔽层未接地 | 检查5V供电,单点可靠接地 |
| 编码器读数随机跳变 | A/B信号未配上下拉、干扰耦合 | 调整GPIO上下拉,缩短线缆,加磁环 |
6. 实验中的常见问题与排查技巧:从毛刺到级联失效
6.1 组合逻辑毛刺为什么难抓,要怎么消
用示波器抓74LS138的输出,有时会看到在输入切换过程中,明明应该保持高电平的Y输出上出现一个很窄的低电平脉冲,这就是竞争冒险产生的毛刺。原因是A、B、C三条输入线的信号到达译码器内部与门的时间不同:有的线先到,有的线后到,在极短时间里就会出现一个错误的临时状态,组合逻辑没有寄存器的“同步”保护,所以这个临时状态会直接反应到输出。
理论上,毛刺可以通过在逻辑表达式里添加冗余项来消除,比如利用卡诺图找多余圈合并项,但工程里更常用的做法是加选通脉冲或输出端并联一个小电容做滤波。选通脉冲的思路是:等输入信号都稳定下来后,再打开一个“门”让输出通过,这个门通常由时钟信号或控制信号充当,相当于把组合逻辑输出“锁存”到稳定的那一段。对低速数字电路来说,输出到地并联一个几十到几百皮法的电容也能把高频毛刺平滑掉,但上高速时就别这么干,会把正常边沿也废掉。
抓毛刺用示波器也有技巧。毛刺往往是单次的、极窄的,普通自动触发根本逮不住。我习惯把触发模式设成“单次”,触发电平设到问题电压附近,然后用一根很短的接地弹簧针代替长地线夹,减少探针环路引入的高频噪声。如果被测信号是一个周期性的切换过程,还可以用“脉宽触发”功能专门抓窄脉冲。总之,调试这类问题急不得,先把触发通道调好,再去怀疑芯片。
6.2 级联场景下的“反逻辑”陷阱
级联74LS138做4线-16线译码器时,最常见的错误是使能端的极性搞反。G1要求高电平有效,G2A和G2B要求低电平有效,三者是“与”的关系。以A3作为片选高位时,第一片需要A3=0时工作,所以要经过反相器接到G1;第二片需要A3=1时工作,直接接G1,同时G2A和G2B都必须接地。多了一个反相器,就多了一次“思维取反”,很多人会把第一片的接法漏掉反相器,结果A3=0时两片都不动,A3=1时两片都在抢。
还有一种“用输出使能做数据分配器”时的极性陷阱:数据D如果接在G2A上,而G2A是低有效,当D=1时芯片被禁能,输出Y全部为高;D=0时芯片使能,选中路输出低电平。也就是说,你对某一路输出看到的是D的反相信号,不是D本身。如果要把D原样送出去,要么把D接到G1上并知道高电平有效,要么在输出端再做一次反相。很多实验报告上的“分配器结果和理论不一致”,根子就在这里。
针对级联,我给自己定了一条“必查清单”:第一步核对每片芯片的EI/使能端初始状态,第二步确认输出端反相端子的接法,第三步用万用表测每个输出引脚的静态电平,第四步单独测每片芯片的功能,最后再整体联调。这套顺序虽然慢,但能避免“问题在两片芯片之间互相甩锅”的僵局。
6.3 按键编码输入抖动、编码不稳定的实战处理
给74LS148配按键输入时,毛刺不只在输出端出现,按键本身就是一个巨大的干扰源。机械按键的簧片在按下和释放瞬间会不断弹跳,持续时间从几毫秒到几十毫秒不等。如果你直接把按键接到编码器输入端,按一下键盘,编码器可能连续输出好几个不同的编码,看起来就像是“按键乱跳”。这不是编码器坏了,而是输入信号本身脏。
硬件上最经典的消抖方案是RC低通滤波器加施密特触发器。按键串联一个小电阻到编码器输入,再在输入引脚对地并联一个电容,让抖动被积分平滑掉;后面用施密特反相器做整形,恢复出边沿干净的数字电平。RC时间常数取1ms到10ms之间比较合适,太小滤不干净,太大会让按键响应变慢。软件上,单片机也可以做延时消抖:检测到电平变化后,延时10到20ms再读一次,确认状态一致才认为是有效按下。
另外,使用74LS148做键盘编码时,要习惯把“无有效输入”和“有有效输入”分开处理。无输入时GS为高,此时即使有低电平输入也可能是噪声,处理逻辑应该忽略这种状态;只有GS变低,输出编码才可采信。这样配合硬件滤波,编码器的稳定性会有质的提升。我记得有次帮学生调四路抢答器,每抢一次显示数字就乱跳,最后查出是按键供电线上长了,加上滤波电容后立马稳了。排干扰这种事,看似是小问题,实际往往决定一个项目能不能交付。
就我个人经验来说,把74LS138、74LS148这两块芯片在面包板上亲手搭一次,比你对着书背十遍真值表都有用。它们的原理不复杂,但里面埋着的低有效逻辑、使能端、级联、最小项思想,会在你后面学单片机地址映射、FPGA状态编码、伺服电机控制时反复冒出来。我建议你现在就可以找个实验板,做一个小项目:八个按键输入,经过74LS148编码,再通过74LS138译码,点亮对应一盏灯,最后用数码管把编号显示出来。这个“从按到亮到显示”的小链路,跑通一次,你会发现数字电路里很多零零碎碎的概念突然就全串起来了。
如果是已经在做工程的朋友,那就从编码器测速这个角度入手,用STM32的定时器编码器模式接一个带ABZ的增量编码器,先4倍频测转速,再慢慢过渡到伺服驱动器里的编码器参数配置。踩过几次坑之后,你会建立起一个很重要的心态:任何“编码器”本质上都是把真实世界的信息换一种更高效、更可靠的形式存起来或传出去——弄清楚它输入什么、输出什么、为什么是这个编码规则,比记住任何一个芯片型号都重要。