📦 产品概述
ESP32 多功能波形发生器是一款基于 ESP32 开发板实现的 DDS 信号发生器。 支持通过 WiFi 网页 或 串口命令 两种方式进行控制, 可输出正弦波、三角波、方波、锯齿波四种波形,并支持频率、幅度以及方波占空比的实时调节。
主要特性
🔌 硬件说明
引脚连接
| ESP32 引脚 | 功能 | 说明 |
|---|---|---|
| GPIO25 | 波形输出 | DAC1 模拟输出,连接示波器或负载 |
| GND | 地线 | 与测量设备共地 |
| USB | 供电 + 串口 | 5V 供电,同时用于串口通信 |
硬件连接图
GPIO25 为 DAC 输出,不要连接到超过 3.3V 的电压。
输出阻抗较高,驱动能力弱,建议接高阻抗负载(>10kΩ)。
如需驱动低阻抗负载,建议添加运放缓冲电路。
🚀 首次使用
-
上传程序(默认已烧录)
打开 Arduino IDE → Tools → Board → ESP32 Dev Module → Tools → Port → 你的 COM 口 → 点击上传按钮。 -
WiFi 配置 —— 上传完成后打开串口监视器(115200 波特率),将看到:
=== ESP32 Waveform Generator === Serial commands: reset, restart, status, help ✓ Timer: 100kHz --- WiFi Initialization --- No saved config found ========================================== WiFi Configuration Mode ========================================== Enter SSID:依次输入 WiFi 信息(不同 IDE 输入方式或有不同,Arduino IDE 是输入完直接回车):Enter SSID: ChinaNet-home ← 输入你的 WiFi 名称 Enter Password: 12345678 ← 输入密码 ✓ Config saved to EEPROM ← 自动保存即使输错也没关系,连接不上会再次提示输入。Connecting to ChinaNet-home......... ✓ WiFi connected! IP: 192.168.1.100 ✓ Web server started → Open http://192.168.1.100
-
访问网页 —— 在浏览器地址栏输入串口显示的 IP 地址(如
http://192.168.1.100),即可打开控制界面。⚠ 你获得的 IP 不一定是上面这个,请以串口实际显示的 IP 为准。
🌐 Web 控制界面
控制项说明
| 控制项 | 类型 | 范围 | 说明 |
|---|---|---|---|
| 波形选择 | 下拉菜单 | 正弦 / 三角 / 方波 / 锯齿 | 实时切换波形类型 |
| 占空比 | 滑杆 + 输入框 | 0 ~ 100% | 仅方波时显示,调节高电平占比 |
| 频率 | 滑杆 + 输入框 | 1 ~ 5000 Hz | 输出信号频率 |
| 幅度 | 滑杆 + 输入框 | 0 ~ 255 | 输出电压(0 = 0V,255 = 3.3V) |
| 开始 | 按钮 | — | 启动波形输出 |
| 停止 | 按钮 | — | 停止输出(输出 0V) |
拖动滑杆 → 数字输入框同步更新
直接在数字框输入 → 滑杆同步移动
支持精确数值设定
⌨ 串口命令
打开串口监视器(115200 波特率),输入以下命令后回车:
命令列表
| 命令 | 功能 | 说明 |
|---|---|---|
help | 显示帮助 | 列出所有可用命令 |
status | 显示系统状态 | 显示 WiFi 和波形参数 |
reset | 清除 WiFi 配置 | 清除后需要重启设备 |
restart | 重启 ESP32 | 设备重新启动 |
命令示例
1. 查看状态
2. 清除 WiFi 配置(更换网络时使用)
3. 重启设备
4. 帮助
⚙ DDS 原理与实现
什么是 DDS
DDS(Direct Digital Synthesis,直接数字频率合成)是一种 从单个固定频率的参考时钟生成任意波形的全数字技术。与传统的模拟振荡器(如 VCO、PLL)不同, DDS 通过数字累加和查表的方式合成波形,具有以下显著优势:
核心原理
DDS 的核心由三个部分构成:N 位相位累加器、波表(Wave Table / LUT)和 DAC(数模转换器)。
(FTW / phaseInc)
(phaseAcc, 32bit)
每个时钟: += phaseInc
(512 点)
(8-bit)
每个采样时钟周期,相位累加器加上一个固定的增量(频率字 phaseInc), 累加器的高位作为地址去波表中查值,查到的波形数据送给 DAC 输出。当累加器溢出时自然回到零, 实现循环输出,保证相邻周期的相位连续。
频率计算公式
设采样率为 Fs,累加器位宽为 N,目标频率为 Fout,则相位增量(频率字)为:
本项目参数代入:
| 参数 | 符号 | 值 |
|---|---|---|
| 采样率 | Fs | 100,000 Hz(100 kHz) |
| 累加器位宽 | N | 32 bit |
| 波表长度 | M | 512 点 |
| 频率字计算 | phaseInc | targetFreq × 232 ÷ 100000 |
| 理论频率分辨率 | ΔF | Fs ÷ 2N = 100000 ÷ 4294967296 ≈ 0.000023 Hz |
本项目的 DDS 实现
① 波表预生成(generateWaveTable())
启动时在 SRAM 中生成一个 512 点的 uint8_t waveTable[512],每个点对应
一个 DAC 输出值(0 ~ 255)。
- 正弦波:通过
sin(2π × t)计算,范围 [-1, +1] 映射到 [0, 255] - 三角波:分段线性函数——0→25% 上升,25%→75% 下降,75%→100% 上升
- 方波:根据占空比阈值判定,前半周期输出最大值,后半周期输出最小值
- 锯齿波:线性递增
y = 2t - 1
波表在波形类型、幅度或占空比变化时重新生成。
② 相位累加器(phaseAcc)
32 位无符号整数 volatile uint32_t phaseAcc,每个定时器中断自动累加
phaseInc。累加器 自然溢出 即为一个完整周期的结束,
溢出后从 0 继续累加,保证相邻周期的相位连续,无需任何软件干预。
③ 查表输出(onTimer() ISR)
定时器中断以 100 kHz 的频率触发,在 ISR(中断服务程序)中执行的步骤:
void IRAM_ATTR onTimer() {
if (waveformRunning) {
dacWrite(25, waveTable[phaseAcc >> 23]); // 查表 + DAC 输出
phaseAcc += phaseInc; // 累加相位
}
}
phaseAcc >> 23 右移 23 位(32 - 9 = 23),
取 32 位累加器的高 9 位作为 512 点波表的索引地址(29 = 512)。
查表值直接写入 ESP32 的 8 位 DAC(GPIO25)。
④ 频率更新(updatePhaseIncrement())
void updatePhaseIncrement() {
uint64_t inc = (uint64_t)targetFreq * (1ULL << 32) / SAMPLE_RATE;
phaseInc = (uint32_t)inc;
}
使用 64 位中间变量避免乘法溢出。由于 phaseInc 的变化只影响后续的
累加步进,而不会重置相位累加器,因此频率切换时波形相位是连续的,不会产生跳变或毛刺。
关键代码映射
| 代码位置 | 对应 DDS 部件 | 说明 |
|---|---|---|
#define SAMPLE_RATE | 采样时钟频率 | 100 kHz |
#define WAVE_TABLE_SIZE | 波表大小 | 512 点 |
waveTable[512] | 查找表 (LUT) | 存储预计算波形值 |
phaseAcc | 相位累加器 | 32-bit,溢出自动回绕 |
phaseInc | 频率字 / 相位增量 | 控制输出频率 |
onTimer() | 采样输出 ISR | 每个中断输出一个 DAC 值 |
phaseAcc >> 23 | 波表地址生成 | 取高 9 位寻址 512 点波表 |
updatePhaseIncrement() | 频率调谐字计算 | 公式: freq × 2³² ÷ Fs |
generateWaveTable() | 波表重构 | 波形/幅度/占空比变化时调用 |
为什么选择 32 位累加器?
为什么选择 512 点波表?
DDS 信号流程图
按需重建 512 点波表
频率 → 相位增量换算
📊 技术参数
电学参数
| 参数 | 值 | 说明 |
|---|---|---|
| 供电电压 | 5V (USB) | 通过 USB 口供电 |
| 输出电压 | 0 ~ 3.3V | 8 位 DAC 分辨率 |
| 输出阻抗 | ≈ 5 kΩ | 建议负载 > 10 kΩ |
| 输出频率 | 1 Hz ~ 5 kHz | 100 kHz 采样率 |
| 频率分辨率 | ≈ 0.000023 Hz | 32 位 DDS 累加器 |
| 输出引脚 | GPIO25 | DAC1 通道 |
波形参数
| 波形 | 特征 | 占空比可调 |
|---|---|---|
| 正弦波 | 平滑、低失真 | ❌ |
| 三角波 | 线性上升 / 线性下降 | ❌ |
| 方波 | 快速电平跳变 | ✅(0% ~ 100%) |
| 锯齿波 | 缓慢上升、快速下降 | ❌ |
采样精度
| 参数 | 值 |
|---|---|
| DAC 分辨率 | 8-bit(256 级) |
| 采样率 | 100 kHz |
| 波表点数 | 512 点 |
| 5 kHz 每周期点数 | 20 点 |
| 1 kHz 每周期点数 | 100 点 |
| 50 Hz 每周期点数 | 2000 点 |
🔧 故障排除
问题 1:没有波形输出
| 可能原因 | 解决方法 |
|---|---|
| GPIO25 未连接 | 检查杜邦线连接是否牢固 |
| GND 未共地 | 确保示波器 / 负载与 ESP32 共地 |
| 波形未开始 | 点击网页"开始"按钮启动输出 |
| 幅度为 0 | 调节幅度滑杆到 > 0 |
问题 2:WiFi 连接失败
使用
reset 命令清除配置后重新配置。确保 WiFi 是 2.4 GHz 频段(ESP32 不支持 5 GHz WiFi)。
检查路由器是否开启了 MAC 地址过滤。
问题 3:网页无法访问
电脑和 ESP32 必须在同一局域网内。
尝试
ping <ESP32-IP> 测试连通性。临时关闭 Windows 防火墙进行测试。
问题 4:波形有毛刺 / 不光滑
降低幅度(避免 DAC 非线性区)。
检查电源纹波,建议使用质量较好的 USB 供电。
问题 5:方波占空比不正确
占空比滑块仅在方波时显示。调节后波形会重新生成。
常用命令速查
🌐 网页操作
| 操作 | 说明 |
|---|---|
| 浏览器打开 IP | 访问控制界面 |
| 选择波形 | 切换正弦/三角/方波/锯齿 |
| 拖动滑杆 | 调节频率/幅度/占空比 |
| 点击开始 | 启动波形输出 |
| 点击停止 | 停止输出 |
⌨ 串口命令
| 命令 | 用途 |
|---|---|
help | 显示帮助 |
status | 查看状态 |
reset | 清除 WiFi 配置 |
restart | 重启设备 |