1. 项目概述:将ESP32改造成基于网页的示波器
Bojan Jurca开发的Esp32_oscilloscope项目,是一个能将普通ESP32开发板变身成网络示波器的开源固件。这个方案最吸引人的地方在于,它完全基于Arduino生态,通过WiFi连接就能在浏览器中查看波形,摆脱了专业示波器笨重且昂贵的限制。
我在实际测试中发现,这个方案特别适合电子爱好者进行基础电路调试。它支持ESP32全系列芯片(包括ESP32-S2/S3/C3),能同时处理数字信号(0/1)和模拟信号(0-4095)。虽然每屏只能显示736个采样点,但对于大多数低频应用场景已经足够。相比我之前用过的Scoppy方案(基于树莓派Pico W),ESP32更强的处理能力让波形刷新更加流畅。
提示:这个项目最初是为了展示ESP32在Arduino环境下的多任务处理能力,后来才发展成完整的示波器方案。理解这个背景很重要,因为它解释了为什么固件中会有一些特殊的实现方式。
2. 硬件准备与工作原理
2.1 所需硬件清单
要复现这个项目,你需要准备以下硬件:
- 任意型号ESP32开发板(推荐ESP32-S3,因其ADC性能更优)
- 微型USB数据线(用于供电和烧录)
- 待测电路或信号源(电压请勿超过3.3V)
- 可选:分压电路(用于测量高于3.3V的信号)
2.2 核心工作原理解析
这个示波器的核心在于ESP32的I2S接口和WiFi功能的巧妙结合:
信号采集层:利用I2S接口的高速特性,以最高可达1MHz的速率采样GPIO状态。对于模拟信号,则通过内置ADC转换(12位精度,0-4095)。
数据处理层:采样数据通过双缓冲机制暂存,一个缓冲区用于采集时,另一个缓冲区通过网络发送,实现了采集和传输的并行处理。
网络传输层:内置Web服务器通过WiFi发送数据到浏览器,采用轻量级的HTTP协议而不是WebSocket,这是为了兼容性考虑。
可视化层:浏览器中的JavaScript解析收到的数据,使用Canvas API实时绘制波形。项目自带的oscilloscope.html文件包含了完整的绘图逻辑。
// 关键代码片段:I2S配置 i2s_config_t i2s_config = { .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX), .sample_rate = 1000000, // 1MHz采样率 .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT, .communication_format = I2S_COMM_FORMAT_STAND_I2S, .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1, .dma_buf_count = 8, .dma_buf_len = 1024 };3. 固件烧录与配置详解
3.1 开发环境搭建
安装最新版Arduino IDE(建议2.3.2以上)
添加ESP32开发板支持:
- 文件→首选项→附加开发板管理器网址中添加:
https://raw.githubusercontent.com/espressif/arduino-esp32/gh-pages/package_esp32_index.json - 工具→开发板→开发板管理器→搜索安装"esp32"
- 文件→首选项→附加开发板管理器网址中添加:
安装必要库:
- WebServer库(内置)
- WiFi库(内置)
- FS库(内置)
- I2S库(内置)
3.2 关键配置修改
在项目的config.h文件中,必须修改以下参数:
// 网络配置 - 必须修改 #define DEFAULT_STA_SSID "你的WiFi名称" // 最大32字符 #define DEFAULT_STA_PASSWORD "你的WiFi密码" // 最大64字符 #define HOSTNAME "MyScope" // 设备主机名,用于mDNS访问 // 文件系统选择(根据硬件决定) #define FILE_SYSTEM FILE_SYSTEM_FAT // 有外部Flash的板子 // #define FILE_SYSTEM FILE_SYSTEM_PROGMEM // 无外部Flash的板子重要提示:如果使用PROGMEM模式,需要提前将oscilloscope.html文件转换为C数组格式。项目提供了转换脚本html_to_c.html,用浏览器打开即可完成转换。
3.3 分区方案选择
根据不同的ESP32型号,需要选择正确的分区方案:
对于ESP32-WROOM系列:
- 工具→Partition Scheme→"Default 4MB with spiffs (1.2MB APP/1.5MB SPIFFS)"
对于ESP32-S3系列:
- 工具→Partition Scheme→"16MB FAT (12MB APP/4MB FAT)"
对于ESP32-C3系列:
- 工具→Partition Scheme→"2MB FAT (1MB APP/1MB FAT)"
4. 文件系统部署实战
4.1 文件上传方法
项目需要部署三个关键文件到ESP32的文件系统:
- oscilloscope.html(主界面)
- android-192-osc.png(Android图标)
- apple-180-osc.png(iOS图标)
对于有外部Flash的板子,推荐使用以下任一方法上传:
方法一:通过Arduino IDE上传
- 安装ESP32FS插件(从GitHub下载)
- 将文件放入项目目录下的data文件夹
- 工具→ESP32 Sketch Data Upload
方法二:通过Web界面上传
- 访问http://esp32-ip/upload
- 使用网页表单直接上传文件
4.2 文件系统性能优化
在实际使用中,我发现文件系统配置会显著影响性能:
簇大小设置:
- 对于小文件(<10KB),建议使用512字节簇
- 修改方法:在fatfs_config.h中设置
#define CONFIG_FATFS_SECTORSIZE 512
缓存策略:
- 增加文件缓存可以提升网页加载速度
- 在webserver.cpp中修改:
#define HTTP_CACHE_SIZE 2048 // 默认512,建议调整为2048
内存分配:
- 如果遇到内存不足,可以调整堆大小:
#define I2S_DMA_BUF_SIZE 1024 // 默认2048,内存紧张时可减半
- 如果遇到内存不足,可以调整堆大小:
5. 高级使用技巧与性能调优
5.1 采样率与精度平衡
ESP32的ADC在高速采样时精度会下降,这是硬件限制。通过实测,我总结出以下最佳实践:
| 采样率 | 有效位数 | 适用场景 |
|---|---|---|
| 1MHz | 6-7位 | 数字信号捕获 |
| 500kHz | 8位 | 方波/脉冲测量 |
| 100kHz | 10位 | 音频信号分析 |
| 10kHz | 12位 | 精密电压测量 |
要修改采样率,编辑i2s_oscilloscope.cpp中的:
const uint32_t SAMPLE_RATE = 100000; // 单位Hz5.2 多通道测量技巧
虽然项目默认只使用一个ADC通道,但ESP32实际上支持多路复用。通过修改代码可以实现:
在setup()中添加:
adc1_config_width(ADC_WIDTH_BIT_12); adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11); adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11);在采样循环中交替读取:
int val1 = adc1_get_raw(ADC1_CHANNEL_0); int val2 = adc1_get_raw(ADC1_CHANNEL_3);
5.3 网页界面定制
oscilloscope.html文件支持深度定制:
修改波形颜色:
ctx.strokeStyle = "#FF0000"; // 改为红色波形添加测量标尺:
function drawGrid() { // 在draw()函数中添加网格绘制逻辑 ctx.strokeStyle = "#AAAAAA"; ctx.lineWidth = 0.5; // 绘制垂直网格... }增加触发功能:
let triggerLevel = 2048; // 中值触发 let triggerEnabled = true;
6. 常见问题与解决方案
6.1 连接问题排查
现象:无法连接到WiFi
- 检查SSID/密码是否正确(注意大小写)
- 尝试将WiFi频段锁定为2.4GHz(ESP32不支持5GHz)
- 修改代码增加调试输出:
WiFi.onEvent([](WiFiEvent_t event) { Serial.printf("[WiFi] Event: %d\n", event); });
现象:网页无法加载
- 检查文件系统是否成功上传
- 尝试访问http://esp32-ip/ 查看基本页面是否正常
- 清除浏览器缓存后重试
6.2 信号测量异常
现象:波形抖动严重
- 确保ESP32接地良好
- 在信号输入端添加0.1uF电容滤波
- 降低采样率以提高稳定性
现象:ADC读数不准确
- 在代码中启用ADC校准:
esp_adc_cal_characterize(ADC_UNIT_1, ADC_ATTEN_DB_11, ADC_WIDTH_BIT_12, 1100, &adc_chars); - 避免在WiFi传输时进行高精度测量(射频干扰)
6.3 性能优化技巧
内存不足:
- 减少DMA缓冲区数量(i2s_config.dma_buf_count)
- 禁用不必要的功能(如mDNS)
WiFi延迟:
- 将ESP32尽量靠近路由器
- 修改WiFi模式为WIFI_MODE_STA(仅站模式)
- 设置WiFi信道固定值(避免自动切换)
采样丢失:
- 增加双缓冲区大小
- 优化网络传输间隔(默认100ms可调整为200ms)
7. 项目扩展与进阶应用
7.1 外置ADC扩展
对于需要更高精度的场景,可以接入外置ADC(如ADS1115):
硬件连接:
- ADS1115的SCL→ESP32 GPIO22
- ADS1115的SDA→ESP32 GPIO21
- VDD→3.3V
代码修改:
#include <Adafruit_ADS1X15.h> Adafruit_ADS1115 ads; void setup() { ads.begin(); ads.setGain(GAIN_ONE); // ±4.096V }
7.2 数据记录功能
添加SD卡模块可实现长时间波形记录:
安装SD库:
#include <SD.h> #define SD_CS 5在采样循环中添加:
File dataFile = SD.open("/datalog.csv", FILE_APPEND); dataFile.printf("%lu,%d\n", millis(), adcValue); dataFile.close();
7.3 远程访问配置
通过端口转发实现互联网访问(需路由器支持):
在路由器设置端口转发:
- 外部端口:8080→内部IP:80
配置DDNS服务(如No-IP):
#define USE_DDNS true #define DDNS_SERVER "dynupdate.no-ip.com" #define DDNS_HOSTNAME "yourscope.ddns.net"安全建议:
- 添加HTTP基本认证
- 限制访问IP范围
- 启用HTTPS(需额外证书)
我在实际项目中发现,这个ESP32示波器最实用的场景是教育领域和学生实验。相比商业示波器,它的成本几乎可以忽略不计,而且通过网络访问的特性让多人协作观察成为可能。一个特别有用的技巧是:当测量高频噪声时,可以临时关闭WiFi的自动休眠功能(WiFi.setSleep(false)),这能显著降低底噪。