STM32用CD74HC4067扩展16路ADC采集方案与调试指南
2026/9/8 9:11:46 网站建设 项目流程

这段时间做一个小项目的监控功能,MCU 用的是 STM32F103C8T6,片上 ADC 只有 10 个输入通道,但现场要同时盯的模拟量有 16 路。换大芯片舍不得,外挂一堆 ADC 芯片又嫌贵,最后选了一片 CD74HC4067 模拟开关来扩展。整个方案从画板到调通,前后折腾了两三天,中间踩了两个坑,一个跟 RC 建立时间有关,一个跟通道串扰有关,都属于那种你不实际吃一次亏、光看数据手册想不到的隐蔽问题。这篇文章把完整的选型思路、接线方式、HAL 驱动代码以及两个调试坑的完整排查过程记录下来,给后面做多路模拟量采集的朋友当个参考。

如果你也在纠结“ADC 通道不够用”,或者已经在用 4067 但发现数据不干净,这篇文章能帮你省下不少排查时间。内容覆盖从硬件参数理解到软件采样策略,再到实际调试中出现的两个典型坑,全程用 STM32 的 HAL 库作为示例,其他平台思路完全通用。

1. 方案选型:16路模拟采集到底怎么搞

1.1 三个常见方案的取舍

多路模拟采集的常见做法大概有三条路,我在动手之前把三种都过了一遍。

第一种,直接换一颗 ADC 通道更多的 MCU。STM32F103C8T6 只有 10 路 ADC 输入,如果换到 F103ZET6 这种大封装,确实能到 16 路以上。但问题是硬件改动太大,PCB 要重新画,核心板要换,固件里引脚的映射也要全改。如果你只是缺一两路,这么干还说得过去;缺六路以上,成本就开始不划算了。

第二种,外挂 I2C / SPI 接口的 ADC 芯片。ADS1115 这类芯片精度高、软件也简单,一颗 4 通道、16 位分辨率,做精密测量非常合适。但单颗只有 4 路,16 路就要 4 颗,不但价格上去了,I2C 总线上挂 4 颗芯片的地址也要花心思处理。而且这种方案没法做同步采样,所有通道轮流转换,刷新率完全取决于 I2C 速度。低速监测场景能接受,但对响应速度稍有要求的场合就比较吃力。

第三种,就是模拟开关配合 MCU 内置 ADC 使用。单片机只需要留一个 ADC 引脚,前面挂一个 CD74HC4067 这种 16 选 1 的模拟开关,把 16 路信号轮询切换进去。硬件改动最小,成本最低,一片才几块钱,而且两片级联能直接扩到 32 路。虽然做不到 16 路同步采集,但对于温度、压力、电池电压这类几十毫秒级变化的信号,速度完全够用。

三种方案的适用边界其实很清楚,我用表格整理一下:

方案通道数BOM成本精度同步性适用场景
换多通道MCU最多几十路可同步引脚充裕、预算充足的新产品
外挂ADC芯片单颗2~8路,可级联中高高(16位起)多颗可同步高精度低速采集
模拟开关+内置ADC单颗16路,级联可扩展受开关参数影响单ADC轮流采样几十路以内的慢变信号

这个项目要测的是 16 路缓慢变化的直流电压信号,精度要求 12 位 ADC 基本够用,所以第三种方案最合理。方案定下来之后,下一步就是具体选哪颗模拟开关。

1.2 为什么选 CD74HC4067 而不是 CD4051 / 74HC4051

模拟开关这个品类里,大家用得最多的是 CD4051 和 74HC4051,它们都是 8 通道,3 根地址线选通,协议简单。但 4051 的问题是通道数不够,16 路信号如果用 4051,就要两片再加一个片选信号,做起来并不比直接用一片 4067 省事。

CD74HC4067 是 16 通道模拟开关,4 根地址线 S0~S3,直接把 16 路分成 0~15 号通道。对超过 8 路的场景来说,一片 4067 在布线和代码上都要简洁得多。

