介绍
用于水质监测节点的pH传感器模组,基于模拟电压输出型pH探头+信号调理板。支持三点标定(pH 4.00/6.86/9.18缓冲液),通过ESP32的ADC读取电压并线性拟合出pH值。配套Python Qt标定工具和C++固件驱动,适用于水环境监测、水产养殖、污水处理等场景。
用于水质监测节点的pH传感器模组,基于模拟电压输出型pH探头+信号调理板。支持三点标定(pH 4.00/6.86/9.18缓冲液),通过ESP32的ADC读取电压并线性拟合出pH值。配套Python Qt标定工具和C++固件驱动,适用于水环境监测、水产养殖、污水处理等场景。
| 参数 | 值 |
|---|---|
| 精度 | ±0.1 pH (标定后) |
| 分辨率 | 0.01 pH |
| ADC分辨率 | 12-bit (ESP32) |
| 供电电压 | 3.3V / 5V |
| 响应时间 | <30s (达到稳定读数) |
| 工作温度 | 0 ~ 60°C |
| 拟合公式 | pH = k·V + b (线性) |
| 探头接口 | BNC |
| 标定方式 | 三点标定 (pH 4.00/6.86/9.18) |
| 测量范围 | 0.00 ~ 14.00 pH |
| 输出信号 | 模拟电压 (mV级,经信号调理板放大后送入ADC) |
| 通信接口 | GPIO (ADC) |
| 配套工具 | Python Qt 三点标定工具 (ph_calib) |
| 单片机平台 | ESP32-S3 (Arduino框架) |
# pH 传感器模组 — 代码例程 (ESP32 Arduino)
## 1. GPIO 初始化
```cpp
#include <Arduino.h>
// pH 探头 ADC 引脚(可根据实际接线修改)
#define PH_ADC_PIN 4
// 标定参数:每块板不同,由 ph_calib 工具生成后填入
#ifndef PH_V686
#define PH_V686 1.3699f // pH=6.86 缓冲液对应电压 (V)
#endif
#ifndef PH_V918
#define PH_V918 1.1168f // pH=9.18 缓冲液对应电压 (V)
#endif
void setup() {
Serial.begin(115200);
// ADC 初始化:12-bit 分辨率,11dB 衰减(~3.3V 满量程)
analogReadResolution(12);
analogSetPinAttenuation(PH_ADC_PIN, ADC_11db);
Serial.println("pH Sensor ready.");
Serial.printf("PH_V686=%.4f PH_V918=%.4f\n", PH_V686, PH_V918);
}
```
---
## 2. 驱动函数
### 2.1 读取 pH 探头电压(多次采样取均值)
```cpp
/**
* @brief 读取 pH 探头输出电压 (V)
* @note 连续采样 N 次取均值,降低噪声
* @return 电压值,单位 V
*/
static float read_ph_voltage() {
const int N = 20; // 采样次数
uint32_t sum_mv = 0;
for (int i = 0; i < N; ++i) {
sum_mv += analogReadMilliVolts(PH_ADC_PIN);
delay(2);
}
return (sum_mv / (float)N) / 1000.0f;
}
```
### 2.2 电压转 pH(两点线性插值)
```cpp
/**
* @brief 电压转 pH 值
* @param v 探头电压 (V)
* @return pH 值
* @note 线性模型: pH = k·v + b
* 其中 k = (6.86-9.18)/(V686-V918)
* b = 6.86 - k*V686
*/
static float voltage_to_ph(float v) {
constexpr float k = (6.86f - 9.18f) / (PH_V686 - PH_V918);
return 6.86f + k * (v - PH_V686);
}
```
### 2.3 综合读取(电压 + pH 一起返回)
```cpp
/**
* @brief 读取 pH 探头并返回电压和 pH
* @param v_out [out] 原始电压 (V)
* @return pH 值 (0.00 ~ 14.00)
*/
static float read_ph(float* v_out = nullptr) {
float v = read_ph_voltage();
if (v_out) *v_out = v;
float ph = voltage_to_ph(v);
// 钳位到合理范围
if (ph < 0.0f) ph = 0.0f;
if (ph > 14.0f) ph = 14.0f;
return ph;
}
```
---
## 3. 完整示例 — 每 2 秒打印一次 pH
```cpp
#include <Arduino.h>
// ==================== 引脚 & 标定参数 ====================
#define PH_ADC_PIN 4
#ifndef PH_V686
#define PH_V686 1.3699f
#endif
#ifndef PH_V918
#define PH_V918 1.1168f
#endif
// ==================== 驱动函数 ====================
static float read_ph_voltage() {
const int N = 20;
uint32_t sum_mv = 0;
for (int i = 0; i < N; ++i) {
sum_mv += analogReadMilliVolts(PH_ADC_PIN);
delay(2);
}
return (sum_mv / (float)N) / 1000.0f;
}
static float voltage_to_ph(float v) {
constexpr float k = (6.86f - 9.18f) / (PH_V686 - PH_V918);
return 6.86f + k * (v - PH_V686);
}
static float read_ph(float* v_out = nullptr) {
float v = read_ph_voltage();
if (v_out) *v_out = v;
float ph = voltage_to_ph(v);
if (ph < 0.0f) ph = 0.0f;
if (ph > 14.0f) ph = 14.0f;
return ph;
}
// ==================== setup & loop ====================
void setup() {
Serial.begin(115200);
delay(300);
analogReadResolution(12);
analogSetPinAttenuation(PH_ADC_PIN, ADC_11db);
Serial.println("===== pH Sensor Demo =====");
Serial.printf("PH_ADC_PIN = GPIO%d\n", PH_ADC_PIN);
Serial.printf("PH_V686 = %.4f V\n", PH_V686);
Serial.printf("PH_V918 = %.4f V\n", PH_V918);
Serial.println("==========================");
}
void loop() {
float voltage = 0.0f;
float ph = read_ph(&voltage);
Serial.printf("[pH] voltage=%.4f V => pH=%.2f\n", voltage, ph);
delay(2000);
}
```
**预期输出**(串口 115200):
```
===== pH Sensor Demo =====
PH_ADC_PIN = GPIO4
PH_V686 = 1.3699 V
PH_V918 = 1.1168 V
==========================
[pH] voltage=1.2345 V => pH=7.12
[pH] voltage=1.2342 V => pH=7.13
...
```
---
## 4. 标定模式固件(calib)
烧录此固件后,配合 Python `ph_calib` 工具完成三点标定:
```cpp
#include <Arduino.h>
#define PH_ADC_PIN 4
void setup() {
Serial.begin(115200);
analogReadResolution(12);
analogSetPinAttenuation(PH_ADC_PIN, ADC_11db);
Serial.println("[PH_CAL] CALIB MODE READY");
}
void loop() {
const int N = 16;
uint32_t sum_mv = 0;
for (int i = 0; i < N; ++i) {
sum_mv += analogReadMilliVolts(PH_ADC_PIN);
delay(5);
}
float v = (sum_mv / (float)N) / 1000.0f;
Serial.printf("[PH_CAL] v=%.4f\n", v);
delay(100); // ~5 Hz 输出
}
```
输出格式:`[PH_CAL] v=1.2345`,供标定工具正则匹配。
---
## 5. 在 platformio.ini 中覆盖标定参数
```ini
[env:my_node]
build_flags =
-DPH_V686=1.3699f
-DPH_V918=1.1168f
```
> ⚠️ 每块板的参数不同,务必用标定工具测量后填入!
暂无参考文献