项目概述

本项目用一块 ESP32 与 XR2206 函数信号发生器 组成一台简易的频率计 + 真实波形监视器:

  1. 测频:XR2206 的方波输出接入 ESP32 的 GPIO34,使用 ESP32 硬件脉冲计数器(PCNT)对脉冲累加,再用"闸门计数法"换算成频率。
  2. 波形显示:XR2206 的当前波形输出(正弦 / 三角 / 方波)接入 GPIO35,通过 ADC 真实采样,在 ST7789 屏幕上画出"真实 ADC 波形",附带上升沿触发、自动量程与削波检测。
  3. 双界面:按 GPIO27 键在 数据界面(大字频率) 与 波形界面(滚动示波) 之间切换。
  4. 网页监视:ESP32 开启软 AP(SSID ESP32-XR2206),手机连上热点后访问 http://192.168.4.1,可看到频率数字 + 由真实采样数据绘制成网页 canvas 波形(300ms 轮询刷新)。

项目亮点

  • PCNT 硬件计数测频,几乎不占 CPU:脉冲计数交给 ESP32 硬件外设完成,主循环只需要几十毫秒读取一次计数。
  • 自适应闸门:闸门时长会在 1s ~ 4s 之间自动调整——计数太少自动加倍闸门提高精度,计数太多恢复 1s 保证响应速度。
  • 真实 ADC 波形,不是"画出来的正弦":屏幕和网页都显示 GPIO35 的真实采样点,方波就是方波、削波就提示削波。
  • 触发与防混叠兼顾:采集前先"摸底"找电平范围,用中值 + 滞回做上升沿触发,保证每帧波形起点一致;采样间隔又按频率自适应,高频不延时连续采。
  • 自动量程 + 削波报警:波形幅度过小时自动切全量程;当采样值大量贴着 0 / 4095 两端时判定为输入削波,屏幕红色提示 CLIP! turn AMP down
  • 网页端与屏幕端双界面:软 AP + HTTP JSON 接口,手机浏览器即可实时看频率与波形,无需额外上位机软件。
  • 代码分层极简:FreqCounter / ModeButton / Display / WebUI 四个类各司其职,主程序只负责初始化与调度。

项目难点及解决方案