这里必须提醒一个买器件的坑:市面上 CD4067BE 和 CD74HC4067 外观几乎一样,但完全是两种东西。CD4067BE 属于 4000 系列 CMOS,工作电压范围宽,但导通电阻典型值几百欧,而且切换速度慢,用在单片机上虽然也能工作,信号损耗和控制时序都很别扭。CD74HC4067 属于 HC 高速 CMOS,3.3V 供电下导通电阻实测大约几十到一百欧,切换时间在纳秒级别,才是真正适合 MCU 扩展 ADC 的方案。买模块或买散片的时候,一定要看清丝印上有没有 HC 字样,别买错了。

2. 硬件接线与参数理解

2.1 引脚分布与真值表

CD74HC4067 的引脚功能分配如下:

引脚名称功能说明
C0 ~ C1516 路模拟输入/输出通道
COM公共端,接 MCU 的 ADC 输入
S0 ~ S3通道选择地址线(S0 为最低位)
EN使能引脚,低电平有效
VCC工作电源,2V ~ 12V
GND

选通逻辑很简单:S0~S3 组合成一个 4 位二进制数,对应 0~15 号通道。比如 S3S2S1S0 = 0000 选通 C0,S3S2S1S0 = 1010 选通 C10。EN 引脚拉低时芯片正常工作,拉高时所有通道全部关闭,COM 端呈高阻态。

我的接线方式是:单片机 PA1 配置为 ADC 输入,接到 4067 的 COM 端;PA2~PA5 配置为推挽输出,分别接 S0~S3;PA6 接 EN。如果你用其他单片机,思路完全一样,只是 GPIO 编号不同。

2.2 核心参数:导通电阻、漏电流、寄生电容

很多朋友拿到 4067 就直接往板子上焊,信号也能采到,但数据总是不对劲。要理解后面两个调试坑,必须先理解这三个参数。

第一个是导通电阻(Ron)。CD74HC4067 在 3.3V 供电时,实测导通电阻通常在 70~100 欧左右。很多人的第一反应是这 100 欧会跟信号源分压,把电压吃掉。其实在 ADC 采样这个场景里,采样保持电容稳定之后没有直流电流流过,Ron 上不会产生直流压降。Ron 真正影响的不是稳态精度,而是建立时间——它和后面接的电容组成了一个 RC 低通,让信号需要一定时间才能充到最终值。信号源内阻越大,这个建立时间越长。

第二个是关断通道的漏电流。4067 本质上是一堆 CMOS 传输门,通道关闭时并不是理想开路,源漏之间的 PN 结反偏仍然会有微安甚至更小的漏电流。这个漏电流在源阻抗很低时几乎没影响,但如果你接的是高内阻信号源,漏电流乘以源内阻就会变成一个可观的偏移电压。这一点在第二个调试坑里体现得非常明显。

第三个是寄生电容。4067 的 COM 端和每个通道之间都存在寄生电容,数据手册上虽然没有专门给一个明确的“COM to Channel”容值,但实际测量大概在十几到几十皮法量级。这些电容会和导通电阻、外部源阻抗一起构成 RC 网络,影响信号建立的快慢。

实际工程里,这部分 RC 时间常数常常被人忽略,导致采样结果出现莫名其妙的误差。我曾经在板子上为了滤除高频噪声,在每路输入前加了 10kΩ 电阻和 100nF 电容的组合,结果 4067 切换通道后,信号要经过大约 1ms 才能稳定。这种情况下如果用默认的 ADC 采样时间,读到的自然就是错的值。

2.3 接线示意与双片级联

单片的接线就不画图了,文字描述足够清楚:所有传感器的输出接到 C0~C15,4067 的 COM 接 MCU 的 ADC 引脚,S0~S3 接四个 GPIO,EN 接一个 GPIO。需要注意所有通道的参考地必须跟单片机共地,不共地的话测量值完全没有意义。

如果你要采集的通道超过 16 路,可以用两片甚至更多片 4067 级联。最常用的做法是共用 S0~S3,把每片的 COM 分别接到不同的 ADC 通道上。比如两片 4067 接在 ADC1 的通道 1 和通道 2 上,这样就是 32 路输入。如果 ADC 引脚也紧张,那就只能给每片 4067 的 EN 单独接一个 GPIO,先拉低要用的那片,再关掉上一片,重复利用同一个 ADC 引脚。

