跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
C++大前端算法

基于 ESP32 的 ADS1115 多通道数据采集与 Web 监控系统

基于 ESP32 与 ADS1115 构建多通道数据采集系统,支持单端及差分电压测量。通过 Web 服务器实现数据实时传输与 Chart.js 可视化展示。详解硬件接线、I2C 通信协议、寄存器配置及代码逻辑,并提供常见问题排查指南。重点解决差分模式下寄存器配置切换问题,结合 Chart.js 实现波形可视化。涵盖硬件接线、代码逻辑、I2C 协议及常见问题排查。

草莓泡芙发布于 2026/4/7更新于 2026/5/2114 浏览
基于 ESP32 的 ADS1115 多通道数据采集与 Web 监控系统

基于 ESP32 的 ADS1115 多通道数据采集系统

本项目基于 ESP32-WROOM-32 主控板,结合 TI ADS1115 16 位高精度 ADC 模数转换器,实现了一个功能完整的多通道数据采集与 Web 监控系统。系统不仅支持传统的 4 通道单端电压测量,更实现了 A0-A1 差分电压测量功能,并通过现代化的 Web 界面实时展示数据变化趋势。

项目难点及解决方案

问题描述: 在单次转换模式下,每次测量都需要重新配置 MUX 通道选择寄存器。频繁切换差分和单端模式可能导致数据读取错误。

解决方案: 采集流程中先读取差分数据、再读取单端数据,每次读取前库自动完成寄存器重新配置,避免手动操作寄存器的出错。

一、系统接线部分

1.1 硬件清单

组件型号/规格数量备注
主控板ESP32-WROOM-321核心控制器
ADC 模块ADS1115 16 位1高精度模数转换
杜邦线公对公若干连接线
电位器10kΩ2模拟信号源
电源5V/2A1供电

1.2 接线方案表

根据代码设计,接线配置如下:

ESP32 引脚ADS1115 引脚连接说明备注
GPIO21SDAI2C 数据线模块内置上拉电阻
GPIO22SCLI2C 时钟线模块内置上拉电阻
3.3VVDD电源正极电源 5V 供电,避免模块损坏
GNDGND电源地共地很重要
电位器 1AIN0通道 0 输入差分正输入端
电位器 2AIN1通道 1 输入差分负输入端
GNDAIN2通道 2 输入单端测量
-AIN3通道 3 输入单端测量

注意:GAIN_ONE 模式输入电压必须在±4.096V 范围内

1.3 接线示意图

![图片]

PS:旋转电位器和 ADS1115 ADC 模块都采用系统 3.3V 供电

1.4 实物连接图

![图片]

二、安装与使用部分

2.1 导入代码

在开发环境中搜索并下载项目代码。

![图片]

2.2 连接与上传

连接设备后验证端口并上传固件。

![图片]

2.3 调试串口监视器

打开串口监视器查看日志输出。

![图片]

三、代码讲解部分

代码文件结构

主程序文件,实现 WiFi 连接、ADS1115 数据采集、WebServer 搭建;头文件,存储 Web 页面的 HTML/CSS/JavaScript 代码。

3.1 初始化配置

// 增益设置:GAIN_ONE (+/- 4.096V) // 1 bit = 0.125mV 
const float multiplier = 0.000125; 
void setup() { 
    Serial.begin(115200); 
    // 1. 初始化 ADS1115 
    if (!ads.begin()) { 
        Serial.println("无法初始化 ADS1115,请检查连线!"); 
        while (1); 
    } 
    // 设置增益以匹配 3.3V 系统,同时保留一定的余量 
    ads.setGain(GAIN_ONE); 
    // 2. 连接 WiFi 
    WiFi.begin(ssid, password); 
    Serial.print("正在连接 WiFi"); 
    while (WiFi.status() != WL_CONNECTED) { 
        delay(500); 
        Serial.print("."); 
    } 
    Serial.println("\nWiFi 已连接"); 
    Serial.print("访问地址:http://"); 
    Serial.println(WiFi.localIP()); 
    // 3. 配置 Web 服务器路由 
    // 首页 
    server.on("/", HTTP_GET, []() { 
        server.send_P(200, "text/html", index_html); 
    }); 
    // API 接口:返回 JSON 数据 
    server.on("/data", HTTP_GET, []() { 
        String json = "{"; 
        json += "\"diff_raw\":" + String(raw_diff) + ","; 
        json += "\"diff_v\":" + String(volt_diff, 4) + ","; 
        json += "\"v0\":" + String(volt_a0, 4) + ","; 
        json += "\"v1\":" + String(volt_a1, 4) + ","; 
        json += "\"v2\":" + String(volt_a2, 4); 
        json += "}"; 
        server.send(200, "application/json", json); 
    }); 
    server.begin(); 
    Serial.println("HTTP 服务器已启动"); 
}

