CD74HC4067多路复用器扩展ADC通道的完整实战指南
2026/9/9 4:04:52 网站建设 项目流程

1. 为什么我会选CD74HC4067而不是直接买一块ADC板

先交代一下背景。手头一个项目需要采集16路模拟量,MCU用的是一颗自带2个ADC外设的STM32,内部ADC通道拢共加起来也就十几个,但光留给传感器信号调理电路的接口就占掉了大半——有的通道接了电位器,有的接了NTC热敏电阻分压,还有几路要监测外部0到5V的电压输入。扣除参考电压测量、内部温度传感器这些占用的通道之后,真正能自由分配给模拟量采集的ADC输入引脚不到8个。这时候摆在我面前的无非三条路:

  • 换一颗ADC通道更多的MCU,但涉及硬件改板、固件移植,项目周期不允许;
  • 外接一颗独立的ADC芯片,比如ADS1115、ADS1256这类,优点是精度高、带PGA,但成本高,而且I2C/SPI通信时序要重新调;
  • 用模拟多路复用器扩展,也就是CD74HC4067这类芯片,把MCU现有的1路ADC输入扩展成16路模拟输入,通过数字IO选通。

我最后选的是第三种方案。原因很实际:CD74HC4067这颗芯片便宜到可以忽略不计,几毛钱一颗,SOP-24封装也不算难焊,而且它不需要改MCU的ADC配置,软件上无非就是“切通道、等稳定、启动采集”这套循环。对于采样率要求不高的静态或者慢变信号场景,它的性能完全够用。

再说白一点,如果你的采集对象是温度、电位器位置、电池电压、压力传感器这类变化频率极低的信号,用多路复用器扩展通道是最划算的做法。它唯一的短板是不能同时对所有通道采样,同一时刻只能读一路,所以不适合需要多通道同步采集或者单通道高频连续采样的场景。这一点项目评审时就要想清楚,别等板子画完了才发现需求对不上。

另外也顺便说一下为什么没用诸如74HC4051这种8选1的芯片——16路输入如果拆成两组8路,也完全可以,但那样会多占用一路ADC和几个控制引脚,板子布线和代码逻辑都会变复杂。既然4067一个芯片就能解决16路,而且控制引脚只要4根(S0到S3),加上一个使能脚EN,总共5根数字IO,省下来的引脚还能干别的,那就没必要用两颗或者搞级联方案。

2. CD74HC4067的工作原理和关键参数:先看懂再动手

2.1 16路开关的本质其实是一排可控的模拟开关

CD74HC4067是一颗16通道模拟多路复用器/多路分配器,内部结构说白了就是16个模拟开关,同一时刻只有一个开关闭合,把对应的输入通道(X0到X15)接到公共端(SIG)上。选通哪个通道由4根地址线S0到S3的组合决定,S3是最高位,S0是最低位,输入的4位二进制数从0000到1111,正好对应X0到X15这16个通道。

还有一个EN使能脚,低电平有效。把EN拉高之后,所有开关都断开,公共端SIG处于高阻状态。这个引脚在实际项目中挺有用,比如你想在系统刚上电、MCU还没初始化的时候让所有信号通道彻底隔离,就可以想办法把EN脚默认拉高。

地址线和使能脚都是标准的CMOS电平输入,兼容3.3V和5V逻辑,所以接STM32这类3.3V MCU完全没问题。

2.2 几个决定采集效果的参数

用多路复用器做ADC扩展,最怕的就是采集值不准、跳动大。CD74HC4067的数据手册里有几个参数必须提前吃透:

  • 导通电阻Ron:典型值大概在几十欧姆到一百多欧姆之间,手册上标注的Ron一般在40Ω到120Ω这个区间,具体和供电电压、输入电压有关。
  • 导通电阻平坦度ΔRon:不同通道之间的导通电阻差异,一般也有几个欧姆到几十欧姆。
  • 切换时间tON和tOFF:一般是几十纳秒级别,但这只是开关本身的速度。
  • 漏电流:断开通道的漏电流典型值在纳安级别,但温度升高后会增大。

