基于ESP32与NAU7802的咖啡机自动称重计时系统设计与实现

发布时间:2026/5/31 12:19:38

基于ESP32与NAU7802的咖啡机自动称重计时系统设计与实现 1. 项目概述为专业咖啡机注入精准与一致性在精品咖啡的“第三波浪潮”中一杯好咖啡的评判标准早已超越了简单的“提神”功能转向了对风味、产地和萃取过程本身的极致追求。对于意式浓缩咖啡而言两个最关键的量化指标便是萃取液重和萃取时间。任何一位有经验的咖啡师都知道即使使用相同的咖啡豆和研磨度几克液重或几秒时间的偏差都可能导致杯中风味从平衡醇厚滑向尖酸或苦涩。然而并非所有商用或家用咖啡机都内置了高精度的称重与自动停止功能咖啡师往往需要依赖外置的电子秤和计时器在萃取过程中手动观察和操作这不仅对操作者的专注度要求极高也为人为误差留下了空间。我经营的咖啡馆里有一台性能出色的La Marzocco Linea Mini咖啡机但它同样缺少自动称重停止功能。为了在高峰时段也能保证每一杯出品都稳定如一我和团队决定为其“赋能”打造一个集成的自动称重计时系统。这个系统的核心目标很明确让机器在咖啡液达到预设的目标重量时自动停止萃取并实时显示萃取时间将咖啡师从重复的监控操作中解放出来把精力更多地投入到风味调整和客户服务上。我们设定的精度目标是误差控制在0.2克以内这对于追求极致稳定的精品咖啡馆来说是一个合理的挑战。整个系统的硬件核心是一块功能强大的ESP32微控制器它负责协调所有部件从高精度的NAU7802称重传感器模块读取实时重量数据驱动一块16x4字符的LCD显示屏作为人机界面并通过一个微型伺服电机去物理按压咖啡机原有的冲泡开关。下面我将从设计思路到代码实现完整拆解这个项目的每一个环节并分享我们在开发过程中踩过的“坑”和总结出的实用技巧。2. 系统整体设计与核心思路拆解2.1 需求分析与方案选型在设计之初我们明确了几个核心需求高精度称重系统需要能稳定测量流动中的咖啡液重量分辨率至少达到0.1克最终误差带需小于0.5克。实时反馈与交互需要有一个直观的界面显示当前重量、时间和目标值并允许咖啡师快速设置目标重量。非侵入式控制不能对咖啡机原有的电路进行永久性修改以确保机器的保修和安全性。控制方式必须是物理层面的模拟人手操作。稳定性与抗干扰咖啡馆环境可能存在振动、水汽和电磁干扰系统需要具备良好的鲁棒性。成本与可维护性使用广泛可得、文档丰富的组件以控制成本和便于后期维护。基于这些需求我们进行了如下选型主控芯片ESP32 DevKit V1选择ESP32而非更简单的Arduino UNO主要看中其双核处理能力、丰富的IO口以及内置的Wi-Fi/蓝牙功能为未来远程监控或数据记录留出扩展空间。其主频高达240MHz足以轻松处理称重传感器的快速数据读取、滤波算法、伺服电机控制和人机界面刷新等多任务。称重传感器与放大器拆机负载传感器 SparkFun NAU7802这是精度保障的关键。我们从一个废弃的0.01克精度厨房秤中拆解出它的电阻应变式负载传感器。这类传感器输出的是微伏级别的差分信号必须搭配专用放大器。NAU7802是一款24位ADC的称重传感器放大器通过I2C接口通信内置可编程增益放大器PGA和数字滤波器能直接将微弱的模拟信号转化为高精度的数字值其性能远超常见的HX711模块尤其在抗干扰和长期稳定性上表现更优。执行机构9g微型伺服电机为了实现非侵入式控制伺服电机是最佳选择。它可以通过程序精确控制旋转角度我们将其改装成一个“机械手指”在需要停止萃取时转动并按下咖啡机面板上的物理开关。选择9g型号是因为其体积小、扭矩足够且便于安装在机器内部有限的空间里。人机界面16x4 LCD I2C适配板直接驱动一个16x4的LCD需要占用大量IO口至少6个。使用I2C适配板后只需要2个IO口SDA, SCL就能完成控制极大地简化了布线。显示屏用于显示“当前重量”、“目标重量”、“萃取时间”和系统状态。输入控制多按钮复用单模拟引脚为了设置目标重量我们需要“加”、“减”、“开始/停止”等几个按钮。如果每个按钮占用一个数字引脚会很快耗尽ESP32的引脚资源。我们采用了经典的电阻分压网络方案将多个按钮连接到一个模拟输入引脚上通过读取不同的电压值来区分哪个按钮被按下从而用最少的引脚实现多个输入功能。2.2 系统架构与信号流整个系统的工作流程可以概括为一个清晰的闭环控制感知咖啡杯放置在定制亚克力承重台上的负载传感器上。NAU7802以高频率例如80Hz采样传感器信号并通过I2C总线将重量数据发送给ESP32。处理ESP32的主循环持续读取重量数据并应用软件滤波如移动平均或卡尔曼滤波以消除由咖啡滴落、环境振动引起的噪声。同时它通过另一个I2C通道刷新LCD显示并扫描按钮状态。决策当用户按下“开始”键ESP32启动内部计时器并持续比较当前重量与预设目标重量。执行一旦当前重量 目标重量ESP32立即向伺服电机发送指令使其旋转到预设角度推动机械结构按下咖啡机的冲泡开关从而切断水泵电源停止萃取。反馈LCD上实时更新的重量和时间变为静态显示最终萃取结果并提示“完成”。这个架构的优势在于各模块通过标准接口I2C、PWM连接耦合度低便于单独调试和更换。ESP32作为大脑负责所有的逻辑判断和调度。3. 核心硬件解析与搭建要点3.1 称重传感单元从拆解到校准负载传感器的拆解与处理从旧秤上拆传感器是性价比最高的方案但需要格外小心。找到的厨房秤精度为0.01克其内部的单点式负载传感器通常能满足我们的需求。注意拆卸时务必先断开所有电源。用烙铁和吸锡器仔细取下传感器与PCB的连接。传感器本体非常脆弱严禁弯曲、撞击或用蛮力拉扯其金属应变区。拆下后你会看到传感器引出四根颜色各异的线红、黑、白、绿或蓝。这几乎是一个行业标准红 (Red)激励电压正极 (E)黑 (Black)激励电压负极 (E-)白 (White)信号输出正极 (S)绿/蓝 (Green/Blue)信号输出负极 (S-)关键一步许多传感器在焊点或应变梁上涂有保护胶。切勿用化学溶剂或刀片粗暴去除这极易损坏内部脆弱的应变片。如果胶体影响接线可以用精密镊子轻轻剥离或者直接在线材根部焊接延长线。与NAU7802的连接NAU7802模块的接线非常直观。将传感器的四根线对应连接到模块的焊盘上传感器 E (红) - NAU7802E传感器 E- (黑) - NAU7802E-传感器 S (白) - NAU7802A传感器 S- (绿) - NAU7802A-机械结构重建裸传感器无法直接承重。我们使用激光切割的亚克力板制作了一个双层结构底座板固定传感器的一端通常是带有固定孔的一端。承重板放置咖啡杯通过支柱仅与传感器的受力端自由端接触。 这样杯子的重量会使传感器的应变梁发生微弯曲从而改变其电阻值。设计文件DXF/DWG需确保受力方向垂直且结构刚性足够避免侧向力。如果你有3D打印机也可以用PLA等材料打印这个结构但亚克力在潮湿环境下更稳定。3.2 主控与外围电路连接详解ESP32 DevKit V1 引脚分配清晰的引脚规划是项目成功的基础。以下是我们使用的连接方式模块引脚名称连接至 ESP32 引脚备注NAU78023V33.3V务必接3.3VESP32的IO电平是3.3VGNDGND共地SDAGPIO 21I2C 数据线SCLGPIO 22I2C 时钟线LCD (I2C)VCC5V 或 3.3V接5V背光更亮接3.3V更安全GNDGND共地SDAGPIO 21与NAU7802共用SCLGPIO 22与NAU7802共用伺服电机VCC (红)5V需外接5V/2A电源切勿从ESP32的USB口取电GND (棕)GND与ESP32和电源共地信号 (橙)GPIO 13支持PWM输出的任意引脚按钮网络模拟输出GPIO 34仅输入的模拟引脚如GPIO 34, 35, 36, 39中断引脚GPIO 18用于唤醒或检测按钮按下共用I2C总线NAU7802和LCD的I2C适配板共享SDA(21)和SCL(22)引脚这是I2C总线标准所允许的。每个设备都有一个唯一的I2C地址ESP32通过地址来区分它们。通常NAU7802的默认地址是0x2A而常见的LCD I2C模块地址是0x27或0x3F。在代码中初始化两个不同的对象并指定各自地址即可。伺服电机供电的“坑”这是硬件搭建中最容易出错的地方。一个9g伺服电机在堵转比如按压开关遇到阻力的瞬间电流可能超过500mA。ESP32开发板上的5V引脚或USB口无法提供如此大的持续电流强行使用会导致ESP32重启或损坏。实操心得必须为伺服电机准备独立的5V电源如一个5V/2A的DC电源适配器。将此外部电源的“正极”接到伺服电机的VCC“负极”接到伺服电机的GND同时必须将此“负极”与ESP32的GND连接在一起即“共地”。这样控制信号来自ESP32和动力电源来自外部就有了共同的参考零电位伺服电机才能被正确控制。3.3 人机交互与输入设计LCD I2C模块的使用将LCD屏幕插入I2C适配板通常只需要连接背面的16个引脚。使用LiquidCrystal_I2C库可以轻松驱动。在代码中你需要根据屏幕尺寸和I2C地址进行初始化#include Wire.h #include LiquidCrystal_I2C.h LiquidCrystal_I2C lcd(0x27, 16, 4); // 地址0x2716列4行 void setup() { lcd.init(); lcd.backlight(); // 打开背光 lcd.print(Brew Scale Ready); }单模拟引脚读取多按钮这是节省IO口的经典技巧。其原理是利用不同电阻组合产生不同的分压被模拟引脚读取为不同的ADC值。5V | [R1] 10K Ohm (Button A) |---/ ---- 模拟引脚 (GPIO 34) [R2] 4.7K Ohm (Button B) |---/ ---- 模拟引脚 [R3] 2.2K Ohm (Button C) |---/ ---- 模拟引脚 | [R4] 1K Ohm (公共下拉电阻) | GND当没有按钮按下时模拟引脚通过R4下拉到GND读数为0。当按下按钮A时5V通过R1和R4分压产生一个电压值V1。按下B、C时分别通过R2/R4、R3/R4分压产生V2、V3。由于R1、R2、R3阻值不同V1、V2、V3也各不相同。在代码中我们读取模拟引脚的值0-4095对应0-3.3V并映射到一个范围内即可判断是哪个按钮被按下。int readButtons() { int adcVal analogRead(BUTTON_ADC_PIN); if (adcVal 3000) return 0; // 无按钮 if (adcVal 100) return 1; // 按钮A if (adcVal 100 adcVal 500) return 2; // 按钮B if (adcVal 500 adcVal 1000) return 3; // 按钮C return 0; }注意事项电阻值需要精心选择确保每个按钮对应的ADC值区间有足够的“空隙”防止因电源波动或噪声导致误判。在实际焊接前最好用面包板测试并测量出精确的ADC阈值。4. 软件实现与核心逻辑剖析4.1 开发环境与核心库我们使用Arduino IDE进行开发需要提前安装ESP32开发板支持。核心依赖的库包括SparkFun NAU7802 Arduino Library用于与称重传感器放大器通信。LiquidCrystal I2C by Frank de Brabander用于驱动I2C LCD。ESP32Servo(可选)ESP32专用的伺服电机库提供更稳定的PWM控制。也可以使用Arduino标准的Servo库。在代码开始引入必要的库并定义引脚和全局变量#include Wire.h #include SparkFun_NAU7802.h #include LiquidCrystal_I2C.h #include ESP32Servo.h NAU7802 myScale; // 创建NAU7802对象 LiquidCrystal_I2C lcd(0x27, 16, 4); // 创建LCD对象 Servo brewSwitchServo; // 创建伺服电机对象 // 引脚定义 const int SERVO_PIN 13; const int BUTTON_ADC_PIN 34; const int BUTTON_INT_PIN 18; // 全局变量 float currentWeight 0.0; float targetWeight 18.0; // 默认目标18克 unsigned long brewStartTime 0; bool isBrewing false; int servoRestAngle 10; // 伺服电机空闲角度 int servoPressAngle 60; // 伺服电机按下开关的角度4.2 称重传感器的初始化与校准NAU7802的初始化比HX711稍复杂但更强大。在setup()函数中我们需要按顺序完成以下步骤void setup() { Serial.begin(115200); lcd.init(); lcd.backlight(); // 1. 初始化I2C和NAU7802 Wire.begin(); if (myScale.begin() false) { lcd.print(Scale Error!); while(1); // 卡住 } lcd.print(Scale OK); // 2. 配置增益和采样率 myScale.setGain(NAU7802_GAIN_128); // 高增益用于小量程 myScale.setSampleRate(NAU7802_SPS_80); // 80次/秒采样率 // 3. 校准 - 这是保证精度的核心 calibrateScale(); } void calibrateScale() { lcd.clear(); lcd.print(Remove all weight); delay(5000); // 等待用户清空秤盘 myScale.calculateZeroOffset(); // 计算零位偏移去皮 lcd.print(Place 100g weight); delay(5000); // 等待用户放置已知砝码 myScale.calculateCalibrationFactor(100.0); // 计算校准系数已知重量100.0克 myScale.saveCalibration(); // 将校准系数保存到NAU7802的EEPROM中 lcd.print(Calib Done!); delay(2000); }核心原理calculateCalibrationFactor(knownWeight)这个函数执行了最关键的一步。NAU7802会读取当前传感器的原始读数rawValue然后通过公式calFactor rawValue / knownWeight计算出校准系数。之后每次获取重量时都使用weight (currentRawValue - zeroOffset) / calFactor来计算。将校准系数保存到EEPROM后即使断电重启也无需重新校准除非传感器机械结构发生变化。4.3 主循环逻辑与状态机整个系统可以看作一个简单的状态机主循环loop()负责状态切换和任务执行。void loop() { // 1. 读取按钮非阻塞方式 int btn readButtons(); handleButton(btn); // 处理按钮事件设置目标重量、开始/停止 // 2. 读取并滤波重量数据 if (myScale.available()) { long rawReading myScale.getReading(); float newWeight (rawReading - myScale.getZeroOffset()) / myScale.getCalibrationFactor(); // 应用移动平均滤波 currentWeight movingAverageFilter(newWeight); } // 3. 更新显示 updateDisplay(); // 4. 萃取过程控制 if (isBrewing) { unsigned long currentTime millis(); unsigned long elapsedTime currentTime - brewStartTime; // 检查是否达到目标重量 if (currentWeight targetWeight) { stopBrewing(); // 停止萃取 } // (可选) 安全超时停止例如超过60秒强制停止 if (elapsedTime 60000) { stopBrewing(); lcd.setCursor(0, 3); lcd.print(TIMEOUT! ); } } delay(10); // 短延时防止CPU占用率100% }滤波算法的重要性咖啡液滴落是一个动态过程传感器读数会跳动。简单的movingAverageFilter可以平滑数据float weightBuffer[10]; int bufferIndex 0; float movingAverageFilter(float newVal) { weightBuffer[bufferIndex] newVal; bufferIndex (bufferIndex 1) % 10; float sum 0; for (int i 0; i 10; i) { sum weightBuffer[i]; } return sum / 10.0; }更高级的可以选择一阶低通滤波或卡尔曼滤波但移动平均在大多数场景下已经足够。4.4 伺服电机控制与机械联动控制伺服电机按压开关是整个系统的“执行手”。关键在于找到两个关键角度空闲位置和按压位置。void startBrewing() { if (isBrewing) return; isBrewing true; brewStartTime millis(); lcd.setCursor(0, 3); lcd.print(Status: BREWING ); // 伺服电机通常已经处于空闲位置无需动作 } void stopBrewing() { if (!isBrewing) return; isBrewing false; // 1. 控制伺服电机按下开关 brewSwitchServo.write(servoPressAngle); delay(300); // 保持按压300毫秒确保开关触发 // 2. 复位伺服电机 brewSwitchServo.write(servoRestAngle); delay(100); // 3. 更新显示萃取完成 unsigned long brewTime (millis() - brewStartTime) / 1000; lcd.setCursor(0, 3); lcd.print(Done! ); lcd.print(brewTime); lcd.print(s ); }角度确定技巧在安装伺服电机前先用代码写一个简单的角度测试程序让伺服电机在0-180度之间缓慢转动观察其机械臂的运动轨迹。手动将咖啡机开关拨到“开”的位置找到恰好能维持开关开启的伺服电机角度这就是servoPressAngle。然后找到一个让机械臂完全离开开关、不产生任何阻力的角度作为servoRestAngle。5. 系统集成、安装与调试实录5.1 咖啡机内部改装与伺服电机安装La Marzocco Linea Mini的冲泡开关通常是一个瞬时按钮或拨杆。我们的目标是让伺服电机模拟人手按压。安全第一断开咖啡机电源并等待其完全冷却。最好拔掉电源插头。定位开关打开机器顶盖或前面板找到控制水泵启动的物理开关。它通常连接到一个微动开关或电磁阀。设计连接件需要设计一个简单的连接件“机械手指”将伺服电机的旋转运动转化为对开关的直线按压。我们使用3D打印了一个小连杆一端固定在伺服电机的舵盘上另一端有一个柔软的硅胶头用于按压开关。STL文件可以在开源社区找到或自行设计。固定伺服电机使用螺丝或强力的双面胶将伺服电机牢固地安装在机器内部一个不会干涉其他部件且能让“机械手指”准确对准开关的位置。确保所有线缆远离加热部件和运动部件。测试动作在机器不通电的情况下临时连接伺服电机到你的开发系统运行测试程序反复测试按压和释放动作确保行程顺畅、力度足够触发开关但又不过度用力导致损坏。5.2 系统上电与整体测试将所有模块连接好后按顺序上电先给ESP32开发板通过USB和外部5V伺服电机电源上电。此时伺服电机不应动作。观察LCD启动信息应显示“Scale OK”和“Brew Scale Ready”。首次校准按照屏幕提示进行称重传感器的去皮和砝码校准。使用一个准确的100克砝码或已知重量的金属块。功能测试称重测试放上已知重量的物品查看LCD显示是否准确。尝试快速放上取下观察数值是否稳定。按钮测试按下“加”、“减”按钮目标重量值应相应变化。伺服测试在未开始萃取的状态下通过临时修改代码或串口指令触发stopBrewing()函数观察伺服电机是否能准确按压并释放开关。集成测试放上咖啡杯设置一个较小的目标重量如5克按下“开始”。向杯中缓慢倒水模拟咖啡流出当重量达到5克时观察伺服电机是否立即动作同时计时停止。5.3 精度优化与稳定性提升在实际测试中你可能会遇到读数漂移或偶尔跳动的问题。以下是一些优化手段电源净化为NAU7802的模拟部分AVDD引脚提供一个干净的3.3V电源如果可能可以增加一个简单的LC滤波电路减少来自数字电路的噪声。机械减震在亚克力承重台与咖啡机机身之间或传感器安装点处增加硅胶减震垫能有效隔离咖啡机水泵和锅炉工作产生的振动。软件滤波增强除了移动平均可以增加一个“死区”判断。例如只有当连续3次读数都超过目标重量时才触发停止防止单次噪声误触发。int overTargetCount 0; if (currentWeight targetWeight) { overTargetCount; if (overTargetCount 3) { // 连续3次超重才确认 stopBrewing(); overTargetCount 0; } } else { overTargetCount 0; // 一旦重量回落计数器清零 }温度补偿进阶负载传感器的输出会受环境温度影响。如果对长期稳定性要求极高可以在NAU7802附近放置一个温度传感器如DS18B20建立温度-漂移模型在软件中进行补偿。NAU7802本身也内置了温度传感器可以读取其值。6. 常见问题排查与实战心得在开发和调试过程中我们遇到了不少典型问题这里汇总成排查清单希望能帮你少走弯路。问题现象可能原因排查步骤与解决方案LCD屏幕不亮或乱码1. I2C地址错误。2. 电源接错接3.3V但背光需要5V。3. 接线松动。1. 使用I2C扫描程序Arduino IDE示例中有查找正确的设备地址。2. 尝试将VCC接到5V引脚确保共地。3. 检查SDA、SCL是否接反重新插拔连接线。NAU7802读数始终为0或不稳定1. 传感器接线错误或断路。2. 激励电压不足。3. 校准未成功或校准系数丢失。4. 机械安装不当传感器受力卡死或悬空。1. 用万用表测量传感器E和E-之间是否有激励电压约3.3VS和S-之间是否有微小电压变化按压时。2. 确保myScale.begin()返回true并检查I2C通信是否正常。3. 重新执行完整的校准流程并确认调用了saveCalibration()。4. 检查承重平台是否平稳传感器受力点是否正确。伺服电机不动或抖动1. 电源功率不足。2. 信号线接触不良。3. 代码中控制引脚不对或PWM设置问题。4. 机械负载过重卡死。1.这是最常见原因确保使用独立5V/2A电源为伺服电机供电并与ESP32共地。2. 检查信号线是否连接到正确的PWM引脚如GPIO 13。3. 使用servo.attach(pin)时确认引脚号正确。对于ESP32可能需要使用ESP32Servo库。4. 卸下负载空载测试伺服电机是否能正常转动。按钮反应不灵或串键1. 电阻分压网络计算不准确ADC区间重叠。2. 模拟引脚上拉/下拉配置冲突。3. 电源噪声导致ADC值波动。1. 用Serial.print输出每个按钮按下时的原始ADC值重新调整分压电阻确保每个按钮的ADC值区间有至少100-200的间隔。2. 确保模拟引脚模式为INPUT不要启用内部上拉。3. 在模拟引脚与GND之间加一个0.1uF的电容滤波。达到重量后伺服电机不动作1.currentWeight未正确更新或滤波过度延迟。2. 判断条件有误如用了而非。3.isBrewing状态机逻辑错误未进入判断分支。1. 通过串口监视器实时打印currentWeight和targetWeight确认数值。2. 检查if (currentWeight targetWeight)这行代码。3. 在stopBrewing()函数入口加一个Serial.println(“Stop func called”)看是否被执行。系统偶尔自动重启1. 伺服电机工作时引起电源电压骤降导致ESP32欠压复位。2. 程序跑飞或内存泄漏。1.强化电源在ESP32的Vin和GND之间并联一个大电容如1000uF电解电容缓冲电压波动。确保伺服电机电源独立且功率充足。2. 检查代码中是否有大型局部变量导致栈溢出或未处理的异常。最后的几点心得耐心校准称重系统的精度90%取决于校准。找一个绝对准确的砝码可以去计量所购买或校准在无风、稳定的台面上进行多次校准取平均值。预热像许多精密仪器一样通电让系统运行几分钟后再进行校准或关键称重读数会更稳定。安全冗余在实际使用中我们在代码里加了一个“安全超时”例如60秒即使重量传感器万一失效萃取也不会无限进行下去防止咖啡机水泵干烧。外观整合为了让项目更美观我们最终用激光切割了一个小外壳将ESP32、NAU7802等电路板封装起来只露出LCD屏幕和按钮看起来更像一个原装附件。这个项目成功地将一台顶级半自动咖啡机升级为了具备准专业级自动称重功能的智能设备。它不仅保证了我们咖啡馆出品的极致稳定性也成为了一个展示技术如何提升传统手艺的绝佳案例。当你看到伺服电机在精确的时刻“咔哒”一声按下开关LCD上定格住完美的萃取重量和时间时那种工程与艺术结合的满足感正是创客精神的精髓所在。

相关新闻