news 2026/10/6 6:50:47

STM32智能电子秤实战:HX711驱动、滤波与标定完整方案

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
STM32智能电子秤实战:HX711驱动、滤波与标定完整方案

做STM32项目的人,十有八九都会和电子秤题材碰面。一方面它看起来足够简单——一个传感器、一块单片机、一个屏幕,一讲就能明白;另一方面,真要把秤做准、做稳、做得顺手,需要把ADC采样、信号滤波、标定补偿、按键交互、掉电存储、软件状态机这些东西全过一遍。这篇内容是我从原理图设计、PCB打板、固件编写到实物标定的完整复盘,包含了完整方案、驱动代码和实测数据,适合正在做毕设、想练手完整外设驱动、或者准备接一个小项目快速落地的嵌入式开发者参考。

先说清楚我要实现的东西:一台基于STM32的智能计价电子秤,支持称重、去皮、单价输入、金额计算、标定参数与单价掉电保存,通过OLED实时显示重量、单价和总价。硬件核心是STM32F103C8T6主控、平行梁电阻应变式传感器和HX711高精度ADC模块。整体难度中等偏上,但每一步都有明确的验证手段,非常适合当成嵌入式入门后第一个“完整产品级”的练手项目。

1. 先想清楚做什么:功能定义与硬件选型

1.1 产品功能边界:一台秤应该有哪些基本能力

做项目最忌讳一上来就写代码。先定义清楚功能边界,后面所有设计都围绕它展开。我给自己列的清单是:上电自检并且显示稳定的零点;支持去皮操作,也就是放上容器后一键清零;能够通过按键输入单价,单价范围0.01~999.99元/kg;实时显示重量、单价、金额三行信息;标定数据掉电不丢失,重启后能直接使用,不需要重新校准;另外预留一个蜂鸣器,在按键或超量程时给出反馈。

这几点看起来很常规,但每一条都在倒逼底层设计。比如“去皮后称重”要求你能正确处理负的原始读数;“单价输入”需要一个可用的数字编辑状态机,不可能用三个按键直接输入“123.45”;“掉电保存”意味着标定参数不能放在RAM里,必须规划Flash存储;“稳定显示”则完全依赖滤波算法的调参功力。功能清单就是项目的需求文档,越早明确越好。

1.2 主控选型为什么是STM32F103C8T6

有人会问,电子秤而已,用个51单片机或者8位AVR不就行了?确实可以,但我要考虑三点:生态成熟度、调试便利性和后续扩展空间。

STM32F103C8T6是我个人在这个项目里的首选。首先是成本,一块最小系统板几块钱到十几块钱,淘宝上货源充足;其次是调试,支持SWD单线调试,配上STM32CubeProgrammer或者OpenOCD,烧写和断点调试都很方便,这对排查滤波参数、查看ADC原始值时太重要了;最后是外设资源,64KB Flash、20KB SRAM、两个I2C、三个USART、一个12位ADC,做完电子秤之后想扩展USB、蓝牙、物联网网关都还有余量。对于毕设和产品原型来说,这颗芯片属于“够用且好查资料”的最优解。

1.3 传感器与ADC芯片的搭配逻辑

称重传感器我选的是常见的平行梁电阻应变式传感器,量程5kg。这种传感器在电子秤、厨房秤里极其常见,形状像一个扁扁的悬臂梁,四个应变片贴成一个惠斯通电桥。选择5kg量程是因为日常计价场景里500g到5kg的重量段最常用,量程太大传感器灵敏度下降,量程太小稍微放重点东西就满偏。

传感器输出的是差分毫伏信号,满量程时大约只有1mV/V,5V激励下最高输出5mV,这个信号直接给MCU的12位ADC完全不够看——12位ADC在3.3V参考下,一个LSB约0.8mV,全量程才6~7个码,几乎什么都测不出来。所以ADC芯片的选择是整个项目最关键的一步,我用的是HX711。

