从74LS148到磁编码器:编码译码原理与工程应用全解析
1. 理解编码器与译码器数字电路里的“翻译桥”1.1 为什么编码器“编码”这件事如此重要我在带学生做数字电子技术实验时经常问第一句话如果让你把一个8路的按键状态传给单片机你会怎么做新手很可能老老实实拉8根I/O口线一个一个读稍微有点经验的人会想到按键实际只有“按下/松开”两种状态8个按键一共有256种组合而你真正关心的只有少数几种。这时候编码器的价值就出来了把多路信号按照某种规则压缩成一组二进制码用更少的线去表达同样的信息量。这就是编码器最核心的定位——多输入到少输出的信息压缩。74LS148就是最经典的8线-3线优先编码器8个输入最多只需3根输出线就能表达整整省掉5根线。别小看这5根线几十年前电路板上走线资源宝贵少一根线就意味着更小的板面积、更低的成本和更少的故障点即便放到今天编码器的思想仍然是总线通信、存储地址管理、指令集设计的地基。从搜索引擎热词里能看到“编码器工作原理”、“增量式编码器”、“绝对值式编码器”、“磁编码器”这些高频搜索说明大家对编码器的理解已经从教科书里的门电路延展到了工业测速、电机控制、位置检测这些真实场景。这篇文章我打算从教科书里的基础芯片讲起一路把这些热词背后的东西串起来讲让刚入门的朋友知道门电路和电机编码器其实是同一个思想在不同物理层面上的落地。1.2 译码器是编码器的逆过程吗先给结论功能上互为逆过程逻辑上却有着本质区别。编码器面对的是“多个输入可能同时有效”的情况所以它有优先级只认最该认的那一路译码器面对的是“一组二进制码”它要做的是一对多地把这个码翻译成某一条线有效输出是互斥的。74LS138就是个教科书级的3线-8线译码器。3根地址输入8根译码输出任一时刻只有一个输出有效低电平其余全部为高。它和编码器正好组成一套完整的信息通路A端编码B端译码中间用3根线连起来就能够实现8路信号的远距离传输或逻辑选择。我在实际板卡里用138做过内存片选扩展一段地址总线接进来A15、A14、A13 三位就能决定这8个外设芯片里到底“叫醒”哪一个效果非常干净。还有一个让很多人困惑的点译码器的输出是低有效还是高有效。74LS148和74LS138的输出全都是低有效也就是“有效的时候输出0”。这不是设计者故意为难人而是TTL电路里拉低比拉高更容易驱动、抗干扰更好同时在总线系统里有“线与”这个天然优势。很多初学者在这里栽跟头拿着LED的高电平点亮电路去接138发现LED全都不亮其实只要把LED接到输出端和VCC之间灌电流方式立刻就能工作。1.3 信息表示的压缩与还原我特别想用一个比喻来帮助理解这对组合编码器就像把一个大房间里的8个人分成3组每人身上挂个编号牌用3位数字就能找到任何一个人译码器则是根据编号牌把人领出来。这中间压缩的是“线缆资源”还原的是“控制目标”。整个数字系统里地址总线、数据总线、控制信号的产生处处都是这对“翻译桥”在起作用。热词里还出现了“lav编码器”、“ffmpeg编码器”、“自编码器”这些概念说实话它们和数字电路里的编码器已经不是一个范畴了但底层思想是相通的——都是用某种规则做信息压缩。理解了74LS148的优先级机制你再看视频编码里的码率控制、再看自编码器的瓶颈层都会有一种“原来是一个套路”的豁然开朗。这篇博文后面我也会专门讲一讲这些“同名的异类”帮大家把脑子里这几团概念分清楚。2. 核心芯片逻辑拆解74LS148 与 74LS1382.1 优先编码器的真值表与逻辑表达式推导先动手画一下74LS148的内部逻辑。它有8个输入 I0-I7低有效3个编码输出 Y2-Y0低有效还有两个扩展用的输出 GS 和 EO。优先级从高到低是 I7 I6 I5 I4 I3 I2 I1 I0。当 I7 为低时不管别人是什么状态输出必定是对应 I7 的编码。初学者最容易犯的错是低有效输入看得头晕。我建议自己先画一张“高有效”版本的8线-3线优先编码器真值表比如设输入 A7-A0高有效优先级 A7 最高输出 Q2-Q0 高有效先把逻辑想清楚再往低有效上翻译。高有效下的逻辑式可以写成Q2 A4·~A5·~A6·~A7 A5·~A6·~A7 A6·~A7 A7 Q1 A2·~A3·~A4·~A5·~A6·~A7 A3·~A4·~A5·~A6·~A7 A6·~A7 A7 Q0 A1·~A2 A3·~A4 A5·~A6 A7这组式子表达的意思就是某一级的输入有效时比它优先级更高的输入必须全部无效这个输入才能参与编码。推导过程如果觉得长可以直接用卡诺图化简化简完跟上面的结果对照一下基本就能记住了。低有效的148版本在芯片内部相当于把这些输入输出都加了一层反相器。实际用起来我建议新手在面包板上搭一次148驱动8个按键数码管显示编号的实验。先把148的 E1使能端低有效接地8个按键一端接地、一端接输入引脚输出端接一个反相器阵列再接LED或者直接接74LS48驱动数码管。按下哪个键数码管就显示对应的按键编号。这个实验做完优先编码器的“优先”两个字是刻在脑子里的比看十遍手册都管用。2.2 3-8译码器的工作原理与级联扩展74LS138的三根地址线 A2-A1-A0 的组合有8种000到111每种对应一个输出 Y0-Y7 变成低电平。三个使能端 G1高有效、G2A低有效、G2B低有效全部满足条件译码才真正生效。级联成4-16译码器是复试和面试经常问的题。思路是第一片138处理地址的低三位第二片处理高三位而最高位地址线 A3 用来决定哪一片工作。具体做法是把 A3 直接接到第一片的 G1 或者第二片的某个使能端同时保证两片的使能条件互斥。我之前给实验室做过一个4-16存储器体选电路用了两片138加上一个反相器A15 为低时选通第一片8个体A15 为高时通过反相器让第二片工作另外8个体16个体整整齐齐全部到位。级联时有个很容易踩的坑使能端的时序。138的输入到输出是有传输延迟的地址变化的那一瞬间输出可能产生毛刺。比如从地址011跳变到100其中某一位先变、某一位后变中间会闪出一个不属于011也不属于100的“非法”组合对应的译码输出就会出现一个极窄的低脉冲。这在驱动锁存器或触发器的片选信号时会导致误锁存。我的习惯是所有片选信号都加一级寄存器同步或者用74LS373/374把地址先锁存住再做译码宁可多花一个芯片也不跟毛刺较劲。2.3 译码器的典型应用数码管驱动与地址译码译码器最轻松的场景是数码管扫描驱动。一个4位共阴数码管段选码用74LS48或者CD4511这种BCD-7段译码器直接输出位选码用74LS138来轮流为每一位提供电源。动态扫描的情况下138的三根地址线不断周期变化就能让4位数码管“同时”显示4个数字。数码管扫描频率记得调到50Hz以上不然人眼能看出闪动。我见过不少同学在实验板上把扫描周期调成100ms屏幕闪得眼睛疼还以为是芯片坏了其实就是扫描频率不够高。另一个重要场景就是前面说的地址译码。在51单片机和8086时代的板卡里地址空间被切成若干段每一段对应一个外设或一片存储芯片138就是做这个“切段”的刀。80C31外部程序存储器用一片2764地址总线 A12-A0 连芯片地址A15、A14、A13 接138的输入138的 Y0-Y7 分别接8片2764的片选一个64KB的存储空间就划分好了。这个设计思路到今天还在用很多ARM处理器内部的“总线矩阵”和“外设时钟门控”本质上就是个更复杂的译码网络。3. 从课本到工程增量式、绝对值与磁编码器3.1 增量式编码器是什么A/B/Z三相的正交解码课本讲完74LS148不少人心里会问那我电机上装的编码器也是这个东西吗答案是电机编码器不叫这个名字机制也完全不同但它同样是在“编码”位置信息。增量式编码器是工业自动化里最常见的一种它内部有一个码盘码盘上刻画着均匀的透光/遮光条纹光栅转动时光电传感器输出两路相位相差90度的方波信号习惯上叫A相和B相。转动方向不同A、B之间的超前滞后关系就不同。判断方向的方法很简单A相上升沿的时候如果B相是高电平说明码盘正转如果B相是低电平说明反转。把A、B两路信号各当成一位二进制码一个转动周期会出现00-01-11-10四种状态正好对应一个四状态的循环。所谓“4倍频”就是把这4个状态全部检测出来每变化一个状态就计一个数所以一圈的计数等于物理光栅条纹数的4倍。测速精度一下就提高了一个量级。增量式编码器还有一根Z相每转一圈只发出一个脉冲用来做机械零点定位。实际接线的教训是Z相一定要接上不然后期做设备回零点时你会怀疑人生。我调试过一台自动化设备只用A/B测算位置断电再上电位置信息全部丢失每次都要手动找原点。后来老老实实把Z相接进PLC的高速计数模块上电后执行一次找零动作就解决了。3.2 绝对值式编码器与磁编码器AS5047P绝对值编码器则是另一种路子它的码盘上每一圈都刻着独一无二的二进制码型读出来就知道现在处在360度里的哪个绝对位置断电再上电也不会丢位置。它有两种输出形式并行输出管脚一大堆串行输出走SPI或RS485。绝对值编码器的核心参数是“单圈分辨率”常见的有17位131072、23位8388608这些数字看着夸张其实就是把一圈360度切成了2的N次方份。磁编码器则是近年越来越火的方向。热词里提到的AS5047P是奥地利微电子ams后来并入SGP半导体其实是ams OSRAM现在归SGP这里我不展开品牌归属问题一颗14位的磁角度传感器内部集成了霍尔阵列和CORDIC算法直接输出绝对角度分辨率16384即每圈2^14个位置。它的好处是抗污染、耐振动、体积小码盘和芯片之间可以隔着塑料或铝壳非磁性材料所以防水防尘好做。我用AS5047P做过一个云台电机的位置环。硬件上只需要在电机转轴末端贴一个径向充磁的小磁片传感器正对磁片中心间距控制在1-3mm左右上电之后SPI读取角度寄存器值稳定在0-16383之间。需要注意的坑磁片必须严格对中偏心会导致角度波动另外传感器周围不要有强磁性物体电机本身的永磁体如果离得太近也会干扰。解决方法是把传感器支架尽量远离转子或者在中间加磁屏蔽片。3.3 伺服电机默认编码器线数262144到底代表什么热词里有个很有意思的问题“汇川伺服ms1h4在驱动器里查看到默认编码器线数是262144这个数值可以改吗”。262144这个数字看起来像随手写的其实非常讲究2的18次方刚好是262144。这意味着一圈被分成了262144份大约是0.00137度一个脉冲已经远超绝大多数机械系统的执行精度。你在驱动器里看到的这个数是编码器反馈的物理分辨率由编码器本身决定通常改不了。但是“实际运动精度”是可以通过电子齿轮比调整的。伺服驱动器接收上位机发的脉冲指令电子齿轮比把指令脉冲数换算成电机的实际位移。比如默认一圈要262144个指令脉冲如果你把电子齿轮比设为262144/10000那上位机只需要发10000个脉冲电机就转一圈。所以你真正该调的是电子齿轮比而不是编码器线数强行去改编码器分辨率只会让反馈乱套。有一点要提醒如果驱动器软件里有“编码器分辨率”或“编码器线数”这个参数并且允许修改一般有两种情况一是它会把分辨率数值重新写入编码器内部寄存器没有厂家授权的特殊工具做不了二是软件把它当“用户自定义换算系数”来使用改完不影响编码器本身的物理输出只影响显示和控制精度。不论是哪种我都建议先看手册或者直接问厂家技术支持。伺服电机的编码器和普通增量编码器不一样它内部常有电池保存的多圈数据乱写参数可能导致位置丢失。3.4 测速场景里的分频倍频与方向判断用编码器测速时倍频和分频经常被人搞混。倍频是把编码器输出的脉冲精度提升的手段前面说的4倍频是单片机对A、B两相全部上升沿和下降沿都做计数得到的分频则是为了匹配上位机接口或减小高频干扰在编码器后面加分频电路或软件分频。把这两个概念分清楚你在看数据手册里的“编码器线数”的时候就不会懵线数是物理条纹数不是倍频后的计数。方向判断是另一个容易踩坑的点。STM32的定时器编码器模式用硬件做正交解码计数方向由A、B相位自动决定。但如果你把A、B接反了计数方向就反了。调试方法也很简单手动缓慢转动电机轴一圈看计数器是递增还是递减如果和预期相反交换A、B两根线即可。还有一种情况是电机正转但计数器递减这在闭环系统里会导致正反馈失控电机猛冲甚至撞限位务必先检查方向再上伺服。4. 实战用STM32定时器编码器模式做电机测速4.1 硬件接线与基本配置步骤这里给一个可以直接抄作业的电机测速方案STM32F103 带霍尔正交输出的增量编码器例如常见的欧姆龙E6B2-CWZ6C200线/圈 一个带减速箱的直流电机。接线如下编码器A相接TIM4_CH1PB6B相接TIM4_CH2PB7这是Timer4的通道1和通道2VCC和GND按编码器要求接好注意编码器供电电压和STM32的I/O电平是否兼容E6B2-CWZ6C是5V供电输出也是5V需要在信号线上串联1k电阻分压或者用双向电平转换模块。CubeMX配置顺序先选TIM4Clock Source里勾选Internal Clock然后在Combined Channels下拉里选Encoder Mode此时Channel1和Channel2自动变成Encoder A和Encoder B极性都选Rising上升沿计数模式选Combined Rising/Falling也就是对两个通道的上升沿和下降沿都计数这就是4倍频Period也就是ARR设成65535配合32位无符号计数在F103的16位定时器里溢出中断里做扩展计数就行。有一点建议初学的时候先把编码器的输出A、B信号用示波器确认一下确保有方波再进单片机。没有示波器的话可以用万用表量直流电压转动电机时A或B对GND的电压应在大约0V和供电电压之间变化。接着再读TIM4的CNT寄存器如果ANT值随转动而变化说明硬件通路已经通了一半。4.2 编码器模式下的关键参数计算STM32定时器编码器模式支持的倍频系数有1倍频、2倍频和4倍频三种由TIM_SMCR寄存器里的SMS[2:0]位和CCER里的CC1P/CC2P位组合决定。最常用的是4倍频也就是对A、B的每个上升沿和下降沿都计数。假设编码器物理线数是2004倍频后一圈的计数就是800。速度计算的关键是采样周期的选择。我一般固定一个时间窗口比如10ms每次进入定时中断时读一次CNT然后把CNT清零或记录差值。设编码器每圈总计数为N比如800时间窗口为T秒那么转速圈/分钟就是RPM (deltaCNT / N) / T * 60举个例子10ms内CNT增加了40个计数N800T0.01秒那么转速 (40/800)/0.01*60 300转/分。这里要特别注意CNT是16位的转动很快时会溢出65536次溢出也就是要处理溢出。我习惯是断开定时器中断和计数器更新在DMA或主循环里快速读取读CNT时溢出中断服务函数里把高16位标志加一这样实际上就有了32位计数值。F103的TIM4是16位定时器400线编码器4倍频后一圈1600计数转速6000转/分时每秒160000个计数16位定时器每0.4秒就溢出了采样周期必须小于这个值。4.3 读数抖动与滤波处理编码器读数抖动的场景我至少见过五种电路接触不良、机械振动、电磁干扰、电源纹波大、A/B相接线过长导致信号衰减。如果你是白面包板搭的电路优先怀疑接触不良每根杜邦线都重新插一遍。如果电机启动瞬间读数乱跳大概率是电源问题电机启动电流很大把单片机的VCC拉低单片机本身就处于不稳定的工作状态必须给电机单独一路电源编码器供电最好也从独立小电源取。软件滤波我的经验是滑动平均值滤波最实用。维护一个长度为8的数组每10ms采样一次去掉最大和最小值剩下6个取平均。这个滤波器对偶尔的毛刺非常有效而且平滑度高。缺点是有约80ms的延迟对于转速环控制来说足够了如果是电流环或者要求更快的响应就把窗口缩到4。还有一种情况是电机低速时CNT读数在某个值附近±1抖动这是编码器量化的必然结果不是故障不必过度滤波把真实速度信息滤没了。4.4 方向反向、溢出与零位处理方向反了是新手最常见的问题。我在调一个四轮小车时反复确认过A、B接线没有错但实际转起来计数方向还是反的后来发现是电机供电线反接了。编码器只是检测码盘转动不关心电机供电所以把电机两根线换过来计数方向自然就反了。这种情况下不必动编码器接线直接软件处理可以在初始化时配置TIM4的CCER里的CC1P和CC2P或者干脆读出方向标志位时取反。注意千万不要在电机转动时拔插编码器线热插拔容易把芯片的ESD保护打坏。零位处理是闭环系统绕不开的话题。增量编码器的Z相脉冲是每一圈的机械零点如果电机带动丝杠或转台转动断电再上电后电机的绝对位置未知必须先让设备走一次“找零”流程往固定方向缓慢移动直到检测到Z相下降沿才认定位置归零。这个流程看起来土但工业机器人和数控机床都是这么干的除非你用绝对值编码器才能上电即知位置。5. 常见问题排查速查从课本实验到工程调试5.1 组合逻辑电路中的毛刺与竞争冒险做74LS138译码实验时用示波器看Y输出会发现电平平稳但地址切换的瞬间经常有窄毛刺。这个现象叫竞争冒险是组合逻辑电路的固有属性。原因在于信号从A0传到138内部的不同路径上经历的延迟不同导致某一瞬间出现了地址的非法组合对应的输出被短暂错误拉低然后又恢复。处理毛刺有几种思路第一种是输出端加RC低通滤波这适合负载电流小的信号比如接到LED显示或者施密特触发器前面时间常数选1-10us左右第二种是输出端接D触发器打一拍让信号在时钟沿时刻再采样毛刺被时序电路直接滤掉第三种是尽量缩短地址线的长度、对地址线做等长设计从根源上减小延迟差。另外如果毛刺只是偶尔影响显示而不影响逻辑功能有时候直接忽略也不是不行但千万别在给锁存器片选或中断引脚的信号上忽略。5.2 译码器输出带不动负载的原因排查很多同学把LED直接串电阻接到138的Y端发现灯不亮或者亮度很低。原因往往是驱动方式不对。74LS138输出低电平时灌电流能力大约8mA输出高电平时拉电流能力只有0.4mA左右。LED正确接法是把LED阴极接到Y端、阳极通过限流电阻接到VCC也就是灌电流驱动反过来用拉电流驱动电流不够LED自然暗。这个规律适用于74LS系列大多数芯片。如果负载电流更大比如驱动继电器或蜂鸣器就必须加三极管或达林顿管甚至用ULN2003这种集成的达林顿阵列来扩流。我一直强调芯片的数据手册里看输出电流参数的IOL和IOHIOL代表灌电流能力IOH代表拉电流能力两者数量级经常差好几倍。设计电路前花一分钟确认这个参数能省下半天的排故时间。5.3 广义编码器困惑播放器缺解码器和AI自编码器最后聊一个搜索引擎里特别有意思的现象很多人搜“编码器”的意图并不是数字电路而是遇到了“您需要新的编码器来播放此项”的弹窗或者在用FFmpeg处理视频时总在挑编码器参数。这其实是“编码器”这个名词在不同领域里的不同含义。在视频播放领域编码器/解码器Codec负责对音视频流做压缩和解压缩。弹窗提示“需要新编码器”通常意味着播放器缺少对应的解码器比如下载了H.265/HEVC编码的视频但播放器或操作系统不支持硬解解决办法是安装解码插件或者用支持该解码器的播放器例如VLC、PotPlayer。FFmpeg里常用的编码器有libx264H.264、libx265H.265、libvpx-vp9VP9这些都是软件编码器编码质量和速度之间的取舍才是调参的关键。在AI领域自编码器Autoencoder是无监督学习的一种网络结构包含编码器和解码器两部分编码器把高维数据压缩到低维解码器再重建回来。它和74LS148一样都是压缩和还原的框架只不过它的压缩规则不是人编的是神经网络从数据里学出来的。理解了这个“同构”关系你再看任何一种编码器都会觉得没那么神秘。5.4 编码器信号踩坑速查表现象可能原因排查思路译码器输出全高/全低使能端条件不满足检查G1、G2A、G2B电平是否符合手册要求LED亮度太暗驱动方式错误/限流电阻过大改为灌电流驱动电阻取470-1kΩ编码器读数方向反A/B接反或电机供电反调换A/B信号线或软件取反方向标志读数跳动剧烈电源纹波/地线回路/接触不良独立供电缩短杜邦线用屏蔽线高速时读数丢失采样周期大于溢出周期/信号衰减缩短采样周期处理CNT溢出加缓冲驱动伺服电机编码器线数无法修改物理分辨率固定改用电子齿轮比调节指令脉冲与位移关系播放视频提示缺少编码器解码器未安装安装解码器或改用第三方播放器这张表并不是用来背的建议收藏起来遇到问题先对号入座再动手。排查有一个原则永远不要破先硬件后软件先供电后信号。电源上电一瞬间的纹波、地线上的压差是无数奇怪现象的源头。我把实验室里的所有编码器都强制要求独立供电共地但分开电源从此再没遇到过因为电源引起的读数异常。我的经验沉淀我带过的每一个数字电路实验班都会在编码器和译码器这两块芯片上花掉比预期多一倍的时间。不是芯片有多难而是它们牵扯出来的知识点实在密集高低有效、使能逻辑、竞争冒险、级联扩展、驱动力、时序配合哪一个拿出来都够新手研究一阵。但这些恰恰是数字系统的骨架弄懂之后再碰到任何组合逻辑芯片看手册的速度都明显更快。如果让我给读者一个最务实的建议我会说先搭一次148138的组合实验再拿STM32做一次编码器测速这两个实操做完你对“编码器”的理解就不再是一个名词而是脑子里真正立体的数字系统图像。之后再碰到伺服驱动器里262144这样的数字你能一眼看懂它背后的位数和原理碰到播放器弹窗提示缺解码器也不再一头雾水。最后分享一个小技巧把74LS148和74LS138的完整真值表手抄一遍然后不看资料把逻辑表达式推出来再对照数据手册检查。这个动作我每带一届学生都建议他们做几乎所有人做完之后都告诉我“原来芯片是这么设计的”。数字电路这东西背手册不如推真值表推真值表不如亲手焊一遍。