GAIN_ONE 增益倍数 1,满量程±4.096V;multiplier 每个 LSB 对应的电压值(0.125mV)

3.2 多模式数据采集

// --- 变量存储 --- 
int16_t raw_diff; // 差分原始值 
int16_t raw_a0, raw_a1, raw_a2; // 单端原始值 
float volt_diff, volt_a0, volt_a1, volt_a2; // 转换后的电压值 
void loop() { 
    server.handleClient(); 
    // --- 关键步骤:切换模式读取数据 --- 
    // 注意:频繁切换配置寄存器会消耗一点时间,但为了同时显示单端和差分是必须的。 
    // 1. 读取 A0-A1 差分值 (Differential) 
    // 如果 A0 > A1,值为正;如果 A1 > A0,值为负 
    raw_diff = ads.readADC_Differential_0_1(); 
    volt_diff = raw_diff * multiplier; 
    // 2. 读取单端值 (Single Ended) 用于参考 
    raw_a0 = ads.readADC_SingleEnded(0); 
    volt_a0 = raw_a0 * multiplier; 
    raw_a1 = ads.readADC_SingleEnded(1); 
    volt_a1 = raw_a1 * multiplier; 
    raw_a2 = ads.readADC_SingleEnded(2); // 备用通道 
    volt_a2 = raw_a2 * multiplier; 
    // 简单的串口调试 (可选) 
    // Serial.printf("Diff: %.4f V, A0: %.4f V, A1: %.4f V\n", volt_diff, volt_a0, volt_a1); 
    delay(5); // 短暂延时,避免 CPU 过载 
}

测量 AIN0 和 AIN1 之间的电压差、结果可正可负,代表相对极性、差分模式能抑制共模噪声,提高测量精度。

3.3 Web 数据接口

// --- 全局对象 --- 
WebServer server(80); 
// 3. 配置 Web 服务器路由 
// 首页 
server.on("/", HTTP_GET, []() { 
    server.send_P(200, "text/html", index_html); 
}); 
// API 接口:返回 JSON 数据 
server.on("/data", HTTP_GET, []() { 
    String json = "{"; 
    json += "\"diff_raw\":" + String(raw_diff) + ","; 
    json += "\"diff_v\":" + String(volt_diff, 4) + ","; 
    json += "\"v0\":" + String(volt_a0, 4) + ","; 
    json += "\"v1\":" + String(volt_a1, 4) + ","; 
    json += "\"v2\":" + String(volt_a2, 4); 
    json += "}"; 
    server.send(200, "application/json", json); 
}); 
server.begin();

使用 JSON 格式便于前端解析、保留 4 位小数确保精度同时提供原始值和计算值。

3.4 前端数据可视化

<script> 
// --- Chart.js 初始化配置 --- 
const ctx = document.getElementById('voltageChart').getContext('2d'); 
// 创建渐变填充 
let gradient = ctx.createLinearGradient(0, 0, 0, 400); 
gradient.addColorStop(0, 'rgba(102, 252, 241, 0.4)'); // 顶部颜色 
gradient.addColorStop(1, 'rgba(102, 252, 241, 0)'); // 底部透明 
const voltageChart = new Chart(ctx, { 
    type: 'line', 
    data: { 
        labels: [], // 时间轴标签 
        datasets: [{ 
            label: 'Differential Voltage (A0 - A1)', 
            data: [], 
            borderColor: '#66fcf1', 
            backgroundColor: gradient, 
            borderWidth: 2, 
            pointRadius: 0, // 隐藏数据点,使线条更平滑 
            fill: true, 
            tension: 0.4 // 曲线平滑度 
        }] 
    }, 
    options: { 
        responsive: true, 
        maintainAspectRatio: false, 
        scales: { 
            x: { display: false }, // 隐藏 X 轴标签保持简洁 
            y: { 
                grid: { color: '#333' }, 
                ticks: { color: '#888' }, 
                suggestedMin: -4.0, 
                suggestedMax: 4.0 
            } 
        }, 
        plugins: { 
            legend: { 
                labels: { color: '#c5c6c7' } 
            } 
        }, 
        animation: false // 禁用动画以提高实时性能 
    } 
}); 
// --- 数据获取与更新逻辑 --- 
const maxDataPoints = 100; // 图表保留的数据点数量 
function updateDashboard() { 
    fetch('/data') 
    .then(response => response.json()) 
    .then(data => { 
        // 1. 更新卡片数值 
        document.getElementById('valDiff').innerText = data.diff_v.toFixed(4); 
        document.getElementById('val0').innerText = data.v0.toFixed(4); 
        document.getElementById('val1').innerText = data.v1.toFixed(4); 
        document.getElementById('val2').innerText = data.v2.toFixed(4); 
        // 2. 更新图表 
        // 获取当前时间戳作为简单的标签 
        const now = new Date().toLocaleTimeString(); 
        // 添加新数据 
        voltageChart.data.labels.push(now); 
        voltageChart.data.datasets[0].data.push(data.diff_v); 
        // 如果数据点过多,移除最早的数据 
        if (voltageChart.data.labels.length > maxDataPoints) { 
            voltageChart.data.labels.shift(); 
            voltageChart.data.datasets[0].data.shift(); 
        } 
        voltageChart.update(); 
    }) 
    .catch(error => console.error('Error:', error)); 
} 
// 设置刷新频率 (100ms = 10Hz 刷新率) 
setInterval(updateDashboard, 100); 
</script>