Ron这个参数对ADC采集精度的影响最直接。虽然MCU的ADC本身输入阻抗很高(STM32的ADC采样电容在采样阶段等效阻抗有几千欧姆甚至更高),但如果你信号的源阻抗也很高,那Ron就会和源阻抗、采样电容组成一个RC滤波器,导致采样电容充不满,最后读到的值就偏低。后面我会详细说这个问题,这也是第二个调试坑的核心。

2.3 一个不太起眼但必须注意的事:公共端SIG的接法

CD74HC4067的公共端通常叫SIG或者COM,在数据手册里也叫Common I/O。这颗芯片的开关是双向的,也就是说信号可以随便从哪一边进、哪一边出,用起来非常灵活。但在ADC扩展这种场景下,SIG这个引脚一定要接到MCU的ADC输入引脚上,而16个通道X0到X15则接各路待测信号。

还有一个小细节容易被忽略:SIG引脚上如果走的是高频或者快速变化的信号,建议在SIG引脚对地加一个小电容,比如几十皮法到几百皮法,目的是滤掉通道切换时产生的毛刺。但注意不能加的太大,否则会和Ron组成低通滤波器,拖慢建立时间,导致通道切换后要等很久信号才能稳定,反而影响采样速度。

3. 硬件接线:看似简单,但几个细节决定了后面少踩坑

3.1 引脚分配建议

接MCU的时候,我实际用到的引脚如下:

CD74HC4067引脚功能接MCU引脚说明
S0~S3通道选择地址线4个普通GPIO推挽输出,速度无所谓,默认低
EN使能(低有效)GPIO不用时拉高,用的时候拉低
SIG公共输入/输出ADC输入引脚直接连ADC通道对应的引脚
X0~X1516路模拟输入各路传感器信号接待测信号
VCC正电源3.3V或5V按手册范围供电
GND系统地

有一点值得单独提出来说:地址线不要悬空,即使某个通道暂时用不到,也要在初始化阶段把GPIO全部配置好并输出确定电平。CMOS器件最怕输入悬空,悬空会导致输入电平不定,内部电路可能反复导通,产生额外功耗,严重的时候甚至可能影响其他通道的选通。

3.2 供电电压和信号电压的范围

CD74HC4067的供电范围是2V到6V,我板子上3.3V和5V都给这颗芯片供过电,工作都正常。需要注意的是,信号电压不能超过供电电压。如果你用3.3V给芯片供电,那输入到X通道的电压不能超过3.3V,否则芯片内部的ESD保护二极管会导通,导致测量失真甚至损坏芯片。

在这个项目里,因为MCU的ADC参考电压是3.3V,所以我直接用3.3V给4067供电,各路传感器输出的模拟信号也都是0到3.3V范围,匹配得很好。如果你的信号有0到5V的,那就得把4067接到5V供电,同时确认MCU的ADC输入引脚容忍5V,或者中间加一级电阻分压、运放跟随处理,不能硬怼。

3.3 两个我实际用过的接法变体

第一种是最常规的,CD74HC4067的SIG直接连到MCU的ADC引脚,使用单通道循环切换模式。这也是本篇文章默认采用的接法。它的优点是硬件最简单,缺点是采样过程中MCU要一直干预通道切换,CPU占用率偏高,不过对慢速采样来说无所谓。

第二种是给SIG加一级运放跟随器再接ADC。这个接法对信号源阻抗高的情况特别有效——运放跟随器输入阻抗极高,输出阻抗极低,等于把信号源和4067的Ron隔离开来,让ADC采样电容充电时间不再受Ron和信号源内阻的影响。代价是多一颗运放和几个电阻电容,但采集稳定性的提升是质的飞跃。如果项目里要采集的信号源阻抗在10kΩ以上,我非常建议直接上跟随器。

