#include <SD.h>
#include <HX711_ADC.h>
#include <EEPROM.h>
#include <U8g2lib.h>
#include <SimpleKalmanFilter.h> // 引入卡尔曼滤波库
// 定义常量
const int REFRESH_INTERVAL_MS = 250; // OLED 显示屏刷新间隔,单位:毫秒
const float DEFAULT_CALIBRATION_VALUE = 88.88; // 默认校准值
const int FILTER_SIZE = 5; // 中值滤波窗口大小
const float SAMPLING_INTERVAL = 0.1; // 采样间隔,单位:秒
U8G2_SSD1306_128X64_NONAME_F_HW_I2C u8g2(U8G2_R0, /* reset=*/ U8X8_PIN_NONE);
float i;
float time;
float time2;
float a; // 声明变量 a
unsigned long lastRefreshTime = 0; // 声明变量 lastRefreshTime
const int HX711_dout = 5; // 接 HX711 dout
const int HX711_sck = 4; // 接 HX711 sck
HX711_ADC LoadCell(HX711_dout, HX711_sck);
const int calVal_calVal_eepromAdress = 0;
SimpleKalmanFilter kalmanFilter(2, 2, 0.1); // 初始化卡尔曼滤波器
float measurementBuffer[FILTER_SIZE]; // 用于存储测量值的缓冲区
int bufferIndex = 0; // 缓冲区索引
unsigned long lastSamplingTime = 0; // 记录上次采样的时间
/**
* @brief 初始化 OLED 显示屏并显示准备信息和各模块状态
*/
void initDisplayAndShowStatus() {
u8g2.begin();
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(0, 16, "准备中...");
// 检查 SD 卡是否可用
if (SD.begin()) {
u8g2.drawStr(0, 32, "SD 卡: 正常");
} else {
u8g2.drawStr(0, 32, "SD 卡: 异常");
}
// 检查 HX711 传感器是否初始化成功
boolean hx711Initialized = false;
LoadCell.begin();
unsigned long stabilizingtime = 2000; // tare 精度可通过增加稳定时间来提高
boolean _tare = true; // 如果不想在下一阶段执行 tare,将其设置为 false
LoadCell.start(stabilizingtime, _tare); // 去掉 if 语句,因为 start 函数返回 void
if (LoadCell.getTareTimeoutFlag()) {
u8g2.drawStr(0, 48, "HX711: 异常");
} else {
u8g2.drawStr(0, 48, "HX711: 正常");
}
u8g2.sendBuffer();
}
/**
* @brief 处理 HX711 传感器的初始化和校准
* @param calibrationValue 校准值
*/
void initAndCalibrateHX711(float calibrationValue) {
// 已在 initDisplayAndShowStatus 中进行了部分初始化,此处继续完成校准等操作
if (LoadCell.getTareTimeoutFlag()) {
Serial.println("Timeout, check MCU>HX711 wiring and pin designations");
return;
} else {
LoadCell.setCalFactor(calibrationValue); // 设置校准因子(浮点数)
Serial.println("Startup is complete");
}
}
/**
* @brief 刷新 OLED 显示屏的内容
*/
void refreshDisplay() {
u8g2.clearBuffer();
u8g2.setFont(u8g2_font_ncenB14_tr);
u8g2.drawStr(0, 16, "当前推力:");
char str[10]; // 用于存储转换后的字符串
dtostrf(kalmanFilter.updateEstimate(i / 1000 * 9.8), 6, 2, str); // 将浮点数转换为字符串
u8g2.drawStr(80, 16, str); // 使用转换后的字符串
u8g2.drawStr(0, 32, "最大推力:");
dtostrf(a / 1000 * 9.8, 6, 2, str); // 将浮点数转换为字符串
u8g2.drawStr(80, 32, str); // 使用转换后的字符串
u8g2.sendBuffer();
}
/**
* @brief 处理数据采集和存储的主循环
*/
void mainLoop() {
static boolean newDataReady = false;
const int serialPrintInterval = 500; // 增加该值可降低串口打印活动频率
// 检查是否有新数据/开始下一次转换
if (LoadCell.update()) {
newDataReady = true;
}
// 获取数据集中的平滑值
if (newDataReady) {
i = LoadCell.getData();
// 卡尔曼滤波
float filteredValue = kalmanFilter.updateEstimate(i / 1000 * 9.8);
if (filteredValue > a) {
a = filteredValue;
}
Serial.print("当前推力:");
Serial.print(i);
Serial.print("g");
Serial.print(" ");
Serial.print("累计最大推力:");
Serial.print(a);
Serial.print("g");
Serial.print(" ");
Serial.print("累计最大 kg:");
Serial.print(a / 1000);
Serial.print("kg");
Serial.print(" ");
Serial.print("累计最大 N:");
Serial.print(a / 1000 * 9.8);
Serial.print("N");
Serial.print(" ");
Serial.print(time);
Serial.print(" ");
Serial.println(time2); // 打印数据方便调试
// 记录数据
unsigned long currentMillis = millis();
if (currentMillis - lastSamplingTime >= SAMPLING_INTERVAL * 1000) {
File file = SD.open("test.txt", FILE_WRITE);
if (file) {
file.print(i); // 数据输出
file.print(" ");
file.print(a); // 数据输出
file.print(" ");
file.print(a / 1000); // 单位转换 kg
file.print(" ");
file.print(a / 1000 * 9.8); // 单位转换 N
file.print(" ");
file.print(time); // 总共数据量用以计算时间
file.print(" ");
file.println(time2); // 时间输出
file.close();
lastSamplingTime = currentMillis;
} else {
digitalWrite(8, HIGH);
delay(150);
digitalWrite(8, LOW);
delay(150); // 检测 SD 卡是否丢失
}
}
}
// 处理复位键操作
if (digitalRead(3) == LOW) {
LoadCell.tareNoDelay();
}
// 处理置零状态
if (LoadCell.getTareStatus()) { // 置零设置
Serial.println("Tare complete");
digitalWrite(8, LOW);
a = 0.0;
} else {
digitalWrite(8, HIGH);
}
// 根据时间间隔刷新显示屏
unsigned long currentMillis = millis();
if (currentMillis - lastRefreshTime >= REFRESH_INTERVAL_MS) {
refreshDisplay();
lastRefreshTime = currentMillis;
}
}
void setup() {
Serial.begin(57600);
pinMode(3, INPUT_PULLUP); // 设置复位按键
pinMode(8, OUTPUT); // 设置蜂鸣器输出
initDisplayAndShowStatus();
float calibrationValue = DEFAULT_CALIBRATION_VALUE; // 读取校准值或使用默认值
initAndCalibrateHX711(calibrationValue);
File file = SD.open("test.txt", FILE_WRITE);
if (file) {
file.println(" ");
file.println(" ");
file.println("以上数据作废 ");
file.println("开始记录新数据:");
file.println("数据从左到右是 当前推力(g) 最大推力(g) 最大推力(kg) 最大推力(N) 数据量 时间");
file.close();
}
}
void loop() {
mainLoop();
}