HX711是专为桥式传感器设计的24位差分ADC,内部集成了低噪声可编程增益放大器(PGA)。这意味着传感器的5mV信号可以经过128倍放大变成640mV,再交给24位ADC量化,相当于把信号链路里最容易出问题的模拟放大环节用一颗芯片解决掉。模块价格只要几块钱,还自带稳压和滤波电路,非常成熟。

1.4 硬件BOM清单与采购注意点

器件型号/规格数量说明
主控板STM32F103C8T6最小系统板1带SWD调试接口即可
称重传感器平行梁式,5kg,1mV/V1注意买到的是完整电桥,不是单个应变片
ADC模块HX711模块1买带屏蔽壳、有焊盘引出E+/E-/A+/A-的版本
显示0.96寸 OLED,I2C接口,SSD130614脚版本接线最方便
按键轻触开关4实现在称重/单价/去皮/确认功能
蜂鸣器有源5V蜂鸣器模块1用三极管驱动,别直接接IO
电源USB 5V供电,或18650+TP40561建议初期用USB电源,稳定可靠
外壳亚克力板或3D打印1传感器固定结构是关键,后面细说

采购时重点看几个容易踩坑的细节:HX711模块上最好能看到AVDD和VDD的独立引脚,后面做电源设计会用到;传感器的引线颜色务必看规格书,不同厂家的红色、黑色、白色、绿色定义可能不同,接错就会输出负信号或者烧坏芯片。

2. 信号链路拆解:应变片如何变成可读的24位数字

2.1 惠斯通电桥:几毫伏的原始信号从哪里来

电阻应变式传感器的核心是一个惠斯通电桥。四个电阻应变片贴在弹性梁的上下表面,受力时梁发生形变,一对应变片被拉伸(电阻增大),另一对被压缩(电阻减小)。电桥的输出电压和电阻变化量成比例,公式可以粗略写成:

[ V_{out} \approx \frac{V_{exc}}{4} \times ( \frac{\Delta R_1}{R_1} - \frac{\Delta R_2}{R_2} + \frac{\Delta R_3}{R_3} - \frac{\Delta R_4}{R_4} ) ]

实际传感器出厂时已经把这四个应变片调平衡了,我们拿到手的是一个四线或五线的完整电桥组件。以我用的5kg传感器为例,5V激励、满量程5kg时输出约5mV,也就是说1g的重量变化大约只对应1μV左右的电压变化。这正是普通ADC完全无法处理、必须用HX711这类高增益24位芯片的原因。

2.2 HX711在信号链路中的位置与优势

HX711内部把“仪表放大器+24位Σ-Δ ADC+串行接口”集成到了一起。它的输入通道A支持差分输入,增益可选128或64,通道B增益固定为32。电子秤场景下,我们把传感器的E+和E-接到AVDD和地,S+和S-接到A+和A-,选择通道A增益128,正好匹配1mV/V级别的传感器。

为什么不用STM32内部ADC?原因有三:第一是分辨率不够,12位在5mV满量程信号下几乎没有有效数字;第二是内部ADC是单端输入,采样的是电压绝对值,电源纹波和地噪声都会直接叠加进去;第三是没有内置的可编程增益放大,外部要自己搭仪表放大器,成本和噪声控制难度直线上升。HX711把这些问题一次性解决,它本身就是为了称重场景设计的“标准答案”。

2.3 24位补码、DOUT/SCK时序与增益切换

HX711和MCU之间的通信非常简单:两个引脚,DOUT和SCK,完全靠时序握手。

  • DOUT为高电平时表示转换尚未完成;
  • DOUT拉低表示转换完成,此时MCU可以读取数据;
  • MCU在SCK引脚上产生25个脉冲,每个脉冲的上升沿让DOUT输出1位数据,先高位后低位,共24位;
  • 第25个脉冲决定下一次转换的通道和增益:只来1个额外脉冲对应通道A增益128,来2个额外脉冲对应通道B增益32,来3个额外脉冲对应通道A增益64。