系统流程图

![图片]

差分测量模式深度解析

// 读取 A0-A1 差分原始值,底层自动配置寄存器 
raw_diff = ads.readADC_Differential_0_1(); 
// 转换为实际电压(有符号,支持正负电位差) 
volt_diff = raw_diff * multiplier;

ADS1115 的差分测量是将两个输入引脚(A0/A1)的电位差作为输入信号,而非相对于 GND 的单端信号,核心优势是抑制共模干扰。

差分测量原理图

当 A0 电压 > A1 电压时,raw_diff为正,volt_diff为正;当 A0 电压 < A1 电压时,raw_diff为负,volt_diff为负。

![图片]

差分量程与增益配置一致(GAIN_ONE 对应 ±4.096V),即 A0-A1 的电位差范围为 -4.096V~+4.096V。

四、项目结果演示

4.1 操作流程

按照接线方案表完成 ESP32 与 ADS1115 的连接,A0/A1 接电位器(模拟差分信号),A2 接备用传感器,修改主程序 SSID 和 PASSWORD 为实际 WiFi 路由信息。

上电运行

给 ESP32 上电,打开串口监视器,设置波特率为 115200,等待 WiFi 连接成功,记录打印的'访问地址',如 http://192.168.x.x。

![图片]

数据查看

打开电脑 / 手机浏览器,输入上述访问地址,即可看到实时电压数值和差分电压波形。

信号调试

调节电位器,观察 A0/A1 电压变化,以及差分电压的实时波形变化。

![图片]

4.2 视频演示

ESP32+ADS1115 多通道采集:差分电压实时波形可视化

完整演示 ESP32 驱动 ADS1115 的多通道单端 / 差分采集流程,包含代码烧录、代码修改、WiFi 连接、Web 可视化全流程,直观展示差分电压随输入信号变化的实时波形,以及各通道电压的高精度显示效果。

五、ADS1115 技术讲解

ADS1115 具有一个输入多路复用器 (MUX),可实现双路差分输入或四路单端输入测量。兼容 I2C 的 16 位低功耗精密模数转换器 (ADC)。

![图片]

Multiplexer 复用器

![图片]

ADS1115 包含两个差分输入,AIN0 和 AIN1 可以与 AIN3 进行差分测量,多路复用器由配置寄存器中的位 MUX [2:0] 配置。

5.1 寄存器配置

ADS1115 有 4 个寄存器,本项目核心用到配置寄存器(0x01)和转换寄存器(0x00)。

转换寄存器(0x00)

![图片]

存储 ADC 转换后有符号的原始值,ESP32 读取该寄存器值后,乘以转换系数即可得到实际电压。

配置寄存器(0x01)[15:0]

![图片]

16 位配置寄存器用于控制工作模式、输入选择、数据速率、满量程范围和比较器模式。

① MUX 位详解(输入选择):

![图片]

本项目设置 MUX[2:0] 位为 000,使用差分通道 AIN0 和 AIN1。

② PGA 位详解(增益设置):

![图片]

本项目设置 PGA[2:0] 位为 001,采用 GAIN_ONE 增益。

5.2 I2C 通信协议

① I2C 地址选择

ADS1115 有一个地址引脚 ADDR,用于配置器件的 I2C 地址。该引脚可连接至 GND、VDD、SDA 或 SCL,通过一个引脚即可选择四种不同的地址。

![图片]

② 向寄存器写入数据

要访问 ADS111x 中的特定寄存器,主机必须首先向地址指针寄存器中的寄存器地址指针位 P [1:0] 写入适当的值。

![图片]

地址指针寄存器是在从机地址字节、低电平的读 / 写位以及从机成功应答之后直接写入,从机进行应答,主机发出停止条件或重复起始条件。

③ 从寄存器读取数据

从 ADS111x 读取数据时,先前写入位 P [1:0] 的值决定了要读取的寄存器。要更改读取的寄存器,必须向 P [1:0] 写入新值。

![图片]

④ 数据格式