4. 驱动代码:从通道选通到数据滤波的完整实现

4.1 基础配置:GPIO和ADC初始化

我用的MCU是STM32F103系列,开发环境是STM32CubeIDE,HAL库。先看GPIO和ADC的初始化逻辑:

#define MUX_S0_PIN GPIO_PIN_0 #define MUX_S1_PIN GPIO_PIN_1 #define MUX_S2_PIN GPIO_PIN_2 #define MUX_S3_PIN GPIO_PIN_3 #define MUX_EN_PIN GPIO_PIN_4 #define MUX_GPIO_PORT GPIOA void MUX_Init(void) { GPIO_InitTypeDef GPIO_InitStruct = {0}; __HAL_RCC_GPIOA_CLK_ENABLE(); GPIO_InitStruct.Pin = MUX_S0_PIN | MUX_S1_PIN | MUX_S2_PIN | MUX_S3_PIN | MUX_EN_PIN; GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull = GPIO_NOPULL; GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW; HAL_GPIO_Init(MUX_GPIO_PORT, &GPIO_InitStruct); /* EN默认拉高,所有通道断开 */ HAL_GPIO_WritePin(MUX_GPIO_PORT, MUX_EN_PIN, GPIO_PIN_SET); }

ADC初始化的部分就不贴完整代码了,核心是配置一个ADC通道,设置为单次转换模式,采样时间尽量拉长。我实际设置的采样周期是55.5个ADC时钟周期,也就是ADC_SAMPLETIME_55CYCLES_5这个选项。对于多路复用器扩展场景,采样时间长一点能有效降低信号源阻抗对采样结果的影响,后面会详细解释原因。

4.2 通道切换与采样的核心函数

