欢迎光临
我们一直在努力

FDC2212 + STM32G030 液面探测:IIC 读数跳动导致下探深度不一致的排查与解决

摘要:本文针对 FDC2212 电容传感芯片配合 STM32G030 实现液面探测时,IIC 读取的电容值存在跳动、导致每次下探到液面的深度不一致的问题,从硬件布局、驱动时序、采样滤波、判定算法四个层面给出可落地的排查顺序与解决方案,并给出关键代码示例。

一、问题现象与本质分析

典型现象是:探头以固定速度下探,理论上每次接触液面时应该记录到几乎相同的 Z 轴位置,但实际每次触发点相差几十微米到几毫米不等,重复性差。同时观察 FDC2212 的原始转换值(DATA_CHx),会发现即使探头静止不动,读数也在持续跳动。

需要先明确一点:FDC2212 输出的是频率/转换计数值,不是直接的电容值,其分辨率极高(28 位),因此它对噪声、寄生电容、温漂和参考时钟抖动都非常敏感。读数跳动是“果”,真正的原因通常分布在以下几个环节:

  • 传感端:探头电极的寄生电容不稳定、屏蔽不完整、外部干扰耦合。
  • 时钟端:FDC2212 使用外部晶振作为参考,晶振抖动或负载电容不匹配会直接放大读数噪声。
  • 驱动端:IIC 时序、寄存器配置(转换时间、驱动电流、时钟分频)不合理。
  • 算法端:单次采样直接判定、没有滤波、没有基线跟踪、没有迟滞,导致判定点抖动。

二、先量化:确认跳动到底有多大