需要特别注意,HX711输出的24位数据是二进制补码,第23位(最高位)是符号位,实际范围是-2^23到2^23-1。空载时电桥不可能绝对平衡,输出可能是正,也可能是负。直接把这个24位值当无符号数用会出现严重的怪数据,必须做符号扩展。

2.4 驱动代码实现:从忙等到符号扩展

我先给出HX711驱动的核心代码。这里使用STM32 HAL库加模拟GPIO时序的方式实现,SCK用PB1,DOUT用PB0。

/* hx711.h */ #ifndef __HX711_H #define __HX711_H #include "main.h" #define HX711_SCK_PORT GPIOB #define HX711_SCK_PIN GPIO_PIN_1 #define HX711_DOUT_PORT GPIOB #define HX711_DOUT_PIN GPIO_PIN_0 #define HX711_SCK_H() HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET) #define HX711_SCK_L() HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET) void HX711_Init(void); int32_t HX711_Read(void); /* 返回带符号的24位ADC原始值 */ #endif
/* hx711.c */ #include "hx711.h" #include "delay.h" void HX711_Init(void) { GPIO_InitTypeDef gpio = {0}; __HAL_RCC_GPIOB_CLK_ENABLE(); gpio.Mode = GPIO_MODE_OUTPUT_PP; gpio.Pull = GPIO_PULLUP; gpio.Speed = GPIO_SPEED_FREQ_HIGH; gpio.Pin = HX711_SCK_PIN; HAL_GPIO_Init(HX711_SCK_PORT, &gpio); gpio.Mode = GPIO_MODE_INPUT; gpio.Pull = GPIO_PULLUP; gpio.Pin = HX711_DOUT_PIN; HAL_GPIO_Init(HX711_DOUT_PORT, &gpio); HX711_SCK_L(); HAL_Delay(20); } int32_t HX711_Read(void) { uint32_t value = 0; /* DOUT从高变低表示一次转换完成,这里忙等待 */ while (HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN)); for (uint8_t i = 0; i < 24; i++) { HX711_SCK_H(); delay_us(1); value <<= 1; if (HAL_GPIO_ReadPin(HX711_DOUT_PORT, HX711_DOUT_PIN)) value++; HX711_SCK_L(); delay_us(1); } /* 第25个脉冲:保持通道A增益128 */ HX711_SCK_H(); delay_us(1); HX711_SCK_L(); /* 24位二进制补码转int32_t */ if (value & 0x800000) value |= 0xFF000000; return (int32_t)value; }

这段代码里最关键的是符号扩展,我见过好几个新手把HX711读回来的0x7FFFFF、0xFFFFFF直接当成无符号数做均值滤波,结果数据永远不对。另外,忙等DOUT期间,如果传感器接线断开,DOUT可能一直保持高电平,程序会卡死在这个while里,所以实际产品上一般会加超时退出逻辑,但作为教学项目,先保证链路通顺更重要。

3. 硬件电路与PCB设计:把噪声挡在源头

3.1 供电架构:3.3V与5V之间的事情

供电是电子秤最容易翻车的环节。传感器激励需要稳定的正电压,MCU需要3.3V逻辑电源,HX711需要模拟电源(AVDD)给传感器激励,还需要数字电源(VDD)给内部逻辑。

我建议的接法是:USB的5V作为总电源输入,经过AMS1117-3.3得到3.3V给STM32和OLED,同时给HX711的VDD供电;HX711的AVDD单独从5V经过一个RC滤波(10Ω串联电阻+100μF并联电容)之后接入,这样传感器激励是5V整电压,而SCK和DOUT的IO电平由VDD决定,也就是3.3V逻辑,和STM32完全兼容。

