
做这个项目的起因其实很现实——毕业设计要选个既能体现单片机应用、又方便现场演示的题目智能计价电子秤几乎是最合适的选项之一。它把称重传感器、信号采集、人机交互、数据处理这些单片机课程里的核心知识点全串在一起了而且完成度好坏一眼就能看出来。本文就从需求拆解开始把基于STM32的智能计价电子秤从硬件选型到软件实现再到实测排错的完整思路像跟朋友拆项目一样讲清楚。不管你是准备拿它当毕设、课设还是纯粹想做一个实用小工具都可以把这篇文章当作一份能直接“抄作业”的参考方案。1. 智能计价电子秤的需求拆解与整体方案定调动手之前先把“智能计价电子秤”这七个字拆开看。电子秤解决的是“多重”和“多少钱”两个基本问题加了一个“智能”前缀意味着它要具备比普通弹簧秤或机械台秤更高级的属性能自动采集重量、能输入单价并自动计算金额、能清晰显示、能方便校准甚至可以在超重或参数异常时给出提示。作为单片机毕设作品功能不必盲目追求多但每个功能都必须稳定可复现。1.1 功能清单怎么定才不会被答辩老师质疑合理的做法是先梳理基本功能再设计扩展功能区分哪些是核心必做项哪些是锦上添花。核心功能建议锁定下面这四条重量采集支持0到几公斤量程分辨率至少到1g能够稳定读数。单价输入允许通过按键设置每斤或每公斤的单价并能修改、查看。自动计价根据重量和单价实时计算总价重量变化时金额同步刷新。显示与提示同时显示重量、单价、金额三项信息超量程或传感器异常时给出警告。扩展功能可以在主体跑通后自行增加比如称重去皮Tare、单价记忆掉电保存、累计金额、语音播报、蓝牙发送到手机、阈值超限蜂鸣报警。我用STM32F103C8T6做主控因为这块芯片在毕设圈里太常见了资料多、下载调试工具便宜、引脚也够用答辩时拿出去说硬件选型也站得住脚。1.2 整体方案选型主控、传感器、屏幕怎么搭整体架构其实是一个典型的“传感器→信号调理→MCU→显示/按键”链路。传感器输出的微弱电压信号不能直接被STM32的ADC使用所以中间要加一级专用的24位高精度ADC芯片也就是HX711。具体硬件清单和角色分配如下表所示模块选型作用主控STM32F103C8T6数据处理、逻辑控制、外设调度称重传感器电阻应变式悬臂梁传感器量程5kg或10kg把重量转化为差分电压信号AD转换HX711把微伏级差分信号放大并数字化显示LCD1602字符液晶带I2C转接或直驱显示重量、单价、金额输入4x4矩阵键盘或独立按键输入单价、去皮、清零提示有源蜂鸣器、LED超重报警、按键提示电源5V USB供电或锂电池模块给传感器、HX711和STM32供电这套方案的合理之处在于HX711内置了低噪声可编程放大器增益支持32/64/128配合5kg传感器时可以直接用128倍增益不需要额外的仪表放大器硬件电路非常简洁。STM32F103C8T6虽然内部有12位ADC但用来称重却不够因为传感器的满量程差分输出往往只有几毫伏12位分辨率量化出来精度太低所以外置HX711是这类电子秤项目的主流做法。电源方面要注意传感器和HX711的模拟电源尽量独立滤波我实测中发现当供电纹波大时重量数据会出现周期性跳字。2. 硬件选型与关键器件原理称重传感器、HX711和STM32的搭配逻辑很多新手拿到这个项目后第一反应是网上随便买一套模块回来拼结果数据不是乱跳就是完全读不到。原因通常是没弄懂传感器和ADC到底怎么工作只照着别人的接线图连了线出现问题时毫无排查方向。这一章专门把原理讲透。2.1 电阻应变式传感器的工作原理和接线方式智能计价电子秤常见的传感器是铝制悬臂梁式电阻应变传感器内部结构是贴在弹性体上的四个电阻应变片组成惠斯通电桥。当重物压在传感器一端时弹性体发生微小形变两个应变片被拉伸、两个被压缩导致电桥失去平衡在激励电压两端产生一个与载荷成正比的差分电压。我用的是5kg量程的悬臂梁传感器红色线接激励电压E黑色线接E-白色线接信号输出S绿色线接S-。有些模块的线序不一样买回来第一件事就是拿万用表测激励端电阻一般在350欧姆左右信号端电阻也在350欧姆左右如果数值异常多半是接线或传感器有问题。实际接线时传感器激励电压建议直接接HX711模块上的E和E-而不是单独从STM32的3.3V拉一根线过去。HX711模块上一般已经做了一路稳压和滤波用它的电源给传感器供电噪声会小很多。2.2 HX711为什么能胜任电子秤信号采集HX711是一颗专为高精度电子秤设计的24位ADC芯片内部集成了低噪声放大器、稳压电源和时钟电路。与普通ADC最大的区别在于它的输出是串行数据通过DOUT数据输出和SCK时钟两根线与MCU通信。关键参数如下参数典型值说明分辨率24位理论细分度极高可编程增益32 / 64 / 128通过SCK脉冲数选择数据输出速率10Hz或80Hz通过RATE引脚选择工作电压2.6V ~ 5.5V兼容STM32电平选择增益128时满量程差分输入范围约为±20mV配合5kg传感器理论上可以分辨到0.01g以下。不过实际系统受机械振动、电源噪声和传感器线性度影响做到1g分辨率是完全没问题的这已经满足计价秤的需求了。HX711读数据的过程很有意思DOUT平时为高电平当转换完成后会变低此时MCU开始给SCK脉冲。每给一个SCK高脉冲DOUT输出一位数据从最高位开始共24位。在第25个脉冲时DOUT回到高电平同时决定下一次转换使用的增益。对于24位数据读取的是二进制补码格式可以直接计算。2.3 STM32F103C8T6的引脚资源分配我的引脚分配方案如下供参考PA0HX711_DOUT配置为输入PA1HX711_SCK配置为推挽输出PB0~PB7LCD1602数据口若用I2C转接则只需PB6、PB7PC0~PC74x4矩阵键盘行/列PA8蜂鸣器PA9按键LED提示分配引脚时要注意避开STM32F103C8T6的启动引脚BOOT0和晶振引脚以及JTAG占用的PA13/PA14/PA15。但如果你用的是ST-Link通过SWD下载程序PA13和PA14会被占用所以我把矩阵键盘的列线放在PC口避免冲突。这个看起来是小问题实际调试时如果JTAG和键盘冲突程序会莫名其妙跑飞还很难查。2.4 电路连接时的几个关键经验接线顺序建议先把STM32最小系统板和HX711模块的电源分别接通然后接传感器到HX711最后再连HX711与STM32之间的信号线。千万不要在带电的情况下反复插拔传感器信号线容易烧坏传感器内部的应变片或HX711的输入级。HX711模块的大电容和稳压芯片已经做了基本滤波但如果你想让数据更稳可以在传感器的E和E-之间并联一个100uF的电解电容再并联一个0.1uF的瓷片电容形成高频和低频双重去耦。我实测过加上这两个电容后空载数据的峰峰值抖动从原本的±3个AD码缩小到±1个AD码左右。3. 称重数据的采集与标定HX711时序、滤波算法与重量换算硬件连好以后最大的任务就是把重量数据从原始AD码变成一个可读、稳定的以克为单位的重量值。这一章是电子秤的灵魂所在也是答辩时容易被问细节的地方。我会把代码思路和坑点交替着讲。3.1 HX711数据读取代码的完整写法HX711的等待转换完成和数据移位读取逻辑可以用标准的位操作实现。我写的驱动函数如下uint8_t HX711_IsReady(void) { return GPIO_ReadInputDataBit(HX711_PORT, HX711_DOUT_PIN) Bit_RESET; } uint32_t HX711_ReadRaw(void) { uint32_t data 0; uint8_t i 0; while (GPIO_ReadInputDataBit(HX711_PORT, HX711_DOUT_PIN) Bit_SET); for (i 0; i 24; i) { GPIO_SetBits(HX711_PORT, HX711_SCK_PIN); data data 1; if (GPIO_ReadInputDataBit(HX711_PORT, HX711_DOUT_PIN) Bit_SET) { data; } GPIO_ResetBits(HX711_PORT, HX711_SCK_PIN); } // 第25个脉冲选择增益128 GPIO_SetBits(HX711_PORT, HX711_SCK_PIN); GPIO_ResetBits(HX711_PORT, HX711_SCK_PIN); return data; }特别注意HX711_SCK引脚置高后一定要延时至少1微秒再读取数据我使用的是普通IO模拟如果置高后立刻拉低协议上没问题但在STM32 GPIO速度配置不当的时候容易误读。更稳妥的方法是每给一个脉冲后加delay_us(2)。读回来的data是一个24位有符号整数在32位变量里以无符号形式保存也是可以的。后续计算重量时需要先把它强制转换为int32_t因为原始值是补码形式如果不转换直接做减法可能会得到荒谬的结果。3.2 零漂处理与多级滤波刚上电时传感器即使空载HX711读到的AD码也不是0而是一千五百到两千左右挂在不同的秤体结构上数值还会漂。这是因为电桥没有完全平衡以及放大器本身的零点偏置。所以程序启动后要做一次“去皮归零”操作记录当前空载时的AD值记为offset_value。重量计算的基本公式是weight_gram (raw_value - offset_value) / scale_factor * 1000其中scale_factor表示每1千克重量对应的AD码差值。这个值需要通过标定得到。为了提高稳定性我不会直接把单次读取的AD值拿去算重量而是用“滑动平均中值剔除”的办法。每次采集8个原始值去掉最大值和最小值剩余六个取平均得到一个filtered_raw。然后拿这个滤波值去做重量计算。实测下来这个方案在平稳状态下重量显示能稳定到±1g以内在人为抖动秤体时也不会出现跳变几克的情况。如果对实时性要求更高可以把滑动窗口设成5点。对于PID控制或高速动态称量场景可能需要更复杂的滤波算法但计价秤这种静态称量场景均值滤波已经非常够用了。3.3 怎么用砝码标定出一个可靠的scale_factor标定是整个项目里最容易被忽略、但直接决定称量准确度的环节。很多同学把代码下载进去后看到有数值变化就说“成功了”结果放上100g砝码只显示85g这就是scale_factor不对。我的标定步骤是这样的在传感器空载状态下执行去皮记录空闲滤波AD值。放上标准砝码比如200g越多越好我这里用了500g标准砝码。读取此时的滤波AD值算出与空载的差值。用差值的绝对值除以砝码质量kg得到每千克对应的AD值比如差值450000500g就是0.5kg则scale_factor 450000 / 0.5 900000。把scale_factor写进程序里的常量或者通过串口/按键在线调整。标定时砝码要放在传感器的受力点上也就是秤盘中心位置。如果砝码偏置因为悬臂梁传感器的应变片对受力点位置敏感同重量的东西放在秤盘前面和后面读数会不一样这会让人误以为是硬件问题实际上是机械结构问题。遇到这种情况需要给电子秤加装一个固定的秤盘支架尽量让被测物体始终落在同一个受力区域。仪表还要做线性检查只标一个点其实不够严格。理想做法是标定两个点比如先放200g记录系数再放1000g记录系数如果两个系数差异小于2%取平均即可。如果差异超过5%说明传感器线性度有问题或安装结构存在摩擦阻力要优先检查机械部分而不是去堆算法。3.4 单位转换与金额计算的核心逻辑电子秤在商品交易场景中通常有两种计价单位按千克计价或按“斤”计价。中国大陆的市斤是500g很多人习惯按斤报价。我的程序里设置了一个单位标志位通过按键切换按公斤计价时price单位为“元/kg”按市斤计价时price单位为“元/斤”计算金额前统一转换到克这个基本单位float weight_kg (float)filtered_value / 1000.0f; float amount; if (unit_mode UNIT_KG) { amount weight_kg * price_per_kg; } else { amount weight_kg * 2.0f * price_per_kg_500g; }浮点数在STM32上运算速度虽然远低于整数但F103C8T6有FPU吗没有Cortex-M3是软件浮点。单价和金额计算是低频操作用float完全没问题。但要注意如果把重量和金额直接相乘后用于显示不要反复累加否则会出现金额飘移。正确做法是每次采集到新的重量值后重新用“重量×单价”计算一次金额而不是在之前的金额上增减。4. 计价逻辑与交互界面按键输入、单价设置和LCD显示的实现细节功能再正确如果人机交互做得别扭答辩演示效果也会打折扣。这段我重点说按键和显示这两个最容易被轻视的部分以及一些提高使用体验的小设计。4.1 矩阵键盘的扫描逻辑与按键防抖处理我用的是4x4矩阵键盘按键数量多支持0-9数字键、单价输入、去皮、清零、单位切换等功能。矩阵键盘的原理是分行扫描把所有行线设置为输入带上拉把所有列线设置为输出每次拉低一列然后读行线状态如果某一行变低就找到对应按键。扫描不能放在主循环里裸奔我的做法是用一个5ms周期的软件定时器触发扫描函数。每5ms扫描一次连续两次扫描到同一个键值才认为有效这样消掉了机械抖动。按键释放后再触发一次对应功能避免按下一次执行多次。这里有一个非常关键的经验矩阵键盘的列扫描顺序和物理布局要一致还要在程序里维护一个按键码映射表。我第一次做的时候物理按键明明按的是数字“5”程序却识别成“8”查了一小时发现是列线顺序和数组没对好。最好在按键扫描函数里先打印键值到串口验证整排按键都正确后再继续写业务逻辑。4.2 单价输入的交互设计数字拼接与小数处理单价不是整数的概率很大比如“23.5元/kg”所以输入逻辑要支持小数。我的方案是规定单价最多两位小数按下数字键时把它当作整数累积最后再在显示和计算时除以100。这样能避免浮点数的二进制误差。举个例子用户依次按下“2”、“3”、“5”内部的值变化是0 → 2 → 23 → 235显示时用price_display internal_value / 100在LCD上显示为2.35。这个方法的优势是所有按键处理和显示格式化都非常简单不会出现浮点数累积误差。最后计算金额时再除以100转为浮点。这个设计在答辩时可以直接回答“如何保证价格精度”的问题因为金额是按“分”为最小单位用整数保存的只有显示和最终乘法时才转浮点用户输入过程中的误差为零。4.3 LCD1602显示策略重量、单价、金额怎么排版LCD1602只有两行一行为16个字符要同时显示三项核心信息排版是个小技巧。我采用的方案是第一行W:0000g P:023.50也就是左侧显示重量右侧显示单价。第二行A:000.00 T:0.500kg左侧显示金额右侧显示去皮后的净重。宽度上要注意对齐W后面补足5个数字字符P后面补足6个字符这样数字变化时不会出现错位或残影。LCD1602本身没有自动清屏的概念如果不重新写入旧位置就会留残影所以每次刷新重量时我先把整行对应区域用空格填充再重新写入新数值。有人喜欢把计价结果字体显示得特别大但1602规格就是5x8点阵做不到大字号。如果想提升视觉冲击力可以换OLED或TFT彩屏但那些屏幕的内存占用量明显变大对STM32F103C8T6来说1602反而是最稳重、最不容易出问题的选择。4.4 去皮功能背后的数据处理逻辑“去皮”在电子秤里是一个非常常见的操作意思是把当前容器重量从称重结果中减掉只显示容器里货物的净重。我的实现方式是维护一个tare_offset变量。去皮时读取当前滤波AD值把它当成新的零点偏移保存下来。之后每次计算重量都改成weight_raw (filtered_value - tare_offset) / scale_factor;这样当用户把盘子或纸盒放在秤上并按“去皮”后系统就默认这个重量是0。再去掉容器后重量会显示为负数程序里要做一个下限截断避免显示“-0.123kg”这种奇怪的数据。有个细节去皮操作不能破坏最初真正的零漂基准。我维护了两个变量一个是power_on_offset上电空载零点一个是current_offset当前去皮零点。按“清零”键时把current_offset重置为power_on_offset。这样逻辑清晰不会去了一次皮之后再也回不到原始零点。5. 常见坑点与实测调试记录从零到稳定运行的完整排错路径这个项目在制作过程中一定会踩几个坑。我把实际调试中遇到过的、以及身边同学经常问的问题集中整理出来按排查链路给各位展示而不是直接给结论这样以后再遇到类似问题时思路会更清晰。5.1 传感器读数一直为最大量程或完全不变出现这个问题时我首先检查的是HX711模块的DOUT引脚电平是否正常。上电后如果不接任何重物DOUT应该每秒钟翻转多次数据准备好时变低读完后又变高。如果DOUT一直为高说明HX711没有转换完成原因通常是SCK引脚被错误拉低导致芯片处于复位等待状态或者传感器差分信号异常让ADC饱和。排查步骤建议如下用万用表测量HX711的VCC和AVDD电压正常芯片有专门的模拟电源输出大约为5V或4.3V。测量传感器E和E-之间的电压应该接近HX711的稳压输出。测量传感器S和S-之间的电压空载时通常接近0mV用手压传感器时电压应变化到几毫伏。如果S和S-之间电压很大或不变说明传感器已损坏或接线错误。我这里曾经遇到过传感器接线时把E和S接反导致读数直接变到最大。换回来后一切正常。所以遇到问题先怀疑接线再怀疑芯片别急着改代码。5.2 重量数值漂移、跳字严重跳字是计价秤最影响体验的问题。跳字可能来自三个层面电源、机械振动、算法。我实测中发现电源导致跳字的特征非常明显空载数值呈周期性波动波动的频率接近电源纹波的100Hz波动幅度能到几个AD码。解决办法主要是加强滤波电容并在HX711的DVDD引脚与地之间并联0.1uF电容。还要注意ST-Link供电时若笔记本USB口供电不稳数据也会跳。这时改用独立5V适配器或锂电池供电会立刻改善。机械振动导致的跳字是安装结构问题。如果传感器只用螺丝悬空固定没有和秤盘支撑结构紧密连接那么称重时传感器会轻微晃动产生虚假应力。建议传感器一端用螺丝固定在底板支架上另一端作为受力端悬空且受力端不要直接用手去碰。算法层跳字的特征是数据已经做了滤波但偶尔还会先跳一下再恢复这种一般是出现了离群值比如瞬间干扰。把刚才说的“最大值最小值剔除”加进滑动平均就能治本。5.3 价格计算正确但显示小数位错乱这个问题发生在把整数内部值转浮点显示时。比如内部值是235想显示23.5直接用num / 100会得到2.35错一位小数点。原因是在整数除法中235/100 2转浮点前要先乘或者强制转换。正确写法是float price_display internal_price / 100.0f;末尾一定要带.0f否则会被当成整数除法。这类问题特别适合在答辩时的提问环节拿出来讲因为能体现你对数据类型的敏感性。5.4 按键偶尔不响应或连击不响应大多是因为按键扫描函数放在了一个被中断频繁打断的地方或者主循环里有Delay阻塞。连击则是因为防抖时间不够或者松开检测缺失。我的建议是按键扫描放进定时器中断或一个固定时基的调度器里并维护键值缓存。每次触发动作后必须等待按键释放再允许下一次触发否则用户按住数字键不放会将同一数字连续输入多次。我在程序里用了一个简单的状态机按键按下且状态为“空闲”时转入“按下确认”状态并记录当前键值等到读取到“释放”信号且状态为“按下确认”时才执行对应动作并回到“空闲”。这样无论用户多快按几下系统都能正确响应单次按下事件。5.5 下载程序失败或调试器连接不上STM32F103C8T6最常用的调试工具是ST-Link下载方式建议选SWD模式只接SWDIO、SWCLK、GND、3.3V四根线。如果出现“No target connected”错误优先检查BOOT0引脚是否被硬件拉高。正常运行时BOOT0必须拉低如果悬空可能会不定时导致程序不工作。另一个常见原因是芯片引脚配置错误比如把PA13或PA14配置成普通GPIO输出后SWD调试接口就被禁用了。解决办法是按住复位键点击下载瞬间松开让芯片在上电瞬间停止执行用户程序然后擦除才能恢复。这也是为什么我建议把按键接口放在PC口而不是PA口的原因。SWD接口占用的是PA13/PA14虽然可以复用但一旦配置错误轻则无法调试重则要反复复位擦除非常折腾。5.6 实物测试与精度验证方法最后是验收环节。我用电子秤标准砝码做了三组测试空载稳定性测试、单点精度测试、线性度测试。空载稳定性测试是上电后连续读取30秒重量值记录最大最小变化。经过加电容、滤波后30秒内波动不超过1g。单点精度测试放上500g标准砝码读数稳定在500g±1g。线性度测试分别放200g、500g、1000g记录误差均不超过2g。这些数据在写报告和答辩PPT时很有说服力。如果你们学校要求作品有创新点你还可以在现有基础上增加蓝牙模块把重量和金额发送到手机APP或者加一个EEPROM记录每次交易数据这些扩展都是现成的方案。做这个项目我个人最大的体会是单片机毕设的出彩点从来不是堆功能而是把每个功能做扎实。从HX711的时序读到标定系数的确定再到人机交互的细节优化每一步都值得花时间反复推敲。当你看着自己设计的秤稳稳地显示“W:0500g P:016.00 A:008.00”时那种成就感是刷课设代码给不了的。希望这篇文章能帮你少走几段弯路早点把作品调到稳定状态。