Обновление
This commit is contained in:
parent
5b206d8493
commit
bdaa10b99c
474
ADC_Temp.c
474
ADC_Temp.c
|
|
@ -1,14 +1,49 @@
|
|||
//
|
||||
// Created by cfif on 02.12.2025.
|
||||
//
|
||||
#include "stdint.h"
|
||||
#include "ADC_Temp.h"
|
||||
#include <math.h>
|
||||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP]; // Таблица на TABLE_SIZE_LOOKUP значений
|
||||
// Структура для хранения табличных данных
|
||||
typedef struct {
|
||||
int temp_c; // Температура (°C)
|
||||
float r_nom; // Номинальное сопротивление (Ω)
|
||||
} ntc_table_entry;
|
||||
|
||||
// Таблица из документа InCar
|
||||
static const ntc_table_entry ntc_table[] = {
|
||||
// Таблица из документа KST45
|
||||
static const ntc_table_entry ntc_table_kst45[] = {
|
||||
{-40, 100950.0f},
|
||||
{-35, 72777.0f},
|
||||
{-30, 53100.0f},
|
||||
{-25, 39111.0f},
|
||||
{-20, 29121.0f},
|
||||
{-15, 21879.0f},
|
||||
{-10, 16599.0f},
|
||||
{-5, 12695.0f},
|
||||
{0, 9795.0f},
|
||||
{5, 7616.0f},
|
||||
{10, 5970.0f},
|
||||
{15, 4712.0f},
|
||||
{20, 3747.0f},
|
||||
{25, 3000.0f},
|
||||
{30, 2417.0f},
|
||||
{35, 1959.0f},
|
||||
{40, 1598.0f},
|
||||
{45, 1311.0f},
|
||||
{50, 1081.0f},
|
||||
{55, 895.9f},
|
||||
{60, 746.4f},
|
||||
{65, 624.9f},
|
||||
{70, 525.6f},
|
||||
{75, 444.4f},
|
||||
{80, 377.4f},
|
||||
{85, 321.7f}
|
||||
};
|
||||
|
||||
// Таблица из документа Incar
|
||||
static const ntc_table_entry ntc_table_incar[] = {
|
||||
{-40, 101000.0f},
|
||||
{-35, 72600.0f},
|
||||
{-30, 52720.0f},
|
||||
|
|
@ -16,12 +51,12 @@ static const ntc_table_entry ntc_table[] = {
|
|||
{-20, 28620.0f},
|
||||
{-15, 21390.0f},
|
||||
{-10, 16120.0f},
|
||||
{-5, 12260.0f},
|
||||
{-5, 12260.0f},
|
||||
{-4, 11620.0f},
|
||||
{-3, 11010.0f},
|
||||
{-2, 10440.0f},
|
||||
{-1, 9907.0f},
|
||||
{0, 9399.0f},
|
||||
{0, 9399.0f},
|
||||
{1, 8924.0f},
|
||||
{2, 8473.0f},
|
||||
{3, 8048.0f},
|
||||
|
|
@ -31,7 +66,7 @@ static const ntc_table_entry ntc_table[] = {
|
|||
{7, 6570.0f},
|
||||
{8, 6250.0f},
|
||||
{9, 5947.0f},
|
||||
{10, 5661.0f},
|
||||
{10, 5661.0f},
|
||||
{15, 4441.0f},
|
||||
{20, 3512.0f},
|
||||
{25, 2795.0f},
|
||||
|
|
@ -49,40 +84,104 @@ static const ntc_table_entry ntc_table[] = {
|
|||
{85, 283.0f}
|
||||
};
|
||||
|
||||
// Глобальная структура для хранения таблиц быстрого доступа
|
||||
fast_lookup_tables_t g_fast_tables = {
|
||||
.kst45_initialized = false,
|
||||
.incar_initialized = false,
|
||||
.kst45_r1 = 3300.0f,
|
||||
.incar_r1 = 3300.0f
|
||||
};
|
||||
|
||||
// Активная конфигурация
|
||||
static ntc_config_t active_config = {
|
||||
.table_type = TABLE_KST45,
|
||||
.r1 = 3300.0f,
|
||||
.start_temp = -40,
|
||||
.end_temp = 85,
|
||||
.table_size = TABLE_SIZE_KST45
|
||||
};
|
||||
|
||||
// Вспомогательная функция для получения таблицы по типу
|
||||
static const ntc_table_entry* get_table_by_type(eNtcTable table_type, uint16_t* size, int16_t* start_temp, int16_t* end_temp) {
|
||||
const ntc_table_entry* table = NULL;
|
||||
*size = 0;
|
||||
|
||||
switch(table_type) {
|
||||
case TABLE_KST45:
|
||||
table = ntc_table_kst45;
|
||||
*size = TABLE_SIZE_KST45;
|
||||
*start_temp = -40;
|
||||
*end_temp = 85;
|
||||
break;
|
||||
case TABLE_INCAR:
|
||||
table = ntc_table_incar;
|
||||
*size = TABLE_SIZE_INCAR;
|
||||
*start_temp = -40;
|
||||
*end_temp = 85;
|
||||
break;
|
||||
default:
|
||||
table = ntc_table_kst45;
|
||||
*size = TABLE_SIZE_KST45;
|
||||
*start_temp = -40;
|
||||
*end_temp = 85;
|
||||
break;
|
||||
}
|
||||
return table;
|
||||
}
|
||||
|
||||
// Функция для получения указателя на таблицу быстрого доступа по типу
|
||||
static adc_temp_lookup* get_fast_table_by_type(eNtcTable table_type) {
|
||||
switch(table_type) {
|
||||
case TABLE_KST45:
|
||||
return g_fast_tables.kst45;
|
||||
case TABLE_INCAR:
|
||||
return g_fast_tables.incar;
|
||||
default:
|
||||
return g_fast_tables.kst45;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для получения статуса инициализации таблицы
|
||||
static bool is_table_initialized(eNtcTable table_type) {
|
||||
switch(table_type) {
|
||||
case TABLE_KST45:
|
||||
return g_fast_tables.kst45_initialized;
|
||||
case TABLE_INCAR:
|
||||
return g_fast_tables.incar_initialized;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Функция расчёта сопротивления NTC из значения АЦП
|
||||
static float calculate_resistance(uint16_t adc_value) {
|
||||
static float calculate_resistance(uint16_t adc_value, float r1) {
|
||||
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);
|
||||
|
||||
float R_ntc = r1 * (float) adc_value / (ADC_MAX - (float) adc_value);
|
||||
return R_ntc;
|
||||
}
|
||||
|
||||
|
||||
// Бинарный поиск в таблице
|
||||
static int find_interval_index(float resistance) {
|
||||
static int find_interval_index(float resistance, const ntc_table_entry* table, uint16_t table_size) {
|
||||
int left = 0;
|
||||
int right = TABLE_SIZE - 1;
|
||||
int right = table_size - 1;
|
||||
|
||||
// Проверка границ
|
||||
if (resistance >= ntc_table[0].r_nom) return 0;
|
||||
if (resistance <= ntc_table[right].r_nom) return right - 1;
|
||||
if (resistance >= table[0].r_nom) return 0;
|
||||
if (resistance <= 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) {
|
||||
if (mid < table_size - 1 &&
|
||||
resistance <= table[mid].r_nom &&
|
||||
resistance >= table[mid + 1].r_nom) {
|
||||
return mid;
|
||||
}
|
||||
|
||||
if (resistance > ntc_table[mid].r_nom) {
|
||||
if (resistance > table[mid].r_nom) {
|
||||
right = mid - 1;
|
||||
} else {
|
||||
left = mid + 1;
|
||||
|
|
@ -93,12 +192,12 @@ 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) {
|
||||
// Берем две соседние точки из таблицы
|
||||
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;
|
||||
float t1 = (float) table[index].temp_c + 273.15f; // в Кельвинах
|
||||
float t2 = (float) table[index + 1].temp_c + 273.15f;
|
||||
float r1 = table[index].r_nom;
|
||||
float r2 = table[index + 1].r_nom;
|
||||
|
||||
// Вычисляем коэффициент B для интервала
|
||||
float B = logf(r1 / r2) / (1.0f / t1 - 1.0f / t2);
|
||||
|
|
@ -111,11 +210,11 @@ static float interpolate_steinhart(float resistance, int index) {
|
|||
}
|
||||
|
||||
// Линейная интерполяция в логарифмическом масштабе
|
||||
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;
|
||||
static float interpolate_log_linear(float resistance, int index, const ntc_table_entry* table) {
|
||||
float t1 = (float) table[index].temp_c;
|
||||
float t2 = (float) table[index + 1].temp_c;
|
||||
float r1 = table[index].r_nom;
|
||||
float r2 = table[index + 1].r_nom;
|
||||
|
||||
float log_r1 = logf(r1);
|
||||
float log_r2 = logf(r2);
|
||||
|
|
@ -125,7 +224,7 @@ static float interpolate_log_linear(float resistance, int index) {
|
|||
}
|
||||
|
||||
// Более надежная версия с проверкой параметров
|
||||
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) {
|
||||
return -273.15f; // Абсолютный ноль при некорректном сопротивлении
|
||||
|
|
@ -143,7 +242,7 @@ static float interpolate_steinhart_full(float resistance, int index) {
|
|||
// Проверка на физическую реализуемость (температура должна быть положительной в Кельвинах)
|
||||
if (inv_T <= 0.0f || inv_T > 1.0f) { // 1/T не может быть <= 0 (T < 0K) или слишком большим
|
||||
// В случае ошибки возвращаем температуру из таблицы по индексу
|
||||
return (float)ntc_table[index].temp_c;
|
||||
return (float) table[index].temp_c;
|
||||
}
|
||||
|
||||
double temp_K = 1.0f / inv_T;
|
||||
|
|
@ -151,61 +250,302 @@ static float interpolate_steinhart_full(float resistance, int index) {
|
|||
// Дополнительная проверка диапазона (например, для NTC обычно -50...+150°C)
|
||||
if (temp_K < 223.15f || temp_K > 423.15f) { // -50°C...150°C в Кельвинах
|
||||
// Возвращаем значение из таблицы как запасной вариант
|
||||
return (float)ntc_table[index].temp_c;
|
||||
return (float) table[index].temp_c;
|
||||
}
|
||||
|
||||
return (float)(temp_K - 273.15f);
|
||||
return (float) (temp_K - 273.15f);
|
||||
}
|
||||
|
||||
// Основная функция для получения температуры
|
||||
float get_temperature_from_adc(uint16_t adc_value, eAlg use_alg) {
|
||||
float resistance = calculate_resistance(adc_value);
|
||||
// Основная функция для получения температуры с указанием таблицы и R1
|
||||
float get_temperature_from_adc_with_table(uint16_t adc_value, eAlg alg, eNtcTable table_type, float r1) {
|
||||
float resistance = calculate_resistance(adc_value, r1);
|
||||
|
||||
if (resistance <= 0.0f) {
|
||||
return -273.15f; // Ошибка
|
||||
}
|
||||
|
||||
int index = find_interval_index(resistance);
|
||||
uint16_t table_size;
|
||||
int16_t start_temp, end_temp;
|
||||
const ntc_table_entry* table = get_table_by_type(table_type, &table_size, &start_temp, &end_temp);
|
||||
|
||||
if (index < 0 || index >= TABLE_SIZE - 1) {
|
||||
int index = find_interval_index(resistance, table, table_size);
|
||||
|
||||
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;
|
||||
if (resistance >= table[0].r_nom) return (float) start_temp;
|
||||
if (resistance <= table[table_size - 1].r_nom) return (float) end_temp;
|
||||
return -273.15f; // Ошибка
|
||||
}
|
||||
|
||||
if (use_alg == ALG_STEINHART) {
|
||||
return interpolate_steinhart(resistance, index);
|
||||
} else if (use_alg == ALG_STEINHART_FULL) {
|
||||
return interpolate_steinhart_full(resistance, index);
|
||||
if (alg == ALG_STEINHART) {
|
||||
return interpolate_steinhart(resistance, index, table);
|
||||
} else if (alg == ALG_STEINHART_FULL) {
|
||||
return interpolate_steinhart_full(resistance, index, table);
|
||||
} else {
|
||||
return interpolate_log_linear(resistance, index);
|
||||
return interpolate_log_linear(resistance, index, table);
|
||||
}
|
||||
}
|
||||
|
||||
// Функция для получения температуры с активной конфигурацией
|
||||
float get_temperature_from_adc(uint16_t adc_value, eAlg alg) {
|
||||
return get_temperature_from_adc_with_table(adc_value, alg, active_config.table_type, active_config.r1);
|
||||
}
|
||||
|
||||
adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP]; // Таблица на TABLE_SIZE_LOOKUP значений
|
||||
// Функция для получения сопротивления из значения АЦП с указанием таблицы
|
||||
float get_resistance_from_adc_with_table(uint16_t adc_value, eNtcTable table_type, float r1) {
|
||||
return calculate_resistance(adc_value, r1);
|
||||
}
|
||||
|
||||
// Функция для получения сопротивления с активной конфигурацией
|
||||
float get_resistance_from_adc(uint16_t adc_value) {
|
||||
return calculate_resistance(adc_value, active_config.r1);
|
||||
}
|
||||
|
||||
// Инициализация таблицы быстрого поиска для конкретной таблицы
|
||||
void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg) {
|
||||
uint16_t table_size;
|
||||
int16_t start_temp, end_temp;
|
||||
const ntc_table_entry* table = get_table_by_type(table_type, &table_size, &start_temp, &end_temp);
|
||||
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
|
||||
|
||||
// Сохраняем значение R1 для этой таблицы
|
||||
if (table_type == TABLE_KST45) {
|
||||
g_fast_tables.kst45_r1 = r1;
|
||||
} else {
|
||||
g_fast_tables.incar_r1 = r1;
|
||||
}
|
||||
|
||||
// Находим рабочий диапазон АЦП
|
||||
uint16_t min_valid_adc = 0;
|
||||
uint16_t max_valid_adc = 0;
|
||||
|
||||
// Значения для граничных точек
|
||||
float temp_at_min_adc = 0.0f;
|
||||
float temp_at_max_adc = 0.0f;
|
||||
float res_at_min_adc = 0.0f;
|
||||
float res_at_max_adc = 0.0f;
|
||||
|
||||
// Ищем минимальное АЦП, при котором температура >= start_temp (максимальная температура)
|
||||
for (uint16_t adc = 1; adc < ADC_MAX; adc++) {
|
||||
float resistance = calculate_resistance(adc, r1);
|
||||
float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1);
|
||||
|
||||
if (temp >= start_temp && temp <= end_temp) {
|
||||
min_valid_adc = adc;
|
||||
temp_at_min_adc = temp;
|
||||
res_at_min_adc = resistance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Ищем максимальное АЦП, при котором температура <= end_temp (минимальная температура)
|
||||
for (uint16_t adc = (uint16_t)(ADC_MAX - 1); adc > 0; adc--) {
|
||||
float resistance = calculate_resistance(adc, r1);
|
||||
float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1);
|
||||
|
||||
if (temp >= start_temp && temp <= end_temp) {
|
||||
max_valid_adc = adc;
|
||||
temp_at_max_adc = temp;
|
||||
res_at_max_adc = resistance;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Заполняем таблицу для всего диапазона ADC от 0 до 4095
|
||||
uint32_t adc_step = ((uint32_t)(ADC_MAX - 1) * 1000) / (TABLE_SIZE_LOOKUP - 1);
|
||||
uint32_t current_adc = 0;
|
||||
uint16_t prev_adc = 0;
|
||||
|
||||
void init_fast_lookup_table(eAlg use_alg) {
|
||||
// Создаем таблицу для быстрого преобразования АЦП->температура
|
||||
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP; i++) {
|
||||
uint16_t adc = i * (uint8_t)roundf(ADC_MAX / (TABLE_SIZE_LOOKUP - 1)); // Для 12-битного АЦП (0-4095)
|
||||
float temp = get_temperature_from_adc(adc, use_alg);
|
||||
fast_lookup[i].adc_value = adc;
|
||||
fast_lookup[i].temp_c = (int16_t) (temp * 10.0f); // Храним с точностью 0.1°C
|
||||
uint16_t adc;
|
||||
|
||||
if (i == 0) {
|
||||
adc = 0;
|
||||
current_adc = 0;
|
||||
prev_adc = 0;
|
||||
} else if (i == TABLE_SIZE_LOOKUP - 1) {
|
||||
adc = (uint16_t)(ADC_MAX - 1);
|
||||
} else {
|
||||
current_adc += adc_step;
|
||||
adc = (uint16_t)(current_adc / 1000);
|
||||
|
||||
// Убеждаемся, что значения монотонно возрастают и нет дубликатов
|
||||
if (adc <= prev_adc) {
|
||||
adc = prev_adc + 1;
|
||||
}
|
||||
|
||||
// Убеждаемся, что не выходим за пределы
|
||||
if (adc >= (uint16_t)(ADC_MAX - 1)) {
|
||||
adc = (uint16_t)(ADC_MAX - 2);
|
||||
}
|
||||
}
|
||||
|
||||
float resistance;
|
||||
float temp;
|
||||
|
||||
// Определяем, находится ли ADC в рабочем диапазоне
|
||||
if (adc <= min_valid_adc) {
|
||||
// Зона низких ADC (высокая температура) - используем граничное значение
|
||||
resistance = res_at_min_adc;
|
||||
temp = temp_at_min_adc;
|
||||
} else if (adc >= max_valid_adc) {
|
||||
// Зона высоких ADC (низкая температура) - используем граничное значение
|
||||
resistance = res_at_max_adc;
|
||||
temp = temp_at_max_adc;
|
||||
} else {
|
||||
// В рабочем диапазоне - вычисляем нормально
|
||||
resistance = calculate_resistance(adc, r1);
|
||||
temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1);
|
||||
}
|
||||
|
||||
fast_table[i].adc_value = adc;
|
||||
fast_table[i].temp_c = (int16_t)(temp * 10.0f);
|
||||
fast_table[i].resistance_ohm = resistance;
|
||||
fast_table[i].table_type = table_type;
|
||||
|
||||
prev_adc = adc;
|
||||
}
|
||||
|
||||
// Устанавливаем флаг инициализации
|
||||
if (table_type == TABLE_KST45) {
|
||||
g_fast_tables.kst45_initialized = true;
|
||||
} else {
|
||||
g_fast_tables.incar_initialized = true;
|
||||
}
|
||||
}
|
||||
|
||||
int16_t get_temperature_fast(uint16_t adc_value) {
|
||||
// Простой поиск в таблице с линейной интерполяцией
|
||||
uint16_t index = adc_value / (uint8_t)roundf(ADC_MAX / (TABLE_SIZE_LOOKUP - 1)); // Делим на 16 для TABLE_SIZE_LOOKUP = 256
|
||||
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 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);
|
||||
// Инициализация обеих таблиц
|
||||
void init_both_tables(float r1_kst45, float r1_incar, eAlg use_alg) {
|
||||
init_fast_lookup_table(TABLE_KST45, r1_kst45, use_alg);
|
||||
init_fast_lookup_table(TABLE_INCAR, r1_incar, use_alg);
|
||||
}
|
||||
|
||||
// Установка активной конфигурации
|
||||
void set_active_config(eNtcTable table_type, float r1) {
|
||||
active_config.table_type = table_type;
|
||||
active_config.r1 = r1;
|
||||
|
||||
uint16_t table_size;
|
||||
get_table_by_type(table_type, &table_size, &active_config.start_temp, &active_config.end_temp);
|
||||
active_config.table_size = table_size;
|
||||
}
|
||||
|
||||
// Получение активной конфигурации
|
||||
const ntc_config_t* get_active_config(void) {
|
||||
return &active_config;
|
||||
}
|
||||
|
||||
// Получение таблиц быстрого доступа
|
||||
const fast_lookup_tables_t* get_fast_tables(void) {
|
||||
return &g_fast_tables;
|
||||
}
|
||||
|
||||
// Быстрая функция для конкретной таблицы
|
||||
int16_t get_temperature_log_fast_for_table(uint16_t adc_value, eNtcTable table_type) {
|
||||
if (!is_table_initialized(table_type)) {
|
||||
// Если таблица не инициализирована, используем обычный расчет
|
||||
float temp = get_temperature_from_adc_with_table(adc_value, ALG_STEINHART, table_type,
|
||||
(table_type == TABLE_KST45) ? g_fast_tables.kst45_r1 : g_fast_tables.incar_r1);
|
||||
return (int16_t)(temp * 10.0f);
|
||||
}
|
||||
|
||||
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
|
||||
|
||||
// Простой линейный поиск (так как таблица небольшая - 4096 элементов)
|
||||
for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP - 1; i++) {
|
||||
if (adc_value >= fast_table[i].adc_value && adc_value <= fast_table[i + 1].adc_value) {
|
||||
// Линейная интерполяция
|
||||
uint16_t adc1 = fast_table[i].adc_value;
|
||||
uint16_t adc2 = fast_table[i + 1].adc_value;
|
||||
int16_t temp1 = fast_table[i].temp_c;
|
||||
int16_t temp2 = fast_table[i + 1].temp_c;
|
||||
|
||||
if (adc2 == adc1) {
|
||||
return temp1;
|
||||
}
|
||||
|
||||
return temp1 + ((int32_t)(temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1);
|
||||
}
|
||||
}
|
||||
|
||||
// Если не нашли, возвращаем ближайшее значение
|
||||
if (adc_value <= fast_table[0].adc_value) {
|
||||
return fast_table[0].temp_c;
|
||||
} else {
|
||||
return fast_table[TABLE_SIZE_LOOKUP - 1].temp_c;
|
||||
}
|
||||
}
|
||||
|
||||
// Быстрые функции с использованием активной таблицы
|
||||
int16_t get_temperature_log_fast(uint16_t adc_value) {
|
||||
return get_temperature_log_fast_for_table(adc_value, active_config.table_type);
|
||||
}
|
||||
|
||||
// Альтернативная простая версия
|
||||
int16_t get_temperature_linear_fast(uint16_t adc_value) {
|
||||
return get_temperature_log_fast_for_table(adc_value, active_config.table_type);
|
||||
}
|
||||
|
||||
// Функция для получения сопротивления из температуры для конкретной таблицы
|
||||
float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table_type) {
|
||||
if (!is_table_initialized(table_type)) {
|
||||
return 0.0f;
|
||||
}
|
||||
|
||||
adc_temp_lookup* fast_table = get_fast_table_by_type(table_type);
|
||||
|
||||
// Защита от выхода за границы
|
||||
if (temperature_c10 >= fast_table[0].temp_c) {
|
||||
return fast_table[0].resistance_ohm;
|
||||
}
|
||||
if (temperature_c10 <= fast_table[TABLE_SIZE_LOOKUP - 1].temp_c) {
|
||||
return fast_table[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
|
||||
}
|
||||
|
||||
// Бинарный поиск интервала по температуре
|
||||
int left = 0;
|
||||
int right = TABLE_SIZE_LOOKUP - 1;
|
||||
|
||||
while (left <= right) {
|
||||
int mid = left + (right - left) / 2;
|
||||
|
||||
if (temperature_c10 <= fast_table[mid].temp_c &&
|
||||
temperature_c10 >= fast_table[mid + 1].temp_c) {
|
||||
// Нашли интервал
|
||||
int16_t temp_high = fast_table[mid].temp_c;
|
||||
int16_t temp_low = fast_table[mid + 1].temp_c;
|
||||
float res_high = fast_table[mid].resistance_ohm;
|
||||
float res_low = fast_table[mid + 1].resistance_ohm;
|
||||
|
||||
if (temp_high == temp_low) {
|
||||
return res_high;
|
||||
}
|
||||
|
||||
// Интерполяция в логарифмическом масштабе
|
||||
float log_res_high = logf(res_high);
|
||||
float log_res_low = logf(res_low);
|
||||
float log_res = log_res_high + (log_res_low - log_res_high) *
|
||||
(float)(temp_high - temperature_c10) / (float)(temp_high - temp_low);
|
||||
|
||||
return expf(log_res);
|
||||
}
|
||||
|
||||
if (temperature_c10 > fast_table[mid].temp_c) {
|
||||
right = mid - 1;
|
||||
} else {
|
||||
left = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return fast_table[TABLE_SIZE_LOOKUP - 1].resistance_ohm;
|
||||
}
|
||||
|
||||
// Функция для получения сопротивления из температуры (обратное преобразование)
|
||||
float get_resistance_log_fast(int16_t temperature_c10) {
|
||||
return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type);
|
||||
}
|
||||
|
||||
// Упрощенная версия с линейным поиском
|
||||
float get_resistance_fast_simple(int16_t temperature_c10) {
|
||||
return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type);
|
||||
}
|
||||
90
ADC_Temp.h
90
ADC_Temp.h
|
|
@ -6,41 +6,83 @@
|
|||
#define MDF_ADC_TEMP_KST45_14_2_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "stdbool.h"
|
||||
|
||||
// Константы
|
||||
#define ADC_MAX 4095.0f // 12-битный АЦП
|
||||
#define R1 3400.0f // Сопротивление делителя напряжения
|
||||
#define TABLE_START_TEMP (-40)
|
||||
#define TABLE_END_TEMP 85
|
||||
#define TABLE_SIZE 38
|
||||
|
||||
// Параметры Steinhart-Hart для термистора
|
||||
#define koef_A 0.001741624168166423
|
||||
#define koef_B 0.00017003940268680147
|
||||
#define koef_C 0.0000004890545443703666
|
||||
|
||||
#define TABLE_SIZE_LOOKUP 1024
|
||||
|
||||
// Структура для хранения табличных данных
|
||||
typedef struct {
|
||||
int temp_c; // Температура (°C)
|
||||
float r_nom; // Номинальное сопротивление (Ω)
|
||||
} ntc_table_entry;
|
||||
// Типы таблиц NTC
|
||||
typedef enum {
|
||||
TABLE_KST45 = 0, // Таблица из документа KST45
|
||||
TABLE_INCAR = 1 // Таблица из документа Incar
|
||||
} eNtcTable;
|
||||
|
||||
// Алгоритмы расчёта температуры
|
||||
typedef enum {
|
||||
ALG_STEINHART = 0,
|
||||
ALG_STEINHART_FULL = 1,
|
||||
ALG_LINEAR = 2
|
||||
} eAlg;
|
||||
|
||||
// Предварительно вычисленная таблица для быстрого доступа
|
||||
// Константы
|
||||
#define ADC_MAX 4095.0f // 12-битный АЦП
|
||||
|
||||
// Параметры Steinhart-Hart для термистора (общие для всех таблиц)
|
||||
#define koef_A 0.001741624168166423
|
||||
#define koef_B 0.00017003940268680147
|
||||
#define koef_C 0.0000004890545443703666
|
||||
|
||||
// Размеры таблиц
|
||||
#define TABLE_SIZE_KST45 26
|
||||
#define TABLE_SIZE_INCAR 38
|
||||
#define TABLE_SIZE_LOOKUP 256
|
||||
|
||||
// Предварительно вычисленная таблица для быстрого доступа для каждой таблицы
|
||||
typedef struct {
|
||||
uint16_t adc_value; // Значение АЦП
|
||||
int16_t temp_c; // Температура в °C * 10 (для фиксированной точки)
|
||||
uint16_t adc_value; // Значение АЦП
|
||||
int16_t temp_c; // Температура в °C * 10 (для фиксированной точки)
|
||||
float resistance_ohm; // Сопротивление в Ом, соответствующее значению АЦП
|
||||
eNtcTable table_type; // Тип таблицы, для которой вычислены данные
|
||||
} adc_temp_lookup;
|
||||
|
||||
void init_fast_lookup_table(eAlg use_alg);
|
||||
// Структура конфигурации для NTC
|
||||
typedef struct {
|
||||
eNtcTable table_type; // Тип используемой таблицы
|
||||
float r1; // Сопротивление делителя напряжения (Ом)
|
||||
int16_t start_temp; // Начальная температура таблицы (°C)
|
||||
int16_t end_temp; // Конечная температура таблицы (°C)
|
||||
uint16_t table_size; // Размер таблицы
|
||||
} ntc_config_t;
|
||||
|
||||
// Структура для хранения таблиц быстрого доступа для каждой конфигурации
|
||||
typedef struct {
|
||||
adc_temp_lookup kst45[TABLE_SIZE_LOOKUP];
|
||||
adc_temp_lookup incar[TABLE_SIZE_LOOKUP];
|
||||
bool kst45_initialized;
|
||||
bool incar_initialized;
|
||||
float kst45_r1;
|
||||
float incar_r1;
|
||||
} fast_lookup_tables_t;
|
||||
|
||||
// Глобальная структура для доступа к таблицам
|
||||
extern fast_lookup_tables_t g_fast_tables;
|
||||
|
||||
// Функции инициализации и конфигурации
|
||||
void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg);
|
||||
void init_both_tables(float r1_kst45, float r1_incar, eAlg use_alg);
|
||||
void set_active_config(eNtcTable table_type, float r1);
|
||||
const ntc_config_t* get_active_config(void);
|
||||
const fast_lookup_tables_t* get_fast_tables(void);
|
||||
|
||||
// Основные функции получения температуры
|
||||
float get_temperature_from_adc(uint16_t adc_value, eAlg alg);
|
||||
int16_t get_temperature_fast(uint16_t adc_value);
|
||||
float get_temperature_from_adc_with_table(uint16_t adc_value, eAlg alg, eNtcTable table_type, float r1);
|
||||
float get_resistance_from_adc(uint16_t adc_value);
|
||||
float get_resistance_from_adc_with_table(uint16_t adc_value, eNtcTable table_type, float r1);
|
||||
|
||||
// Быстрые функции с использованием предварительно вычисленной таблицы
|
||||
int16_t get_temperature_log_fast(uint16_t adc_value);
|
||||
int16_t get_temperature_log_fast_for_table(uint16_t adc_value, eNtcTable table_type);
|
||||
int16_t get_temperature_linear_fast(uint16_t adc_value);
|
||||
float get_resistance_log_fast(int16_t temperature_c10);
|
||||
float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table_type);
|
||||
float get_resistance_fast_simple(int16_t temperature_c10);
|
||||
|
||||
#endif //MDF_ADC_TEMP_KST45_14_2_H
|
||||
1037
ADC_Temp_Table.c
1037
ADC_Temp_Table.c
File diff suppressed because it is too large
Load Diff
|
|
@ -1,13 +0,0 @@
|
|||
//
|
||||
// Created by cfif on 16.12.2025.
|
||||
//
|
||||
|
||||
#ifndef HVAC_M7_ADC_TEMP_TABLE_H
|
||||
#define HVAC_M7_ADC_TEMP_TABLE_H
|
||||
|
||||
#include "ADC_Temp.h"
|
||||
|
||||
extern const adc_temp_lookup fast_lookup_Incar[TABLE_SIZE_LOOKUP];
|
||||
extern const adc_temp_lookup fast_lookup_KST45[TABLE_SIZE_LOOKUP];
|
||||
|
||||
#endif //HVAC_M7_ADC_TEMP_TABLE_H
|
||||
Loading…
Reference in New Issue