这里有个常见的坑:很多淘宝HX711模块把AVDD和VDD直接连在一起,模块整体按照5V供电。这种接法下,DOUT输出高电平就是5V,直接接到STM32的PB0有可能超过GPIO的耐压范围(普通引脚不允许超过VDD+0.3V)。解决方案有两个:一是像我这样飞线改模块,把VDD引脚切出来单独接3.3V;二是用分压电阻把DOUT降到3.3V。我推荐前者,稳定且不影响信号边沿。

3.2 引脚分配和硬件接口规划

我的引脚分配如下:

功能引脚说明
HX711 DOUTPB0输入,上拉
HX711 SCKPB1输出,推挽
OLED SDAPB7I2C1数据线
OLED SCLPB6I2C1时钟线
按键1PA0去皮/确认
按键2PA1单价模式切换
按键3PA2加/移位
按键4PA3减
蜂鸣器PA4推挽输出,经三极管驱动
SWDPA13/PA14调试保留

几个设计要点:PA0天然带WKUP唤醒功能,作为按键输入不需要外部上拉,开启内部上拉即可;I2C1和HX711的DOUT不要放在相邻引脚,避免数字翻转干扰模拟读取;蜂鸣器绝不能用IO直接驱动,必须加一个S8050三极管,否则电流会把IO拉垮。

3.3 焊接与通电前检查清单

如果自己做PCB,打样回来先别急着焊芯片。我的检查顺序是:

  • 先用万用表二极管档检查电源正负之间有没有短路;
  • 只焊电源部分(USB座、稳压芯片、电容),通电测试3.3V和5V电压;
  • 焊MCU最小系统(晶振、复位、BOOT0下拉),用SWD能连上说明MCU工作正常;
  • 再焊HX711和传感器接口,此时先不要插传感器,测量E+和E-之间的电压是否为5V;
  • 最后焊OLED和按键。

传感器接错线导致的故障最隐蔽。我遇到过接反后读数显示一个很大的负数,查了半天才发现是S+和S-接反。建议在传感器线束端用热缩管或者标签纸把颜色定义写清楚,别靠记忆。另外,固定传感器的螺丝不要一下拧死,要用内六角扳手对角均匀预紧,最后再统一力矩锁紧。这个细节直接影响四角误差,也就是秤台四个角放同样重量的东西读数不一致的问题。

4. 固件分层与调度:称重、显示、按键怎么协调工作

4.1 前后台系统:裸机上怎么组织代码

这个项目的固件没有上RTOS,用的是最典型的前后台结构:后台是主循环,前台是定时器中断。整个工程分成三个目录:

Project/ ├── BSP/ │ ├── hx711.c/h │ ├── oled.c/h │ ├── key.c/h │ ├── buzzer.c/h │ └── flash_save.c/h ├── App/ │ ├── scale.c/h // 称重与标定逻辑 │ ├── price.c/h // 单价编辑与金额计算 │ └── ui.c/h // OLED界面状态机 └── main.c

BSP层管芯片外设,App层管业务逻辑,main.c只做初始化和循环调度。这么做的好处是:调试的时候能快速定位问题在硬件还是逻辑;以后想换主控或者换显示驱动,只需要替换BSP对应文件,App层完全不用动。

4.2 主循环调度:定时器Tick与状态标志

我采用一个1ms的SysTick中断作为系统心跳,在中断里做三件事:按键去抖计时、OLED界面刷新计时、蜂鸣器持续时间控制。主循环做的则是对时间要求不那么苛刻的事情——读HX711、跑滤波算法、计算结果、按当前状态更新显示。

不能直接在中断里读HX711,因为它的读取是阻塞的,DOUT拉低后需要连续翻转SCK25次,中途被打断会导致时序错乱;但也不能在主循环里用HAL_Delay做任何延时,否则OLED刷新和按键扫描会被拖死。这就是前后台系统的核心协作方式:中断只负责记录“时间到了”,主循环负责干活。

