From 6cf52262e2729ab7260d935cc068287bd51c1d71 Mon Sep 17 00:00:00 2001 From: cfif Date: Wed, 1 Apr 2026 11:16:24 +0300 Subject: [PATCH] Init --- APP/inc/ADC_Temp.h | 61 ++++++++---- APP/main.c | 52 +++++++--- APP/src/ADC_Temp.c | 233 ++++++++++++++++++++++++++++----------------- 3 files changed, 230 insertions(+), 116 deletions(-) diff --git a/APP/inc/ADC_Temp.h b/APP/inc/ADC_Temp.h index 1fce8a9..cdb9227 100644 --- a/APP/inc/ADC_Temp.h +++ b/APP/inc/ADC_Temp.h @@ -7,39 +7,68 @@ #include -// Константы -#define ADC_MAX 4095.0f // 12-битный АЦП -#define R1 3300.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 4096 +// Типы таблиц 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 4096 + // Предварительно вычисленная таблица для быстрого доступа typedef struct { 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; + +// Функции инициализации и конфигурации +void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg); +void set_active_config(eNtcTable table_type, float r1); +const ntc_config_t* get_active_config(void); + +// Основные функции получения температуры float get_temperature_from_adc(uint16_t adc_value, eAlg alg); +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_linear_fast(uint16_t adc_value); -float get_resistance_from_adc(uint16_t adc_value); // Новая функция для получения сопротивления - float get_resistance_log_fast(int16_t temperature_c10); float get_resistance_fast_simple(int16_t temperature_c10); + +// Вспомогательные функции +void print_fast_lookup_table(void); +void print_table_info(void); + #endif //MDF_ADC_TEMP_KST45_14_2_H \ No newline at end of file diff --git a/APP/main.c b/APP/main.c index 8b7c49d..ac96abe 100644 --- a/APP/main.c +++ b/APP/main.c @@ -4,22 +4,16 @@ extern adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP]; int main() { - // Инициализация таблицы быстрого поиска - init_fast_lookup_table(ALG_STEINHART); + uint16_t adc_value = 1980; - uint16_t value = 1980; + printf("\n-----------TABLE_KST45------------------\n"); - // Получение температуры различными методами - float T_ALG_STEINHART = get_temperature_from_adc(value, ALG_STEINHART); - int16_t T_FAST = get_temperature_log_fast(value); - float resistance = get_resistance_from_adc(value); - - printf("T_ALG_STEINHART = %f °C\n", T_ALG_STEINHART); - printf("T_FAST = %.1f °C\n", T_FAST / 10.0f); - printf("Resistance = %.2f Ω\n", resistance); - - float R = get_resistance_log_fast(227); - printf("Resistance FAST = %.2f Ω\n", R); +// Инициализация с таблицей KST45 и R1=3300 Ом + init_fast_lookup_table(TABLE_KST45, 3000.0f, ALG_STEINHART); +// Получение температуры + float temp = get_temperature_from_adc(adc_value, ALG_STEINHART); + int16_t temp_fast = get_temperature_log_fast(adc_value); + printf("ADC: %u, temp_fast: %.1f °C\n", adc_value, temp_fast / 10.0f); // Пример доступа к таблице @@ -31,6 +25,7 @@ int main() { fast_lookup[i].resistance_ohm); } + // Пример доступа к таблице printf("\nПример данных из таблицы быстрого поиска:\n"); for(int i = 0; i < 5; i++) { printf("ADC: %u, Temp: %.1f °C, Resistance: %.2f Ω\n", @@ -39,5 +34,34 @@ int main() { fast_lookup[i].resistance_ohm); } + + + printf("\n-----------INCAR------------------\n"); +// Смена конфигурации на INCAR с R1=20000 Ом +// set_active_config(TABLE_INCAR, 2000.0f); + init_fast_lookup_table(TABLE_INCAR, 20000.0f, ALG_STEINHART); + + temp_fast = get_temperature_log_fast(adc_value); + printf("ADC: %u, temp_fast: %.1f °C\n", adc_value, temp_fast / 10.0f); + + // Пример доступа к таблице + printf("\nПример данных из таблицы быстрого поиска:\n"); + for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 5; i--) { + printf("ADC: %u, Temp: %.1f °C, Resistance: %.2f Ω\n", + fast_lookup[i].adc_value, + fast_lookup[i].temp_c / 10.0f, + fast_lookup[i].resistance_ohm); + } + + // Пример доступа к таблице + printf("\nПример данных из таблицы быстрого поиска:\n"); + for(int i = 0; i < 5; i++) { + printf("ADC: %u, Temp: %.1f °C, Resistance: %.2f Ω\n", + fast_lookup[i].adc_value, + fast_lookup[i].temp_c / 10.0f, + fast_lookup[i].resistance_ohm); + } + + return 0; } \ No newline at end of file diff --git a/APP/src/ADC_Temp.c b/APP/src/ADC_Temp.c index 728495b..6e1812f 100644 --- a/APP/src/ADC_Temp.c +++ b/APP/src/ADC_Temp.c @@ -1,9 +1,9 @@ // // Created by cfif on 02.12.2025. // -#include "stdint.h" #include "ADC_Temp.h" #include +#include // Структура для хранения табличных данных typedef struct { @@ -11,9 +11,8 @@ typedef struct { float r_nom; // Номинальное сопротивление (Ω) } ntc_table_entry; -/* // Таблица из документа KST45 -static const ntc_table_entry ntc_table[] = { +static const ntc_table_entry ntc_table_kst45[] = { {-40, 100950.0f}, {-35, 72777.0f}, {-30, 53100.0f}, @@ -41,10 +40,9 @@ static const ntc_table_entry ntc_table[] = { {80, 377.4f}, {85, 321.7f} }; -*/ // Таблица из документа Incar -static ntc_table_entry ntc_table[] = { +static const ntc_table_entry ntc_table_incar[] = { {-40, 101000.0f}, {-35, 72600.0f}, {-30, 52720.0f}, @@ -85,38 +83,75 @@ static ntc_table_entry ntc_table[] = { {85, 283.0f} }; -// Предварительно вычисленная таблица для быстрого доступа +// Глобальная таблица быстрого доступа adc_temp_lookup fast_lookup[TABLE_SIZE_LOOKUP]; +// Активная конфигурация +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; +} + // Функция расчёта сопротивления 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; } - 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; @@ -127,12 +162,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); @@ -145,11 +180,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); @@ -159,7 +194,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; // Абсолютный ноль при некорректном сопротивлении @@ -177,7 +212,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; @@ -185,67 +220,84 @@ 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); } -// Основная функция для получения температуры -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_resistance_from_adc(uint16_t adc_value) { - return calculate_resistance(adc_value); +// Функция для получения температуры с активной конфигурацией +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); } -void init_fast_lookup_table(eAlg use_alg) { - // Сначала найдем рабочий диапазон АЦП, который дает температуры в пределах таблицы +// Функция для получения сопротивления из значения АЦП с указанием таблицы +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); + + // Находим рабочий диапазон АЦП uint16_t min_valid_adc = 0; uint16_t max_valid_adc = 0; - float min_temp = TABLE_START_TEMP; - float max_temp = TABLE_END_TEMP; - // Ищем минимальное АЦП, при котором температура >= TABLE_START_TEMP + // Ищем минимальное АЦП, при котором температура >= start_temp for (uint16_t adc = 1; adc < ADC_MAX; adc++) { - float resistance = calculate_resistance(adc); - float temp = get_temperature_from_adc(adc, ALG_STEINHART); + float resistance = calculate_resistance(adc, r1); + float temp = get_temperature_from_adc_with_table(adc, ALG_STEINHART, table_type, r1); - if (temp >= TABLE_START_TEMP && temp <= TABLE_END_TEMP) { + if (temp >= start_temp && temp <= end_temp) { min_valid_adc = adc; break; } } - // Ищем максимальное АЦП, при котором температура <= TABLE_END_TEMP + // Ищем максимальное АЦП, при котором температура <= end_temp for (uint16_t adc = (uint16_t)(ADC_MAX - 1); adc > 0; adc--) { - float resistance = calculate_resistance(adc); - float temp = get_temperature_from_adc(adc, ALG_STEINHART); + float resistance = calculate_resistance(adc, r1); + float temp = get_temperature_from_adc_with_table(adc, ALG_STEINHART, table_type, r1); - if (temp >= TABLE_START_TEMP && temp <= TABLE_END_TEMP) { + if (temp >= start_temp && temp <= end_temp) { max_valid_adc = adc; break; } @@ -255,32 +307,52 @@ void init_fast_lookup_table(eAlg use_alg) { if (min_valid_adc == 0) min_valid_adc = 1; if (max_valid_adc == 0) max_valid_adc = (uint16_t)(ADC_MAX - 1); - printf("Диапазон АЦП: %u - %u\n", min_valid_adc, max_valid_adc); - - // Заполняем таблицу, равномерно распределяя АЦП в рабочем диапазоне + // Заполняем таблицу for (uint16_t i = 0; i < TABLE_SIZE_LOOKUP; i++) { - // Линейная интерполяция АЦП в рабочем диапазоне float ratio = (float)i / (TABLE_SIZE_LOOKUP - 1); uint16_t adc = min_valid_adc + (uint16_t)(ratio * (max_valid_adc - min_valid_adc)); - float resistance = calculate_resistance(adc); - float temp = get_temperature_from_adc(adc, use_alg); + float resistance = calculate_resistance(adc, r1); + float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1); // Ограничиваем температуру пределами таблицы - if (temp < TABLE_START_TEMP) temp = TABLE_START_TEMP; - if (temp > TABLE_END_TEMP) temp = TABLE_END_TEMP; + if (temp < start_temp) temp = (float)start_temp; + if (temp > end_temp) temp = (float)end_temp; fast_lookup[i].adc_value = adc; fast_lookup[i].temp_c = (int16_t)(temp * 10.0f); fast_lookup[i].resistance_ohm = resistance; + fast_lookup[i].table_type = table_type; } + + // Обновляем активную конфигурацию + set_active_config(table_type, r1); } +// Установка активной конфигурации +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; +} + +// Быстрые функции с использованием предварительно вычисленной таблицы int16_t get_temperature_log_fast(uint16_t adc_value) { // Защита от выхода за границы if (adc_value >= fast_lookup[TABLE_SIZE_LOOKUP - 1].adc_value) { return fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c; } + if (adc_value <= fast_lookup[0].adc_value) { + return fast_lookup[0].temp_c; + } // Бинарный поиск интервала int left = 0; @@ -302,7 +374,6 @@ int16_t get_temperature_log_fast(uint16_t adc_value) { int16_t temp1 = fast_lookup[mid].temp_c; int16_t temp2 = fast_lookup[mid + 1].temp_c; - // Избегаем деления на ноль if (adc2 == adc1) { return temp1; } @@ -317,10 +388,9 @@ int16_t get_temperature_log_fast(uint16_t adc_value) { } } - return fast_lookup[0].temp_c; // Если не нашли, возвращаем первое значение + return fast_lookup[0].temp_c; } - // Альтернативная простая версия int16_t get_temperature_linear_fast(uint16_t adc_value) { // Находим интервал @@ -346,18 +416,13 @@ int16_t get_temperature_linear_fast(uint16_t adc_value) { return temp1 + ((int32_t) (temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1); } - -// Функция для получения сопротивления из температуры (обратное преобразование) // Функция для получения сопротивления из температуры (обратное преобразование) float get_resistance_log_fast(int16_t temperature_c10) { - // temperature_c10 - температура в °C * 10 (например, 250 = 25.0°C) - // Таблица отсортирована по убыванию температуры (от max к min) - // Защита от выхода за границы - if (temperature_c10 >= fast_lookup[0].temp_c) { // >= максимальной температуры + if (temperature_c10 >= fast_lookup[0].temp_c) { return fast_lookup[0].resistance_ohm; } - if (temperature_c10 <= fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c) { // <= минимальной температуры + if (temperature_c10 <= fast_lookup[TABLE_SIZE_LOOKUP - 1].temp_c) { return fast_lookup[TABLE_SIZE_LOOKUP - 1].resistance_ohm; } @@ -368,19 +433,14 @@ float get_resistance_log_fast(int16_t temperature_c10) { while (left <= right) { int mid = left + (right - left) / 2; - // Таблица отсортирована по убыванию температуры if (temperature_c10 <= fast_lookup[mid].temp_c && temperature_c10 >= fast_lookup[mid + 1].temp_c) { // Нашли интервал - // mid - точка с большей температурой - // mid+1 - точка с меньшей температурой + int16_t temp_high = fast_lookup[mid].temp_c; + int16_t temp_low = fast_lookup[mid + 1].temp_c; + float res_high = fast_lookup[mid].resistance_ohm; + float res_low = fast_lookup[mid + 1].resistance_ohm; - int16_t temp_high = fast_lookup[mid].temp_c; // большая температура - int16_t temp_low = fast_lookup[mid + 1].temp_c; // меньшая температура - float res_high = fast_lookup[mid].resistance_ohm; // сопротивление при большей температуре - float res_low = fast_lookup[mid + 1].resistance_ohm; // сопротивление при меньшей температуре - - // Избегаем деления на ноль if (temp_high == temp_low) { return res_high; } @@ -395,9 +455,9 @@ float get_resistance_log_fast(int16_t temperature_c10) { } if (temperature_c10 > fast_lookup[mid].temp_c) { - right = mid - 1; // ищем в сторону больших температур + right = mid - 1; } else { - left = mid + 1; // ищем в сторону меньших температур + left = mid + 1; } } @@ -439,4 +499,5 @@ float get_resistance_fast_simple(int16_t temperature_c10) { } return fast_lookup[TABLE_SIZE_LOOKUP - 1].resistance_ohm; -} \ No newline at end of file +} +