HX711数据不稳定问题
根本原因PC14/PC15 是 STM32F1 的 OSC32 晶振引脚即使不启用 LSE这两个引脚也受备份域保护有以下严重限制最大输出频率仅 3MHz无法可靠驱动 SCK驱动能力极弱最大灌电流仅 3mAGPIO 读取不稳定导致位错位 → RAW 值大幅跳变#include hx711.h /* 全局变量 */ static uint8_t g_gain HX711_GAIN_128; // 增益设置 static int32_t g_offset 0; // 零点偏移 static float g_scale 1.0f; // 比例系数 /* 微秒级延时 */ static void HX711_Delay_us(uint32_t us) { uint32_t i; // 72MHz系统时钟调整系数以获得更准确的延时 for(i 0; i us * 18; i) { __NOP(); } } /** * brief HX711初始化 * note DT: PA3 (输入) * SCK: PA4 (输出) */ void HX711_Init(void) { GPIO_InitTypeDef GPIO_InitStruct {0}; /* 使能GPIOA时钟 */ __HAL_RCC_GPIOA_CLK_ENABLE(); /* 配置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_HIGH; HAL_GPIO_Init(HX711_SCK_PORT, GPIO_InitStruct); /* 配置DT为上拉输入 */ GPIO_InitStruct.Pin HX711_DT_PIN; GPIO_InitStruct.Mode GPIO_MODE_INPUT; GPIO_InitStruct.Pull GPIO_PULLUP; HAL_GPIO_Init(HX711_DT_PORT, GPIO_InitStruct); /* 初始化SCK为低电平 */ HX711_SCK_LOW(); /* 设置默认增益 */ HX711_SetGain(HX711_GAIN_128); /* 等待HX711稳定 */ HAL_Delay(100); /* 等待HX711稳定后再去皮 */ HAL_Delay(500); // 增加稳定时间 /* 自动去皮清零 */ HX711_Tare(10); } /** * brief 检查HX711是否准备好 * return 1: 准备好, 0: 未准备好 */ uint8_t HX711_IsReady(void) { return (HX711_DT_READ() GPIO_PIN_RESET) ? 1 : 0; } /** * brief 读取HX711原始数据 * return 24位AD值 */ uint32_t HX711_Read(void) { uint32_t data 0; uint8_t i; /* 等待HX711准备好超时保护 */ uint32_t timeout 200000; while(!HX711_IsReady() timeout--) { HX711_Delay_us(1); } if(timeout 0) { HX711_SCK_LOW(); // 确保SCK低电平避免进入掉电模式 return 0; } /* 关中断防止时序被打断导致位错位 */ __disable_irq(); /* 读取24位数据 - HX711规格书时序SCK上升沿后在高电平期间读DT */ data 0; for(i 0; i 24; i) { HX711_SCK_HIGH(); HX711_Delay_us(1); // 在SCK高电平期间读取DT数据 data data 1; if(HX711_DT_READ()) { data | 0x01; } HX711_SCK_LOW(); HX711_Delay_us(1); } /* 设置增益(额外的时钟脉冲) */ for(i 0; i g_gain; i) { HX711_SCK_HIGH(); HX711_Delay_us(1); HX711_SCK_LOW(); HX711_Delay_us(1); } /* 开中断 */ __enable_irq(); /* 将24位数据转换为有符号32位数据 */ if(data 0x800000) { data | 0xFF000000; } return data; } /** * brief 读取HX711平均值 * param times: 采样次数 * return 平均AD值 */ uint32_t HX711_ReadAverage(uint8_t times) { int64_t sum 0; // 使用int64_t防止溢出 uint8_t i; for(i 0; i times; i) { sum (int32_t)HX711_Read(); // 转换为有符号数 HAL_Delay(10); } return (uint32_t)(sum / times); } /** * brief 设置HX711增益 * param gain: 增益选择 * HX711_GAIN_128: 通道A增益128 * HX711_GAIN_32: 通道B增益32 * HX711_GAIN_64: 通道A增益64 */ void HX711_SetGain(uint8_t gain) { g_gain gain; HX711_Read(); // 读取一次以应用新的增益设置 } /** * brief 去皮(设置零点) * param times: 采样次数 */ void HX711_Tare(uint8_t times) { int64_t sum 0; uint8_t i; /* 丢弃前2次预热读数等待ADC内部稳定 */ for(i 0; i 2; i) { HX711_Read(); HAL_Delay(10); } for(i 0; i times; i) { sum (int32_t)HX711_Read(); HAL_Delay(10); } g_offset (int32_t)(sum / times); } /** * brief 获取重量值 * return 重量值(单位由比例系数决定) */ int32_t HX711_GetWeight(void) { #define HX711_SAMPLE_NUM 5 int32_t buf[HX711_SAMPLE_NUM]; int32_t tmp; uint8_t i, j; int64_t sum 0; float weight; /* 采样5次 */ for(i 0; i HX711_SAMPLE_NUM; i) { buf[i] (int32_t)HX711_Read(); HAL_Delay(10); } /* 冒泡排序升序 */ for(i 0; i HX711_SAMPLE_NUM - 1; i) { for(j 0; j HX711_SAMPLE_NUM - 1 - i; j) { if(buf[j] buf[j 1]) { tmp buf[j]; buf[j] buf[j 1]; buf[j 1] tmp; } } } /* 去掉最大值和最小值取中间3次均值 */ for(i 1; i HX711_SAMPLE_NUM - 1; i) { sum buf[i]; } /* 重量计算(均值 - 零点值) / 比例系数 */ weight (float)((int32_t)(sum / (HX711_SAMPLE_NUM - 2)) - g_offset) / g_scale; /* 小于0视为空载噪声返回0 */ if(weight 0.0f) { return 0; } return (int32_t)weight; #undef HX711_SAMPLE_NUM } /** * brief 设置比例系数 * param scale: 比例系数(AD值/重量单位) * note 需要通过校准获得此值 * 例如: 放置100g砂码读取AD差值为1000则scale 1000/100 10 * 注意如果数值为负说明传感器接线反了可传入负值校正 */ void HX711_SetScale(float scale) { if(scale 0.0f) scale 1.0f; // 防止除零错误 g_scale scale; } /** * brief 设置零点偏移 * param offset: 零点偏移值 */ void HX711_SetOffset(int32_t offset) { g_offset offset; } /** * brief HX711进入掉电模式 */ void HX711_PowerDown(void) { HX711_SCK_LOW(); HX711_SCK_HIGH(); HAL_Delay(1); } /** * brief HX711退出掉电模式 */ void HX711_PowerUp(void) { HX711_SCK_LOW(); }#ifndef __HX711_H #define __HX711_H #include main.h /* HX711引脚定义 */ #define HX711_DT_PORT GPIOA #define HX711_DT_PIN GPIO_PIN_3 #define HX711_SCK_PORT GPIOA #define HX711_SCK_PIN GPIO_PIN_4 /* HX711控制宏 */ #define HX711_SCK_HIGH() HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_SET) #define HX711_SCK_LOW() HAL_GPIO_WritePin(HX711_SCK_PORT, HX711_SCK_PIN, GPIO_PIN_RESET) #define HX711_DT_READ() HAL_GPIO_ReadPin(HX711_DT_PORT, HX711_DT_PIN) /* HX711增益选择 */ #define HX711_GAIN_128 1 // 通道A增益128 #define HX711_GAIN_32 2 // 通道B增益32 #define HX711_GAIN_64 3 // 通道A增益64 /* 函数声明 */ void HX711_Init(void); uint8_t HX711_IsReady(void); uint32_t HX711_Read(void); uint32_t HX711_ReadAverage(uint8_t times); void HX711_SetGain(uint8_t gain); void HX711_Tare(uint8_t times); int32_t HX711_GetWeight(void); void HX711_SetScale(float scale); void HX711_SetOffset(int32_t offset); void HX711_PowerDown(void); void HX711_PowerUp(void); #endif /* __HX711_H */