主循环的伪代码可以这么理解:

while (1) { if (g_ui_tick_10ms) // 10ms标志,由定时器置位 { g_ui_tick_10ms = 0; read_and_filter(); // 读一次HX711并更新滤波结果 update_weight(); // 更新当前重量值 refresh_display(); // 按状态机刷新OLED } handle_key(); // 按键处理放在主循环,做短按/长按判断 }

4.3 滤波算法选型:让重量读数不再跳

HX711在10SPS采样率下,空载原始值的跳动量通常在±4到±10个码之间,对应到5kg量程大约是±1g到±2g。如果不滤波直接显示,OLED上的小数位会跳个不停。我试过三种方案,最终推荐“中位值平均滤波”。

简单滑动平均响应最快,但对于突然的脉冲干扰(比如碰一下秤台)特别敏感,一个坏点就能把平均值拉偏。一阶滞后滤波(低通滤波)很平滑,但参数α调大调小都很纠结,调小则重量变化响应慢得像老牛,调大则滤波效果不明显。最后用的中位值平均滤波:连续取11个样本,去掉一个最大值和一个最小值,对中间9个值求平均。这个算法兼顾了抗脉冲干扰和响应速度,在电子秤这种低频、以静态测量为主的场合效果很好。

#define FILTER_N 11 static int32_t buf[FILTER_N]; static uint8_t idx = 0; int32_t Scale_MedianAverage(int32_t new_sample) { int32_t tmp[FILTER_N]; int32_t sum = 0; buf[idx] = new_sample; idx = (idx + 1) % FILTER_N; for (uint8_t i = 0; i < FILTER_N; i++) tmp[i] = buf[i]; /* 简单的排序找最大最小值 */ int32_t max = tmp[0], min = tmp[0]; for (uint8_t i = 1; i < FILTER_N; i++) { if (tmp[i] > max) max = tmp[i]; if (tmp[i] < min) min = tmp[i]; } uint8_t skip = 0; for (uint8_t i = 0; i < FILTER_N; i++) { if (!skip && tmp[i] == max) { skip = 1; continue; } sum += tmp[i]; } skip = 0; for (uint8_t i = 0; i < FILTER_N; i++) { if (!skip && tmp[i] == min) { skip = 1; continue; } sum += tmp[i]; } return sum / (FILTER_N - 2); }

实测下来,11点中位值平均滤波能把跳动从±6个码压到±1个码左右,对应到重量大约是±0.2g到±0.5g,OLED上基本稳定。滤波算法没有绝对的“最好”,关键是想清楚你要滤掉的是白噪声还是脉冲干扰,然后再选择对应的数学手段。

4.4 非阻塞按键扫描:5ms一次的去抖状态机

按键部分我采用的方案是:定时器每5ms扫描一次按键状态,每个按键维护一个小型状态机,状态在“释放”和“按下”之间切换,只有连续两次扫描都读到相同状态才认为状态有效。这样顺便把硬件机械抖动的去抖也做掉了,完全不用delay。

长按和短按的区分是靠“按下持续时间计数器”实现的。小于50ms的抖动被状态机滤掉;按键按下超过500ms进入长按逻辑(用于进入标定模式);短按则触发对应短按事件(去皮、切换单位)。这种非阻塞扫描方式最大的好处是不会打断HX711的阻塞读时序,两个东西独立工作,各不干扰。

5. 计价逻辑、去皮与掉电存储

5.1 称重与计价的状态机设计

计价逻辑是整个项目里业务最复杂的地方。我把系统分成四个状态:状态S1“正常称重”、状态S2“单价编辑”、状态S3“标定模式”、状态S4“超量程保护”。

正常称重状态下,OLED第一行显示重量,第二行显示单价,第三行显示金额;按“去皮”键记录当前容器重量作为去皮偏移;按“单价”键进入单价编辑状态。单价编辑状态下,按键2切换当前编辑位(百位、十位、个位、十分位、百分位,共5位),按键3和按键4在当前位上加减0~9,再次按“单价”键确认退出并保存到Flash。标定模式需要长按去皮键5秒进入,防止日常误触。

状态机用枚举变量实现,每个状态下按键回调不一样。写的时候注意一点:状态切换时要清掉所有按键抖动标志和界面刷新标志,否则刚切换状态就触发了旧状态的事件。

5.2 去皮逻辑与负重量处理

去皮本质上是记录当前滤波后的ADC平均值作为“偏移量”。定义如下:

typedef struct { int32_t offset; /* 空载/去皮后的零点偏移,ADC码 */ float scale; /* 标定系数,ADC码/kg */ } Scale_Param; float Scale_GetWeightKg(void) { /* raw是经过滤波的当前ADC原始值 */ int32_t adc = raw - param.offset; if (adc < 0) adc = 0; /* 不允许显示负重量 */ float weight_kg = (float)adc / param.scale; return weight_kg; }

注意一点,去皮后如果盘中重量减掉(比如拿走了容器),ADC原始值会小于offset,差值变成负数。业务上显示0.000即可,但计算金额时要防止负数金额出现。如果在标定模式下原始值为负,说明传感器预紧力不足或者电桥不平衡,需要调整传感器机械安装,而不是靠代码把负值压掉。

5.3 单价输入方案:三个按键怎么完成小数点编辑

电子秤单价输入是一个典型的“有符号定位”编辑场景。我采用“当前位编辑”方式:用按键在五位数位之间移动光标,每个位单独加/减。原理上和老式电子表的设置一样,没有用全键盘矩阵,省掉了大量IO。

单价存储为浮点数不方便,浮点比较和取整都有隐患,所以实际项目中我把单价用整型保存,单位是“分/kg”。编辑过程中维护一个uint16_t price_cents,金额计算时重量乘以单价再除以100,结果按“分”四舍五入。这样既避免了浮点运算的边界问题,也能做到精确显示到分。

5.4 标定参数的掉电保存:内部Flash还是外部EEPROM

标定参数(offset和scale)和单价都是需要掉电保存的数据。两种方案:外部AT24C02 I2C EEPROM,或者直接使用STM32内部Flash。

AT24C02好处是写入寿命高(100万次)、按字节操作方便,坏处是多一颗器件、多一份驱动代码。内部Flash的好处是零成本、不增加PCB面积,但坏处是写入前必须先擦除整个扇区,而且Flash的擦写寿命只有1万次左右。对于电子秤这种标定参数一年也写不了几次的场景,内部Flash完全够用,我就采用了双备份方案:把参数写进两个独立扇区,每次写入交替使用,上电时先读两个扇区并校验,如果其中一个损坏就自动用另一个恢复。

写入Flash前要特别注意:擦除操作期间如果掉电,数据可能永久损坏。双备份能把这种风险降到最低。实际填代码时,先用结构体把参数打包,加上帧头和CRC校验,然后写扇区;上电读取时校验CRC,失败则回退备份扇区。这个设计思路不限于电子秤,任何需要保存少量配置参数的嵌入式项目都可以直接照搬。

6. 标定、实测与踩坑复盘

6.1 两点标定法:操作步骤与注意事项

电子秤的标定我采用最简单也最实用的两点标定:记下空载时的ADC平均值作为offset,放上标准砝码记下ADC平均值,计算scale = (满量程ADC - 空载ADC) / 砝码重量。

我的标定流程固定在开机至少预热30秒之后进行,因为传感器刚上电时漂移最明显。长按去皮键5秒进入标定模式,此时OLED显示“CAL-0”,保持空载按确认,系统连续采样50次取均值作为offset;随后提示放上1kg标准砝码,再按确认,系统采样50次取均值作为full。计算scale后自动写入Flash,重启后验证读数和砝码是否一致。

这里给新手一个建议:标定用的标准砝码精度越高越好,最差也要用体型小的铸铁砝码,不要随便拿一个装了水的矿泉水瓶当标准,因为你根本不知道它净重是多少。标定误差会一直被存到Flash里,后面所有的称重结果都建立在这个基准之上。

6.2 滤波前后的实测数据对比

我用的传感器是5kg量程、5V激励、HX711增益128,10SPS采样率。以下是同一台设备在两种状态下的实测原始ADC值和换算重量:

测试重量未滤波ADC跳变范围滤波后ADC跳变范围滤波后显示重量 波动
0g±8码±1码0.0 ±0.2g
500g±7码±1码500.2 ±0.3g
1000g±9码±2码999.8 ±0.5g
2500g±6码±1码2500.3 ±0.3g
5000g(满量程)±10码±2码5000.7 ±0.6g

整体线性度在满量程的0.1%以内,对计价场景来说完全够用。可以看到滤波后跳码大幅缩小,但常态误差本质上是传感器的线性度和标定基准决定的,滤波搞不定。如果发现某一点的误差超过0.5%,建议先怀疑砝码是否放偏或者传感器机械固定是否松动。

6.3 五个典型坑与规避方法

第一个坑是HX711数据符号扩展。我一开始直接把24位无符号数转成float去算重量,结果空载显示一个巨大的正数,放上东西反而减少。查了两小时,最后打印原始值才发现读到的0xFFFFFF实际上是-1。用int32_t做符号扩展后再看,一切正常。

第二个坑是传感器四角误差。标定完成后,四个角分别放1kg砝码,读数分别是998g、1003g、1005g、999g。问题出在传感器固定底板不平和螺丝力矩不均匀。我把秤台四个角的支撑垫高调整,用水平仪校准,同时用扭矩螺丝刀统一锁紧力矩后,四角误差收敛到±2g以内。

第三个坑是OLED地址错误。淘宝买的0.96寸OLED驱动芯片和地址可能是0x3C或0x3D,实际读取地址寄存器前先扫描两个地址。另外模块上如果没有焊接I2C上拉电阻,通信会时断时续,我用万用表量了才发现SDA和SCL对地没有10k上拉,补上后正常。

第四个坑是HX711模块的AVDD和VDD被连死。模块默认5V供电,DOUT输出的高电平实测接近5V,直接接3.3V的STM32引脚虽然短期内没烧,但这种操作等于每天都在走钢丝。我把模块上的AVDD引脚割开,飞线单独接3.3V给VDD,才算彻底安心。

第五个坑是上电前30秒的零点漂移。只开机就立刻去皮、立刻标定,几分钟后重量值会慢慢偏移。后来我在系统上电后加了一个“预热提示”状态,OLED显示“WARM UP”直到上电满30秒才允许测重和标定,这个体验上的小细节对稳定性提升非常明显。

整个项目从画原理图到稳定出数,大概花了一个周末加两个晚上。最大的收获不是把秤做出来了,而是把ADC采样、滤波、状态机、掉电存储这些零散的知识点串成了一条完整的决策链——每一个设计决策都有前因后果,都能从信号链路上解释清楚。如果让我再给后来者一个建议:先不要把精力放在界面上,优先把HX711的信号调稳,拿到一个可信的重量读数;只要原始数据稳定,后面做UI、计价、扩展物联网都是水到渠成的事情。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/6 6:50:17

嘉立创PCB全流程实战:从原理图到量产成品板

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 6:50:01

MOS管当二极管用:五个隐藏技巧与选型避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 6:48:03

FPGA/ASIC时钟MUX互斥约束实战:clock_groups -exclusive详解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 6:48:00

Type-C接口CC逻辑与E-MARK芯片深度解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/6 6:48:00

线性稳压器为什么会烫?从1117发热到DCDC散热设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华