diff --git a/README.md b/README.md index df34545..f95a8f0 100644 --- a/README.md +++ b/README.md @@ -50,7 +50,7 @@ W = 100 × (m1 - m0) / (m0 - m) ### Удержание кнопки (4-6 секунд) Автоматическое тарирование (обнуление весов) -### Удержание кнопки (8-10 секунд) +### Удержание кнопки (8+ секунд) Калибровка с эталонным грузом 100г ## Режим нагрева diff --git a/grunt_stand.ino b/grunt_stand.ino index 7bc0827..fc671b6 100644 --- a/grunt_stand.ino +++ b/grunt_stand.ino @@ -57,14 +57,13 @@ const unsigned long HEAT_DURATION = 900000; // 15 минут = 900000 мс bool heating_active = false; // Циклический нагрев -const unsigned long HEAT_ON_TIME = 30000; // 30 секунд нагрева -const unsigned long HEAT_OFF_TIME = 20000; // 20 секунд паузы +const unsigned long HEAT_ON_TIME = 20000; // 15 секунд нагрева +const unsigned long HEAT_OFF_TIME = 30000; // 30 секунд паузы unsigned long last_cycle_change = 0; // Время последнего переключения bool heat_cycle_on = false; // Текущее состояние цикла (вкл/выкл) -// Для постоянного расчета W с фильтрацией -float current_W = 0.0; // Текущее значение влажности (сырое) -float filtered_W = 0.0; // Отфильтрованное значение W для отображения +// Для расчета W (без фильтрации) +float current_W = 0.0; // Текущее значение влажности float max_W = 0.0; // Максимальное значение W за время нагрева unsigned long last_W_update = 0; const unsigned long W_UPDATE_INTERVAL = 500; // Обновлять W каждые 500 мс @@ -357,12 +356,23 @@ void loop() { // Обновляем W каждые W_UPDATE_INTERVAL мс if (millis() - last_W_update > W_UPDATE_INTERVAL) { - current_W = calculateW(); // Вычисляем сырое значение W - filtered_W = w_filter.update(current_W); // Фильтруем для отображения + current_W = calculateW(); // Вычисляем W напрямую (без фильтра) + + // DEBUG: выводим все значения для диагностики + Serial.print("m="); + Serial.print(m, 4); + Serial.print(" m1="); + Serial.print(m1, 4); + Serial.print(" m0="); + Serial.print(m0, 4); + Serial.print(" W="); + Serial.print(current_W, 4); + Serial.print(" max_W="); + Serial.println(max_W, 4); // Обновляем максимальное значение W - if (filtered_W > max_W) { - max_W = filtered_W; + if (current_W > max_W) { + max_W = current_W; } last_W_update = millis(); @@ -467,7 +477,7 @@ void updateDisplay() { heat_cycle_on = true; last_cycle_change = millis(); last_W_update = millis(); - w_filter.reset(); // Сбрасываем фильтр W при начале нагрева + // Фильтр W удалён - используем прямое значение max_W = 0.0; // Сбрасываем максимальное W digitalWrite(HEAT_PIN, HIGH); break; @@ -529,8 +539,8 @@ void handleButton() { // Тарирование 4-6 секунд performTaring(); } - else if (press_duration >= MIN_CAL_TIME && press_duration <= MAX_CAL_TIME) { - // Калибровка 8-10 секунд + else if (press_duration >= MIN_CAL_TIME) { + // Калибровка 8+ секунд performCalibration(); } else if (press_duration < 1000) { @@ -605,21 +615,38 @@ void displayHeating() { lcd.setCursor(0, 0); lcd.print(line1); - // Вторая строка: только максимальный W + // Вторая строка: масса (слева) и W (справа) char line2[17]; - char m_buf[6]; + char w_buf[6]; + char mass_buf[7]; // Форматируем максимальный W if (max_W >= 100) { - strcpy(m_buf, ">99"); + strcpy(w_buf, ">99"); } else { - dtostrf(max_W, 5, 1, m_buf); + dtostrf(max_W, 4, 1, w_buf); } - // Формат: "Wmax: XX.X%" - snprintf(line2, sizeof(line2), "W:%s%%", m_buf); + // Форматируем массу m0 (показываем когда индуктор выключен) + if (!heat_cycle_on) { + // Индуктор выключен - показываем текущую массу + if (m0 >= 100.0) { + strcpy(mass_buf, ">99g"); + } else if (m0 <= -10.0) { + strcpy(mass_buf, "<-9g"); + } else { + dtostrf(m0, 5, 2, mass_buf); + strcat(mass_buf, "g"); + } + // Формат: "XX.XXg W:XX.X%" + snprintf(line2, sizeof(line2), "%-8s %s%%", mass_buf, w_buf); + } else { + // Индуктор включен - показываем только W по центру + snprintf(line2, sizeof(line2), " * %s%%", w_buf); + } - printCentered(1, line2); + lcd.setCursor(0, 1); + lcd.print(line2); } void displayHeatingComplete() { @@ -683,7 +710,6 @@ void performTaring() { scale.tare(); median_filter.reset(); display_filter.setImmediate(0.0); - w_filter.reset(); // Если был режим нагрева - выходим из него if (heating_active) { @@ -708,6 +734,10 @@ void performCalibration() { } void calibrationProcedure() { + Serial.println("=== CALIBRATION START ==="); + Serial.print("Old calibration_factor: "); + Serial.println(calibration_factor, 6); + lcd.clear(); lcd.setCursor(0, 0); lcd.print("Calibration "); @@ -717,9 +747,11 @@ void calibrationProcedure() { digitalWrite(HEAT_PIN, LOW); heating_active = false; heat_cycle_on = false; + Serial.println("Heating was active, turned off"); } // Шаг 1: Clear platform + Serial.println("Step 1: Waiting for empty platform..."); lcd.setCursor(0, 1); lcd.print("Clear platform "); @@ -733,14 +765,22 @@ void calibrationProcedure() { delay(100); // Сообщение о тарировании + Serial.println("Step 2: Taring..."); lcd.setCursor(0, 1); lcd.print("Taring... "); + // ВАЖНО: Устанавливаем scale=1.0 ПЕРЕД тарированием, + // чтобы получать сырые значения и избежать зацикливания калибровки + scale.set_scale(1.0); + Serial.println("Scale set to 1.0 for raw measurements"); + // Тарируем весы (устанавливаем ноль) delay(500); // Даем время на стабилизацию scale.tare(); + Serial.println("Tare complete"); // Шаг 2: Set 100g + Serial.println("Step 3: Waiting for 100g weight..."); lcd.setCursor(0, 1); lcd.print("Set 100g "); @@ -754,29 +794,47 @@ void calibrationProcedure() { delay(100); // Сообщение о сохранении результатов 100г + Serial.println("Step 4: Measuring 100g raw values (15 samples)..."); lcd.setCursor(0, 1); lcd.print("saving results "); - // Измеряем среднее значение 100г (15 измерений) + // Измеряем среднее СЫРОЕ значение 100г (15 измерений) + // scale=1.0, поэтому get_units() возвращает сырые значения delay(1000); // Даем время на стабилизацию float weight_sum = 0; for (int i = 0; i < 15; i++) { - float reading = scale.get_units(1); + float reading = scale.get_units(1); // При scale=1.0 это сырое значение weight_sum += reading; + Serial.print(" Raw sample "); + Serial.print(i + 1); + Serial.print(": "); + Serial.println(reading, 2); delay(100); } float weight_average = weight_sum / 15; + Serial.print("Raw weight sum: "); + Serial.println(weight_sum, 2); + Serial.print("Raw weight average: "); + Serial.println(weight_average, 2); + Serial.print("CALIBRATION_WEIGHT: "); + Serial.println(CALIBRATION_WEIGHT, 2); + // Вычисляем коэффициент калибровки - // После tare() шкала обнулена, поэтому weight_average - это разница веса напрямую - // Проверяем, что груз действительно поставлен (вес больше 10 единиц) - if (abs(weight_average) > 10) { + // scale=1.0 и tare() выполнен, поэтому weight_average - это СЫРОЕ значение АЦП + // new_factor = raw_value / known_weight + // Проверяем, что груз поставлен (сырое значение больше 1000 единиц АЦП) + if (abs(weight_average) > 1000) { calibration_factor = weight_average / CALIBRATION_WEIGHT; + Serial.print("New calibration_factor: "); + Serial.println(calibration_factor, 6); + // Проверяем, что коэффициент положительный if (calibration_factor <= 0) { // Ошибка: отрицательный или нулевой коэффициент - неправильная калибровка // (датчик подключен неправильно или вес убрали вместо добавления) + Serial.println("ERROR: calibration_factor <= 0!"); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Calibration "); @@ -786,11 +844,14 @@ void calibrationProcedure() { } else { // Сохраняем коэффициент в EEPROM saveCalibrationToEEPROM(calibration_factor); + Serial.println("Calibration factor saved to EEPROM"); // Устанавливаем новый коэффициент scale.set_scale(calibration_factor); + Serial.println("Scale updated with new factor"); // Сообщение об успешной калибровке + Serial.println("=== CALIBRATION OK ==="); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Calibration "); @@ -800,6 +861,11 @@ void calibrationProcedure() { } } else { // Сообщение о неудачной калибровке (груз не поставлен или слишком легкий) + Serial.print("ERROR: abs(raw_weight_average) = "); + Serial.print(abs(weight_average), 2); + Serial.println(" <= 1000, raw ADC value too low!"); + Serial.println("Check: is 100g weight placed? Is HX711 connected?"); + Serial.println("=== CALIBRATION FAILED ==="); lcd.clear(); lcd.setCursor(0, 0); lcd.print("Calibration "); @@ -813,4 +879,5 @@ void calibrationProcedure() { // Возврат в режим READY current_state = STATE_READY; need_display_clear = true; + Serial.println("Returned to READY state"); } \ No newline at end of file