在动手改硬件之前,先把“跳动”量化出来,否则无法判断优化是否有效。建议做如下测试:

  • 探头悬空静止,连续采集 1000 次 DATA_CHx,记录最大值、最小值、标准差。
  • 探头固定在某一固定高度(例如距液面 1 mm),重复上述采集。
  • 记录每次下探的触发点位置,统计重复性误差。
  • 如果静止状态下标准差已经达到几百甚至上千个 LSB,说明噪声主要来自硬件或配置;如果静止时很稳、只有下探过程中跳动,则更可能是机械振动、线缆晃动或算法判定问题。

    三、硬件层面的关键措施

    3.1 参考时钟必须稳定

    FDC2212 的转换结果与参考时钟频率成正比,时钟抖动会 1:1 传递到读数上。务必使用质量较好的外部晶振(常见 40 MHz),并注意:

    • 晶振负载电容按规格书匹配,不要凭经验取值。
    • 晶振尽量靠近芯片,走线短且包地,远离 IIC 和电源开关节点。
    • 不要用 MCU 的 MCO 输出或内部 RC 作为 FDC2212 的参考时钟。

    3.2 电极与屏蔽

    • 传感电极到芯片的走线尽量短,最好小于几厘米,并使用同轴或屏蔽线。
    • 屏蔽层接到板子的模拟地,不要与数字地混接后再单点接地,避免地弹。
    • 电极背面加保护环(Guard),由 FDC2212 的驱动信号驱动,抑制外部电场耦合。
    • 探头线缆在下探过程中会弯折、靠近金属结构件,寄生电容随之变化,这是“每次深度不同”的常见隐藏原因,建议固定线缆走向并做应力释放。

    3.3 电源与去耦

    FDC2212 的模拟电源需要干净。建议 AVDD 与 DVDD 分别用 LDO 供电,靠近引脚放置 1 μF + 0.1 μF 去耦电容,模拟地与数字地单点连接。STM32G030 的 IIC 上拉电阻建议 2.2 kΩ~4.7 kΩ,并在 SDA/SCL 上串 22~33 Ω 电阻抑制振铃。

    四、寄存器配置优化

    FDC2212 的噪声与转换时间、驱动电流、时钟分频强相关。核心思路是在满足响应速度的前提下尽量加长转换时间,因为转换时间越长,等效带宽越窄,噪声越低。

    寄存器作用优化建议
    CLOCK_DIVIDERS_CHx 传感器时钟分频 按规格书推荐值配置,保证传感器频率在 10 kHz~10 MHz 范围内
    SETTLECOUNT_CHx 建立时间 适当加大,保证每次转换前稳定
    RCOUNT_CHx 转换时间(参考时钟周期数) 在允许的采样率内尽量取大,例如 0x200~0x800
    DRIVE_CURRENT_CHx 传感器驱动电流 从 0 开始逐步增大,直到振幅达到量程的 50%~80%,不要过驱
    CONFIG(休眠/激活) 工作模式 使用连续转换模式,避免频繁启停引入的建立误差

    特别注意:驱动电流过大会让传感器进入非线性区,读数跳动反而加剧。建议用示波器观察传感器波形,确认振幅合适。

    五、STM32G030 驱动与 IIC 读取

    5.1 读取时序要正确

    FDC2212 的 DATA 寄存器是 28 位,分两个 16 位寄存器存放,读取时必须先读 MSB 再读 LSB,且两次读取之间不能被新的转换结果打断。推荐做法是:

    #define FDC2212_ADDR (0x2A << 1)
    #define REG_DATA_CH0 0x00
    #define REG_STATUS 0x18

    /* 读取一次 CH0 的 28 位转换结果 */
    uint32_t FDC2212_ReadChannel0(void)
    {
    uint8_t buf[2];
    uint32_t msb, lsb;

    /* 先读 MSB 寄存器 */
    HAL_I2C_Mem_Read(&hi2c1, FDC2212_ADDR, REG_DATA_CH0, I2C_MEMADD_SIZE_8BIT,
    buf, 2, 100);
    msb = ((uint32_t)buf[0] << 8) | buf[1];

    /* 再读 LSB 寄存器 */
    HAL_I2C_Mem_Read(&hi2c1, FDC2212_ADDR, REG_DATA_CH0 + 1, I2C_MEMADD_SIZE_8BIT,
    buf, 2, 100);
    lsb = ((uint32_t)buf[0] << 8) | buf[1];

    return ((msb & 0x0FFF) << 16) | lsb;
    }

    注意 MSB 寄存器只有低 12 位有效,必须做掩码,否则高位状态位会污染结果,表现为读数周期性跳变。

    5.2 检查 IIC 通信本身是否可靠

    • 读取 STATUS 寄存器,确认转换完成标志,避免读到“正在更新”的中间值。
    • 检查 HAL_I2C 返回值,通信失败时不要用旧值参与判定。
    • STM32G030 的 IIC 时钟建议 100 kHz~400 kHz,过高时在长线缆下容易出错。
    • 如果使用软件 IIC,注意 SCL 高电平时间与总线电容,必要时降低速率。

    六、软件滤波与判定算法

    即使硬件优化到位,读数仍会有一定噪声,因此算法层必须做滤波和稳健判定。这是解决“每次下探深度不同”最直接有效的一环。

    6.1 多级滤波

  • 中值滤波:连续采 5~9 个点取中值,剔除偶发尖峰(IIC 误码、电磁脉冲)。
  • 滑动平均:对中值结果再做 8~16 点滑动平均,降低白噪声。
  • 一阶低通:y = y + α(x – y),α 取 0.1~0.3,兼顾响应速度与平滑度。
  • #define MED_N 5
    #define AVG_N 8

    static uint32_t med_buf[MED_N];
    static uint32_t avg_buf[AVG_N];
    static uint8_t med_idx, avg_idx;
    static float lpf_y = 0.0f;

    static uint32_t median5(uint32_t *a)
    {
    uint32_t t[MED_N];
    for (int i = 0; i < MED_N; i++) t[i] = a[i];
    for (int i = 0; i < MED_N – 1; i++)
    for (int j = 0; j < MED_N – 1 – i; j++)
    if (t[j] > t[j + 1]) { uint32_t tmp = t[j]; t[j] = t[j + 1]; t[j + 1] = tmp; }
    return t[MED_N / 2];
    }

    float FDC2212_GetFiltered(void)
    {
    uint32_t raw = FDC2212_ReadChannel0();

    med_buf[med_idx++ % MED_N] = raw;
    uint32_t med = median5(med_buf);

    avg_buf[avg_idx++ % AVG_N] = med;
    uint32_t sum = 0;
    for (int i = 0; i < AVG_N; i++) sum += avg_buf[i];
    float avg = (float)sum / AVG_N;

    lpf_y += 0.2f * (avg – lpf_y);
    return lpf_y;
    }

    6.2 基线跟踪与差分判定

    不要用绝对阈值判定液面,因为环境温漂、湿度、容器材质都会让基线缓慢漂移。正确做法是:

    • 下探前在空气中采集一段数据,作为动态基线。
    • 判定量使用 Δ = 当前值 – 基线,而不是绝对值。
    • 基线用慢速低通持续跟踪(时间常数几秒),只在“未接触液面”状态下更新。

    6.3 迟滞 + 连续确认

    单点超过阈值就触发,是导致重复性差的直接原因。建议:

    #define TH_ON 120.0f /* 触发阈值 */
    #define TH_OFF 60.0f /* 释放阈值,形成迟滞 */
    #define CONFIRM_N 3 /* 连续确认次数 */

    static uint8_t confirm_cnt = 0;
    static uint8_t touched = 0;

    void Liquid_Detect_Task(float delta)
    {
    if (!touched) {
    if (delta > TH_ON) {
    if (++confirm_cnt >= CONFIRM_N) {
    touched = 1;
    confirm_cnt = 0;
    /* 记录当前 Z 轴位置作为液面位置 */
    Liquid_OnDetected();
    }
    } else {
    confirm_cnt = 0;
    }
    } else {
    if (delta < TH_OFF) {
    touched = 0;
    }
    }
    }

    阈值应通过实测确定:让探头缓慢接近液面,记录 Δ 随距离变化的曲线,取曲线拐点附近、且明显高于噪声标准差 5~8 倍的值作为 TH_ON。

    6.4 下探速度与采样率匹配

    如果下探速度过快而采样率不足,两次采样之间探头已经移动了较大距离,判定点自然离散。计算方式:

    单次判定位移 = 下探速度 ÷ 有效采样率

    例如下探速度 5 mm/s、有效采样率 50 Hz,则每次采样间隔对应 0.1 mm 位移,重复性误差至少在这个量级。若要求更高精度,需要降低下探速度或在接近液面时减速(两段式下探)。

    七、推荐的排查顺序

  • 静止采集 1000 点,量化噪声水平,确认问题严重程度。
  • 检查参考晶振、去耦、屏蔽与线缆固定,排除硬件干扰。
  • 核对寄存器配置,尤其是 RCOUNT、DRIVE_CURRENT 和 MSB 掩码。
  • 加入中值 + 滑动平均 + 低通三级滤波。
  • 改为动态基线 + 差分判定 + 迟滞 + 连续确认。
  • 调整下探速度与采样率匹配,必要时两段式下探。
  • 重复测试,统计触发点重复性,验证改善效果。
  • 八、总结

    FDC2212 读数跳动导致下探深度不一致,很少是单一原因造成的。硬件上要保证参考时钟稳定、电极屏蔽良好、线缆走向固定;配置上要在响应速度允许的前提下加长转换时间、合理设置驱动电流;软件上必须做多级滤波、动态基线跟踪和带迟滞的连续确认判定。按“先量化、再硬件、后算法”的顺序逐项排查,通常可以把触发点重复性从毫米级改善到几十微米级。

    赞(0)
    未经允许不得转载:171主机测评 » FDC2212 + STM32G030 液面探测:IIC 读数跳动导致下探深度不一致的排查与解决
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址