以二进制补码格式提供 16 位数据。正满量程(+FS)输入产生的输出代码为 7FFFh,负满量程(–FS)输入产生的输出代码为 8000h。

![图片]

对于超过满量程的信号,输出会钳位在这些代码上。

电压计算原理

ADS1115 的输出代码与输入电压的关系为:电压 = (ADC 读数 × 满量程电压) / (2¹⁵ - 1)

在 GAIN_ONE 模式下:满量程电压 = 4.096V、分辨率 = 4.096V / 32767 ≈ 0.125mV。

六、常见问题解答(FAQ)

Q1:测量负电压的原理?

A: ADS1115 本身不能直接测量负电压(相对 GND)。但通过以下方法间接测量:

  1. 使用差分模式时 V-接负电压,V+接 GND。
  2. 使用电平移位电路将负电压抬升到 0-3.3V 范围。
  3. 使用双电源供电给 ADS1115 提供±2.5V 电源。

Q2:Web 页面能打开,但数值不更新 / 波形无变化?

A:排查步骤:

  1. 检查 ESP32 是否仍连接 WiFi。
  2. 检查浏览器控制台(F12)是否有报错。
  3. 确认代码中 setInterval(updateDashboard, 100) 未被注释,刷新频率正常。

Q3: I2C 地址冲突怎么办?

A:ADS1115 的 I2C 地址由 ADDR 引脚决定:默认 ADDR 接地 0x48、ADDR 接 VDD 地址为 0x49、ADDR 接 SDA 地址为 0x4A、ADDR 接 SCL 地址为 0x4B。在代码 Adafruit_ADS1115 ads(0x49); 中修改地址为 0x49。

项目资源整合:

ADS1115 库文件:Adafruit_ADS1X15

ADS1115 数据手册:ADS111x datasheet

目录

  1. 基于 ESP32 的 ADS1115 多通道数据采集系统
  2. 项目难点及解决方案
  3. 一、系统接线部分
  4. 1.1 硬件清单
  5. 1.2 接线方案表
  6. 1.3 接线示意图
  7. 1.4 实物连接图
  8. 二、安装与使用部分
  9. 2.1 导入代码
  10. 2.2 连接与上传
  11. 2.3 调试串口监视器
  12. 三、代码讲解部分
  13. 代码文件结构
  14. 3.1 初始化配置
  15. 3.2 多模式数据采集
  16. 3.3 Web 数据接口
  17. 3.4 前端数据可视化
  18. 四、项目结果演示
  19. 4.1 操作流程
  20. 4.2 视频演示
  21. 五、ADS1115 技术讲解
  22. 5.1 寄存器配置
  23. 5.2 I2C 通信协议
  24. 六、常见问题解答(FAQ)
  25. Q1:测量负电压的原理?
  26. Q2:Web 页面能打开,但数值不更新 / 波形无变化?
  27. Q3: I2C 地址冲突怎么办?
  • 💰 8折买阿里云服务器限时8折了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 🤖 一键搭建Deepseek满血版了解详情
  • 一键打造专属AI 智能体了解详情
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • 基于 AR 眼镜的亲戚称呼助手开发实战
  • 2026 年 AI 智能体变革:OpenClaw 重塑数字员工协作模式
  • Unity VR 眼镜端高分辨率全景视频播放性能优化
  • AI 辅助自动生成 WPS Visio 流程图实战指南
  • Python 构建 AI 助手:文档总结、代码生成与智能检索实战
  • 大模型 API 注册与调用实战:OpenAI、文心一言与通义千问
  • GitHub Copilot 四种模式区别:Agent、Ask、Edit、Plan
  • C++原子操作:从底层原理到实战应用
  • 飞算 JavaAI 插件安装与 Spring Boot 项目生成实战
  • JavaScript WebAPI 实战指南:DOM 操作与事件处理
  • 数据结构:常见时间复杂度与空间复杂度
  • Windows 部署 OpenClaw 接入飞书机器人配置指南
  • Windows 部署 OpenClaw 接入飞书机器人配置指南
  • .NET WebApi 项目必要配置项详解
  • Trae AI IDE 使用指南
  • Linux 动静态库制作与使用:ar 与 ldconfig 详解
  • JavaSE 核心知识点总结
  • 若依 (RuoYi) 低代码框架深度解析与选型指南
  • 学习大语言模型原理必看的 10 篇论文
  • 停车管理系统 APP 前端设计与实现

相关免费在线工具

  • 加密/解密文本

    使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online

  • Gemini 图片去水印

    基于开源反向 Alpha 混合算法去除 Gemini/Nano Banana 图片水印,支持批量处理与下载。 在线工具,Gemini 图片去水印在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online

  • Markdown转HTML

    将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online

  • HTML转Markdown

    将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online