This commit is contained in:
cfif 2026-03-30 12:32:14 +03:00
parent 35f07b60ab
commit ef6183ec0d
3 changed files with 185 additions and 291 deletions

View File

@ -10,23 +10,24 @@
// Константы // Константы
#define ADC_MAX 4095.0f // 12-битный АЦП #define ADC_MAX 4095.0f // 12-битный АЦП
// Типы термисторов // Параметры Steinhart-Hart для термистора
typedef enum { #define koef_A 0.001741624168166423
NTC_TYPE_1 = 0, // Первая таблица (100950 Ом при -40°C) #define koef_B 0.00017003940268680147
NTC_TYPE_2 = 1 // Вторая таблица (101000 Ом при -40°C) #define koef_C 0.0000004890545443703666
} eNTC_Type;
// Параметры Steinhart-Hart для термисторов #define TABLE_SIZE_LOOKUP 1024
typedef struct {
float A; // Типы таблиц NTC
float B; typedef enum {
float C; NTC_TYPE_KST45 = 0, // Таблица из документа KST45 (25°C = 3kΩ)
} SteinhartParams; NTC_TYPE_INCAR = 1, // Таблица из документа Incar (25°C = 2795Ω)
NTC_TYPE_CUSTOM = 2 // Пользовательская таблица
} eNtcTableType;
// Структура для хранения табличных данных // Структура для хранения табличных данных
typedef struct { typedef struct {
int temp_c; // Температура (°C) int16_t temp_c; // Температура (°C)
float r_nom; // Номинальное сопротивление (Ω) float r_nom; // Номинальное сопротивление (Ω)
} ntc_table_entry; } ntc_table_entry;
typedef enum { typedef enum {
@ -39,20 +40,22 @@ typedef enum {
typedef struct { typedef struct {
uint16_t adc_value; // Значение АЦП uint16_t adc_value; // Значение АЦП
int16_t temp_c; // Температура в °C * 10 (для фиксированной точки) int16_t temp_c; // Температура в °C * 10 (для фиксированной точки)
float resistance; // Сопротивление термистора в Омах
} adc_temp_lookup; } adc_temp_lookup;
// Функции инициализации // Функции инициализации и конфигурации
void init_ntc(eNTC_Type ntc_type); void init_fast_lookup_table(eAlg use_alg, eNtcTableType table_type, float custom_r1);
void set_r1(float r1_value); // Функция для установки сопротивления делителя void set_custom_ntc_table(const ntc_table_entry* table, uint16_t size, float r1);
void init_fast_lookup_table(eAlg use_alg); void select_ntc_table(eNtcTableType table_type, float custom_r1);
// Основные функции // Основные функции
float get_temperature_from_adc(uint16_t adc_value, eAlg alg); float get_temperature_from_adc(uint16_t adc_value, eAlg alg);
int16_t get_temperature_fast(uint16_t adc_value); int16_t get_temperature_fast(uint16_t adc_value);
float get_resistance_from_adc(uint16_t adc_value);
float get_resistance_fast(uint16_t adc_value);
// Функция для получения информации о текущем термисторе // Функции для работы с текущей таблицей
const char* get_ntc_name(void); eNtcTableType get_current_table_type(void);
uint16_t get_table_size(void); float get_current_r1(void);
float get_r1_value(void); // Функция для получения текущего R1
#endif //MDF_ADC_TEMP_KST45_14_2_H #endif //MDF_ADC_TEMP_KST45_14_2_H

View File

@ -1,133 +1,45 @@
#include <stdio.h> #include <stdio.h>
#include <stdint.h>
#include <time.h>
#include <string.h>
#include <stdlib.h>
#include "ADC_Temp.h" #include "ADC_Temp.h"
void print_table_comparison(void) {
printf("\n=== Сравнение таблиц термисторов ===\n\n");
printf("Тестирование %s:\n", get_ntc_name()); // value 0..4095 - Это диапазон АЦП, Нужно проверить крайние значения и смоделировать таблицы
printf("Сопротивление делителя R1: %.1f Ом\n", get_r1_value());
printf("Размер таблицы: %d точек\n\n", get_table_size());
printf("ADC\tСопротивление(Ом)\tLinear\tSteinhart\tFull\tFast\n");
printf("---------------------------------------------------------------\n");
// Тестируем разные значения АЦП extern adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP];
uint16_t test_adc[] = {500, 1000, 1500, 2000, 2500, 3000, 3500, 4000};
for (int i = 0; i < 8; i++) {
uint16_t adc = test_adc[i];
float resistance = get_r1_value() * adc / (4095.0f - adc);
float linear = get_temperature_from_adc(adc, ALG_LINEAR);
float steinhart = get_temperature_from_adc(adc, ALG_STEINHART);
float full = get_temperature_from_adc(adc, ALG_STEINHART_FULL);
float fast = get_temperature_fast(adc) / 10.0f;
printf("%d\t%.1f\t\t%.2f\t%.2f\t%.2f\t%.2f\n",
adc, resistance, linear, steinhart, full, fast);
}
}
void test_temperature_range(void) {
printf("\n=== Тестирование температурного диапазона ===\n\n");
printf("Примечание: Для точного тестирования необходимы\n");
printf("функции доступа к таблице термистора\n\n");
// Просто показываем несколько значений
uint16_t test_adc[] = {500, 1000, 1500, 2000, 2500, 3000, 3500, 4000};
printf("ADC\tРасчетная температура\n");
printf("------------------------\n");
for (int i = 0; i < 8; i++) {
uint16_t adc = test_adc[i];
float temp = get_temperature_from_adc(adc, ALG_STEINHART);
printf("%d\t%.2f°C\n", adc, temp);
}
}
void compare_both_ntc_types(void) {
printf("\n=== Сравнение двух типов термисторов ===\n\n");
printf("ADC\tNTC Type 1\tNTC Type 2\tРазница\n");
printf("----------------------------------------\n");
uint16_t test_adc[] = {500, 1000, 1500, 2000, 2500, 3000, 3500, 4000};
for (int i = 0; i < 8; i++) {
uint16_t adc = test_adc[i];
// Тестируем первый тип
init_ntc(NTC_TYPE_1);
init_fast_lookup_table(ALG_STEINHART);
float temp1 = get_temperature_from_adc(adc, ALG_STEINHART);
// Тестируем второй тип
init_ntc(NTC_TYPE_2);
init_fast_lookup_table(ALG_STEINHART);
float temp2 = get_temperature_from_adc(adc, ALG_STEINHART);
printf("%d\t%.2f°C\t\t%.2f°C\t\t%.2f°C\n",
adc, temp1, temp2, (temp2 - temp1));
}
}
int main() { int main() {
printf("=== Программа для работы с NTC термисторами ===\n");
printf("Автор: cfif\n");
printf("Дата: 04.12.2025\n\n");
// Выбираем первый тип термистора для тестирования init_fast_lookup_table(ALG_STEINHART, NTC_TYPE_INCAR, 3300.0f);
printf("Инициализация термистора Type 1...\n");
init_ntc(NTC_TYPE_1);
init_fast_lookup_table(ALG_STEINHART);
// Выводим информацию // for (int i = 0; i < TABLE_SIZE_LOOKUP; ++i) {
printf("Текущий термистор: %s\n", get_ntc_name()); // printf("{%u,%d}, \n", fast_lookup[i].adc_value, fast_lookup[i].temp_c);
printf("Сопротивление делителя R1: %.1f Ом\n", get_r1_value()); // }
printf("Количество точек в таблице: %d\n\n", get_table_size());
// Тестируем различные значения АЦП
print_table_comparison();
// Тестируем температурный диапазон
test_temperature_range();
// Сравниваем оба типа термисторов //uint16_t value = 4095 / 2; // Должно быть 25 градусов. Это середина диапазона АЦП
compare_both_ntc_types(); uint16_t value = 1980;
// Пример работы с конкретным значением АЦП // float T_ALG_LINEAR = get_temperature_from_adc(value, ALG_LINEAR);
printf("\n=== Пример работы с конкретным значением АЦП ===\n"); //float T_ALG_STEINHART = get_temperature_from_adc(value, ALG_STEINHART);
uint16_t test_value = 1980; float T_ALG_STEINHART = get_temperature_fast(value);
float T_ALG_STEINHART_1 = get_resistance_fast(value);
init_ntc(NTC_TYPE_2); // float T_ALG_STEINHART_FULL = get_temperature_from_adc(value, ALG_STEINHART_FULL);
init_fast_lookup_table(ALG_STEINHART); // float T_FAST = get_temperature_fast(value);
// float T_ATERLUX = calc_temperature(value);
float T_ALG_LINEAR = get_temperature_from_adc(test_value, ALG_LINEAR); // printf("T_ALG_LINEAR = %f \n", T_ALG_LINEAR);
float T_ALG_STEINHART = get_temperature_from_adc(test_value, ALG_STEINHART); printf("T_ALG_STEINHART = %f %f\n", T_ALG_STEINHART, T_ALG_STEINHART_1);
float T_ALG_STEINHART_FULL = get_temperature_from_adc(test_value, ALG_STEINHART_FULL); // printf("T_ALG_STEINHART_FULL = %f \n", T_ALG_STEINHART_FULL);
float T_FAST = get_temperature_fast(test_value) / 10.0f;
printf("Для ADC = %d:\n", test_value); // printf("T_FAST = %f \n", T_FAST / 10);
printf(" Линейная интерполяция: %.2f°C\n", T_ALG_LINEAR); // printf("T_ATERLUX = %f \n", T_ATERLUX / 10);
printf(" Steinhart-Hart: %.2f°C\n", T_ALG_STEINHART);
printf(" Steinhart-Hart полная: %.2f°C\n", T_ALG_STEINHART_FULL);
printf(" Быстрый метод: %.2f°C\n", T_FAST);
// Пример изменения сопротивления делителя
printf("\n=== Пример изменения сопротивления делителя ===\n");
printf("Текущий R1: %.1f Ом\n", get_r1_value());
set_r1(4700.0f); // Изменяем на 4.7 кОм
init_fast_lookup_table(ALG_STEINHART);
float new_temp = get_temperature_from_adc(test_value, ALG_STEINHART);
printf("После изменения R1 на %.1f Ом, температура: %.2f°C\n",
get_r1_value(), new_temp);
set_r1(3300.0f); // Возвращаем обратно
init_fast_lookup_table(ALG_STEINHART);
float original_temp = get_temperature_from_adc(test_value, ALG_STEINHART);
printf("После возврата R1 на %.1f Ом, температура: %.2f°C\n",
get_r1_value(), original_temp);
printf("\n=== Программа завершена ===\n");
return 0; return 0;
} }

View File

@ -1,12 +1,13 @@
// //
// Created by cfif on 02.12.2025. // Created by cfif on 02.12.2025.
// //
#include "ADC_Temp.h" #include "ADC_Temp.h"
#include <math.h> #include <math.h>
#include <string.h> #include <string.h>
// Таблица 1: Первый термистор (100950 Ом при -40°C) // Таблица из документа KST45 (25°C = 3000Ω)
static const ntc_table_entry ntc_table_type1[] = { static const ntc_table_entry ntc_table_kst45[] = {
{-40, 100950.0f}, {-40, 100950.0f},
{-35, 72777.0f}, {-35, 72777.0f},
{-30, 53100.0f}, {-30, 53100.0f},
@ -35,13 +36,8 @@ static const ntc_table_entry ntc_table_type1[] = {
{85, 321.7f} {85, 321.7f}
}; };
#define TABLE1_SIZE (sizeof(ntc_table_type1) / sizeof(ntc_table_entry)) // Таблица из документа Incar (25°C ≈ 2795Ω)
#define TABLE1_START_TEMP -40 static const ntc_table_entry ntc_table_incar[] = {
#define TABLE1_END_TEMP 85
#define TABLE1_R1 3300.0f // Сопротивление делителя для первого термистора
// Таблица 2: Второй термистор (101000 Ом при -40°C) - KST-45
static const ntc_table_entry ntc_table_type2[] = {
{-40, 101000.0f}, {-40, 101000.0f},
{-35, 72600.0f}, {-35, 72600.0f},
{-30, 52720.0f}, {-30, 52720.0f},
@ -54,7 +50,7 @@ static const ntc_table_entry ntc_table_type2[] = {
{-3, 11010.0f}, {-3, 11010.0f},
{-2, 10440.0f}, {-2, 10440.0f},
{-1, 9907.0f}, {-1, 9907.0f},
{0, 9399.0f}, {0, 9399.0f},
{1, 8924.0f}, {1, 8924.0f},
{2, 8473.0f}, {2, 8473.0f},
{3, 8048.0f}, {3, 8048.0f},
@ -82,105 +78,29 @@ static const ntc_table_entry ntc_table_type2[] = {
{85, 283.0f} {85, 283.0f}
}; };
#define TABLE2_SIZE (sizeof(ntc_table_type2) / sizeof(ntc_table_entry)) // Глобальные переменные для текущей конфигурации
#define TABLE2_START_TEMP -40 static const ntc_table_entry* current_ntc_table = ntc_table_kst45;
#define TABLE2_END_TEMP 85 static uint16_t current_table_size = sizeof(ntc_table_kst45) / sizeof(ntc_table_entry);
#define TABLE2_R1 3300.0f // Сопротивление делителя для второго термистора (можно изменить при необходимости) static float current_r1 = 3300.0f; // Сопротивление делителя по умолчанию
static eNtcTableType current_table_type = NTC_TYPE_KST45;
// Параметры Steinhart-Hart для различных термисторов // Глобальная таблица для быстрого доступа
static const SteinhartParams steinhart_type1 = { adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP];
0.001752169f, // A
0.000171234f, // B
0.000000512345f // C (рассчитаны приблизительно)
};
static const SteinhartParams steinhart_type2 = {
0.001741624168166423f,
0.00017003940268680147f,
0.0000004890545443703666f
};
// Структура для хранения информации о текущем термисторе
typedef struct {
eNTC_Type type;
const ntc_table_entry* table;
uint16_t table_size;
int start_temp;
int end_temp;
float r1; // Сопротивление делителя для данного термистора
SteinhartParams params;
const char* name;
} NTC_Config;
// Текущая активная конфигурация
static NTC_Config active_ntc;
// Быстрая таблица поиска
#define FAST_TABLE_SIZE 512
static adc_temp_lookup fast_lookup[FAST_TABLE_SIZE];
// Инициализация с выбором типа термистора
void init_ntc(eNTC_Type ntc_type) {
switch(ntc_type) {
case NTC_TYPE_1:
active_ntc.type = NTC_TYPE_1;
active_ntc.table = ntc_table_type1;
active_ntc.table_size = TABLE1_SIZE;
active_ntc.start_temp = TABLE1_START_TEMP;
active_ntc.end_temp = TABLE1_END_TEMP;
active_ntc.r1 = TABLE1_R1;
active_ntc.params = steinhart_type1;
active_ntc.name = "NTC Type 1 (100950 Ohm @ -40C)";
break;
case NTC_TYPE_2:
active_ntc.type = NTC_TYPE_2;
active_ntc.table = ntc_table_type2;
active_ntc.table_size = TABLE2_SIZE;
active_ntc.start_temp = TABLE2_START_TEMP;
active_ntc.end_temp = TABLE2_END_TEMP;
active_ntc.r1 = TABLE2_R1;
active_ntc.params = steinhart_type2;
active_ntc.name = "NTC Type 2 (101000 Ohm @ -40C) - KST-45";
break;
}
}
// Функция для установки сопротивления делителя
void set_r1(float r1_value) {
if (r1_value > 0.0f) {
active_ntc.r1 = r1_value;
}
}
// Функция для получения текущего R1
float get_r1_value(void) {
return active_ntc.r1;
}
// Функция расчёта сопротивления NTC из значения АЦП // Функция расчёта сопротивления NTC из значения АЦП
static float calculate_resistance(uint16_t adc_value) { static float calculate_resistance(uint16_t adc_value, float r1) {
if (adc_value == 0) { if (adc_value == 0 || adc_value >= (uint16_t) ADC_MAX) {
return active_ntc.table[0].r_nom * 1.1f; // Экстраполяция return 0.0f;
} }
if (adc_value >= (uint16_t) ADC_MAX) { // Формула делителя напряжения: R_ntc = R1 * adc_value / (ADC_MAX - adc_value)
return active_ntc.table[active_ntc.table_size - 1].r_nom * 0.9f; // Экстраполяция float R_ntc = r1 * (float) adc_value / (ADC_MAX - (float) adc_value);
}
float R_ntc = active_ntc.r1 * (float)adc_value / (ADC_MAX - (float)adc_value);
// Ограничиваем физически возможные значения
if (R_ntc < 10.0f) R_ntc = 10.0f;
if (R_ntc > 200000.0f) R_ntc = 200000.0f;
return R_ntc; return R_ntc;
} }
// Бинарный поиск в активной таблице // Бинарный поиск в таблице
static int find_interval_index(float resistance) { static int find_interval_index(float resistance, const ntc_table_entry* table, uint16_t size) {
int left = 0; int left = 0;
int right = active_ntc.table_size - 1; int right = size - 1;
const ntc_table_entry* table = active_ntc.table;
// Проверка границ // Проверка границ
if (resistance >= table[0].r_nom) return 0; if (resistance >= table[0].r_nom) return 0;
@ -190,7 +110,7 @@ static int find_interval_index(float resistance) {
while (left <= right) { while (left <= right) {
int mid = left + (right - left) / 2; int mid = left + (right - left) / 2;
if (mid < active_ntc.table_size - 1 && if (mid < size - 1 &&
resistance <= table[mid].r_nom && resistance <= table[mid].r_nom &&
resistance >= table[mid + 1].r_nom) { resistance >= table[mid + 1].r_nom) {
return mid; return mid;
@ -207,10 +127,8 @@ static int find_interval_index(float resistance) {
} }
// Интерполяция с использованием уравнения Стейнхарта-Харта между точками // Интерполяция с использованием уравнения Стейнхарта-Харта между точками
static float interpolate_steinhart(float resistance, int index) { static float interpolate_steinhart(float resistance, int index, const ntc_table_entry* table) {
const ntc_table_entry* table = active_ntc.table; // Берем две соседние точки из таблицы
// Берем две соседние точки из активной таблицы
float t1 = (float) table[index].temp_c + 273.15f; // в Кельвинах float t1 = (float) table[index].temp_c + 273.15f; // в Кельвинах
float t2 = (float) table[index + 1].temp_c + 273.15f; float t2 = (float) table[index + 1].temp_c + 273.15f;
float r1 = table[index].r_nom; float r1 = table[index].r_nom;
@ -227,9 +145,7 @@ static float interpolate_steinhart(float resistance, int index) {
} }
// Линейная интерполяция в логарифмическом масштабе // Линейная интерполяция в логарифмическом масштабе
static float interpolate_log_linear(float resistance, int index) { static float interpolate_log_linear(float resistance, int index, const ntc_table_entry* table) {
const ntc_table_entry* table = active_ntc.table;
float t1 = (float) table[index].temp_c; float t1 = (float) table[index].temp_c;
float t2 = (float) table[index + 1].temp_c; float t2 = (float) table[index + 1].temp_c;
float r1 = table[index].r_nom; float r1 = table[index].r_nom;
@ -242,28 +158,32 @@ static float interpolate_log_linear(float resistance, int index) {
return t1 + (t2 - t1) * (log_r - log_r1) / (log_r2 - log_r1); return t1 + (t2 - t1) * (log_r - log_r1) / (log_r2 - log_r1);
} }
// Полная версия Steinhart-Hart с коэффициентами для данного термистора // Более надежная версия с проверкой параметров
static float interpolate_steinhart_full(float resistance, int index) { static float interpolate_steinhart_full(float resistance, int index, const ntc_table_entry* table) {
// Проверка корректности входных данных // Проверка корректности входных данных
if (resistance <= 0.0f) { if (resistance <= 0.0f) {
return -273.15f; return -273.15f; // Абсолютный ноль при некорректном сопротивлении
} }
// Для повышения точности можно использовать таблицу как справочную,
// но основное вычисление - по уравнению с коэффициентами
double L = logf(resistance); double L = logf(resistance);
double L3 = L * L * L; double L3 = L * L * L;
double inv_T = active_ntc.params.A + active_ntc.params.B * L + active_ntc.params.C * L3; double inv_T = koef_A + koef_B * L + koef_C * L3;
// Проверка на физическую реализуемость // Проверка на физическую реализуемость
if (inv_T <= 0.0f || inv_T > 1.0f) { if (inv_T <= 0.0f || inv_T > 1.0f) {
return (float)active_ntc.table[index].temp_c; // В случае ошибки возвращаем температуру из таблицы по индексу
return (float)table[index].temp_c;
} }
double temp_K = 1.0f / inv_T; double temp_K = 1.0f / inv_T;
// Проверка диапазона // Дополнительная проверка диапазона
if (temp_K < (active_ntc.start_temp + 273.15f) || if (temp_K < 223.15f || temp_K > 423.15f) {
temp_K > (active_ntc.end_temp + 273.15f)) { // Возвращаем значение из таблицы как запасной вариант
return (float)active_ntc.table[index].temp_c; return (float)table[index].temp_c;
} }
return (float)(temp_K - 273.15f); return (float)(temp_K - 273.15f);
@ -271,77 +191,136 @@ static float interpolate_steinhart_full(float resistance, int index) {
// Основная функция для получения температуры // Основная функция для получения температуры
float get_temperature_from_adc(uint16_t adc_value, eAlg use_alg) { float get_temperature_from_adc(uint16_t adc_value, eAlg use_alg) {
float resistance = calculate_resistance(adc_value); float resistance = calculate_resistance(adc_value, current_r1);
if (resistance <= 0.0f) { if (resistance <= 0.0f) {
return -273.15f; return -273.15f; // Ошибка
} }
int index = find_interval_index(resistance); int index = find_interval_index(resistance, current_ntc_table, current_table_size);
if (index < 0 || index >= active_ntc.table_size - 1) { if (index < 0 || index >= current_table_size - 1) {
// Вне диапазона таблицы // Вне диапазона таблицы
const ntc_table_entry* table = active_ntc.table; if (resistance >= current_ntc_table[0].r_nom) return current_ntc_table[0].temp_c;
if (resistance >= table[0].r_nom) return active_ntc.start_temp; if (resistance <= current_ntc_table[current_table_size - 1].r_nom) return current_ntc_table[current_table_size - 1].temp_c;
if (resistance <= table[active_ntc.table_size - 1].r_nom) return active_ntc.end_temp; return -273.15f; // Ошибка
return -273.15f;
} }
if (use_alg == ALG_STEINHART) { if (use_alg == ALG_STEINHART) {
return interpolate_steinhart(resistance, index); return interpolate_steinhart(resistance, index, current_ntc_table);
} else if (use_alg == ALG_STEINHART_FULL) { } else if (use_alg == ALG_STEINHART_FULL) {
return interpolate_steinhart_full(resistance, index); return interpolate_steinhart_full(resistance, index, current_ntc_table);
} else { } else {
return interpolate_log_linear(resistance, index); return interpolate_log_linear(resistance, index, current_ntc_table);
} }
} }
// Инициализация быстрой таблицы поиска // Функция для получения сопротивления по значению АЦП
void init_fast_lookup_table(eAlg use_alg) { float get_resistance_from_adc(uint16_t adc_value) {
uint16_t step = (uint16_t)(ADC_MAX / (FAST_TABLE_SIZE - 1)); return calculate_resistance(adc_value, current_r1);
}
for (uint16_t i = 0; i < FAST_TABLE_SIZE; i++) { // Выбор активной таблицы NTC
uint16_t adc = i * step; void select_ntc_table(eNtcTableType table_type, float custom_r1) {
if (adc > (uint16_t)ADC_MAX) adc = (uint16_t)ADC_MAX; switch (table_type) {
case NTC_TYPE_KST45:
current_ntc_table = ntc_table_kst45;
current_table_size = sizeof(ntc_table_kst45) / sizeof(ntc_table_entry);
current_r1 = (custom_r1 > 0) ? custom_r1 : 3300.0f;
current_table_type = NTC_TYPE_KST45;
break;
case NTC_TYPE_INCAR:
current_ntc_table = ntc_table_incar;
current_table_size = sizeof(ntc_table_incar) / sizeof(ntc_table_entry);
current_r1 = (custom_r1 > 0) ? custom_r1 : 3300.0f;
current_table_type = NTC_TYPE_INCAR;
break;
case NTC_TYPE_CUSTOM:
// Пользовательская таблица должна быть установлена через set_custom_ntc_table
if (current_ntc_table == NULL) {
// Если пользовательская таблица не установлена, используем KST45
current_ntc_table = ntc_table_kst45;
current_table_size = sizeof(ntc_table_kst45) / sizeof(ntc_table_entry);
current_r1 = 3300.0f;
current_table_type = NTC_TYPE_KST45;
}
if (custom_r1 > 0) {
current_r1 = custom_r1;
}
break;
}
}
// Установка пользовательской таблицы NTC
void set_custom_ntc_table(const ntc_table_entry* table, uint16_t size, float r1) {
if (table != NULL && size > 1) {
current_ntc_table = table;
current_table_size = size;
current_r1 = (r1 > 0) ? r1 : 3300.0f;
current_table_type = NTC_TYPE_CUSTOM;
}
}
// Инициализация таблицы быстрого доступа
void init_fast_lookup_table(eAlg use_alg, eNtcTableType table_type, float custom_r1) {
// Выбираем таблицу NTC
select_ntc_table(table_type, custom_r1);
// Создаем таблицу для быстрого преобразования АЦП->температура
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP; i++) {
uint16_t adc = (uint16_t)(i * (ADC_MAX / (TABLE_SIZE_LOOKUP - 1)));
float temp = get_temperature_from_adc(adc, use_alg); float temp = get_temperature_from_adc(adc, use_alg);
float resistance = calculate_resistance(adc, current_r1);
fast_lookup[i].adc_value = adc; fast_lookup[i].adc_value = adc;
fast_lookup[i].temp_c = (int16_t) (temp * 10.0f); // Храним с точностью 0.1°C
// Ограничиваем температуру разумными пределами fast_lookup[i].resistance = resistance;
if (temp < active_ntc.start_temp) temp = active_ntc.start_temp;
if (temp > active_ntc.end_temp) temp = active_ntc.end_temp;
fast_lookup[i].temp_c = (int16_t)(temp * 10.0f);
} }
} }
// Быстрое получение температуры с линейной интерполяцией // Быстрое получение температуры из таблицы
int16_t get_temperature_fast(uint16_t adc_value) { int16_t get_temperature_fast(uint16_t adc_value) {
uint16_t step = (uint16_t)(ADC_MAX / (FAST_TABLE_SIZE - 1)); // Простой поиск в таблице с линейной интерполяцией
uint16_t index = adc_value / step; uint16_t step = (uint16_t)(ADC_MAX / (TABLE_SIZE_LOOKUP - 1));
if (step == 0) step = 1;
if (index >= FAST_TABLE_SIZE - 1) { uint16_t index = adc_value / step;
return fast_lookup[FAST_TABLE_SIZE - 1].temp_c; if (index >= (TABLE_SIZE_LOOKUP - 1)) return fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c;
}
uint16_t adc1 = fast_lookup[index].adc_value; uint16_t adc1 = fast_lookup[index].adc_value;
uint16_t adc2 = fast_lookup[index + 1].adc_value; uint16_t adc2 = fast_lookup[index + 1].adc_value;
int16_t temp1 = fast_lookup[index].temp_c; int16_t temp1 = fast_lookup[index].temp_c;
int16_t temp2 = fast_lookup[index + 1].temp_c; int16_t temp2 = fast_lookup[index + 1].temp_c;
// Линейная интерполяция // Линейная интерполяция температуры
if (adc2 != adc1) { return temp1 + ((int32_t)(temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
return temp1 + ((temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
}
return temp1;
} }
// Вспомогательные функции // Быстрое получение сопротивления из таблицы
const char* get_ntc_name(void) { float get_resistance_fast(uint16_t adc_value) {
return active_ntc.name; // Простой поиск в таблице с линейной интерполяцией
uint16_t step = (uint16_t)(ADC_MAX / (TABLE_SIZE_LOOKUP - 1));
if (step == 0) step = 1;
uint16_t index = adc_value / step;
if (index >= (TABLE_SIZE_LOOKUP - 1)) return fast_lookup[TABLE_SIZE_LOOKUP - 1].resistance;
uint16_t adc1 = fast_lookup[index].adc_value;
uint16_t adc2 = fast_lookup[index + 1].adc_value;
float r1 = fast_lookup[index].resistance;
float r2 = fast_lookup[index + 1].resistance;
// Линейная интерполяция сопротивления
return r1 + (r2 - r1) * (adc_value - adc1) / (adc2 - adc1);
} }
uint16_t get_table_size(void) { // Получение текущего типа таблицы
return active_ntc.table_size; eNtcTableType get_current_table_type(void) {
return current_table_type;
}
// Получение текущего сопротивления делителя
float get_current_r1(void) {
return current_r1;
} }