ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

基于STM32的电导率测量仪:从原理到源代码实现

2026/9/16 22:15:05 拓冰建站 浏览量
基于STM32的电导率测量仪:从原理到源代码实现 简介一套基于STM32单片机设计的电导率测量仪完整工程适合电子、自动化、计算机等专业学生开展嵌入式课程设计或毕业设计也可供研发人员快速搭建低成本工业级溶液电导率检测方案。项目从实际测量需求出发完成了硬件模块设计与软件驱动编写硬件包括正弦波信号发生、滤波、信号放大以及负电源电压转换等电路软件覆盖温度采集、模数转换、液晶显示、触摸交互、SD卡存储及串口打印最终可实时显示并保存测量结果。压缩包包含101个文件主体为C语言源程序与头文件另有原理图、PCB设计文档、工程配置和说明文档压缩包大小约73MB。目前已有648人浏览学习项目代码均经过运行验证参考价值较高。下载后结合说明文档可快速理解电导率测量的完整实现脉络并可在现有基础上扩展其他传感测量功能。1. 基于STM32的电导率测量仪到底在解决什么如果直接往电导率探头上加直流电读数会在一分钟内持续漂移这不是算法问题是电化学上的必然离子会在电极表面形成双电层相当于在溶液电阻上串联了一个电容。把直流换成交流极性换向又会带来一个前冲ADC 上出现的是一段充放电波形而不是平稳电压。基于STM32的电导率测量仪就是用定时器产生固定频率的交流激励、让采样时刻避开换向沿再通过跨阻放大、量程切换、电导率换算和温度补偿把探头本身的物理效应逐个拆掉。标题里的“源代码文档说明”透露出交付物不只是几条 ADC 读取语句而是激励时序、量程判定、校准参数存取和探头常数设置这些完整链路。这套设计能同时覆盖纯水电导率、农业肥液浓度和工业废水监测差别只在探头常数的标定和量程硬件选择。2. 电导率测量原理与探头参数计算2.1 电极常数 K怎么把溶液电阻换算成电导率电导率的国际单位是西门子每厘米S/cm较小的测量对象常用 μS/cm 和 mS/cm。探头的两根电极之间夹着溶液溶液就是一个电阻。几何形状决定了这个电阻和电导率之间有一个固定比例称为电极常数 K单位是 cm⁻¹σ K / R其中 R 是两电极之间溶液的等效电阻σ 是电导率。工业上常见的 K 值有 0.1、1.0 和 10K 越大适合测量的电导率范围越高。比如 K1.0 的探头测到 R7.07 kΩ那么 σ1/7070≈141 μS/cm。如果换成 K10 的探头同样的电阻值代表 1414 μS/cm所以拿到探头必须先确认 K 值或者用标准溶液反向标定出实际 K。即使是同一批次探头加工偏差也会让 K 出现在 0.951.05 之间项目源代码里应该留一个 probe_k 参数并允许校准改写。设计测量仪时还要注意K 是在探头完全浸没且电极间距固定时定义的。如果液位没到指定位置等效 K 会变化读数偏低。因此结构设计上要保证探头插入深度一致。2.2 为什么不能用直流或低频信号测电阻用直流电测电导率相当于对电化学电池做电解实验。正极附近产生氧化反应负极附近产生还原反应离子浓度分布被改变测量的是“正在变化中的溶液”而不是真实的电导率。解决思路是换向正向通电一段时间后反向前通电让两次电解作用相互抵消。这个换向频率就是激励频率。但激励频率也不能随意提高。频率越高电极引线和溶液寄生电容的分流效应越明显高频电流会从电容路径直接流过导致测得电导率偏大。同时换向瞬间电极双电层电容要重新充电如果此时 ADC 采样读到的根本不是溶液电流。常见做法是取 1 kHz 左右的方法波切换后等待 300500 μs 再采样让电极电容充放电接近结束。后面的固件设计会按这个思路安排定时器。2.3 二极、四极与电感式探头怎么选对于基于STM32的独立仪表探头选型直接决定硬件复杂度和适用范围。探头类型激励方式典型量程污染影响电路复杂度二极式跨接交流电压测电流0.055 μS/cm20 mS/cm电极表面污染影响明显低适合入门四极式恒流注入另两极测电压0.1 μS/cm200 mS/cm表面污染影响较小中多一路电压采样电感式线圈感应涡流10 mS/cm 以上无电极接触不怕污染高需要处理非正弦信号标题中直接标“电导率测量仪”而且带源代码大概率是从二极式做起。二极式结构简单只需一组激励输出加一路电流检测源代码里不需要处理第二路 ADC 同步先跑通整体数据链路再扩展其他探头类型是最合理的路径。若一开始就要求高精度在线监测那就选四极式但电路的模拟通道和代码里的量程分档都会明显变多。2.4 温度系数为什么必须补偿溶液电导率随温度上升而增大一般规律是每升高 1 ℃ 增加 1%2.5%具体数值和溶液成分有关。如果不补偿夏天和冬天同一种溶液读数能差出 20% 以上。国家标准和大部分设备都把结果折算到 25 ℃补偿公式用线性近似σ25 σt / (1 α × (t - 25))α 是溶液温度系数中性盐溶液取 0.020稀盐水取 0.0200.023酸和碱溶液系数更高可达 0.025 以上。这个公式在 060 ℃ 范围内足够用纯水除外纯水的电导率来源与温度的关系不满足简单线性近似需要额外查表。源代码里建议把 α 做成可配置参数而不是写死。3. 硬件信号链设计从探头到 ADC 的每个环节3.1 用定时器产生的交流激励信号如何加到探头上激励源最简单的实现方式是用两个 GPIO 交替输出高低电平先让 A 引脚为高、B 引脚为低一段时间后反过来。这样探头两端得到一个幅值对称的交流方波平均直流分量为零能最大程度减少电极电解。不过直接用 GPIO 翻转会产生两个问题一是翻转沿的上升速度过快容易引起振铃二是幅值等于单片机供电电压在低电导率测量时电流太大。更稳妥的方案是使用 STM32 高级定时器输出互补 PWM接两个三极管或 MOS 管组成简单 H 桥。互补输出还支持死区时间配置防止上下管同时导通。激励幅值不要直接取 3.3 V建议经过分压衰减到 ±0.5 V 左右。这个电压已经能推动探头产生足够的测量电流又不会在高电导率溶液里造成明显的电解发热。以 3.3 V 供电、两个 33 kΩ 电阻分压输出幅度约 0.5 V探头两端配置差分驱动总摆幅约 1 V。如果只做原理验证直接用两个 GPIO 和一个三极管反相器切换方向也能工作。测量精度要求高的场景才需要把电压基准改成专用基准源比如 REF3033避免电源波动直接进入测量结果。3.2 跨阻放大与自动量程切换探头输出的电流范围很宽。以 K1 的探头为例1 μS/cm 的纯水对应 1 MΩ电流只有 0.5 μA而 10 mS/cm 的工业废水对应 100 Ω电流达到 5 mA。同一个放大器不可能同时接受这两个数量级的信号必须要切换量程。典型信号链是探头电流先经过跨阻放大器变成电压。跨阻放大器的反馈电阻 Rf 决定转换比例输出电压等于激励电压峰值乘以 Rf 再除以溶液电阻。Rf 越大对小电流越灵敏但大电流时会饱和。自动量程就是通过模拟开关或继电器切换不同阻值的 Rf。运算放大器要选低偏置电流、轨到轨输入输出的器件因为探头是高阻抗源偏置电流会直接形成测量误差。前端还要加一个串联保护电阻和两个反并联二极管防止探头接反或电极短路时电流过大。PCB 上跨阻电阻周围要做开槽或屏蔽环因为反馈节点是高阻节点漏电流会直接影响精度。3.3 ADC 采样相位与激励信号同步交流激励下ADC 不能在方波翻转的瞬间采样。激励电压换向后电极双电层电容开始充电探头电流要经过一段稳定时间才接近真实值。这个稳定时间大约在 100 μs 到 500 μs 之间具体取决于探头电容。为了简单可靠大多数 STM32 项目会用两个定时器配合TIM1 产生激励方波TIM2 用来做采样延时。TIM1 中断里翻转激励方向后TIM2 延时 400 μs 再触发 ADC 启动。这样每次都在方波电平的中段采样避开换向沿。还有一种做法是用 ADC 的外部触发源直接接到定时器的 TRGO 事件但这种映射在不同 STM32 芯片上引脚不同不建议第一版就引入。3.4 一套可以直接抄的跨阻参数表下面这组参数对应三个量程激励电压峰值按 0.5 V、探头常数 K1.0 设计。量程电导率上限溶液电阻下限跨阻 RfADC 端信号峰值R120 μS/cm50 kΩ100 kΩ1.0 VR22 mS/cm500 Ω1 kΩ1.0 VR320 mS/cm50 Ω100 Ω1.0 V这三个 Rf 值刚好使每个量程满刻度时 ADC 输入信号都接近 1 V再经过一级 3 倍增益放大后达到 3 V接近 ADC 满量程充分利用 12 位分辨率。切换量程时先断开当前通道再闭合目标通道避免瞬间短路。若溶液电阻低于 Rf 对应的下限输出会明显饱和固件事先计算并切换低一档量程即可。温度采集用 NTC 或 DS18B20 都可以。NTC 响应快但要多一路运算放大器DS18B20 是数字接口节省模拟通道缺点是封装尺寸较大。对仪表而言温度稳定性比速度更重要普通 NTC 加 10 kΩ 分压电路的温度分辨率也能做到 0.1 ℃。4. STM32 固件实现与源代码结构4.1 源代码按哪几层组织才能复用拿到“源代码文档说明”这类项目最容易踩的坑是把所有逻辑堆在 main.c 里。激励翻转、量程切换、电导率计算、串口打印混在一起改一个功能就要重新理解全局流程。我习惯把源代码分成四层app/ conductivity.h /* 对外接口测量值、校准参数 */ conductivity.c /* 电导率计算、温度补偿 */ measure.h measure.c /* 激励时序、ADC 采样、量程切换 */ drv/ adc_drv.c /* ADC 初始化与轮询读取 */ temp_drv.c /* 温度传感器驱动 */ uart_drv.c /* 输出调试 */ doc/ 信号链计算.xlsx 校准记录.mdmeasure.c 只负责拿原始 ADC 值conductivity.c 负责把原始值换算成电导率。这样换一个探头型号只改 conductivity.c 里的 probe_k 参数换一块 STM32 芯片只改 drv 层和 CubeMX 生成代码。文档说明里如果看到类似分层代码一般比较容易移植。实际项目里我会把量程自动切换的判断也放在 measure.c因为它依赖 ADC 原始值和硬件量程档位不属于电化学计算。4.2 激励方波与 ADC 采样的最小代码这是最核心的一小段逻辑基本思路是翻转激励方向、延时跳过不稳定区、启动 ADC、取原始值。以下代码用 GPIO 翻转方式演示省去具体芯片引脚配置便于理解流程。/* 激励方向切换EXC_A 和 EXC_B 是两个 GPIO 引脚 */ static void excitation_toggle(void) { HAL_GPIO_TogglePin(EXC_A_GPIO_Port, EXC_A_Pin); HAL_GPIO_TogglePin(EXC_B_GPIO_Port, EXC_B_Pin); } /* 单点采样跳过换向暂态后读取 ADC */ static uint16_t sample_once(void) { excitation_toggle(); delay_us(400); /* 等待电极电容稳定 */ HAL_ADC_Start(hadc1); HAL_ADC_PollForConversion(hadc1, 10); return (uint16_t)HAL_ADC_GetValue(hadc1); } /* 连续采样多次取平均降低尖峰干扰 */ uint16_t measure_raw(void) { uint32_t sum 0; for (uint8_t i 0; i 8; i) { sum sample_once(); } return (uint16_t)(sum / 8); }这段代码里有两个关键参数400 μs 的延时长度取决于探头电容不能盲目加长否则采样周期变长刷新率下降也不能太短否则采到换向脉冲。取 8 次平均是为了抑制电源纹波和电磁干扰但不能抑制系统性的直流偏置误差那要靠校准解决。若使用双定时器触发 ADC 的方式原理和这段一致只是把 delay_us 换成定时器延时后触发代码可以放在定时器回调里。4.3 电导率计算与温度补偿实现从 ADC 原始值到最终显示值中间经历过放大器增益、偏置电压、量程 Rf 等环节。固件里统一用一阶线性表达式/* 将 ADC 值换算为电导率temp 为实测温度 */ float calc_conductivity(uint16_t raw, float temp) { float v_sample raw * 3.3f / 4095.0f; /* V_ZERO 是交流信号未接入时的零点GAIN 是后级增益 */ float v_ac (v_sample - V_ZERO) / GAIN; /* 根据量程档位取对应的跨阻 Rf */ float r_solution (VEXC_PEAK * Rf) / v_ac; float cond probe_k / r_solution; /* 当前温度下电导率 */ float alpha solution_alpha; /* 折算到 25 ℃ 基准 */ return cond / (1.0f alpha * (temp - 25.0f)); }v_sample 是 ADC 直接读数V_ZERO 必须在硬件空载时测量并保存否则零点偏差会直接叠加到测量结果。VEXC_PEAK 是激励方波的峰值电压不是峰峰值比如 ±0.5 V 摆幅的方波峰值就是 0.5 V。GAIN 和 Rf 在量程切换时会变化固件里要在每次量程切换之后更新这两个变量。这段代码里最容易被忽略的是温度补偿量 α 的单位。如果溶液温度系数写成 0.020那么温度差要代入 25而不是 55 或 250否则补偿量会差十倍。建议在源代码注释里明确写“alpha 是每摄氏度相对变化率”。4.4 校准参数应该存在哪里探头常数 K、零点 V_ZERO、温度系数 α 属于校准参数断电不能丢失。把它们直接定义成 const 常量会带来麻烦每次校准时要重新编译烧录。正确做法是存储在 STM32 内部 Flash 的最后一个扇区或外挂 EEPROM 中。固件启动时先读取存储区校验四个字节的 CRC 或简单的魔数校验通过才使用保存值否则回退到默认值。写入时要先擦除再编程避免频繁写 Flash。以下是一段示意typedef struct { uint32_t magic; float probe_k; float v_zero; float alpha; } calib_t; void save_calib(const calib_t *cal) { uint32_t flag disable_interrupts(); HAL_FLASH_Unlock(); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, CALIB_ADDR, cal-magic); /* 后续字段按顺序写入 */ HAL_FLASH_Lock(); enable_interrupts(flag); }写入 Flash 期间的延时较长必须关闭中断否则激励方波会暂停或串口数据错乱。串口调试时如果发现校准后参数不生效优先检查读取函数里有没有重新 load 到运行变量很多项目只改了 Flash没有更新 RAM 中的运行值。5. 量程分档校准流程与误差控制5.1 两点校准的完整操作步骤拿到一台还没标定的电导率仪直接测样品是不可信的。至少需要两种不同电导率的标准液常见的组合是 147 μS/cm 和 1.413 mS/cm。校准前探头要用去离子水冲洗干净再用待测标准液润洗一遍避免上一杯溶液的残留。操作顺序如下将探头放入 147 μS/cm 标准液等待温度读数稳定。记录当前显示值计算修正后的 probe_k。换成 1.413 mS/cm 标准液重复一次。如果两个点的修正比例相差超过 5%检查量程是否切换正确、探头是否完全浸没。将两组比例求平均后写入 Flash。两点校准实际修正的是整个信号链路的增益误差包括 Rf 精度、探头几何偏差和放大器增益误差。如果两个点修正比例不一致说明电路存在非线性常见原因是低量程时信号太弱被偏移电压淹没。这时重新设置 V_ZERO 往往比调 probe_k 效果更好。5.2 用标准液反推量程切换阈值量程切换不能只看 ADC 原始值因为每个量程的增益不同。固件里应该在切换到某个量程后计算当前电导率再判断是否超过该量程上限的 90% 或低于下限的 10%。以下是一段量程判断逻辑uint8_t decide_range(float cond_mS) { /* 返回 0小量程1中量程2大量程 */ if (cond_mS 0.02f) return 0; if (cond_mS 2.0f) return 1; return 2; }阈值设置要加回滞否则测量值在分界点附近抖动时量程开关会频繁切换除了缩短模拟开关寿命还会让输出数值跳变。一般做法是上限切大档阈值使用 90%从大档切回小档使用 70%。这段回滞逻辑写在 measure.c 里紧挨着硬件开关切换位置最好不要放到 conductivity.c因为它和模拟开关状态强相关。5.3 常见误差源与排查方向最容易把新手困住的是电极之间的振荡。激励信号通过探头后进入 ADC如果探头引线过长引线电感和电容会在方波换向瞬间产生振铃幅度大的时候能持续 100 μs 以上采样点刚好落在振铃区间读数就忽高忽低。解决方法是把激励线和采样线分开探头使用屏蔽线且屏蔽层单端接地采样点尽可能靠近运放输入。第二个常见误差是运放供电不足产生的削波。测量高电导率溶液时如果反馈电阻选择过大跨阻输出很容易顶到电源轨。削波后的波形是平顶ADC 读出的电压不再随电导率增加而量程判断靠 ADC 值又无法识别已经饱和于是显示一个虚高的电导率。这里要加上溢出判断ADC 值连续多次超过满量程的 95%强制切换到下一档量程。第三是温度传感器没有紧贴溶液。DS18B20 用防水探头时热传导滞后明显温度稳定前读出的补偿系数是错的。室温下相差 2 ℃电导率读数会有 4% 左右的偏差比大多数电路的固有误差都要大。6. 用标准电阻验证整机和固件的三个技巧6.1 用精密电阻代替探头做整机自检标准液会污染、会挥发标定一次成本不低。调试时更快捷的验证方法是用高精度金属膜电阻直接接在探头接线端子上。因为电导率仪的激励信号是交流普通色环电阻的寄生电容很小等效为纯电阻使用。以 K1.0 探头为例接入 6.8 kΩ 电阻理论电导率为 147 μS/cm接入 707 Ω 电阻理论电导率为 1.413 mS/cm。把这两个值当作目标去对比屏幕显示偏差不超过 0.5% 说明模拟链路和电导率换算逻辑正确。用电阻代替标准液的好处是可以排除温度因素因为电阻不随溶液温度变化更容易定位到电路本身的问题。6.2 利用原始 ADC 值判断干扰是来自模拟端还是数字端把固件里的计算暂时屏蔽只用串口打印原始 ADC 值可以迅速缩小问题范围。方法是在测量循环里加一个开关让 new_cond 的整个计算分支都被跳过只发送 raw。打印的 raw 值如果来回跳动超过 30 个 LSB说明干扰来自模拟前端。此时用示波器观察探头两端方波检查换向沿后面是否有振铃并试着把延迟时间从 400 μs 加到 600 μs。如果 raw 值稳定但计算出的电导率漂移说明问题出在补偿公式或参数类型上重点检查 v_ac 是不是被零点电压减成负数。6.3 文档说明应该按什么顺序读源代码压缩包里往往包含原理图、PCB、说明文档和代码。我每次拿到这种打包项目首先是打开说明文档看“量程参数表”和“探头选型”两页确认项目设计目标接着看原理图里跨阻电阻周围有没有保护环最后才打开源代码。这部分验证顺序直接决定后续调试方向。如果文档说明里直接给出了 Rf 参数先用它换算一下满量程信号幅度确认和 ADC 电压范围匹配再开始烧录程序能少走一大半弯路。本文还有配套的精品资源点击获取