#include "Arduino.h" #include "HermitCrab.h" #include "NTC_10K.h" #include "Config.h" const float resistance[] = { 3360850.37, // -40°C 1973470.32, // -35°C 1179560.43, // -30°C 718858.73, // -25°C 445267.47, // -20°C 281046.96, // -15°C 180321.36, // -10°C 117081.11, // -5°C 77147.90, // 0°C 51471.97, // 5°C 34838.43, // 10°C 23847.63, // 15°C 16594.38, // 20°C 12307.39, // 21°C 11739.87, // 22°C 11203.64, // 23°C 10696.86, // 24°C 10217.84, // 25°C 9527.52, // 26°C 9076.66, // 27°C 8656.02, // 28°C 8263.81, // 29°C 7897.84, // 30°C 5868.86, // 35°C 4383.72, // 40°C 3315.12, // 45°C 2527.73, // 50°C 1942.15, // 55°C 1505.11, // 60°C 1174.71, // 65°C 926.23, // 70°C 735.99, // 75°C 588.91, // 80°C 474.43, // 85°C 384.48, // 90°C 313.88, // 95°C 258.87, // 100°C 215.64, // 105°C 181.10, // 110°C 153.01, // 115°C 129.77, // 120°C 110.27, // 125°C 94.03, // 130°C 80.13, // 135°C 68.18, // 140°C 57.99, // 145°C 49.30 // 150°C }; const int16_t temp_C[] = { -40, -35, -30, -25, -20, -15, -10, -5, 0, 5, 10, 15, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 115, 120, 125, 130, 135, 140, 145, 150 }; NTC_10K ntc; void NTC_10K::setup(bool bNegativePolarity) { m_bNegativePolarity = bNegativePolarity; _vRef = 3.3f; _RESO = 4095; m_nTemp = -9999; m_fTemp = -9999.0; m_fLastTemp = 0.0f; pinMode(PIN_NTC, INPUT); // Set PIN_NTC as input analogReadResolution(12); // Set ADC resolution to 12 bits (0-4095) analogSetAttenuation(ADC_11db); // Set attenuation for full-scale 3.3V } /** * @brief Reads NTC sensor, calculates temperature via interpolation, * and applies an Exponential Moving Average (EMA) filter. * * History: * - 2026-04-16: Refactored from Simple Moving Average (SMA) to EMA with float buffer. * - 2026-04-16: Optimized interpolation to reduce CPU cycles. * - 2026-04-16: Implemented aggressive alpha (0.01) to mitigate 5°C PWM noise. * - 2026-04-16: Upgraded lastTemp to float (m_fLastTemp) for total precision. */ void NTC_10K::readSensor() { float Vin; float currentInstantTemp; // High-precision intermediate // 1. Hardware Acquisition int adcValue = constrain(analogRead(PIN_NTC), 1, 4094); // 2. Voltage and Resistance Calculation Vin = (float)adcValue * _vRef / _RESO; float r; if (m_bNegativePolarity) { r = (Vin / (_vRef - Vin)) * rRef; } else { r = ((_vRef - Vin) / Vin) * rRef; } // 3. Table Lookup int i = 0; int tableSize = sizeof(resistance) / sizeof(resistance[0]); while (i < tableSize - 1 && resistance[i] > r) { i++; } // 4. Interpolation Logic (Precise Float Math) if (i == 0 || i == tableSize - 1) { // Use last known good float value if out of bounds currentInstantTemp = (m_fLastTemp != 0.0f) ? m_fLastTemp : 0.0f; } else { // Faster Slope Calculation: y = y0 + m * (r - r0) float m = (temp_C[i] - temp_C[i - 1]) / (resistance[i] - resistance[i - 1]); currentInstantTemp = temp_C[i - 1] + m * (r - resistance[i - 1]); } // 5. Exponential Moving Average (EMA) Filtering if (m_fTemp < -5000.0f) { m_fTemp = currentInstantTemp; } else { // 0.01f Alpha: The 5°C PWM noise now only moves the buffer by 0.05°C per hit. const float alpha = 0.05f; m_fTemp = (currentInstantTemp * alpha) + (m_fTemp * (1.0f - alpha)); } // 6. Update Outputs m_fLastTemp = currentInstantTemp; // Store precise float for next loop m_nTemp = (int16_t)roundf(m_fTemp * 10.0f); // Final integer output (e.g., 25.34 -> 253) }