难点 具体表现 解决方案(代码对应)
16 位计数溢出 PCNT 计数器寄存器是 int16,上限 32767,高频时几十毫秒就溢出丢数 update() 每 50ms 搬运一次 readAndClear(),累计到 32 位 accumCount_FreqMeter.cpp update)
固定闸门无法兼顾精度与响应 闸门太长高频响应慢,太短低频精度差 自适应闸门:count<100 且闸门<4s 则翻倍;count>1000 则恢复 1s(update() 末尾)
波形画面抖动 / 起点乱 不触发直接采,每帧波形相位随机,画面乱跳 captureRealScope() 先 64 次采样摸 max/min,取中值 + 1/20 滞回做上升沿触发(等待 40ms),保证每帧从同相位开始
波形残影叠加 新波形叠在旧波形上,画面重影 绘制前 tft.fillRect() 整块清空绘图区,再画边框与中线
输入削波或幅度贴边 输入超出 ADC 量程被"削平",正弦被削成方波 nearLo<80 / nearHi>4015 各超过 1/8 样本判为削波,波形转红色并提示调低幅度;量程自适应加 1/12 边距
混叠与采样率矛盾 频率高时延时采样会混叠,频率低时又要等 sampleIntervalUs():目标覆盖约 2 个周期;<5Hz 固定 500us;>20kHz 不延时连续采样
按键抖动 / 长按误触 机械按键抖动导致一次变两次 按下瞬间记录 downMs_,抬起时要求按住时长 >30ms 且 <800ms 才记短按(ModeButton::update()
屏幕与 WiFi 库 depcomp 编译期可能报 FS/WiFi/WebServer 与 TFT_eSPI 相互冲突 包含顺序固定:FS.hWiFi.hWebServer.h 在前,TFT_eSPI.h 在后
大批量数据上网页 200 个采样点 + 频率要每 300ms 传输 网页只请求一个 /api/wave,返回紧凑 JSON(字符串预留 reserve(1600)),JS 用 canvas 绘制

一、硬件系统部分

1.1 硬件清单

器件 型号/规格 用途
主控 ESP32 开发板 测频、ADC 采样、显示驱动、软 AP
扩展板 ESP32扩展板 方便接线
信号发生器 XR2206 函数信号发生器 被测信号源(输出方波/正弦/三角,可调频率、幅度)
显示 ST7789 240×240 SPI 彩屏 本地数据显示
分压 电阻分压 把 XR2206 输出幅度降到 0~3.3V 时序之内,保护 ESP32 模拟输入
连接 杜邦线 / 面包板 接线

1.2 接线方案

ESP32 引脚 作用 连接对象 代码宏
GPIO34 测频输入(方波) XR2206 方波输出 → 分压 → 此脚 PIN_FREQ_IN
GPIO35 真实 ADC 波形采样 XR2206 波形输出(任意波形)→ 分压 → 此脚 PIN_WAVE_ADC
GND 共地 XR2206、ESP32、屏幕、按键全部共地

⚠️ 分压电路横向:XR2206 输出幅度可能超过 3.3V,必须分压到 ≤3.3V 才能接 GPIO34/GPIO35,否则可能损坏 ESP32。

1.3 硬件连接图

1.4 实物连接图

二、软件架构设计

2.1 系统初始化(setup()

初始化顺序(ESP32_XR2206_Simple.ino setup())
├─ Serial.begin(115200)            启动串口调试
├─ counter.begin(34)               初始化 PCNT(硬件计数 + 滤波 + 清零)
├─ modeBtn.begin(27)               按键输入上拉
├─ display.begin()                 TFT 初始化 / 旋转 + ADC 设置(12bit,11dB) + 绘制数据界面骨架
└─ web.begin(&counter)             软 AP 模式 + 注册路由 + 启动 HTTP

要点:

  • ADC 配置集中display.begin() 里调用 analogReadResolution(12); analogSetAttenuation(ADC_11db); 后面所有 analogRead() 均为 12 位(0~4095),量程约 0~3.3V 的俾斯。
  • web 回调持指针web.begin(&counter) 传入频率计的指针,网页接口实时读取最新频率。

2.2 主循环逻辑(loop()

loop() 每一轮:
├─ counter.update()      // 搬计数 + 判断闸门结束 → 算频率
├─ web.update()          // 处理网页 HTTP 请求(异步轮询)
├─ modeBtn.update()      // 读取按键,检测短按事件
├─ 若短按 → mode 切换(MODE_DATA ↔ MODE_WAVE),forceRedraw=true
└─ 屏幕刷新调度:
     interval = (mode==WAVE) ? 50ms : 200ms
     若 forceRedraw 或超过 interval → display.render(模式, 频率, AP地址)
  • 刷新率按模式分:波形界面 50ms(快速更波形),数据界面 200ms(大数字不用太勤)。
  • 强制重绘:切换模式的按键瞬间除 lastMode 变化外,还用 forceRedraw 保证重新画一遍新界面的"骨架"。

三、代码拆分讲解

3.1 头文件(FreqMeter.h

配置宏接口集中,四个类对应四个功能模块:

#define PIN_FREQ_IN   34        // 测频输入
#define PIN_WAVE_ADC  35        // 波形 ADC
#define PIN_MODE_BTN  27        // 切换按键
#define WIFI_AP_SSID  "ESP32-XR2206"   // AP 名
#define WIFI_AP_PASS  "12345678"       // AP 密码
#define SCOPE_SAMPLES 200       // 波形采样点总数

类职责:

职责 关键成员
FreqCounter 闸门计数测频 gateLengthMs_(闸门时长)、accumCount_(累计脉冲)、freqHz_
ModeButton 短按检测 wasDown_/downMs_/shortEvent_
Display TFT 渲染 render(mode, hz, ip, forceRedraw)
WebUI 软 AP + HTTP begin(FreqCounter*) / ipString()

3.2 频率计(FreqCounter

初始化——配置 PCNT 单元 0:GPIO34 输入、仅上升沿计数(PCNT_COUNT_INC)、清零计数上下限 ±外层控制在 int16 范围,再加 100 个单位输入滤波:

cfg.pos_mode = PCNT_COUNT_INC;    // 上升沿 +1
cfg.neg_mode = PCNT_COUNT_DIS;    // 下降沿不计
cfg.counter_h_lim = 32767;        // 计数上限(防 int16 溢出)
pcnt_set_filter_value(PCNT_UNIT, 100);  // 滤除毛刺

闸门测频流程update())——本项目最核心的换算逻辑:

// 每 50ms 搬运一次计数,防止 16 位计数溢出
if (elapsed >= 50) accumCount_ += readAndClear();

// 闸门结束:频率 = 累计脉冲数 / 实际闸门时间
if (elapsed >= gateLengthMs_) {
    freqHz_ = accumCount_ * 1000.0f / elapsed;
    // 自适应闸门:计数<100 翻倍闸门;>1000 恢复 1s
    if (accumCount_ < 100 && gateLengthMs_ < 4000) gateLengthMs_ *= 2;
    else if (accumCount_ > 1000 && gateLengthMs_ > 1000) gateLengthMs_ = 1000;
    accumCount_ = 0;
    gateStartMs_ = now;
}

测出的是实际经过时间(elapsed 毫秒),用真实计数 ÷ 真实耗时,避免了闸门边界误差。

3.3 按键(ModeButton

上拉输入 + 边沿检测 + 时间窗判定:

if (down && !wasDown_) { downMs_ = now; }        // 按下瞬间记录时刻
else if (!down && wasDown_) {                     // 抬起
    if (now - downMs_ > 30 && now - downMs_ < 800)
        shortEvent_ = true;                       // 30ms~800ms = 短按
}
wasDown_ = down;

3.4 显示(Display

  • 数据界面:大号数字(6号字)+ 单位 + AP 地址 + 提示条。
  • 波形界面REAL ADC 标题、绘图区边框(x:20, y:55, 宽=采样点数, 高140)、垂直中线、底部频率与提示。

频率格式化 splitFreq()

≤0   → "---"
≥100kHz → 2 位小数 kHz      ≥1000Hz → 3 位小数 kHz
否则 → 1 位小数 Hz(原值)

3.5 采集与波形绘制(captureRealScope / drawRealScope)——核心难点处理

第一步:摸底找电平:连续读 64 次,找 min/max。

第二步:设定触发阈值mid = (min+max)/2,滞回宽 = 幅跨度/20(下限 15)。可适配带直流偏置的正弦/三角波(因为用的是相对中值,不是绝对 0V)。

第三步:等上升沿:波形先低于 mid-滞回,再穿过 mid+滞回 才启动采样(40ms 超时)。

第四步:按频率自适应采样间隔

if (hz  < 5)     return 500;    // 极低频 固定 500us
if (hz  > 20000) return 0;      // 超高频 连续采样
interval = 周期(μs) * 2 / 200;  // 目标窗口 = 2 个周期
clamp(0, 2000)                  // 最长 2000us

第五步:自动量程与削波检测:幅度跨度 <40 用全量程;否则上下留 1/12 边距。统计贴边样本(<80 和 >4015),两端都超 1/8 判为 削波 → 画红色 + 提示 CLIP!

坐标系换算(ADC 值 → 屏幕 Y):

y = SCOPE_Y + SCOPE_H - 1 - (v - lo) * (SCOPE_H - 2) / span;

lo/span 为自动量程后的下限与跨度,SCOPE_H-2 留 1 像素上下边界。)

3.6 网页模块(WebUI

  • 软 AP:WiFi.mode(WIFI_AP); WiFi.softAP(SSID, PASS);
  • 路由:/ 返回内嵌 HTML;/api/wave 与 /api/status 都返回 同一份 JSON(实测频率 + 200 个采样点)。
  • 网页 JS 每 300ms fetch('/api/wave'),canvas 画网格线 + 波形曲线。
{"measured":1000.5,"samples":[1234,1333,...,1024]}

四、操作过程及数据展示

4.1 操作步骤

  1. 接线:按 1.2 表格连接 XR2206、ESP32、按键、屏幕,确保共地。

  2. 烧录:零知派导入工程,选择 零知ESP32烧录,串口监视器 115200 波特率。

  3. 上电:屏幕先显示"数据界面";串口打印:

    ESP32-XR2206 meter + real ADC scope
    WiFi AP: ESP32-XR2206  http://192.168.4.1
    
  4. 手机端浏览:手机连接 WiFi ESP32-XR2206(密码 12345678),浏览器打开 192.168.4.1,即可看到网页频率与实时波形(每 300ms 刷新)。

  5. 切换界面:短按 GPIO27 按键,屏幕在 数据 ↔ 波形 间切换。

  6. 调节信号源:旋转 XR2206 频率/幅度旋钮,观测频率数字与波形变化。

4.2 数据展示

XRR2206 输出不同频率时的屏幕 / 网页显示效果(以实测为准):

输入设置 屏显数据 网页波形 闸门行为
低频(约 50 Hz) 50.0 Hz 完整几个周期 闸门自动加倍拉长至 1s/2/4s 提精度
中频(约 1 kHz) 1.000 kHz 2 个周期窗口 默认 1s 闸门,3 位小数
高频(约 10 kHz) 10.000 kHz 高频密集波 1s 闸门
超高频(>20 kHz) 100.320 kHz 连续采样,可能混叠 采样间隔=0,连续采集
幅度过大 数值不变,波顶/底贴边 波形上下削平 屏幕提示 CLIP!,波形变红

观察点:低频段数字末尾会因闸门变化"慢慢变稳定";幅度太大时屏幕右下角变红提示,此时应调小 XR2206 输出幅度。

4.3 演示视频

零知ESP32--XR2206波形监视器


五、技术原理

5.1 工作原理

频率测量 = 硬件计数 + 闸门时间法

  1. PCNT 硬件在 34 引脚每次上升沿 +1,不做软件轮询(省 CPU)。
  2. 软件每 50ms 搬运一次计数值到 32 位累加器,解决 16 位溢出。
  3. 闸门(默认 1s)结束后:频率 = 累计脉冲 ÷ 实际闸门毫秒 × 1000
  4. 自适应:统计过程中脉冲太少(<100 个)就加倍闸门,让计数更多 → 相对误差降低;脉冲过多(>1000 个)说明取样足够,闸门回到 1s 保持响应。

波形显示 = 真实 ADC 采样 + 软件触发 + 自动缩放

采样流程:
  摸底(min/max) → mid=(min+max)/2 → 滞回判定(跨中线) → 等上升沿 → 间隔采样×200点
绘制流程:
  清空区域 → 自动量程(留边距) → ADC值→屏幕Y映射 → 折线绘制 → 削波检测→红色
  • 触发保证波形稳定不滚屏;自动量程避免幅度小波形贴边;削波检测保护使用者了解幅度是否过载。
  • 采样率自适应:目标是在 200 个采样点里尽量铺满约 2 个周期;低频把采样拉长(塞多个周期),高频只能连续采(受 ADC 转换时间与主循环延时限制,高频可能混叠是正常现象)。

5.2 工作模式配置

软件模式

模式 枚举值 界面 刷新间隔
数据模式 MODE_DATA = 0 大字频率 + 单位 + AP IP 200ms
波形模式 MODE_WAVE = 1 标题 + 示波器波形 + 频率 50ms

切换:GPIO27 短按(30~800ms)在两者间翻转;长按 >800ms 不计。

硬件参数配置(改宏即可适配不同板子 / 接线):

默认 作用
PIN_FREQ_IN 34 测频输入脚(须为 PCNT 可接的引脚)
PIN_WAVE_ADC 35 ADC 采样脚(GPIO32-39 等 ADC1 允许,内部 µF 电压范围允许)
PIN_MODE_BTN 27 按键脚(输入上拉)
WIFI_AP_SSID/PASS ESP32-XR2206 / 12345678 软 AP 凭据
SCOPE_SAMPLES 200 波形点数(与绘图区宽度一致)
ADC 分辨率 12bit analogReadResolution(12)
ADC 倍率 11dB analogSetAttenuation(ADC_11db),量程约 0~3.3V

PCNT 选择注意:GPIO34/35 为模拟 ADC 通道(不可用于 PCNT?实际上 34/35 是纯输入脚,可用于 PCNT;而 GPIO27 不能重复用于 PCNT 而同时被 ADC 使用等)。若换脚,须查阅 ESP32 PC NT 引脚表确保该 GPIO 支持 PCNT 通道。


六、常见问题指引

现象 可能原因 解决办法
频率一直为 0 / 不变 方波没接对 / 分压太弱 / 输入脚不对 检查 GPIO34 接入、分压、接地;串口观察
频率跳变严重 滤波太弱 / 没共地 / 共模噪声 检查接线电感;滤波值已开 100;确认 XR2206 GND 与 ESP826 共地
屏幕波形残影/跳 触发没生效 排查贡献:检查信号幅度、滞回配合;触顶时间 40ms 超时则等不到波形
屏幕显示 CLIP! 输入幅度过大 / 削波 调小 XR2206 输出幅度(或重新分压)
高频波形紊乱/混叠 采样率低于奈奎斯特 属正常高频现象,可观察频率值;网页提示"高频可能混叠"
网页打不开 手机没连热点 / IP 错 / 密码错 连 ESP32-XR2206,密码 12345678,浏览 http://192.168.4.1;串口看 AP 是否启动
屏幕白屏/花屏 ST7789 SPI 接线或 User_Setup.h 引脚配置不符 核对 SCL/SDA/RES/DC/CS 与 User_Setup.h;检查供电电流
按键没反应 接线 / 按压时间窗口 确认接住 GPIO27 与 GND;按 30~800ms
低频精度不足 数据太少 等闸门自适应至 4s(此时数据更新慢但更准)
.ino 编译报 TFT_eSPI 冲突 库包含顺序 保持 FS.h/WiFi.h/WebServer.h 在 TFT_eSPI.h 之前
Logo

智能硬件社区聚焦AI智能硬件技术生态,汇聚嵌入式AI、物联网硬件开发者,打造交流分享平台,同步全国赛事资讯、开展 OPC 核心人才招募,助力技术落地与开发者成长。

更多推荐