uint16_t MUX_ReadChannel(uint8_t ch) { if (ch > 15) return 0; /* 使能芯片 */ HAL_GPIO_WritePin(MUX_GPIO_PORT, MUX_EN_PIN, GPIO_PIN_RESET); /* 先设置地址线,再等通道开关稳定 */ HAL_GPIO_WritePin(MUX_GPIO_PORT, MUX_S0_PIN, (ch & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MUX_GPIO_PORT, MUX_S1_PIN, (ch & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MUX_GPIO_PORT, MUX_S2_PIN, (ch & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MUX_GPIO_PORT, MUX_S3_PIN, (ch & 0x08) ? GPIO_PIN_SET : GPIO_PIN_RESET); /* 关键延时:让开关动作稳定下来 */ delay_us(100); /* 启动ADC转换并等待完成 */ HAL_ADC_Start(&hadc); HAL_ADC_PollForConversion(&hadc, 10); uint16_t value = HAL_ADC_GetValue(&hadc); HAL_ADC_Stop(&hadc); return value; }

看到关键延时没有?就是通道切换后那块100微秒的delay_us。这是第一个调试坑的核心,也是很多人在使用多路复用器扩展ADC时最容易忽略的问题。后面会详细展开。

4.3 轮询所有通道与滤波处理

采集全部16路通道的逻辑很简单:

void MUX_ScanAllChannels(uint16_t *adc_values, uint8_t count) { for (uint8_t i = 0; i < 16; i++) { adc_values[i] = MUX_ReadChannel(i); } }

不过在实际项目中,裸读一次的值跳动往往比较大,尤其是信号源阻抗高或者环境有干扰的情况下。我在这个项目里加了一个中位值平均滤波:先连续采样5次,去掉最大值和最小值,剩下的3个值取平均。这种滤波方式对抑制偶然的脉冲干扰特别有效,同时又不会像单纯滑动平均那样把突变信号抹平。

uint16_t MUX_ReadChannelFiltered(uint8_t ch, uint8_t samples) { uint16_t buf[8]; uint16_t tmp; if (samples > 8) samples = 8; for (uint8_t i = 0; i < samples; i++) { buf[i] = MUX_ReadChannel(ch); } /* 冒泡排序 */ for (uint8_t i = 0; i < samples - 1; i++) { for (uint8_t j = 0; j < samples - 1 - i; j++) { if (buf[j] > buf[j + 1]) { tmp = buf[j]; buf[j] = buf[j + 1]; buf[j + 1] = tmp; } } } /* 去掉最大最小,取平均 */ uint32_t sum = 0; for (uint8_t i = 1; i < samples - 1; i++) { sum += buf[i]; } return (uint16_t)(sum / (samples - 2)); }

4.4 降低CPU占用的一个变体思路

上面贴的是轮询写法,每个通道都要等100微秒延时和ADC转换完成,16个通道一轮下来大概要几十毫秒。如果你觉得太慢,可以把“切换通道”和“读取结果”拆开,先用一个定时器中断把地址线设好,让开关在后台稳定,等到时间后再触发ADC转换。这样一个通道的建立时间就不需要CPU空等了,可以把16通道的扫描时间压缩到毫秒级。

不过说实话,对于温度、电位器这类信号,几十毫秒一轮已经完全够用,我也没在这上面过度优化。只有需要采样率超过100Hz的场景,才值得用中断和DMA来做。

5. 调试坑一:通道切换后读到的还是上一个通道的残留值

5.1 现象描述:无论怎么切,永远是同一个数

硬件焊好、代码写完之后,我第一次上电测试就出了问题。我把X0通道接到3.3V,X1通道接到GND,然后循环打印两个通道的ADC值。结果发现,X1通道读到的值不是0,而是偶尔会跳到4095,跟X0通道一模一样。也就是说,X0切到X1的时候,采集到的永远是X0的残留值。

我当时第一反应是地址线是不是有问题,用万用表量了S0到S3的输出电平,切换X0和X1的时候电平变化完全正常,X0对应0000,X1对应0001,没错。然后又怀疑是X1的焊盘虚焊,用万用表直接量X1引脚和GND之间的电压,确实是0V。那就奇怪了,引脚上明明接的是0V,ADC读出来的却是满量程,这明显不是信号源的问题。

5.2 排查链路:从硬件怀疑到软件时序的转变

排查过程是这样的:

  1. 先用万用表确认X0和X1的信号电平正常——X0=3.3V,X1=0V;
  2. 用示波器看SIG引脚的波形,发现在地址线切换的瞬间,SIG引脚上的电压不会立刻跳变到目标通道的电压,而是呈现一个缓慢的下滑曲线,大概要过几十微秒才能真正稳定到目标电压;
  3. 查数据手册,CD74HC4067的tON和tOFF参数确实只有几十纳秒,但手册里还有另一个参数叫“Break-Before-Make Delay”(先断后合延迟),意思是芯片切换通道时,旧通道先断开,新通道后闭合,这中间会有一小段时间SIG引脚是悬空的;
  4. SIG悬空之后,MCU的ADC引脚和SIG之间的连接还接了一个采样保持电容,而这个电容上存的是上一个通道的电荷——这就是残留值的来源。

所以问题的本质是:地址线切换后,SIG引脚到目标通道之间要重新充电、电压要重新建立,这需要时间,而我在代码里是设置完地址线之后立刻启动ADC转换,ADC在极短时间内就去采样了,采样到的自然是还没有衰减完的旧电压。

5.3 根因分析和彻底解决方案:为什么100微秒延时是必要的

CD74HC4067的开关本体动作很快,纳秒级别就完成,但它只是把一个开关合上而已。开关合上后,SIG引脚上连接的信号路径、MCU的ADC输入引脚上连接的采样电容,这些寄生电容和导通电阻Ron、信号源内阻会形成RC充电回路。充电时间的常数τ约等于Ron乘以等效电容,等效电容包括SIG引脚上的寄生电容、走线电容和MCU ADC引脚的输入电容,加起来保守估计也有几十皮法到几百皮法。

在信号源内阻较低的情况下,比如直接接一个电压源,充电时间可能只有几微秒。但如果信号源内阻高,比如NTC分压网络里的电阻有10kΩ甚至100kΩ,那RC常数就会被拉得很大,建立时间可能从几十微秒飙升到几毫秒。

所以解决方案其实有两个层次:

  • 低层次的办法是加延时,在地址线切换后等待足够时间再启动ADC。我把延时设为100微秒,对大多数低内阻信号源足够了。但如果信号源内阻高,建议先把采样时间加长,再把等待时间增加到1毫秒甚至更长,直到采集值稳定。
  • 高层次的解决办法是加运放跟随器,把信号源和4067隔开。这样ADC采样电容前看到的等效阻抗就是运放输出阻抗,通常在几十欧姆以下,RC常数大幅减小,建立速度大幅加快。

我自己最终是把这两个办法都用上了:硬件上在SIG到MCU ADC之间加了一级运放跟随器,软件上依然保留了100微秒的等待时间。双保险,不管接什么信号源,采集值都很稳定。

5.4 验证方法:怎么确定你的延时到底够不够

一个很实用的验证方法是:写一个测试程序,把X0接3.3V、X1接GND,然后X1切换到X0后,用逐渐增大的延时值去采集X0,每切换一次延时加一档,打印出ADC值随延时的变化曲线。当ADC值不再随延时增大而变化的那个点,就是最小需要的建立时间,在这个基础上再留50%到100%的余量。

我在实际测试中测到的数据曲线是这样的:

等待延时(µs)X0通道ADC读数(参考3.3V)
13900左右,跳动剧烈
54050左右,仍然偏低
204085左右,接近稳定
504090左右,基本稳定
1004092,稳定
2004092,稳定

可以看到,延时在50微秒以下的时候采集值明显偏低且跳动,到100微秒才真正稳定。这说明只靠关断延时(tOFF)和开关建立时间是不够的,必须考虑实际电路中的RC充放电过程。这种验证方法建议每个人都做一遍,因为它能告诉你在这个具体电路下最合理的延时配置,而不是照搬别人的参数。

6. 调试坑二:单独测每一路都准,合在一起测就互相影响

6.1 现象描述:好端端的ADC值突然集体偏移

第二个坑是我在整机测试的时候才发现的。单板调试阶段,每一路单独采集精度都很高,误差只有正负几个LSB。但把16路信号全部接上之后,发现有几路的ADC值明显偏低,而且不是固定偏差,是会随着其他通道的信号变化而抖动的。

比如X7通道接的是一个0到3.3V的电位器,我把电位器拧到一个固定位置,正常情况下ADC读数应该稳定在一个值。但当我去切换其他通道、甚至只切到某些空置通道的时候,X7的读数会莫名其妙地掉几十甚至上百个LSB,切换到另一些通道又恢复正常。刚开始我以为是电源纹波问题,用示波器量了3.3V电源,纹波很小,不到20mV,不应该引起这么大的读数变化。

6.2 排查链路:从电源干扰到浮空通道的推断

排查过程比第一个坑曲折不少:

  1. 先把各路信号源全部断开,只保留一个通道接信号,这时候采集是稳定的;
  2. 逐步接入其他信号源,发现每多接一个高阻抗信号源,原来那个通道的读数就往下掉一点;
  3. 把未接入信号的通道全部短接到地,所有通道的采集值恢复正常;
  4. 用万用表测SIG引脚对GND的电压,在没有信号输入、只有未用通道悬空的情况下,SIG引脚上能测到几十毫伏的随机漂移电压。

到这里就真相大白了:未使用的通道引脚处于悬空状态时,芯片内部和外部寄生电容上会积累电荷,电荷再通过关断通道的漏电流泄放到SIG公共端上,改变SIG引脚的偏置电压。因为ADC采样的是一个很微弱的信号叠加了这层偏置干扰,所以读数就偏了。特别是在信号源内阻较高的情况下,这种影响会被进一步放大。

6.3 根因分析:漏电流、悬空引脚和高阻抗信号源的三方合谋

CD74HC4067的断开通道并不是完全断开的,内部存在漏电流路径。手册上写的是单通道漏电流几十纳安,但多个通道并联起来,漏电流就会叠加。如果未使用通道的引脚悬空,漏电流的大小和方向都不确定,等效于在SIG端注入一个随机噪声电流。这个电流乘上信号源的内阻和导通电阻,就转化成了电压误差。

计算公式很简单:误差电压 = I漏电流总和 × (R信号源 + Ron)。

  • 当信号源内阻是1kΩ时,即使漏电流有100nA,误差电压也只有0.1mV,完全无所谓;
  • 当信号源内阻是100kΩ时,误差电压就变成10mV了,对应12位ADC(3.3V参考)就是12个LSB左右的跳动,这就很可观了。

所以这个坑的本质是:CD74HC4067对高阻抗信号源不友好,而悬空的未用通道会让情况变得更差。

6.4 解决方案:硬件处理为主,软件只能救急

解决思路从根本到临时排列如下:

  1. 未使用通道一律接GND。这是最有效、最省事的办法。板子上所有不用的X通道都通过一个10kΩ电阻接地,这样即使有漏电流,也会被电阻泄放掉,不会在SIG端形成高阻浮动电位。如果空间和成本允许,建议所有16个通道都加上这个下拉电阻,不管用不用。
  2. 降低信号源阻抗。给每路信号加运放跟随器,让4067看到的是低阻抗信号,漏电流的影响自然就小了。这是最彻底的办法,尤其适合传感器输出阻抗较高的场景。
  3. 软件上多做几次采样取平均,虽然能改善一点随机跳变,但解决不了系统性偏差。我在代码里做了中位值平均滤波,效果不错,但不能完全替代硬件处理。

我最终在PCB改版的时候,把所有未使用的X通道全部通过10kΩ电阻接到了GND,同时在SIG到ADC那条线上加了一级运放跟随器。改完之后,不管切换哪个通道、不管接不接信号,16路数据都稳稳的,再没出现抖动问题。

6.5 额外提醒:信号源内阻带来的采样损耗是什么

接续刚才的话题,还有一个容易被忽略的点。STM32的ADC在采样阶段,相当于一个采样电容并联在输入引脚上,采样时间越长,采样电容两端电压越接近信号源开路电压。但如果信号源内阻太大,采样电容在有限的采样时间内充不满,读数就会偏低。这种误差不是4067造成的,而是MCU ADC本身的特性,但4067的Ron会叠加到这个内阻上,让问题更加明显。

解决办法也很简单:把ADC采样时间调到最大档。STM32F103的ADC支持最大239.5个ADC时钟周期的采样时间,对于慢速采集场景直接拉满就行了,价格是采样率下降,但换来的精度提升非常值。

7. 实测数据与调参心得:稳定采集不是玄学

7.1 三组对比数据说明问题

最后把我在这个项目里测到的几组数据放出来,给大家一个直观参考。条件是:STM32F103,12位ADC(0到4095),参考电压3.3V,CD74HC4067供电3.3V,信号源是100kΩ电位器分压网络。

第一组:未处理状态的X7通道读数。

切换目标X7读数跳动幅度
只读X7,其他悬空3070左右±30
切换X0到X63010左右±80
切换X8到X153040左右±60

第二组:加上10kΩ下拉电阻把未用通道全部接地之后。

切换目标X7读数跳动幅度
只读X73085左右±8
切换X0到X63083左右±10
切换X8到X153084左右±9

第三组:再加一级运放跟随器之后。

切换目标X7读数跳动幅度
只读X73090左右±3
切换X0到X15任意通道3090左右±4

可以看到,每做一个处理,数据的稳定性和一致性都在明显改善。最后一组数据,ADC读数的等效电压误差在正负3毫伏以内,对于这个项目的精度需求已经完全够用。

7.2 三个实践里打磨出来的注意事项

第一个,关于SPI/I2C上拉电阻的类比。好多人会把地址线当普通GPIO随便配,但CMOS芯片的输入引脚如果不确定电平,会有一个“半导通”状态区间,此时芯片内部功耗增大,还可能引发不可预测的行为。所以建议在初始化阶段就把所有地址线电平设成确定值。我习惯把所有地址线默认拉低,相当于上电后默认选通X0通道,至少比所有引脚悬空来得安全。

第二个,电源去耦不能省。CD74HC4067虽然功耗很低,但它和其他数字芯片一样,在开关切换瞬间会有电流尖峰,需要在VCC到GND之间放一个0.1µF的陶瓷电容,尽量靠近芯片引脚放置。我第一版板子就是省了这个电容,结果切换瞬间的噪声干扰直接耦合到了SIG引脚的模拟信号上,ADC读数抖动明显。加上电容之后问题立刻缓解。

第三个,也是我觉得最值得说的:排序匹配原则。16路通道不是均匀等效的,不同通道的导通电阻、漏电流可能有差异。在实际项目中,把阻抗最小、信号最稳定的通道配给精度要求高的信号,把高阻抗、容易受干扰的通道留给对精度要求不那么苛刻的信号。我在这个项目里把电池电压监测放在X0通道(直接电阻分压,源阻抗只有几kΩ),把NTC温度传感器放在X8到X15这些靠后的通道上(反正温度信号本来就有滞后性,慢一点无所谓)。这种通道分配方式虽然不是什么硬性规范,但实际用起来能避免很多头疼的问题。

7.3 什么时候不该用CD74HC4067

最后泼一盆冷水。如果你要采集的信号频率超过几十赫兹,或者多路信号需要同步采样,或者精度要求超过12位且信号源阻抗很高,那CD74HC4067这种多路复用方案就不太适合了。这种场景老老实实选独立多通道ADC芯片,或者用带内部多路复用的高速ADC,会更靠谱。我这次能用4067解决问题,靠的是项目本身对采样率要求低、信号都是缓慢变化的物理量,这在选型阶段就已经想清楚了,不是碰运气。

8. 后记:两个坑走过的弯路和一点经验沉淀

回头看看这两个调试坑,一个来自对开关切换动态过程的认知不足,一个来自对芯片静态漏电流和高阻抗信号源的相互作用缺乏预判。它们都不是芯片本身的质量问题,而是使用场景和外围电路设计不当造成的。

第一个坑的教训是:模拟开关的“导通”不是说信号瞬间就等价于直连了,它和后面接的电容、前面接的信号源内阻一起构成了一个真实的RC网络,建立时间是实实在在存在的。第二个坑的教训是:漏电流和悬空引脚在低阻抗信号面前不是个事,但在高阻抗信号面前会被放大成显著的电压误差。

我现在做类似项目,已经养成了一个习惯:拿到多路复用器芯片,先不看它怎么工作,先看数据手册里所有跟模拟性能相关的参数,Ron、漏电流、切换时间、关断隔离度,然后估算一下这些参数在当前信号源阻抗下会造成多大的电压误差。如果算出来不可接受,就提前想好加跟随器、加下拉电阻这些对策,而不是等到板子回来了再去追查莫名其妙的ADC跳动问题。

另外也想提一句,调试这个项目时我把整个排查过程都记录在案,包括每次修改代码前后的现象、波形截图、计算草稿,这些资料在后来做第二个类似方案时帮了大忙——有现成的测试思路和参数配置可以直接复用,省了不少时间。嵌入式调试的坑都是一个个踩出来的,踩完记得写下来,回头再看都是财富。

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

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

立即咨询