高精度电子秤系统,包含硬件设计、软件算法、滤波校准和用户界面。
一、系统总体设计
1.1 系统架构
称重传感器 → 信号调理 → 高精度ADC → STM32 → 显示/通信
(应变片) (仪表放大) (24位Σ-Δ) (数据处理) (LCD/蓝牙)
1.2 技术指标
| 参数 | 规格 | 说明 |
|---|---|---|
| 量程 | 0-5kg | 可扩展 |
| 精度 | 0.01g | 分辨率 |
| 线性度 | ±0.02%FS | 满量程 |
| 采样率 | 10-80Hz | 可调 |
| 显示 | 0.96寸OLED | 显示重量/单位 |
| 接口 | 蓝牙/USB | 数据传输 |
| 供电 | 锂电池/Type-C | 低功耗设计 |
二、硬件电路设计
2.1 核心元件选型
| 模块 | 推荐型号 | 关键参数 | 接口 |
|---|---|---|---|
| 主控MCU | STM32F103C8T6 | 72MHz, 64KB Flash, 20KB RAM | - |
| 称重传感器 | BLR-1KG/5KG | 电阻应变式, 灵敏度2mV/V | 惠斯通电桥 |
| ADC芯片 | HX711 | 24位Σ-Δ, 可编程增益 | GPIO |
| 备选ADC | ADS1232 | 24位, 内置PGA, SPI接口 | SPI |
| 运放 | INA128 | 仪表放大器, 高共模抑制比 | - |
| 显示屏 | SSD1306 0.96" | 128×64 OLED, I2C接口 | I2C |
| 蓝牙模块 | HC-05/HM-10 | 蓝牙4.0/5.0, 透传模式 | UART |
| 电池管理 | TP4056 | 锂电池充电管理 | - |
| LDO | AMS1117-3.3 | 3.3V稳压, 1A输出 | - |
2.2 电路设计
2.2.1 信号调理电路
c
/* 应变片信号调理电路设计 */
// 惠斯通电桥配置:
// R1,R2,R3,R4 = 350Ω (应变片电阻)
// 激励电压: 5V
// 输出电压: Vout = (ΔR/R) * Vex * GF
// 仪表放大器(INA128)配置:
// 增益公式: G = 1 + (50kΩ / Rg)
// 选择Rg = 200Ω → G ≈ 251倍
// 输出电压范围: 0-3.3V
// 低通滤波设计:
// 截止频率: 10Hz (抑制高频噪声)
// RC滤波器: R=10kΩ, C=1.6μF
2.2.2 HX711连接电路
c
/* HX711与STM32连接 */
// HX711引脚定义:
#define HX711_DOUT PA0 // 数据输出
#define HX711_SCK PA1 // 时钟输入
#define HX711_AVDD 5V // 模拟电源
#define HX711_DVDD 3.3V // 数字电源
// 外部参考电压:2.5V基准
#define REF_VOLTAGE 2.5
// 增益选择:
// 通道A: 增益128 (用于差分输入)
// 通道B: 增益32
2.3 PCB设计要点
布局原则:
1. 模拟/数字分区:传感器信号在模拟区
2. 地线分离:模拟地和数字地单点连接
3. 电源滤波:每个IC的电源引脚加0.1μF退耦电容
4. 信号屏蔽:模拟信号线用地线包围
走线规范:
- 应变片信号线:差分走线,等长等距
- 电源线宽:≥0.5mm (1A电流)
- 晶振:靠近MCU,包地处理
三、软件设计与算法
3.1 主程序框架
c
#include "stm32f1xx_hal.h"
#include <stdio.h>
#include <math.h>
#include <string.h>
// 系统定义
#define SAMPLE_RATE 10 // 采样率10Hz
#define FILTER_WINDOW 20 // 滤波窗口大小
#define CALIBRATION_POINTS 3 // 校准点数量
// 全局变量
typedef struct {
float weight_g; // 当前重量(g)
float offset; // 零点偏移
float scale; // 比例系数
float tare_value; // 去皮值
uint8_t unit; // 单位: 0=g, 1=kg, 2=lb, 3=oz
uint8_t mode; // 模式: 0=称重, 1=计数, 2=百分比
uint8_t stability; // 稳定标志
float temperature; // 温度补偿
} ScaleData;
ScaleData scale_data = {0};
float raw_data_buffer[FILTER_WINDOW] = {0};
uint8_t buffer_index = 0;
// 按键定义
#define KEY_TARE PA4
#define KEY_UNIT PA5
#define KEY_MODE PA6
#define KEY_CAL PA7
// 主函数
int main(void) {
// HAL库初始化
HAL_Init();
// 系统时钟配置
SystemClock_Config();
// 外设初始化
MX_GPIO_Init();
MX_I2C1_Init();
MX_USART1_UART_Init();
MX_ADC1_Init();
// 模块初始化
hx711_init();
oled_init();
key_init();
buzzer_init();
// 加载校准参数
load_calibration();
// 开机自检
self_test();
// 主循环
while (1) {
// 1. 读取原始数据
float raw_data = hx711_read_avg(5);
// 2. 数字滤波
float filtered = digital_filter(raw_data);
// 3. 计算重量
scale_data.weight_g = calculate_weight(filtered);
// 4. 稳定性检测
scale_data.stability = check_stability();
// 5. 温度补偿
if (need_temperature_compensation()) {
temperature_compensation();
}
// 6. 更新显示
update_display();
// 7. 处理按键
process_keys();
// 8. 数据上传(如需要)
upload_data();
HAL_Delay(1000 / SAMPLE_RATE);
}
}
3.2 HX711驱动程序
c
/* HX711驱动程序 */
#include "hx711.h"
// HX711初始化
void hx711_init(void) {
GPIO_InitTypeDef GPIO_InitStruct = {0};
// 使能GPIO时钟
__HAL_RCC_GPIOA_CLK_ENABLE();
// 配置SCK为输出
GPIO_InitStruct.Pin = GPIO_PIN_1;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 配置DOUT为输入
GPIO_InitStruct.Pin = GPIO_PIN_0;
GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
GPIO_InitStruct.Pull = GPIO_PULLUP;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);
// 初始状态
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
// 等待HX711就绪
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET);
// 设置增益和通道
hx711_set_gain(HX711_GAIN_A_128);
}
// 设置增益
void hx711_set_gain(uint8_t gain) {
hx711_gain = gain;
// 通过发送脉冲设置增益
// 增益128: 1个脉冲
// 增益64: 3个脉冲
// 增益32: 2个脉冲
for (uint8_t i = 0; i < gain; i++) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
}
}
// 读取单个原始值
int32_t hx711_read(void) {
uint32_t data = 0;
// 等待数据就绪
while (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET);
// 读取24位数据
for (uint8_t i = 0; i < 24; i++) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
data <<= 1;
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
if (HAL_GPIO_ReadPin(GPIOA, GPIO_PIN_0) == GPIO_PIN_SET) {
data++;
}
}
// 设置通道和增益
for (uint8_t i = 0; i < hx711_gain; i++) {
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(1);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
}
// 符号扩展
if (data & 0x800000) {
data |= 0xFF000000;
}
return (int32_t)data;
}
// 读取多次平均值
float hx711_read_avg(uint8_t times) {
int64_t sum = 0;
for (uint8_t i = 0; i < times; i++) {
sum += hx711_read();
HAL_Delay(1);
}
return (float)sum / times;
}
// 去皮(清零)
void hx711_tare(uint8_t times) {
float avg = hx711_read_avg(times);
scale_data.offset = avg;
scale_data.tare_value = 0;
// 保存零点
save_offset(avg);
}
// 校准
void hx711_calibrate(float known_weight) {
// 1. 清零
hx711_tare(10);
// 2. 放置已知重量
HAL_Delay(2000);
// 3. 读取重量
float raw_data = hx711_read_avg(20);
// 4. 计算比例系数
scale_data.scale = (raw_data - scale_data.offset) / known_weight;
// 5. 保存校准系数
save_calibration(scale_data.scale);
}
3.3 数字滤波算法
c
/* 数字滤波算法 */
#include "filter.h"
// 移动平均滤波
float moving_average_filter(float new_value) {
static float buffer[FILTER_WINDOW] = {0};
static uint8_t index = 0;
static float sum = 0;
// 减去最旧的值
sum -= buffer[index];
// 加入新值
buffer[index] = new_value;
sum += new_value;
// 更新索引
index = (index + 1) % FILTER_WINDOW;
return sum / FILTER_WINDOW;
}
// 中值滤波
float median_filter(float new_value) {
static float buffer[5] = {0};
static uint8_t index = 0;
// 更新缓冲区
buffer[index] = new_value;
index = (index + 1) % 5;
// 复制数组并排序
float temp[5];
memcpy(temp, buffer, sizeof(temp));
// 冒泡排序
for (uint8_t i = 0; i < 4; i++) {
for (uint8_t j = 0; j < 4 - i; j++) {
if (temp[j] > temp[j + 1]) {
float tmp = temp[j];
temp[j] = temp[j + 1];
temp[j + 1] = tmp;
}
}
}
// 返回中值
return temp[2];
}
// 卡尔曼滤波
typedef struct {
float q; // 过程噪声协方差
float r; // 测量噪声协方差
float x; // 状态估计值
float p; // 估计误差协方差
float k; // 卡尔曼增益
} KalmanFilter;
float kalman_filter(KalmanFilter *kf, float measurement) {
// 预测
kf->p = kf->p + kf->q;
// 更新
kf->k = kf->p / (kf->p + kf->r);
kf->x = kf->x + kf->k * (measurement - kf->x);
kf->p = (1 - kf->k) * kf->p;
return kf->x;
}
// 复合滤波(移动平均 + 中值)
float composite_filter(float new_value) {
// 中值滤波去除脉冲干扰
float median = median_filter(new_value);
// 移动平均平滑
return moving_average_filter(median);
}
3.4 重量计算与校准
c
/* 重量计算与校准算法 */
#include "calibration.h"
// 计算重量
float calculate_weight(float raw_data) {
// 减去零点偏移
float weight = raw_data - scale_data.offset;
// 减去去皮值
weight -= scale_data.tare_value;
// 应用比例系数
weight = weight / scale_data.scale;
// 非线性补偿
weight = nonlinear_compensation(weight);
// 温度补偿
weight = temperature_compensation(weight);
return weight;
}
// 非线性补偿(二次曲线拟合)
float nonlinear_compensation(float weight) {
// 补偿系数,通过多点校准得到
static const float a = 1.0f; // 一次项系数
static const float b = 0.0001f; // 二次项系数
static const float c = 0.0f; // 常数项
return a * weight + b * weight * weight + c;
}
// 温度补偿
float temperature_compensation(float weight) {
// 读取温度传感器
float temp = read_temperature();
// 温度补偿系数
float tc_scale = 1.0f + 0.0001f * (temp - 25.0f); // 25℃为参考温度
float tc_offset = 0.1f * (temp - 25.0f);
return weight * tc_scale + tc_offset;
}
// 稳定性检测
uint8_t check_stability(void) {
static float last_values[5] = {0};
static uint8_t index = 0;
// 更新历史数据
last_values[index] = scale_data.weight_g;
index = (index + 1) % 5;
// 计算标准差
float sum = 0, mean = 0, variance = 0;
for (uint8_t i = 0; i < 5; i++) {
sum += last_values[i];
}
mean = sum / 5;
for (uint8_t i = 0; i < 5; i++) {
float diff = last_values[i] - mean;
variance += diff * diff;
}
variance /= 5;
float std_dev = sqrt(variance);
// 判断是否稳定
if (std_dev < 0.01f) { // 标准差小于0.01g
return 1; // 稳定
} else {
return 0; // 不稳定
}
}
// 多点校准
void multi_point_calibration(float weights[], uint8_t num_points) {
float raw_data[num_points];
// 读取各校准点的原始数据
for (uint8_t i = 0; i < num_points; i++) {
// 显示提示
display_message("Place %dg", (int)weights[i]);
HAL_Delay(3000);
// 读取数据
raw_data[i] = hx711_read_avg(20);
}
// 最小二乘法拟合线性方程
float sum_x = 0, sum_y = 0, sum_xy = 0, sum_xx = 0;
for (uint8_t i = 0; i < num_points; i++) {
sum_x += weights[i];
sum_y += raw_data[i];
sum_xy += weights[i] * raw_data[i];
sum_xx += weights[i] * weights[i];
}
// 计算斜率和截距
float n = (float)num_points;
float denominator = n * sum_xx - sum_x * sum_x;
if (fabs(denominator) > 0.0001f) {
scale_data.scale = (n * sum_xy - sum_x * sum_y) / denominator;
scale_data.offset = (sum_y - scale_data.scale * sum_x) / n;
}
// 保存校准参数
save_calibration_params(scale_data.offset, scale_data.scale);
}
3.5 OLED显示驱动
c
/* OLED显示驱动程序 */
#include "ssd1306.h"
#include "fonts.h"
// 显示初始化
void oled_init(void) {
// I2C初始化
uint8_t init_cmds[] = {
0xAE, 0x20, 0x10, 0xB0, 0xC8, 0x00, 0x10, 0x40, 0x81, 0xFF,
0xA1, 0xA6, 0xA8, 0x3F, 0xA4, 0xD3, 0x00, 0xD5, 0xF0, 0xD9,
0x22, 0xDA, 0x12, 0xDB, 0x20, 0x8D, 0x14, 0xAF
};
for (uint8_t i = 0; i < sizeof(init_cmds); i++) {
i2c_write_cmd(init_cmds[i]);
}
oled_clear();
}
// 更新显示
void update_display(void) {
char buffer[20];
// 清屏
oled_clear();
// 显示重量
float display_weight = convert_unit(scale_data.weight_g, scale_data.unit);
if (scale_data.mode == 0) { // 称重模式
// 大字体显示重量
snprintf(buffer, sizeof(buffer), "%.2f", display_weight);
oled_put_string(20, 0, buffer, Font_16x26);
// 显示单位
const char *unit_str[] = {"g", "kg", "lb", "oz"};
oled_put_string(90, 0, unit_str[scale_data.unit], Font_11x18);
// 显示稳定性
if (scale_data.stability) {
oled_put_string(0, 4, "Stable", Font_6x8);
} else {
oled_put_string(0, 4, "Moving", Font_6x8);
}
// 显示去皮状态
if (fabs(scale_data.tare_value) > 0.001f) {
oled_put_string(70, 4, "TARE", Font_6x8);
}
} else if (scale_data.mode == 1) { // 计数模式
// 计算数量
float unit_weight = get_unit_weight();
uint32_t count = 0;
if (unit_weight > 0.001f) {
count = (uint32_t)(scale_data.weight_g / unit_weight + 0.5f);
}
// 显示数量
snprintf(buffer, sizeof(buffer), "Count: %lu", count);
oled_put_string(0, 0, buffer, Font_11x18);
snprintf(buffer, sizeof(buffer), "%.2f g/each", unit_weight);
oled_put_string(0, 2, buffer, Font_6x8);
}
// 显示电池电量
display_battery_level();
// 显示单位指示
display_unit_indicator();
}
// 单位转换
float convert_unit(float weight_g, uint8_t unit) {
switch (unit) {
case 0: // g
return weight_g;
case 1: // kg
return weight_g / 1000.0f;
case 2: // lb
return weight_g * 0.00220462f;
case 3: // oz
return weight_g * 0.035274f;
default:
return weight_g;
}
}
四、校准程序
4.1 自动校准程序
c
/* 电子秤校准程序 */
#include "calibration.h"
// 校准状态
typedef enum {
CAL_STATE_IDLE, // 空闲
CAL_STATE_ZERO, // 零点校准
CAL_STATE_WEIGHT, // 重量校准
CAL_STATE_DONE // 完成
} CalibrationState;
CalibrationState cal_state = CAL_STATE_IDLE;
float cal_target_weight = 0;
// 校准处理
void calibration_process(void) {
static uint32_t cal_timer = 0;
static uint8_t cal_step = 0;
switch (cal_state) {
case CAL_STATE_IDLE:
// 等待开始
break;
case CAL_STATE_ZERO:
// 显示提示
oled_put_string(0, 0, "Remove all weight", Font_6x8);
oled_put_string(0, 2, "Press TARE to zero", Font_6x8);
// 检查按键
if (key_pressed(KEY_TARE)) {
hx711_tare(20);
cal_state = CAL_STATE_WEIGHT;
cal_step = 0;
cal_timer = HAL_GetTick();
}
break;
case CAL_STATE_WEIGHT:
if (cal_step == 0) {
// 提示放置100g砝码
oled_put_string(0, 0, "Place 100g weight", Font_6x8);
oled_put_string(0, 2, "Then press TARE", Font_6x8);
if (key_pressed(KEY_TARE)) {
cal_target_weight = 100.0f;
cal_step = 1;
cal_timer = HAL_GetTick();
}
} else if (cal_step == 1) {
// 等待稳定
if (HAL_GetTick() - cal_timer > 3000) {
float raw_data = hx711_read_avg(20);
scale_data.scale = (raw_data - scale_data.offset) / cal_target_weight;
cal_step = 2;
}
} else if (cal_step == 2) {
// 提示放置500g砝码
oled_put_string(0, 0, "Place 500g weight", Font_6x8);
oled_put_string(0, 2, "Then press TARE", Font_6x8);
if (key_pressed(KEY_TARE)) {
cal_target_weight = 500.0f;
cal_step = 3;
cal_timer = HAL_GetTick();
}
} else if (cal_step == 3) {
// 等待稳定
if (HAL_GetTick() - cal_timer > 3000) {
float raw_data = hx711_read_avg(20);
float new_scale = (raw_data - scale_data.offset) / cal_target_weight;
// 取平均值
scale_data.scale = (scale_data.scale + new_scale) / 2.0f;
cal_step = 4;
}
} else if (cal_step == 4) {
// 保存校准参数
save_calibration_params(scale_data.offset, scale_data.scale);
cal_state = CAL_STATE_DONE;
}
break;
case CAL_STATE_DONE:
oled_put_string(0, 0, "Calibration Done!", Font_6x8);
oled_put_string(0, 2, "Scale: %.6f", Font_6x8, scale_data.scale);
HAL_Delay(2000);
cal_state = CAL_STATE_IDLE;
break;
}
}
// 进入校准模式
void enter_calibration_mode(void) {
cal_state = CAL_STATE_ZERO;
cal_step = 0;
}
参考代码 基于STM32的高精度电子秤 www.youwenfan.com/contentcst/133703.html
五、高级功能
5.1 计数功能
c
/* 计数功能实现 */
#include "counting.h"
// 计数模式数据结构
typedef struct {
float unit_weight; // 单件重量
uint32_t quantity; // 数量
uint8_t sample_count; // 取样数量
float samples[10]; // 取样重量
} CountingData;
CountingData count_data = {0};
// 进入计数模式
void enter_counting_mode(void) {
count_data.unit_weight = 0;
count_data.quantity = 0;
count_data.sample_count = 0;
scale_data.mode = 1; // 计数模式
}
// 取样
void take_sample(void) {
if (count_data.sample_count < 10 && scale_data.stability) {
count_data.samples[count_data.sample_count] = scale_data.weight_g;
count_data.sample_count++;
// 更新单件重量
if (count_data.sample_count > 0) {
float sum = 0;
for (uint8_t i = 0; i < count_data.sample_count; i++) {
sum += count_data.samples[i];
}
count_data.unit_weight = sum / count_data.sample_count;
}
}
}
// 计算数量
uint32_t calculate_quantity(void) {
if (count_data.unit_weight > 0.001f) {
return (uint32_t)(scale_data.weight_g / count_data.unit_weight + 0.5f);
}
return 0;
}
// 清除取样
void clear_samples(void) {
count_data.sample_count = 0;
count_data.unit_weight = 0;
}
5.2 数据记录与统计
c
/* 数据记录功能 */
#include "data_log.h"
#define MAX_RECORDS 100
// 称重记录
typedef struct {
uint32_t timestamp; // 时间戳
float weight; // 重量
uint8_t unit; // 单位
uint8_t stable; // 是否稳定
} WeightRecord;
WeightRecord records[MAX_RECORDS];
uint8_t record_index = 0;
uint32_t total_count = 0;
float total_weight = 0;
float max_weight = 0;
float min_weight = 999999;
// 添加记录
void add_record(float weight, uint8_t stable) {
if (record_index >= MAX_RECORDS) {
record_index = 0;
}
records[record_index].timestamp = HAL_GetTick();
records[record_index].weight = weight;
records[record_index].unit = scale_data.unit;
records[record_index].stable = stable;
// 更新统计
total_count++;
total_weight += weight;
if (weight > max_weight) max_weight = weight;
if (weight < min_weight) min_weight = weight;
record_index++;
}
// 获取统计信息
void get_statistics(float *avg, float *max, float *min) {
if (total_count > 0) {
*avg = total_weight / total_count;
} else {
*avg = 0;
}
*max = max_weight;
*min = min_weight;
}
// 保存到EEPROM
void save_records(void) {
// 使用STM32内部EEPROM
uint32_t address = 0x08080000; // EEPROM起始地址
for (uint8_t i = 0; i < MAX_RECORDS; i++) {
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, records[i].timestamp);
address += 4;
uint32_t weight_int = *(uint32_t*)&records[i].weight;
HAL_FLASH_Program(FLASH_TYPEPROGRAM_WORD, address, weight_int);
address += 4;
}
}
六、蓝牙通信
6.1 蓝牙数据传输
c
/* 蓝牙通信协议 */
#include "bluetooth.h"
// 蓝牙命令定义
typedef enum {
CMD_GET_WEIGHT = 0x01, // 获取重量
CMD_SET_TARE = 0x02, // 去皮
CMD_SET_UNIT = 0x03, // 设置单位
CMD_CALIBRATE = 0x04, // 校准
CMD_GET_STAT = 0x05, // 获取统计
CMD_START_LOG = 0x06, // 开始记录
CMD_STOP_LOG = 0x07, // 停止记录
} BluetoothCommand;
// 蓝牙数据处理
void bluetooth_process(uint8_t *data, uint16_t length) {
if (length < 1) return;
uint8_t cmd = data[0];
switch (cmd) {
case CMD_GET_WEIGHT:
send_weight_data();
break;
case CMD_SET_TARE:
hx711_tare(10);
send_ack(CMD_SET_TARE, 1);
break;
case CMD_SET_UNIT:
if (length >= 2) {
scale_data.unit = data[1] & 0x03;
send_ack(CMD_SET_UNIT, 1);
}
break;
case CMD_CALIBRATE:
if (length >= 5) {
float weight = *(float*)&data[1];
calibrate_with_weight(weight);
send_ack(CMD_CALIBRATE, 1);
}
break;
case CMD_GET_STAT:
send_statistics();
break;
}
}
// 发送重量数据
void send_weight_data(void) {
uint8_t buffer[20];
uint8_t index = 0;
buffer[index++] = 0xAA; // 帧头
buffer[index++] = 0x55;
buffer[index++] = 0x01; // 数据类型:重量
// 重量值
float weight = convert_unit(scale_data.weight_g, scale_data.unit);
uint8_t *weight_ptr = (uint8_t*)&weight;
for (uint8_t i = 0; i < 4; i++) {
buffer[index++] = weight_ptr[i];
}
// 单位
buffer[index++] = scale_data.unit;
// 稳定性
buffer[index++] = scale_data.stability;
// 校验和
uint8_t checksum = 0;
for (uint8_t i = 0; i < index; i++) {
checksum ^= buffer[i];
}
buffer[index++] = checksum;
// 发送
HAL_UART_Transmit(&huart1, buffer, index, 100);
}
七、电源管理
7.1 低功耗设计
c
/* 电源管理系统 */
#include "power.h"
// 电源状态
typedef enum {
PWR_STATE_ACTIVE, // 活跃状态
PWR_STATE_IDLE, // 空闲状态
PWR_STATE_SLEEP, // 睡眠状态
PWR_STATE_STANDBY // 待机状态
} PowerState;
PowerState pwr_state = PWR_STATE_ACTIVE;
uint32_t last_activity = 0;
float battery_voltage = 0;
uint8_t battery_level = 100;
// 电源管理任务
void power_management_task(void) {
uint32_t current_time = HAL_GetTick();
// 检测无操作时间
if (current_time - last_activity > 30000) { // 30秒无操作
if (pwr_state == PWR_STATE_ACTIVE) {
enter_idle_state();
}
}
if (current_time - last_activity > 60000) { // 60秒无操作
if (pwr_state == PWR_STATE_IDLE) {
enter_sleep_state();
}
}
// 电池检测
static uint32_t last_battery_check = 0;
if (current_time - last_battery_check > 10000) { // 10秒检测一次
battery_voltage = read_battery_voltage();
battery_level = calculate_battery_level(battery_voltage);
last_battery_check = current_time;
// 低电量警告
if (battery_level < 10) {
low_battery_warning();
}
}
}
// 进入空闲状态
void enter_idle_state(void) {
pwr_state = PWR_STATE_IDLE;
// 降低显示屏亮度
oled_set_contrast(1);
// 降低采样率
SAMPLE_RATE = 2; // 2Hz
}
// 进入睡眠状态
void enter_sleep_state(void) {
pwr_state = PWR_STATE_SLEEP;
// 关闭显示屏
oled_display_off();
// 关闭蓝牙
bluetooth_sleep();
// 进入STOP模式
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);
}
// 唤醒处理
void wakeup_handler(void) {
if (pwr_state == PWR_STATE_SLEEP) {
// 恢复时钟
SystemClock_Config();
// 唤醒外设
oled_display_on();
oled_set_contrast(255);
bluetooth_wakeup();
// 恢复采样率
SAMPLE_RATE = 10;
pwr_state = PWR_STATE_ACTIVE;
}
last_activity = HAL_GetTick();
}
八、测试与校准程序
8.1 系统自检
c
/* 系统自检程序 */
void system_self_test(void) {
printf("=== Electronic Scale Self Test ===\n");
// 1. 内存测试
printf("1. Memory Test...\n");
if (memory_test()) {
printf(" ✓ RAM Test Passed\n");
} else {
printf(" ✗ RAM Test Failed\n");
}
// 2. 外设测试
printf("2. Peripheral Test...\n");
// 测试HX711
int32_t raw = hx711_read();
printf(" HX711 Raw: %ld\n", raw);
if (raw != 0) {
printf(" ✓ HX711 Test Passed\n");
} else {
printf(" ✗ HX711 Test Failed\n");
}
// 测试OLED
oled_test_pattern();
printf(" OLED Test Pattern Displayed\n");
// 3. 传感器测试
printf("3. Sensor Test...\n");
// 读取10次
float readings[10];
for (uint8_t i = 0; i < 10; i++) {
readings[i] = hx711_read_avg(3);
printf(" Reading %d: %.0f\n", i, readings[i]);
HAL_Delay(100);
}
// 计算噪声
float avg = 0, std = 0;
for (uint8_t i = 0; i < 10; i++) {
avg += readings[i];
}
avg /= 10;
for (uint8_t i = 0; i < 10; i++) {
float diff = readings[i] - avg;
std += diff * diff;
}
std = sqrt(std / 9);
printf(" Average: %.2f, Std Dev: %.2f\n", avg, std);
if (std < 100) { // 噪声小于100个计数
printf(" ✓ Sensor Noise Test Passed\n");
} else {
printf(" ✗ Sensor Noise Too High\n");
}
// 4. 按键测试
printf("4. Button Test...\n");
printf(" Please press all buttons...\n");
uint8_t buttons_pressed = 0;
uint32_t start_time = HAL_GetTick();
while (HAL_GetTick() - start_time < 10000) { // 10秒测试时间
for (uint8_t i = 0; i < 4; i++) {
if (key_pressed(i)) {
buttons_pressed |= (1 << i);
printf(" Button %d pressed\n", i);
HAL_Delay(200);
}
}
if (buttons_pressed == 0x0F) { // 所有按键都按下过
printf(" ✓ All Buttons Tested\n");
break;
}
}
if (buttons_pressed != 0x0F) {
printf(" ✗ Button Test Incomplete\n");
}
printf("=== Self Test Complete ===\n");
}
九、完整工程结构
HighPrecisionScale/
├── Core/
│ ├── Src/
│ │ ├── main.c # 主程序
│ │ ├── stm32f1xx_it.c # 中断服务
│ │ └── system_stm32f1xx.c
│ └── Inc/
│ └── main.h
├── Drivers/
│ ├── CMSIS/
│ ├── STM32F1xx_HAL_Driver/
│ └── BSP/
│ ├── hx711.c/.h # HX711驱动
│ ├── ssd1306.c/.h # OLED驱动
│ ├── key.c/.h # 按键驱动
│ └── buzzer.c/.h # 蜂鸣器驱动
├── Middlewares/
│ ├── Filter/
│ │ ├── moving_average.c/.h
│ │ ├── kalman_filter.c/.h
│ │ └── median_filter.c/.h
│ └── Algorithm/
│ ├── calibration.c/.h # 校准算法
│ ├── counting.c/.h # 计数算法
│ └── compensation.c/.h # 补偿算法
├── Application/
│ ├── display.c/.h # 显示管理
│ ├── bluetooth.c/.h # 蓝牙通信
│ ├── power.c/.h # 电源管理
│ └── data_log.c/.h # 数据记录
└── README.md