1. 项目概述:从厨房到工作台的精准测量
如果你和我一样,是个喜欢在工作室里捣鼓点小玩意儿的人,或者对电子秤、压力传感器背后的原理感到好奇,那么“自制一只小台秤”这个项目绝对值得你花上一个周末的时间。这不仅仅是一个简单的焊接和组装活儿,它更像是一次从物理原理到数字信号的完整旅程。核心在于那个小小的芯片——HX711,一个专门为称重传感器设计的24位模数转换器。市面上的电子秤、厨房秤,甚至一些工业设备里,都藏着它的身影。自己做一台,你就能彻底搞懂,从一片金属片的微小形变,到屏幕上那个精确到克的数字,中间到底发生了什么。
这个项目适合谁呢?首先当然是电子爱好者,尤其是对模拟信号采集和单片机应用感兴趣的朋友。其次,对于创客、学生,或者任何想给家里的咖啡角、烘焙区添置一个独一无二、且能显示小数点后一位的精准小秤的人来说,它都是一个绝佳的实践。你不仅能得到一个实用的工具,更重要的是,你会理解应变片电桥、差分信号、模数转换、数字滤波这一整套知识链。整个过程成本不高,主要部件就是一个HX711模块、一个称重传感器(通常是5kg或10kg量程的)、一个单片机(比如Arduino UNO或者ESP8266/ESP32),再加上一些结构件。接下来,我就带你从原理到代码,从硬件到校准,完整地走一遍。
2. 核心硬件选型与原理深潜
2.1 称重传感器:感知压力的“机械心脏”
自制台秤的核心感知元件是称重传感器,最常见的是悬臂梁式。它看起来就是一块金属梁,上面贴着几个关键的小东西——电阻应变片。它的工作原理基于“金属的应变效应”:当金属梁受力弯曲时,其表面会产生微小的拉伸或压缩形变。贴在表面的应变片(一种特殊的电阻)会随之发生电阻值的变化。
通常,四个应变片会以惠斯通电桥的方式连接。两个贴在梁的上表面(受拉),两个贴在梁的下表面(受压)。当没有负载时,电桥平衡,输出电压差为零。一旦放上重物,梁弯曲,上方的应变片被拉长电阻增加,下方的被压缩电阻减小,电桥失去平衡,输出一个与压力成正比的微小电压信号(通常是毫伏级别)。这个信号极其微弱,且容易受到温度、电磁干扰的影响,直接读取几乎不可能,这就需要我们的主角HX711登场了。
注意:选购传感器时,除了量程(如5kg),关键参数是灵敏度,单位是mV/V。常见值为1.0mV/V或2.0mV/V。这意味着在额定电压(如5V)激励下,达到满量程时输出的信号电压幅度。这个值直接影响后续的测量分辨率和精度。
2.2 HX711模块:微信号的“放大镜”与“翻译官”
HX711芯片的作用非常明确:第一,给惠斯通电桥提供稳定的激励电源;第二,将电桥输出的微弱差分模拟电压信号放大;第三,将放大后的模拟信号高精度地转换为数字信号。它集成了可编程增益放大器(PGA)和24位Δ-Σ型模数转换器(ADC)。
为什么是24位ADC?位数决定了ADC的分辨率。对于一个5kg量程、灵敏度2.0mV/V的传感器,在5V激励下,满量程输出信号是10mV。如果使用常见的10位ADC(参考电压5V),其最小分辨电压约为5V/1024 ≈ 4.9mV,这意味着它连传感器的满量程信号都分辨不了几步,精度极差。而24位ADC,其理论分辨率可达5V/(2^24) ≈ 0.3μV,足以清晰分辨传感器输出的微伏级变化,从而实现克甚至更小单位的精确测量。
可编程增益放大器(PGA)允许我们选择128或64倍的增益。对于输出信号较小的传感器(如1mV/V),可以选择128倍增益以获得更好的信噪比;对于信号较大的,可选64倍以避免饱和。HX711模块通常将增益固定为128倍,并通过板载的稳压器为传感器提供稳定的5V或3.3V激励,这比直接用单片机的IO口供电要稳定得多,减少了因电源波动带来的测量误差。
2.3 控制器与结构件:项目的“大脑”与“骨骼”
控制器负责与HX711通信、读取数据、进行计算、校准和显示。最经典的选择是Arduino UNO,其库生态完善,入门简单。如果你希望增加无线传输、网页显示等功能,ESP8266(如NodeMCU)或ESP32是更强大的选择。它们自带Wi-Fi,可以用更少的成本实现物联网称重。
结构件决定了台秤的稳定性和外观。你需要一个坚固的底座来固定传感器的固定端,一个秤盘(或托盘)连接传感器的受力端。中间需要设计一个传力结构,确保重量垂直、均匀地施加在传感器受力点上,避免侧向力影响精度。常用的材料有亚克力板、木板或3D打印件。这里有一个关键技巧:在传感器受力点和秤盘之间,最好使用一个球头或半球形结构连接,这样可以自动对中,消除因放置物品位置偏移产生的扭力,大幅提升测量的重复性。
3. 电路连接与硬件搭建实操
3.1 HX711模块引脚详解与接线图
市面上常见的HX711模块通常有6个引脚:
- VCC:模块电源正极,接5V。
- GND:电源地,与单片机共地。
- DT:数据输出引脚,接单片机任意数字IO口。
- SCK:时钟输入引脚,接单片机另一数字IO口。
- E+:传感器电桥电源正极输出。
- E-:传感器电桥电源负极输出。
- A+, A-:传感器信号正、负输入端。
- B+, B-:另一组差分信号输入(本项目通常不用)。
称重传感器一般有4条线,颜色标准通常是:
- 红色:电源+ (Excitation+)
- 黑色:电源- (Excitation-)
- 白色:信号+ (Signal+)
- 绿色:信号- (Signal-)
接线步骤:
- 供电连接:将Arduino的5V和GND分别连接到HX711模块的VCC和GND。
- 信号连接:将HX711模块的DT和SCK引脚分别连接到Arduino的数字引脚,例如DT接D2,SCK接D3。
- 传感器连接:
- 传感器红线 → HX711模块的E+
- 传感器黑线 → HX711模块的E-
- 传感器白线 → HX711模块的A+
- 传感器绿线 → HX711模块的A-
重要提示:接线务必牢固,接触不良是导致读数跳动、不准的首要原因。建议使用杜邦线焊接,或者用螺丝端子压接。在通电前,再三检查电源正负极是否接反,接反很可能永久损坏传感器或HX711模块。
3.2 机械结构组装要点
机械组装的核心目标是:让传感器的受力端只承受垂直向下的力,并且力要作用在设计的受力中心上。
- 底座固定:用螺丝将传感器的固定端(通常有两个安装孔)牢牢锁在底座板上。底座板本身要足够重、足够稳,防止称重时整个秤体晃动。
- 秤盘连接:在传感器的受力端(通常是一个中心带螺纹的孔)安装一个连接杆。连接杆的上端与秤盘连接。这里就是我前面提到的关键点:强烈建议在连接杆和秤盘之间加入一个“万向节”结构。一个简单的做法是,在连接杆顶端放置一颗钢珠,秤盘底部做一个凹坑。这样,无论物品放在秤盘哪个位置,力都会通过钢珠自动垂直传递到传感器中心,完美解决偏载误差。
- 限位与保护:传感器虽然有量程,但过载或侧向冲击很容易导致其塑性变形而损坏。可以在底座和秤盘之间,围绕传感器安装几个限位螺栓。调整螺栓头部与秤盘底部的间隙为1-2毫米。这样,当放入远超量程的重物或受到冲击时,限位螺栓会先接触并承受大部分力,保护传感器。这个间隙不能太小,否则会影响正常量程内的测量。
4. 软件编程与核心算法解析
4.1 库的安装与基础读数程序
在Arduino IDE中,我们通常使用HX711_ADC库,它比基础的HX711库功能更强大,内置了数字滤波和校准功能。通过库管理器搜索并安装。
下面是一个最基础的、读取原始ADC值的程序:
#include <HX711_ADC.h> // 定义HX711连接的引脚 const int HX711_dout = 2; // DT引脚 const int HX711_sck = 3; // SCK引脚 // 创建HX711对象 HX711_ADC LoadCell(HX711_dout, HX711_sck); void setup() { Serial.begin(57600); delay(10); Serial.println("Initializing..."); LoadCell.begin(); // 启动传感器,参数1.0是初始校准值(未校准时) unsigned long stabilizingtime = 2000; // 稳定时间 boolean _tare = true; // 启动时是否去皮 LoadCell.start(stabilizingtime, _tare); if (LoadCell.getTareTimeoutFlag()) { Serial.println("Timeout, check MCU>HX711 wiring and pin designations"); while (1); } else { LoadCell.setCalFactor(1.0); // 设置校准系数为1.0 Serial.println("Startup is complete"); } } void loop() { // 检查是否有新的数据可供读取 if (LoadCell.update()) { // 获取原始ADC值(未校准) long rawData = LoadCell.getData(); // 获取经过当前校准系数计算后的重量值(单位取决于校准) float weight = LoadCell.getData(); Serial.print("Raw ADC value: "); Serial.print(rawData); Serial.print(" | Weight: "); Serial.print(weight, 1); // 显示1位小数 Serial.println(" g"); } delay(100); }这段代码初始化了HX711,并循环打印原始ADC值和当前重量值。在未校准时,“重量值”是没有意义的数字。
4.2 校准流程:赋予读数真实意义
校准是让这台自制秤变得可用的最关键一步。其物理原理是建立一个线性模型:测量值 = 校准系数 * 原始ADC值 + 零点偏移。HX711_ADC库已经帮我们处理了零点偏移(通过tare()去皮功能),所以我们主要就是确定校准系数。
标准砝码校准法:
- 确保秤盘空载,运行程序,调用
LoadCell.tareNoDelay()进行去皮。此时重量应显示为0。 - 将一个已知精确重量的标准砝码(例如500.0g)放在秤盘中心。
- 等待读数稳定后,记录下此时库函数
LoadCell.getData()返回的“重量”读数,假设是readValue(比如是123456.7)。 - 计算校准系数:
calFactor = (已知重量) / (readValue - 0点值)。因为已经去皮,0点值为0,所以calFactor = 500.0 / 123456.7 ≈ 0.00405。 - 在程序中,通过
LoadCell.setCalFactor(0.00405)设置这个系数。 - 重新运行程序,放上砝码,检查显示是否接近500.0g。可以再使用另一个不同重量的砝码(如200g)进行验证。
为了方便,库提供了串口指令交互的示例。你可以上传Calibration示例代码,然后通过串口监视器发送指令来交互式完成校准和去皮,非常方便。
4.3 数字滤波与软件稳像
原始ADC读数即使在没有负载时也会在小范围内跳动,这是由于电源噪声、热噪声等引起的。直接使用跳动的读数体验很差。HX711_ADC库内置了移动平均滤波。
// 在setup()中,可以设置滤波强度 LoadCell.setSamplesInUse(4); // 使用最近4次采样的平均值 // 或者更高级的,使用内置的平滑滤波 void loop() { static boolean newDataReady = 0; // 检查新数据,并尝试平滑滤波 if (LoadCell.update()) newDataReady = true; if (newDataReady) { if (millis() > t + serialPrintInterval) { float weight = LoadCell.getSmoothedData(); // 获取平滑后的数据! Serial.print("Weight: "); Serial.println(weight, 1); newDataReady = 0; t = millis(); } } }getSmoothedData()函数使用了更复杂的算法来平滑数据,比简单的移动平均效果更好,能让最终显示的数字稳定下来,不会频繁跳动。你还可以在读取后自己增加额外的软件滤波,比如“去极值平均滤波”:连续采样N次,去掉最大最小值,剩下的求平均。
5. 功能扩展与项目优化
5.1 添加显示与交互界面
最基本的显示是接一个0.96寸OLED屏幕(I2C接口)。在代码中引入Adafruit_SSD1306和Adafruit_GFX库。在loop循环中,将获取到的重量值显示在屏幕上,还可以增加单位切换(g/kg/oz)、去皮按钮等功能。
为了操作方便,可以添加两个按钮:一个用于去皮(Tare),一个用于切换单位。去皮功能的实现很简单,在按钮按下时调用LoadCell.tareNoDelay()即可。单位切换则是在显示前对重量值进行数学换算。
// 示例:按钮去皮 const int tareButtonPin = 4; void loop() { if (digitalRead(tareButtonPin) == LOW) { // 假设按钮按下为低电平 delay(50); // 简单消抖 if (digitalRead(tareButtonPin) == LOW) { LoadCell.tareNoDelay(); Serial.println("Tare done"); } while(digitalRead(tareButtonPin) == LOW); // 等待按钮释放 } // ... 其他逻辑 }5.2 物联网升级:使用ESP8266/ESP32
将控制器换成ESP8266,你可以实现:
- 网页服务器:让手机或电脑通过浏览器直接访问ESP的IP地址,看到一个实时显示重量的网页。
- 数据上报:将重量数据定期发送到物联网平台,实现远程监控。例如,做一个智能宠物喂食器,监控余粮重量;或者一个盆栽土壤湿度监测(通过称重花盆失水重量来间接判断)。
- 蓝牙串口:通过手机蓝牙APP读取数据,更方便。
这里以ESP8266创建简易Web服务器为例:
#include <ESP8266WiFi.h> #include <ESP8266WebServer.h> #include <HX711_ADC.h> // ... HX711初始化代码 ... const char* ssid = "Your_WiFi_SSID"; const char* password = "Your_WiFi_Password"; ESP8266WebServer server(80); void handleRoot() { float weight = LoadCell.getSmoothedData(); String html = "<html><body><h1>My Scale</h1><p>Weight: <strong>" + String(weight, 1) + " g</strong></p>"; html += "<p><a href=\"/tare\"><button>Tare</button></a></p>"; // 网页去皮按钮 html += "</body></html>"; server.send(200, "text/html", html); } void handleTare() { LoadCell.tareNoDelay(); server.sendHeader("Location", "/"); server.send(303); } void setup() { // ... 初始化HX711 ... Serial.begin(115200); WiFi.begin(ssid, password); while (WiFi.status() != WL_CONNECTED) { delay(500); Serial.print("."); } Serial.println(""); Serial.print("Connected! IP address: "); Serial.println(WiFi.localIP()); server.on("/", handleRoot); server.on("/tare", handleTare); server.begin(); } void loop() { LoadCell.update(); server.handleClient(); }5.3 提高精度与稳定性的高级技巧
- 电源隔离与滤波:HX711模块和传感器对电源噪声非常敏感。如果使用开关电源(比如手机充电器)为整个系统供电,可能会引入高频噪声。一个有效的办法是使用线性稳压模块(如LM7805)为HX711单独供电,或者在电源入口处增加大容量(如1000uF)电解电容和0.1uF的陶瓷电容进行滤波。
- 温度补偿:应变片的电阻值会随温度变化而漂移,导致零点漂移和灵敏度漂移。对于高精度要求,可以在电路中增加一个温度传感器(如DS18B20),实时监测传感器温度,并在软件中根据一个预制的温度-误差表进行补偿。这是一个进阶话题,需要你记录不同温度下空载和带载的读数来建立模型。
- 多点校准:单点校准(只用一个砝码)假设系统的线性度是完美的。但实际传感器和电路可能存在微小的非线性。更高精度的做法是进行两点或三点校准:空载点(0g)和满量程点(如5kg)是必须的,中间点(如2.5kg)可以进一步修正非线性误差。校准后,可以使用分段线性插值或二次曲线拟合来计算重量。
- 机械隔离:确保整个秤体放置在平稳、无振动的台面上。对于微小重量的测量,甚至需要避免空气流动和人员走动带来的干扰。
6. 常见问题排查与调试心得
在实际制作过程中,你几乎一定会遇到下面这些问题。我把我的踩坑经验总结在这里,希望能帮你快速通关。
问题1:读数乱跳,完全不稳定。
- 检查接线:这是最常见的原因。用手轻轻捏一下杜邦线接头,看读数是否剧烈变化。务必确保所有连接牢固,最好焊接。
- 检查电源:用万用表测量HX711模块的VCC电压是否稳定在5V左右。尝试换用电池或不同的USB口供电,排除电源干扰。
- 检查机械结构:秤盘或传力机构是否稳固?有没有碰到任何东西?传感器本身是否安装平整?轻微的倾斜或应力都会导致读数漂移。
- 添加软件滤波:如前面所述,启用库的平滑滤波或自己增加滤波算法。
问题2:有负载,但读数接近零或不变。
- 检查传感器接线顺序:确认传感器的红、黑、白、绿四根线是否严格按照对应关系接到HX711的E+, E-, A+, A-。最常见的就是信号线正负极接反。
- 测试传感器:用万用表电阻档,测量传感器红黑线之间的电阻(通常是350Ω或1000Ω左右),再测量白绿线之间的电阻(应与红黑间电阻相近)。如果阻值异常(如开路或短路),则传感器可能已损坏。
- 检查增益设置:确认代码中初始化的增益与模块硬件匹配。不过大多数模块固定为128倍,问题不大。
问题3:去皮或校准后,数据依然不准。
- 校准流程错误:确保去皮时秤盘绝对空载。校准时,砝码必须放置在秤盘中心,并等待读数完全稳定(通常需要几秒钟)后再记录。
- 砝码不准:不要用随机物品当砝码。使用经过校准的标准砝码。如果没有,可以用一瓶未开封的500ml矿泉水(约500g)或已知重量的厨房秤进行交叉验证。
- 非线性误差:如果只在轻量时准,重量大了偏差变大,可能是传感器非线性或机械结构在重载下形变。尝试进行两点校准(零点+满量程点)。
问题4:ESP8266读取数据慢或不稳定。
- 注意延时:ESP8266的Wi-Fi和TCP/IP栈会占用大量CPU时间,可能干扰HX711通信时序。在
loop()中,确保LoadCell.update()被频繁调用。避免在update()之间进行长时间的阻塞操作(如delay(1000))。使用非阻塞的定时方式。 - 电源不足:ESP8266在Wi-Fi发射时峰值电流可能超过200mA,如果USB线或电源模块供电不足,会导致电压跌落,影响HX711工作。使用能提供5V/1A以上的电源。
个人心得:
- 耐心是金:硬件项目,尤其是涉及精密测量的,八成的问题出在接触和电源上。遇到问题,先冷静下来,从最基本的连线、供电查起。
- 分步测试:不要一次性写完所有代码。先写最简单的读ADC原始值程序,确认硬件通信正常。再加上滤波显示,最后做校准和高级功能。每一步都验证通过,能极大降低调试难度。
- 机械重于电路:在这个项目里,一个稳定、对称、传力直接的机械结构,对最终精度的影响往往比电路优化更大。多花点时间打磨你的秤盘和连接结构,绝对值得。
- 拥抱不完美:自制台秤,受限于传感器等级、ADC噪声、环境干扰,很难达到商用高端产品的精度和稳定性。但只要重复性够好(即多次称量同一物品结果一致),并且通过校准在常用量程内准确,这个项目就是成功的。它能让你理解原理,满足日常大部分非贸易用途的称重需求,这已经足够了。