基于STM32F103C8T6与HX711的电子秤设计:HAL库驱动与数据校准实战 📅 2026/6/28 22:18:51 1. 项目背景与硬件选型最近在做一个智能厨房项目需要精确测量食材重量。市面上现成的电子秤模块要么精度不够要么价格太高于是决定自己用STM32F103C8T6和HX711搭建一个高精度电子秤系统。这个组合特别适合创客和嵌入式开发者成本不到50元精度却能轻松达到0.1%级别。选择STM32F103C8T6这块蓝色小药丸有几个原因首先是性价比超高20块钱就能买到正品其次它自带硬件SPI和定时器方便与HX711通信最重要的是HAL库支持完善开发效率高。HX711则是专为电子秤设计的24位ADC芯片内部集成放大器直接连接应变片就能用省去了复杂的外围电路。硬件连接非常简单HX711的DT脚接PA1任何GPIO都可SCK脚接PA0VCC接3.3VGND共地应变片的E、E-接HX711的正负输入端2. 开发环境搭建我用的是STM32CubeIDE这个IDE最大的好处是自带HAL库和图形化配置工具。新建工程时选择STM32F103C8T6时钟配置为72MHz外部8MHz晶振倍频。关键是要开启两个外设USART1用于调试输出重量数据TIM2用于实现微秒级延时在CubeMX里配置GPIO时PA0设为输出模式推挽PA1设为输入模式上拉。时钟树配置要注意APB1总线不要超过36MHz否则定时器会出问题。生成代码后记得在main.c里添加重定向printf的代码int fputc(int ch, FILE *f) { HAL_UART_Transmit(huart1, (uint8_t *)ch, 1, 0xff); return ch; }3. HX711驱动实现HX711的通信协议比较特殊不是标准的SPI或I2C需要手动控制时序。在HX711.h中定义几个宏简化操作#define CLK_1 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_SET) #define CLK_0 HAL_GPIO_WritePin(GPIOA, GPIO_PIN_0, GPIO_PIN_RESET) #define Read_PIN HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_1)数据读取的核心在Get_number()函数。HX711每次输出24位数据高位在前。关键是要在时钟下降沿读取数据每个时钟周期保持至少1us的低电平unsigned long Get_number() { val 0; CLK_0; while(!Read_PIN); // 等待数据就绪 for(int i0; i24; i) { HAL_Delay_us(1); CLK_1; val val 1; HAL_Delay_us(1); CLK_0; if(Read_PIN) val; HAL_Delay_us(1); } // 第25个脉冲设置增益 CLK_1; val val ^ 0x800000; // 补码转换 HAL_Delay_us(1); CLK_0; return val; }这里有个坑要注意很多网上的例程没有在读取后清零val变量会导致后续数据异常。实测发现延时参数也很关键太快会导致数据错位太慢会影响采样率。4. 数据校准与滤波处理原始ADC值需要转换为实际重量。我的20kg应变片分度系数是103在Get_Weight()函数中处理long Get_Weight(void) { HX711_Buffer Get_number(); Weight HX711_Buffer; Weight (long)((float)Weight / 103); // 校准系数 return Weight; }校准步骤很关键空载时读取10次取平均值作为零点放置已知重物如500g砝码计算系数 原始ADC值 / 实际重量重复三次取平均主循环中加入了简单的滑动滤波while(1) { static long weights[5] {0}; static int index 0; weights[index] -Get_Weight() First_weight; index (index 1) % 5; long avg 0; for(int i0; i5; i) { avg weights[i]; } printf(%ld\n, avg / 5); HAL_Delay(120); // 约10Hz更新率 }5. 常见问题排查调试时遇到几个典型问题数据全为0检查DT脚是否接触不良HX711供电是否稳定数据跳动大尝试在VCC和GND之间加104电容缩短传感器到HX711的导线读数不稳定确保应变片牢固粘贴避免机械振动通信超时检查while(!Read_PIN)是否有超时退出机制一个实用的调试技巧先用示波器看SCK和DT波形确认时序符合HX711规格书要求。如果没示波器可以用LED闪烁指示通信状态if(Get_number() 0) { HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin); }6. 性能优化技巧经过实测这几个优化很有效将HAL_Delay_us()改为定时器实现精度更高在Get_Weight()中加入温度补偿算法使用DMA传输USART数据降低CPU占用添加按键去皮功能if(HAL_GPIO_ReadPin(BTN_GPIO_Port, BTN_Pin) GPIO_PIN_RESET) { First_weight Get_Weight(); HAL_Delay(200); // 消抖 }电源管理也很重要HX711对电源噪声敏感建议单独LDO给HX711供电模拟和数字地之间加0欧电阻电源走线尽量粗短7. 扩展应用方向这个基础框架可以扩展很多实用功能蓝牙传输加个HC-05模块实现手机APP显示数据记录用SPI Flash存储历史称重数据自动识别通过重量变化模式识别不同食材流量计算结合时间戳计算粉末物料流量比如实现简单的配方功能typedef struct { char name[20]; long target_weight; } Ingredient; Ingredient recipe[] { {面粉, 500}, {糖, 200}, {盐, 5} }; void check_recipe() { for(int i0; i3; i) { while(Get_Weight() recipe[i].target_weight) { printf(请添加%s...\n, recipe[i].name); HAL_Delay(1000); } printf(%s添加完成\n, recipe[i].name); } }8. 工程代码结构建议好的代码组织能大幅提高可维护性我的项目结构如下/Drivers /HX711 hx711.c hx711.h /Filters moving_avg.c /Utils delay.c /Application /Recipe recipe.c /Display lcd.c关键设计原则硬件驱动与业务逻辑分离使用面向接口编程重要参数集中配置版本控制提交注释规范比如将校准系数改为配置文件// config.h #define CALIB_FACTOR 103.0f #define MAX_WEIGHT 20000 // 20kg最后提醒不同批次的应变片灵敏度可能有差异建议每批都做单独校准。实际测试发现温度每变化10℃读数会漂移0.5%左右对精度要求高的场合需要做温度补偿。