STM32HAL库驱动HX711压力传感器:从接线校准到OLED显示的完整避坑指南

张开发
2026/4/14 13:33:22 15 分钟阅读

分享文章

STM32HAL库驱动HX711压力传感器:从接线校准到OLED显示的完整避坑指南
STM32HAL库驱动HX711压力传感器从接线校准到OLED显示的完整避坑指南当你第一次拿到HX711压力传感器模块时可能会被它小巧的体积和简单的四线接口所迷惑。但真正开始动手连接STM32开发板时各种问题就会接踵而至数值跳动不稳定、校准公式理解错误、OLED显示异常...本文将带你一步步避开这些坑完成从硬件连接到软件实现的完整流程。1. 硬件连接那些容易忽略的细节1.1 接线顺序的玄机HX711模块通常有四个引脚VCC、GND、SCK和DT。看似简单的连接却藏着几个关键点电源隔离建议为HX711单独供电避免与STM32共用电源导致干扰。如果必须共用确保电源线足够粗并在VCC和GND之间添加100μF电容。信号线处理SCK和DT线长度不宜超过15cm过长会导致信号衰减。如果必须延长建议使用双绞线。注意不同厂家的HX711模块引脚颜色可能不同务必以模块上的丝印为准不要盲目按照颜色接线。1.2 GPIO初始电平设置在CubeMX中配置SCK引脚时初始电平设置直接影响测量稳定性// 错误的配置会导致数值跳动 GPIO_InitStruct.Pin HX711_SCK_Pin; GPIO_InitStruct.Mode GPIO_MODE_OUTPUT_PP; GPIO_InitStruct.Pull GPIO_NOPULL; GPIO_InitStruct.Speed GPIO_SPEED_FREQ_LOW; // 必须设置为HIGH GPIO_InitStruct.Level GPIO_PIN_SET; HAL_GPIO_Init(HX711_SCK_GPIO_Port, GPIO_InitStruct);如果初始电平设置为LOW取下重物后会出现数值大幅跳动的现象。这是因为HX711内部需要在高电平状态下完成数据转换。2. CubeMX配置关键参数解析2.1 时钟配置HX711对时序要求严格系统时钟配置不当会导致通信失败。推荐配置参数推荐值说明HCLK72MHz保证足够的处理速度APB136MHz外设时钟APB272MHzGPIO时钟2.2 GPIO模式选择DT引脚应配置为上拉输入模式GPIO_InitStruct.Pin HX711_DT_Pin; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; // 必须启用上拉 GPIO_InitStruct.Speed GPIO_SPEED_FREQ_HIGH; HAL_GPIO_Init(HX711_DT_GPIO_Port, GPIO_InitStruct);3. 代码实现避开数据处理的坑3.1 数据读取时序HX711的24位数据需要严格按照时序读取以下是一个稳定的读取函数int32_t HX711_GetData(void) { int32_t count 0; uint8_t i; HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET); HAL_Delay(1); // 等待DT变低 while(HAL_GPIO_ReadPin(HX711_DT_GPIO_Port, HX711_DT_Pin) GPIO_PIN_SET); // 读取24位数据 for(i0; i24; i) { HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_SET); HAL_Delay(1); count count 1; HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET); HAL_Delay(1); if(HAL_GPIO_ReadPin(HX711_DT_GPIO_Port, HX711_DT_Pin) GPIO_PIN_SET) { count; } } // 第25个脉冲选择通道和增益 HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_SET); HAL_Delay(1); HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET); HAL_Delay(1); // 补码转原码 return count ^ 0x800000; }3.2 数据处理与滤波原始数据通常会有噪声需要采用滑动平均滤波#define FILTER_SIZE 5 int32_t filter_buf[FILTER_SIZE] {0}; uint8_t filter_index 0; int32_t HX711_GetFilteredData(void) { filter_buf[filter_index] HX711_GetData(); filter_index (filter_index 1) % FILTER_SIZE; int32_t sum 0; for(uint8_t i0; iFILTER_SIZE; i) { sum filter_buf[i]; } return sum / FILTER_SIZE; }4. 校准实战从理论到实践4.1 校准原理详解HX711的校准需要两个已知点空载值和已知重量值。校准公式为weight (raw_value - offset) * scale其中offset是空载时的原始值scale是比例系数通过已知重量计算得出4.2 分步校准指南获取空载值int32_t offset HX711_GetFilteredData();放置已知重量如100g砝码并获取新值int32_t known_weight_value HX711_GetFilteredData();计算比例系数float scale 100.0f / (known_weight_value - offset);应用校准公式float weight (current_value - offset) * scale;提示如果没有标准砝码可以使用手机等已知重量的物品。例如200g手机对应的100g计算值为(phone_value - offset)/2 offset4.3 校准值存储为避免每次上电重新校准可以将offset和scale存入Flashtypedef struct { int32_t offset; float scale; uint32_t crc; // 校验值 } HX711_Calib_t; void Save_Calibration(HX711_Calib_t *calib) { // 计算CRC32校验值 calib-crc Calculate_CRC32((uint8_t*)calib, sizeof(HX711_Calib_t)-4); // 写入Flash HAL_FLASH_Unlock(); FLASH_Erase_Sector(FLASH_SECTOR_6, VOLTAGE_RANGE_3); HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, 0x08060000, *(uint32_t*)calib); HAL_FLASH_Lock(); } int Load_Calibration(HX711_Calib_t *calib) { // 从Flash读取 memcpy(calib, (void*)0x08060000, sizeof(HX711_Calib_t)); // 校验CRC uint32_t crc Calculate_CRC32((uint8_t*)calib, sizeof(HX711_Calib_t)-4); return (crc calib-crc) ? 0 : -1; }5. OLED显示优化5.1 显示刷新策略频繁刷新OLED会导致闪烁建议采用差异刷新char current_display[20] {0}; char new_display[20] {0}; void Update_Display(float weight) { sprintf(new_display, %.1fg, weight); // 只有数值变化时才刷新 if(strcmp(current_display, new_display) ! 0) { OLED_ClearLine(2); // 清除特定行 OLED_ShowString(2, 2, new_display); strcpy(current_display, new_display); } }5.2 图形化显示对于需要直观显示重量变化的场景可以添加简单的条形图void Draw_Weight_Bar(float weight, float max_weight) { uint8_t max_width 120; // OLED宽度 uint8_t bar_width (uint8_t)((weight / max_weight) * max_width); OLED_DrawRectangle(10, 40, bar_width, 10, OLED_COLOR_NORMAL); OLED_Refresh(); }6. 常见问题排查遇到问题时可以按照以下步骤排查数值始终为0检查DT引脚是否接触良好确认SCK引脚初始电平设置为HIGH测量VCC电压是否在2.6V-5.5V范围内数值跳动严重检查电源是否稳定建议增加滤波电容确保传感器机械结构稳固无振动尝试增加滤波算法的窗口大小OLED无显示检查I2C/SPI线路连接确认OLED初始化代码正确执行测量OLED供电电压通常为3.3V或5V7. 进阶技巧7.1 自动去皮功能实现按下按键自动去皮if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET) { HAL_Delay(50); // 消抖 if(HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin) GPIO_PIN_RESET) { offset HX711_GetFilteredData(); Save_Calibration(calib); } }7.2 低功耗模式对于电池供电的应用可以间歇性唤醒HX711void Enter_LowPower_Mode(void) { // 设置SCK为高电平超过60μs使HX711进入休眠 HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_SET); HAL_Delay(1); // 配置STM32进入STOP模式 HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); } void WakeUp_HX711(void) { // 拉低SCK唤醒HX711 HAL_GPIO_WritePin(HX711_SCK_GPIO_Port, HX711_SCK_Pin, GPIO_PIN_RESET); HAL_Delay(1); }7.3 多传感器切换如果需要使用多个HX711模块可以通过片选信号切换#define HX711_1_CS_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_SET) #define HX711_1_CS_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_4, GPIO_PIN_RESET) #define HX711_2_CS_H HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_SET) #define HX711_2_CS_L HAL_GPIO_WritePin(GPIOA, GPIO_PIN_5, GPIO_PIN_RESET) int32_t Read_HX711(uint8_t sensor_num) { if(sensor_num 1) { HX711_1_CS_L; HX711_2_CS_H; } else { HX711_1_CS_H; HX711_2_CS_L; } return HX711_GetFilteredData(); }

更多文章