// // Created by cfif on 02.12.2025. // #include "stdint.h" #include // Константы #define ADC_MAX 4095.0f // 12-битный АЦП #define R1 20000.0f // Сопротивление делителя напряжения #define TABLE_START_TEMP (-40) #define TABLE_END_TEMP 105 #define TABLE_SIZE 42 // Структура для хранения табличных данных typedef struct { int temp_c; // Температура (°C) float r_nom; // Номинальное сопротивление (Ω) float r_min; // Минимальное сопротивление (Ω) float r_max; // Максимальное сопротивление (Ω) } ntc_table_entry; // Таблица из документа static const ntc_table_entry ntc_table[] = { {-40, 101.0f, 95.63f, 106.3f}, {-35, 72.60f, 68.95f, 76.26f}, {-30, 52.72f, 50.20f, 55.25f}, {-25, 38.66f, 36.91f, 40.42f}, {-20, 28.62f, 27.39f, 29.85f}, {-15, 21.39f, 20.51f, 22.26f}, {-10, 16.12f, 15.50f, 16.74f}, {-5, 12.26f, 11.81f, 12.71f}, {-4, 11.62f, 11.20f, 12.04f}, {-3, 11.01f, 10.62f, 11.41f}, {-2, 10.44f, 10.08f, 10.81f}, {-1, 9.907f, 9.563f, 10.25f}, {0, 9.399f, 9.077f, 9.722f}, {1, 8.924f, 8.621f, 9.227f}, {2, 8.473f, 8.189f, 8.757f}, {3, 8.048f, 7.781f, 8.315f}, {4, 7.646f, 7.396f, 7.897f}, {5, 7.267f, 7.032f, 7.502f}, {6, 6.909f, 6.688f, 7.130f}, {7, 6.570f, 6.363f, 6.778f}, {8, 6.250f, 6.055f, 6.445f}, {9, 5.947f, 5.764f, 6.131f}, {10, 5.661f, 5.489f, 5.833f}, {15, 4.441f, 4.315f, 4.568f}, {20, 3.512f, 3.418f, 3.606f}, {25, 2.795f, 2.726f, 2.865f}, {30, 2.239f, 2.179f, 2.299f}, {35, 1.806f, 1.754f, 1.858f}, {40, 1.464f, 1.420f, 1.509f}, {45, 1.195f, 1.157f, 1.233f}, {50, 0.980f, 0.947f, 1.014f}, {55, 0.809f, 0.780f, 0.837f}, {60, 0.670f, 0.646f, 0.695f}, {65, 0.559f, 0.538f, 0.581f}, {70, 0.468f, 0.450f, 0.487f}, {75, 0.394f, 0.378f, 0.410f}, {80, 0.333f, 0.319f, 0.347f}, {85, 0.283f, 0.271f, 0.296f}, {90, 0.241f, 0.230f, 0.252f}, {95, 0.207f, 0.197f, 0.216f}, {100, 0.178f, 0.169f, 0.186f}, {105, 0.153f, 0.146f, 0.161f} }; // Функция расчёта сопротивления NTC из значения АЦП static float calculate_resistance(uint16_t adc_value) { if (adc_value == 0 || adc_value >= (uint16_t) ADC_MAX) { return 0.0f; } // Формула делителя напряжения: R_ntc = R1 * (ADC_MAX / adc_value - 1) // float R_ntc = R1 * (ADC_MAX / (float)adc_value - 1.0f); float R_ntc = R1 * (float) adc_value / (ADC_MAX - (float) adc_value); return R_ntc; } // Бинарный поиск в таблице static int find_interval_index(float resistance) { int left = 0; int right = TABLE_SIZE - 1; // Проверка границ if (resistance >= ntc_table[0].r_nom) return 0; if (resistance <= ntc_table[right].r_nom) return right - 1; // Бинарный поиск while (left <= right) { int mid = left + (right - left) / 2; if (mid < TABLE_SIZE - 1 && resistance <= ntc_table[mid].r_nom && resistance >= ntc_table[mid + 1].r_nom) { return mid; } if (resistance > ntc_table[mid].r_nom) { right = mid - 1; } else { left = mid + 1; } } return -1; // Не найден } // Интерполяция с использованием уравнения Стейнхарта-Харта между точками static float interpolate_steinhart(float resistance, int index) { // Берем две соседние точки из таблицы float t1 = (float) ntc_table[index].temp_c + 273.15f; // в Кельвинах float t2 = (float) ntc_table[index + 1].temp_c + 273.15f; float r1 = ntc_table[index].r_nom; float r2 = ntc_table[index + 1].r_nom; // Вычисляем коэффициент B для интервала float B = logf(r1 / r2) / (1.0f / t1 - 1.0f / t2); // Используем уравнение Стейнхарта-Харта для вычисления температуры float steinhart = logf(resistance / r1) / B + 1.0f / t1; float temp_k = 1.0f / steinhart; return temp_k - 273.15f; // Конвертация в °C } // Линейная интерполяция в логарифмическом масштабе static float interpolate_log_linear(float resistance, int index) { float t1 = (float) ntc_table[index].temp_c; float t2 = (float) ntc_table[index + 1].temp_c; float r1 = ntc_table[index].r_nom; float r2 = ntc_table[index + 1].r_nom; float log_r1 = logf(r1); float log_r2 = logf(r2); float log_r = logf(resistance); return t1 + (t2 - t1) * (log_r - log_r1) / (log_r2 - log_r1); } // Основная функция для получения температуры float get_temperature_from_adc_AAS_920(uint16_t adc_value, int use_steinhart) { float resistance = calculate_resistance(adc_value); if (resistance <= 0.0f) { return -273.15f; // Ошибка } int index = find_interval_index(resistance); if (index < 0 || index >= TABLE_SIZE - 1) { // Вне диапазона таблицы if (resistance >= ntc_table[0].r_nom) return TABLE_START_TEMP; if (resistance <= ntc_table[TABLE_SIZE - 1].r_nom) return TABLE_END_TEMP; return -273.15f; // Ошибка } if (use_steinhart) { return interpolate_steinhart(resistance, index); } else { return interpolate_log_linear(resistance, index); } } // Предварительно вычисленная таблица для быстрого доступа typedef struct { uint16_t adc_value; // Значение АЦП int16_t temp_c; // Температура в °C * 10 (для фиксированной точки) } adc_temp_lookup; static adc_temp_lookup fast_lookup[256]; // Таблица на 256 значений static void init_fast_lookup_table(void) { // Создаем таблицу для быстрого преобразования АЦП->температура for (int i = 0; i < 256; i++) { uint16_t adc = i * 16; // Для 12-битного АЦП (0-4095) float temp = get_temperature_from_adc_AAS_920(adc, 0); fast_lookup[i].adc_value = adc; fast_lookup[i].temp_c = (int16_t) (temp * 10.0f); // Храним с точностью 0.1°C } } int16_t get_temperature_fast_AAS_920(uint16_t adc_value) { // Простой поиск в таблице с линейной интерполяцией uint8_t index = adc_value >> 4; // Делим на 16 if (index >= 255) return fast_lookup[255].temp_c; uint16_t adc1 = fast_lookup[index].adc_value; uint16_t adc2 = fast_lookup[index + 1].adc_value; int16_t temp1 = fast_lookup[index].temp_c; int16_t temp2 = fast_lookup[index + 1].temp_c; // Линейная интерполяция return temp1 + ((temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1); } // Константы для датчика #define R25 20000.0f // Сопротивление при 25°C #define B 3930.0f // Коэффициент B25/50 #define T25 298.15f // 25°C в Кельвинах // Функция расчёта температуры из сопротивления static float calculate_temperature(float resistance) { if (resistance <= 0) return -273.15f; // Абсолютный ноль // Расчёт по уравнению Стейнхарта-Харта float t_kelvin = 1.0f / (1.0f / T25 + (1.0f / B) * logf(resistance / R25)); return t_kelvin - 273.15f; } // Прямой расчёт температуры из значения АЦП float calculate_temperature_direct_AAS_920(uint16_t adc_value) { float resistance = calculate_resistance(adc_value); return calculate_temperature(resistance); } // сигнал АЦП, (R резистора / R термистора), B термистора, t термистора, разрешение АЦП static float NTC_computeRR(float analog, float baseDiv, uint16_t BB, uint8_t t, uint8_t res) { if (analog <= 0 || isnan(analog)) return INFINITY; analog = baseDiv / ((float) ((1 << res) - 1) / analog - 1.0f); analog = (logf(analog) / (float)BB) + 1.0f / ((float)t + 273.15f); return (1.0f / analog - 273.15f); } // сигнал АЦП, R резистора, B термистора, t термистора, R термистора, разрешение АЦП float NTC_compute_AAS_920(float analog, uint32_t R, uint16_t BB, uint8_t t, uint32_t Rt, uint8_t res) { return NTC_computeRR(analog, (float) R / (float)Rt, BB, t, res); } void zz_AAS_920() { NTC_compute_AAS_920(0, R25, B, 25, (uint32_t)R25, 12); }