3. 驱动代码与采样策略

3.1 HAL 库驱动实现

先说通道选择函数。S0~S3 对应一个 4 位二进制数,直接把通道号按位拆出来写 GPIO 就行:

#define MUX_S0_PIN GPIO_PIN_2 #define MUX_S0_PORT GPIOA #define MUX_S1_PIN GPIO_PIN_3 #define MUX_S1_PORT GPIOA #define MUX_S2_PIN GPIO_PIN_4 #define MUX_S2_PORT GPIOA #define MUX_S3_PIN GPIO_PIN_5 #define MUX_S3_PORT GPIOA #define MUX_EN_PIN GPIO_PIN_6 #define MUX_EN_PORT GPIOA void MUX_SetChannel(uint8_t ch) { HAL_GPIO_WritePin(MUX_S0_PORT, MUX_S0_PIN, (ch & 0x01) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MUX_S1_PORT, MUX_S1_PIN, (ch & 0x02) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MUX_S2_PORT, MUX_S2_PIN, (ch & 0x04) ? GPIO_PIN_SET : GPIO_PIN_RESET); HAL_GPIO_WritePin(MUX_S3_PORT, MUX_S3_PIN, (ch & 0x08) ? GPIO_PIN_SET : GPIO_PIN_RESET); }

初始化时,把 EN 拉高,让 4067 处于全部断开的状态,防止上电瞬间误采到不确定电平:

void MUX_Init(void) { HAL_GPIO_WritePin(MUX_EN_PORT, MUX_EN_PIN, GPIO_PIN_SET); }

读取某个通道的电压,核心逻辑是:先选通道,再等待稳定,最后启动 ADC 转换并取平均。

