
前阵子做一个小项目要在设备里加一个非接触式金属检测功能金属块靠近时把设备从低功耗状态唤醒。当时第一反应是去找专用的电感数字转换芯片算了下成本、面积和通道数觉得不划算就决定试试用PSoC 4 MCU直接做电感感应Inductive Sensing。实测下来效果相当稳这个方案不仅能检测金属是否存在还能测距离、识别金属旋钮角度而且一颗MCU可以同时管多路线圈连主控都省了。这篇文章就把从原理、硬件、固件到产品化的完整经验梳理一遍适合正在评估“用普通MCU直接做电感式接近/位置传感”的工程师参考。即便你之前没接触过PSoC只要做过一点MCU开发跟着思路走也能拿下。1. 项目从哪来PSoC电感感应的底层逻辑1.1 电感感应到底在测什么很多人一听到电感感应就以为要用专用的LDC芯片其实核心原理不复杂一颗线圈和一颗电容组成LC并联谐振回路给这个回路一个激励它会开始振荡振荡频率由电感和电容决定。当有金属物体靠近线圈时金属表面会产生涡流涡流反过来改变线圈的有效电感和等效损耗于是谐振频率发生偏移。我们只要测出频率偏移量就能推断有没有金属靠近、离得多远。用生活里的例子解释LC回路就像一个秋千你推一下它会以固定节奏摆动当你把手放在秋千旁边阻力变大或者改变了秋千的“固有状态”摆动节奏自然就变了。电感感应做的就是“听秋千节奏变了多少”这件事。细节上要注意不同金属对频率的影响方向不一样。对铜、铝这类非铁磁性金属涡流效应占主导等效电感会变小谐振频率上升对钢、铁这类铁磁性金属磁导率增大又会让电感变大频率下降。实际应用中如果只做接近检测不用管方向取频率偏移的绝对值就够了如果要做材质判断这个方向差异反而可以作为参考特征。1.2 为什么选择PSoC而不是专用芯片专用电感数字转换器当然精度高但它本质上是把“线圈激励、比较器整形、频率测量”全部固化在芯片里通道数有限价格也偏高。如果你的产品里已经有MCU再外挂一颗LDC芯片无论从BOM成本还是PCB面积看都不划算。PSoC 4系列的优势在于它把模拟前端做得足够灵活。芯片内部有可配置的比较器、定时器、计数器、数字逻辑块还有一堆可以直接接模拟信号的GPIO。把LC回路接到引脚上用内部比较器把衰减振荡整形成方波再定时器测频率整套信号链全部在芯片内部完成。更关键的是PSoC的GPIO不区分严格的“模拟/数字”引脚每个引脚都可以当模拟输入用。这意味着你可以通过内部模拟路由把多个线圈轮流切换到同一个比较器实现多通道检测。我之前一块板上挂了4个线圈做线性位置传感成本只比单通道方案多几个线圈和电容这在传统方案里很难想象。另外还得提一句PSoC的电容感应CapSense和电感感应有很多相似的软件架构、滤波策略、基线校准思路如果你之前用过CapSense切到电感感应几乎是无缝衔接。官方后来的MagSense技术线也是在这个方向上的延续说明这条路线不是歪门邪道是有正规军背书的。2. 硬件设计线圈、谐振电容和PCB布局2.1 线圈尺寸、圈数和线宽怎么定线圈是整个传感器的探头它的参数直接决定检测距离和灵敏度。经验上检测距离大约等于线圈直径的三分之一到二分之一。比如要求隔着2mm塑料外壳检测到3mm外的金属块线圈直径至少选10mm左右。留足余量很重要因为实际装配后的距离会比理论值差一些我一般按1.5倍余量选型。PCB线圈的设计可以按下面的经验值起步线宽0.2mm0.3mm线间距尽量小与线宽接近圈数20圈到40圈具体电感量大概在10μH50μH范围。这个范围适合PSoC的测量能力不会超出比较器和定时器的工作区间。想要精确确定电感量最好用LCR表实测。一个直径15mm、30圈、线宽0.2mm的圆形螺旋线圈实测电感大约在20μH左右。如果手头没有LCR表也可以先用公式粗算但PCB线圈的寄生电容和走线形状影响很大公式只能作为数量级参考。打样时建议多留几个不同尺寸的线圈位置一块板子上放两个不同直径的线圈实测后再定最终方案。圈数影响灵敏度要特别注意圈数越多电感越大Q值可能会下降共振信号衰减更快。如果发现波形幅度很小不要只想到加大激励先检查是不是圈数太多导致Q值太低。2.2 谐振电容和寄生电容计算并联谐振电容的选择直接影响谐振频率。PSoC比较器和定时器的测量频率范围虽然不是死的但一般建议把谐振频率控制在1MHz到3MHz之间。太低外部噪声干扰明显太高PSoC内部比较器响应速度跟不太上计量误差变大。用公式 f 1 / (2π√(LC)) 来选电容。举个例子线圈电感L22μH想让谐振频率落在1.5MHz左右所需的电容大约为C 1 / ((2π×1.5×10^6)^2 × 22×10^-6) ≈ 0.51nF这个值包含PCB走线寄生电容和PSoC引脚电容。PSoC引脚本身有十几pF的寄生电容走线再贡献几pF到十几pF加起来一般不超过50pF。当计算出的电容值远大于100pF时寄生电容还算不上大问题但如果你算出只有几十pF那寄生电容就会严重拉偏谐振频率必须重新设计。所以我的建议是优先保证线圈电感在20μH左右然后选一个100pF到470pF的电容让谐振频率落在1MHz到3MHz区间。电容务必选NP0/C0G材质温度稳定性好X5R/Z5U这类高介电常数电容在温度变化时容值会明显漂移直接影响频率读数。还有一个容易忽略的点PSoC复位期间引脚默认是高阻LC回路没有激励不会振荡这没问题。但要确保外部电路上不存在会让引脚电压超过电源或低于地的冲击路径否则可能损伤芯片内部ESD结构。2.3 PCB布局的关键几条线圈下方的地平面是最大的坑。铜箔上感生涡流会白白消耗LC回路的能量导致Q值下降、灵敏度锐减。正确做法是在线圈正下方的所有层都挖空铜箔周围至少留出1mm2mm的净空区域。我在第一版打样时吃了教训线圈直接压在大面积底层地上面同样的代码、同样的线圈读数变化幅度比挖空后少了将近一半。当时还以为是器件问题后来把地挖空什么都没改灵敏度立刻回来了。线圈走线建议用圆弧或45度折角避免直角因为直角会形成局部电感突变影响线圈的寄生参数一致性。线圈附近不要走高频信号线特别是I2C、SPI、UART这类有沿跳变的线。如果绕不开必须用地线把它们隔开或者保持至少3倍线宽的距离。线圈到PSoC引脚的连线尽量短走线宽度可以适当放宽到0.3mm以上减小走线寄生电容。不要在线圈和芯片之间加任何串阻或滤波电容这些元件会成为LC回路的一部分使谐振特性不可预测。3. 固件实现从原始频率到稳定输出3.1 PSoC Creator工程怎么搭固件部分是我的本行。在PSoC Creator 4.x里新建工程选一颗PSoC 4比如CY8C4245系列然后搭建数据通路。如果你想走最快的路线可以去官方库找现成的电感感应组件早期Cypress做过一版后来并到了MagSense技术线里在ModusToolbox中间件里也能找到类似功能。它的好处是封装了激励、采样、频率转换省事很多。但如果你的线圈尺寸、谐振频率比较特殊或者你想彻底搞懂工作细节建议手动搭一条通路这也是我推荐的做法。手动方案的核心连接如下线圈接PSoC引脚同时通过内部模拟路由接到比较器输入。给LC回路一个激励脉冲把同引脚或者其他GPIO先配置为输出输出一个几微秒到几十微秒的宽脉冲把能量灌进LC回路。然后把引脚切成高阻输入LC回路自由振荡产生衰减正弦波。比较器把这个正弦波整形成方波输出接到定时器/计数器的捕获输入。定时器用高频时钟测量方波周期MCU读取测量结果。在PSoC Creator里所谓“引脚配置成高阻输入”就是给引脚加一个数字输入缓冲并把驱动模式改成“高阻数字”。激励和采样可以先用软件控制引脚模式切换这个代码很简单适合原型验证如果追求高性能把激励和采样交给内部可编程数字逻辑块自动完成MCU只在结束时去读结果。3.2 原始数据采集数边沿还是测周期测量频率有两种常见做法第一种是计数法固定一个时间窗口比如1ms在窗口内统计方波的上升沿个数。这个方法实现简单但分辨率受限于窗口时间和信号频率。假设谐振频率是1MHz1ms窗口内数到1000个边沿频率分辨率就是1kHz相对偏差千分之一。某些场景够用但你要是想检测3mm外的微小金属块这个分辨率可能不够。第二种是周期测量法用高频定时器测量方波N个周期的总时间反推平均周期。比如高频时钟48MHz测量256个周期信号频率1MHz总时间256μs定时器计数约12288个时钟理论上分辨率能到1/12288远超计数法。周期测量法的代价是消耗一个比较器捕获输入和一个定时器但这对PSoC来说很划算。我强烈建议产物阶段直接用周期测量法。你在调试时看到的读数稳定度会直接决定阈值能不能设得比较松、误触发能不能压下去。代码层面可以这样实现一个简单的频率采集函数uint32_t measurePeriodCounts(void) { Timer_Init(); Timer_Enable(); // 等待第一个捕获事件丢弃 while (0 Timer_GetCaptureStatus()) { } Timer_ResetCapture(); // 等待第二个捕获事件读取周期值 while (0 Timer_GetCaptureStatus()) { } result Timer_GetCaptureValue(); Timer_Disable(); return result; }上面的代码是示意实际PSoC组件接口名称根据你用的器件和组件会略有不同。核心思路是用第一次捕获同步时间基准用第二次捕获得到周期。如果要测平均周期需要连续捕获多次并累加。3.3 滤波、基线跟踪和阈值判断原始周期读数会带噪声尤其是线圈靠近电机、电源波动等场景。直接拿原始数据做判断阈值设低了会误报设高了又降低灵敏度。所以固件里必须加滤波。我的常见组合是先做一次5点中值滤波把偶发的脉冲干扰干掉再做一阶IIR低通系数取0.10.2让曲线平滑下来。中值滤波保边沿特性好不会把真实快速变化抹平IIR让长期读数稳定。两者搭配表现很好。处理完滤波接下来是基线跟踪。上电后线圈周围没有目标物这段时间内采集到的值作为基线存下来。每次新读数和基线做差得到delta值。这个delta就是判断目标物的依据。基线不是一成不变的温度、湿度、机械应力都会让读数缓慢漂移。如果完全不更新基线设备用一段时间后就可能误触发或者失敏。但基线更新不能太积极否则目标物停留在传感器附近时间长了会被当成“新的基线”从而漏报。我的策略是维护一个长期平均值只有当连续几秒没有触发目标检测且当前读数与长期平均值的差小于漂移上限时才以极慢的速度把基线拉向当前值。这样既能跟上环境缓慢变化又不会把真实目标误吸收。阈值判断建议加上滞回。比如触发使用delta大于100Hz释放要等delta小于50Hz。滞回可以有效避免目标处在临界位置时读数的反复抖动。一个简化示例#define TRIGGER_LEVEL_HZ 100 #define RELEASE_LEVEL_HZ 50 #define MAX_DRIFT_HZ 20 int32_t delta currentHz - baselineHz; int32_t absDelta (delta 0) ? -delta : delta; if (targetDetected) { if (absDelta RELEASE_LEVEL_HZ) targetDetected false; } else { if (absDelta TRIGGER_LEVEL_HZ) targetDetected true; }阈值到底设多少取决于你用真实目标物实测出的delta范围。比如目标物紧贴外壳时delta有600Hz那100Hz触发阈值就是合理的留足余量如果只有200Hz阈值就要压低到50Hz左右。4. 实测中的精度和抗干扰问题4.1 温度漂移怎么压温度是电感感应最讨厌的干扰源。铜线圈的电阻温度系数约0.4%/°C温度升高线圈等效电阻变大Q值下降振荡条件变化频率读数跟着漂。PSoC内部比较器的翻转阈值也会随温度稍有变化。两项叠加从0°C到70°C裸读数漂几百Hz到上千Hz很正常。如果你的目标信号本身才几百Hz那就麻烦了。硬件上谐振电容一定要选NP0/C0G材质不要用X5R/Z5U。电容温漂引起的频率偏移是系统性的会直接叠加到目标信号上。线圈走线稍宽一些也能减少电阻随温度变化带来的Q值变化。固件上基线跟踪是兜底方案。只要产品结构确定、装配后没有大幅机械位移慢速基线跟踪基本可以把温漂补偿掉。我实际测试过在温箱里跑温度循环加上慢速基线跟随后读数波动可以从上千Hz压缩到几十Hz以内效果非常明显。要注意的是产品刚上电的头几分钟芯片自身发热会让读数有较快的漂移。所以在固件里前5分钟内基线跟踪速度可以稍微快一点等热平衡后切到慢速模式。4.2 多通道扫描时的串扰如果你的设计要同时接多个线圈通道间的串扰必须处理。串扰来源主要有两个一个是线圈间磁耦合一个是驱动脉冲通过公共参考地回流到邻近通道。最直接的解决方法是拉开间距。两个相邻线圈中心距建议大于线圈直径的2倍这样互感衰减到很低。如果结构空间不允许可以把两个线圈改成90度正交布局磁耦合会大幅下降代价是感应方向受限制。软件上的处理同样重要。扫描顺序不要按通道顺序依次来最好把线圈分成两组先扫奇数组再扫偶数组。比如4个线圈扫描顺序是1、3、2、4。这样做给相邻线圈留出了“静默时间”振铃消退后再测下一个通道读数更干净。还要注意激励脉冲结束后LC回路的衰减振铃会持续一段时间。如果你在这个振铃还没消失时就切换线圈、立即采样得到的频率叠加了残留振铃误差会明显变大。建议在采样窗口前留出几十微秒的稳定时间。这个时间可以从示波器上看到振铃衰减到接近零时确定。4.3 环境干扰的排查顺序遇到读数异常波动时别急着改软件参数先按下面顺序排查供电是否干净。把示波器探头点在PSoC电源引脚上看波纹。如果波纹大先解决电源问题。LC回路对电源噪声的敏感度超乎想象。外部电磁干扰。近距离有大电流线、电机、开关电源它们的磁场会直接耦合进线圈。检查这些干扰源是否和线圈靠得太近必要时调整布局或加屏蔽。机械结构是否发生变化。线圈被螺丝锁紧的扭矩、外壳受压、温度变化导致的材料膨胀都会让线圈电感量发生缓慢变化。如果读数漂移和你的结构件受热有关单纯改滤波收效甚微。最后才怀疑固件。检查是否在主循环里做了太多事导致采样窗口抖动或者中断里耗时长导致读数延迟不规律。我遇到过一次很典型的问题电机一启动读数立刻就跳。排查后发现是电机驱动的地线回流经过线圈下方产生了一个较大的噪声压降。把地线重新规划绕开线圈区域再加上电机驱动端的RC吸收电路问题就解决了。5. 从原型到产品标定、产测和功耗5.1 出厂标定怎么做原型能跑通只是第一步产品化时每个模块的参数都有分散性线圈电感量差异、电容容差、外壳厚度装配差都会让基线值不一样。所以产线上必须做标定。最简单的标定是“两点标定”空载时测一次基线然后在固定位置放一个标准金属块测一次delta两者差值作为灵敏度系数存入Flash。如果产品对精度要求高可以多做几步目标物以0.5mm步进移动记录一组delta-距离曲线线上用查表加线性插值来还原距离。标定时机的选择很关键。我建议在整机装配完成后再标定而不是裸板阶段。因为外壳材质和厚度会影响线圈的有效电感裸板标定和装壳后的实际参数可能差不少。如果外壳是不锈钢之类导电材质影响更大。标定数据建议写进PSoC内部Flash的专用区域或者外挂EEPROM。写Flash要注意先擦后写而且要把数据加上校验和防止异常断电导致标定数据损坏。如果产品有多个通道每个通道都要独立标定。不同通道的灵敏度可能差20%不做通道级校准的话位置计算的线性度会受影响。5.2 低功耗场景怎么设计电池供电的产品用PSoC做金属检测很有竞争力因为PSoC 4的DeepSleep电流很低可以用周期性唤醒扫描来降低平均功耗。典型调度产品平时睡在DeepSleep每10ms醒来一次扫描线圈、滤波、判断整个过程约3ms然后继续睡。计算下来MCU的平均功耗主要取决于扫描期间电流和占空比的乘积比一直跑着省很多。但低功耗设计有两个坑要注意。第一个是首次上电要建立基线这个过程必须在完成标定的前提下进行不能让首次上电的原始读数直接作为基线否则如果线圈周围刚好有金属件基线就偏了。第二个是基线的定期保存。不要每次唤醒都写FlashFlash有擦写寿命建议每隔几分钟或几十次扫描无目标时才保存一次基线。低功耗模式下如果MCU唤醒后第一时间就扫描可能会读到电源稳定前的毛刺。稳妥做法是唤醒后等几百微秒让内部LDO输出电压稳定再启动比较器和定时器。这个几百微秒也是功耗但不做的话读数噪声会很大。5.3 几个让我印象深刻的经验教训最后分享几个实际项目里踩过的坑都是常规文档里不会写的东西。第一个调试时一定要留一个能实时打印原始数值的调试通道。可以是UART也可以是I2C从机。看起来多此一举但等到你调阈值、调滤波参数的时候没有原始数据曲线你就是在盲调。我一般会用UART每秒打印一次滤波前后的值配合串口助手存成CSV在电脑上画曲线对比。第二个线圈走线和焊盘的位置会影响谐振频率。一开始我焊了一颗匹配电容频率读数比设计值偏离了100多kHz怀疑电容参数错了换了好几颗都一样。后来发现是线圈出线端的焊盘铜箔太长多出来几pF寄生电容把频率压下去了。解决方法是把焊盘尽量靠近线圈减小附加面积。第三个如果检测目标很近1mm以内传感器读数的快速变化会比远距离时更加非线性。距离越近delta随距离的变化越陡。做位置标定时一定要在近端多采样几个点否则线性插值在近端误差很大。第四个如果你的目标物是旋转的金属旋钮那么旋钮的齿轮形状会让读数产生周期性波动。这时候阈值和滤波参数不能只用平均值来判断最好在前端加一点峰值保持逻辑把旋钮转过齿尖时的最大delta记录下来再和阈值比较效果会好很多。PSoC做电感感应这条路我用到现在最大的感受是它的门槛不高但上限取决于你对谐振原理和噪声来源的理解。硬件上把线圈、电容、地平面处理干净固件上把周期测量、滤波、基线跟踪做到位大部分项目都能稳定跑起来。如果你也在评估这个方向建议先拿一块PSoC开发板、一个绕好的线圈和一颗电容搭个最小系统实测一组数据再决定要不要往产品里放。