uint16_t MUX_ReadChannel(uint8_t ch, uint8_t samples) { uint32_t sum = 0; MUX_SetChannel(ch); HAL_GPIO_WritePin(MUX_EN_PORT, MUX_EN_PIN, GPIO_PIN_RESET); // 等待信号建立,具体延时见下面分析 delay_us(500); // 丢弃一次转换结果,让采样电容完全刷新 HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 100); (void)HAL_ADC_GetValue(&hadc1); for (uint8_t i = 0; i < samples; i++) { HAL_ADC_Start(&hadc1); HAL_ADC_PollForConversion(&hadc1, 100); sum += HAL_ADC_GetValue(&hadc1); } return (uint16_t)(sum / samples); }

这里 delay_us 可以用 DWT 或者定时器实现。如果你不想折腾微秒延时,直接用 HAL_Delay(1) 也可以,只是 16 个通道轮询一遍的速度会慢一些。我后面会专门算一下这个延时到底该设多大。

3.2 采样时序:什么时候该等,等多久

很多初学者容易踩的一个误区是:切换通道后立刻启动 ADC 转换,认为 4067 是“电子开关”,应该瞬间导通。实际上 4067 的开关切换虽然只有纳秒级,但它后面带的电容网络不会瞬间完成充放电。

做一个简单的定量估算。假设信号源内阻是 1kΩ,4067 的导通电阻约 100Ω,4067 COM 端寄生电容约 30pF,MCU ADC 采样电容约 8pF,PCB 走线寄生约 5pF,总电容大概 43pF。RC 时间常数:

τ = (1000 + 100) × 43 × 10⁻¹² ≈ 47ns

12 位 ADC 要获得稳定读数,通常需要建立到 0.5 个 LSB 以内,也就是大约需要 8.3 个时间常数:

t = 8.3 × 47ns ≈ 390ns

这个数字看起来不大,STM32 的 ADC 采样时间设为 239.5 个时钟周期时,有接近 20μs,远大于 390ns,理论上是够的。但如果我把源阻抗变成 100kΩ,那 τ 就变成了大约 4.3μs,需要稳定时间约 36μs,这时候采样时间 20μs 就不够了,必须额外等待。

更极端的是我在板子上加的 10kΩ + 100nF 抗混叠滤波器,时间常数直接变成 1ms,按 8.3τ 计算需要 8.3ms 才能稳定。这就是第一个调试坑的根源。所以这里的结论是:切换通道后必须延时,延时时长不是拍脑袋定的,而是根据最坏情况下的信号源内阻和外部电容计算出来的。工程上建议留足裕量,慢速采集场景直接延时 1~5ms,保证在任何常见阻抗下都能建立到位。

3.3 采样滤波:平均滤波、中值滤波怎么选

切换稳定之后,下一步就是采样数据处理。我在这个项目里对每个通道连续采 8 次求平均,效果已经很干净。

不同滤波方式适用场景不一样:

  • 平均值滤波对高斯白噪声抑制效果好,适合信号本身稳定、叠加随机噪声的场景,计算量小,最适合单片机轮询多通道。
  • 中值滤波对脉冲干扰特别有效,比如某个通道偶尔被继电器动作干扰出一个尖峰,取中值能把这个尖峰滤掉,缺点是计算量稍大,排序需要几十个周期。
  • 滑动平均适合需要观察缓慢变化的趋势,实时性比每轮重新采 8 次好,但需要在内存里维护一个环形缓冲区。

在 16 路轮询这种场景下,我个人的做法是:每通道采 8 次求平均,同时把这个平均值丢进一个长度为 4 的滑动窗口再平均一次。相当于两级滤波,效果非常稳。如果追求极致的抗脉冲,可以在采样次数稍微多一点的场景用中值加平均的复合滤波,比如先 5 次取中值,再对 3 个中值求平均。

3.4 DMA 采样与多通道扩展的代码思路

用 HAL 库的轮询方式读 ADC,好处是代码直观,缺点是每转换一次要等 CPU 轮询,多路轮询时 CPU 占用率会高一些。如果你想让 CPU 去干别的事,可以用定时器触发 ADC 转换,再用 DMA 把结果搬进内存。

对于 4067 这种外部开关的方案,要注意 DMA 并不是万能的。你只能在选通某一路之后启动一次 DMA 搬运,搬运完再切换下一路。不能在 DMA 连续模式下指望它自己切通道,因为 4067 的地址线是 GPIO 控制的,DMA 不会帮你翻转 GPIO。

两片 4067 的代码也很简单,把 MUX_SetChannel 改成带片选的版本:

void MUX_SetChannel(uint8_t chip, uint8_t ch) { HAL_GPIO_WritePin(MUX_EN1_PORT, MUX_EN1_PIN, chip == 0 ? GPIO_PIN_RESET : GPIO_PIN_SET); HAL_GPIO_WritePin(MUX_EN2_PORT, MUX_EN2_PIN, chip == 1 ? GPIO_PIN_RESET : GPIO_PIN_SET); MUX_SetChannel(ch); }

两片共用 S0~S3,EN 分别控制,选哪片就把哪片拉低,另外一片保持高电平。这样理论上只需要 1 个 ADC 引脚就能扩展到 32 路。

4. 调试坑一:切换后读数爬升,第一帧永远不准

4.1 现象描述与定位

板子打样回来后,我烧了最简单的测试程序:16 路输入全部接 10kΩ 电位器,每个电位器调到不同电压,然后循环读取 16 个通道,把结果显示在串口上。

第一轮测试结果就出了问题。通道 0 读数正常,切换通道 1 后,第一次打印出来的电压明显偏低,偏低幅度从几十毫伏到几百毫伏不等,要等第二次、第三次读取后才慢慢接近实际值。更诡异的是,如果我把某个通道的输入电压调到接近 VCC 的位置,切过去的第一帧读数能低 1V 以上。

开始我怀疑是 4067 引脚接触不良或者电位器本身的问题,但用数字万用表去量 4067 的 COM 引脚,电压又是正确的。这就矛盾了:万用表量到的电压没问题,单片机读出来却是错的。

后来接上示波器看 MCU 的 ADC 引脚波形,真相一下子清楚了。选通开关切换的一瞬间,波形上出现一个很大的下冲,电压先掉到接近 0,再慢慢爬升到目标电压。这个爬升过程不是瞬间完成的,而是要经历一段肉眼可见的时间,大概几百微秒到几毫秒。单片机在这个爬升过程中启动 ADC 转换,读到的自然就是偏低的值。

4.2 根源:RC 建立时间超出预期

为什么波形会有一个爬升过程?这得从 4067 的切换过程说起。4067 内部是 CMOS 传输门,切换的时候并不是像机械开关那样瞬间断开旧通道、瞬间接通新通道。在开关过渡期间,COM 端会经历一个短暂的高阻或不确定状态,同时 COM 端对地存在寄生电容,这些电容上的电荷需要从零重新充电到新通道的电压。

如果只是 4067 本身,这个重新充电的过程大概只有几百纳秒,远小于我的采样周期。问题出在我板子上加的抗混叠滤波器——每路输入前面串了一个 10kΩ 电阻、对地接了一个 100nF 电容。这个 RC 低通的时间常数是 1ms,也就是说,4067 切换通道后,100nF 电容需要大概 5ms 才能完全充到新的电压。

你可能要问,既然信号源通过 10kΩ 电阻和 100nF 电容接在 Cx 引脚上,而 4067 切换后 COM 端直接连到了 Cx 引脚,那 COM 端看到的电压不应该瞬间就是电容上的电压吗?问题在于,4067 关断其他通道之后,COM 端自己的寄生电容(几十 pF)在切换瞬间被放电或短路到地,需要一个充电过程。同时,10kΩ 电阻的存在使得信号源不能大电流地给这些寄生电容充电,充电电流被限制在 VCC/10kΩ 左右,时间常数就变得很长。

这就像一个大水桶(100nF)通过一根细水管(10kΩ)给一个小杯子(COM 寄生电容)倒水,虽然大水桶的水位是准的,但小杯子要慢慢接到和水桶一样平的水位线。

4.3 治本与治标

这个问题有两种解法,一种从硬件治本,一种从软件治标。

治本的方法是降低信号源阻抗。把抗混叠滤波器的电阻从 10kΩ 改成 1kΩ,时间常数变回 100μs 级别;如果允许,甚至可以直接去掉串联电阻,只保留对地电容。当然,抗混叠滤波本身是为了滤除高频噪声,不能随便去,所以更稳妥的设计是每个通道加一个运放跟随器,输出阻抗降到几十欧,这样不管后面接多大的电容都能快速充电。

治标的方法就是我在代码里写的那样:切换通道后加延时,让 RC 网络先稳定下来再启动 ADC 转换。延时时间按下式计算:

t_stable = 8.3 × (R_source + Ron) × C_total

在我的板子上,R_source = 10kΩ,C_total ≈ 100nF,计算出来需要 8.3ms。实际测试延时 10ms 之后,第一帧数据就准了。如果不想等 10ms,可以适当降低精度要求,比如只要求建立到 1% 误差,那 t = 4.6τ ≈ 4.6ms。

另外,即使延时到位,我仍然建议在正式读取前丢弃一次 ADC 转换结果。因为 STM32 的 ADC 采样保持电容在上一轮结束时保存的是上一个通道的电压,切换到新通道后,第一次采样周期里采样电容仍然在放电或充电,直接使用这次转换结果很容易引入误差。

我把这个坑总结成一张小表,方便对照:

检查点现象原因解法
切换后第一帧偏低读数缓慢爬升到目标值RC 建立时间过长加延时、降低源阻抗
采样值跳动无规律示波器上有明显毛刺4067 切换瞬间产生尖峰延时后再采样、丢弃首帧
用万用表正常,MCU 读数不对测量同一节点结果不同ADC 采样时刻落在爬升区间确认采样时刻是否在稳定之后

5. 调试坑二:通道串扰,邻路电位器动了这路跟着跳

5.1 现象描述与排查步骤

第一个坑解决之后,16 路采集基本能用了,但数据还是不太干净。具体表现是:某一路电位器调到 0V,读出来的电压始终有几十毫伏到一百多毫伏的底噪,而且当我转动相邻通道的电位器时,这路的读数会明显跟着变化。

我一开始以为是电源噪声或者地线环路的问题,毕竟 16 路模拟信号挤在一小块板上,串扰很常见。于是我先做了几个简单测试:

第一,把所有输入通道全部接地,读数应该都是 0。测试结果确实是 0,基本排除了 PCB 布线和电源的固定干扰。

第二,只接一个通道输入 3.3V,其余全部接地,读数正常。

第三,把相邻通道接一个 3.3V 电位器,目标通道接地,结果目标通道读数出现了几十毫伏的偏移。

到这里,问题明确指向 4067 内部的通道间串扰,而不是 PCB 布局问题。

5.2 根源:关断漏电流与寄生电容耦合

4067 的每个模拟通道在关闭时并不是完全断开的,内部传输门的源漏之间还存在反偏 PN 结,会形成微小的漏电流。数据手册里这个参数叫 off-state leakage current,典型值在 25°C 下是纳安级到几百纳安,温度升高后会明显变大。

漏电流本身不大,但如果源阻抗很高,就会在源阻抗上形成明显的电压降。举个具体例子:目标通道信号源是一个 10kΩ 电位器分压电路,信号源等效内阻最大 2.5kΩ,对地还有滤波电容。相邻通道的 3.3V 通过 4067 关断通道的漏电流,大概几百纳安,这部分电流流进目标通道的源阻抗,产生的偏移电压:

V_offset = 500nA × 2.5kΩ = 1.25mV

看上去不大,但如果是高内阻信号源,比如一个 100kΩ 的分压器,那偏移就能到 50mV 以上。如果多个相邻通道同时处于高电压,漏电流还会叠加,偏差会更明显。

除了直流漏电,还有交流耦合路径。4067 的通道引脚和 COM 端之间存在寄生电容,典型值在几皮法到十几皮法。相邻通道上的电压发生跳变(比如从 0 跳到 3.3V),会通过这个寄生电容耦合到 COM 端,形成尖峰或毛刺。如果 ADC 恰好在毛刺期间采样,读数就会被拉偏。

为了确认是不是这个原因,我把相邻通道的电位器从 0V 慢慢调到 3.3V,同时用示波器观察目标通道的 COM 端波形。示波器上能看到目标通道的直流电平确实随相邻通道电压线性变化,变化斜率大概 1mV/V,基本符合寄生耦合电容 1~2pF 的估算。

5.3 解决方案:缓冲、降阻、软件去抖三管齐下

串扰问题的本质是 4067 的关断隔离度有限,解决办法从三个层面入手。

硬件层面,最有效的办法是在每个通道的输入端加一个运放跟随器。运放输出阻抗极低(通常小于 1Ω),即使有几百纳安的漏电流灌进去,产生的电压偏移也小到可以忽略。同时运放的驱动能力强,可以有效冲刷寄生电容的耦合电荷。缺点是元件成本增加,16 路就是 16 个运放,面积和成本都不低。

如果不想加运放,可以降低信号源内阻。我的板子上每个通道都有 10kΩ 串联电阻,这个电阻直接放大了漏电流的影响。改成 1kΩ 后,同样的漏电流产生的偏移降为原来的十分之一。代价是抗混叠滤波器的截止频率变高,如果现场没有强干扰,这个代价可以接受。

软件层面,最实用的技巧是切换后延时、多次采样、去极值平均。延时可以让耦合尖峰过去;多次采样取平均可以降低随机噪声;如果某个通道偶尔出现明显跳变,可以在多次采样中先排序再去掉最大最小值,再对剩余值求平均。我在项目中的做法是每通道采 8 次,去掉最大值和最小值,剩余 6 次求平均,效果很好。

另外还有一个容易被忽略的点:没有用到的 4067 通道引脚如果悬空,会因为内部寄生电容耦合大量噪声。把所有空闲通道全部接到地,能明显改善整体干扰水平。

下面这个表整理了串扰问题的排查思路:

观察现象可能原因快速验证方法解决方向
目标通道读数随相邻通道变化关断漏电流过大相邻通道接地后读数是否恢复降低源阻抗、加缓冲
读数在高压通道切换时跳变寄生电容耦合示波器观察COM端毛刺延时采样、加去耦电容
高阻信号源读数整体偏移漏电流在源阻抗上产生压降用低阻源对比测试运放跟随、减小源电阻
空闲通道噪声大悬空引脚耦合干扰空闲通道全部接地未用引脚统一接地

6. 常见问题速查与避坑清单

6.1 快速问题排查表

把这段时间调试中遇到的和朋友反馈过的典型问题整理成一张速查表,遇到异常可以直接对照排查。

现象可能原因排查方向解决建议
所有通道读数都为0EN引脚悬空或电平不对测EN脚电压EN必须软件拉低
所有通道读数波动剧烈4067电源纹波大示波器看VCC波形加0.1μF+10μF去耦电容
某些通道固定偏低S0~S3接线反了或接触不良检查地址线电平万用表量GPIO输出
切换后第一帧异常RC建立时间不足加延时后测试延时5~10ms,丢弃首帧
读数随邻路变化通道间漏电/寄生耦合单通道接地法验证降低源阻抗、软件滤波
读数在小数点后一直跳采样时间太短/电源噪声增大采样周期配置239.5周期采样
多片级联时互相干扰EN控制时序混乱检查两片EN是否同低确保同一时刻只有一片使能

6.2 其他容易踩的小细节

除了上面两个大坑,还有几个细节是实际项目中容易忽略的。

第一个是 EN 引脚不能悬空。之前有一次调试,EN 忘了接,芯片处于不确定状态,16 路读数全部异常。上电初始化时一定先把 EN 拉高,等系统就绪后再拉低使能。

第二个是供电电压和信号电压的范围。CD74HC4067 的模拟开关只能在 VCC 到 GND 之间导通,输入信号超过 VCC 或者低于 GND,内部保护二极管会导通,轻则读数被钳位,重则芯片损坏。如果你的传感器输出是 0~10V 或者有负压,必须先做电平转换或分压,再进 4067。

第三个是购买时的型号问题。前面提到的 CD4067BE 和 CD74HC4067 一定要区分,买模块的时候注意看模块上丝印和商品详情里的型号。便宜的模块质量参差不齐,有些用的是旧库存的 CD4067BE,导通电阻大了几倍,直接导致采样建立时间变长,数据准确度下降。我后来专门在采购单里把 CD74HC4067 的 HC 型号写成红字,就是为了避免再买错。

第四个是温度影响。模拟开关的漏电流随温度升高而指数增大,如果设备在高温环境下运行,串扰问题可能会比常温严重点。在设计裕量时建议按最坏温度条件考虑,或者预留软件校准策略。

关于校准,如果对精度要求高,可以对每个通道做两点或三点校准。方法很简单:每个通道分别输入一个接近 0V 的基准和一个接近满量程的基准(比如 VCC 通过精密电阻分压得到),记录 ADC 读数,得到每个通道的偏置和增益系数,在软件中做线性校正。因为 4067 每个通道的导通电阻略有差异,单独校准每个通道比只校准一个通道然后套用到所有通道更准确。

7. 一些实际操作中的体会

这次用 CD74HC4067 扩展 16 路 ADC 采集,整体方案是成立的,成本低、实现简单,最终效果也能满足项目需求。两个坑踩下来,最大的心得是:模拟开关不是一根导线,它有自己的导通电阻、漏电流和寄生电容,在低速直流采样场景下,这些东西带来的问题大多可以通过“给足稳定时间 + 降低源阻抗 + 软件滤波”来解决。

如果让我重新设计一次,我会在硬件上把每个通道的源阻抗尽量压低,同时在 4067 的输出端加一个 1nF 左右的电容,和 COM 端的寄生电容并联,这样切换时毛刺会被抑制得更干净。软件上会把延时、采样次数、去极值窗口都做成可调参数,方便在不同信号源条件下快速调优。

这套 16 路采集方案后续还可以继续扩展成 32 路、48 路,只要把多片 4067 的 EN 控制好,软件上稍作修改就行。如果你也正在做类似的多路模拟量采集,希望这篇笔记能帮你少走几步弯路。

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

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

立即咨询