diff --git a/APP/main.c b/APP/main.c index 04eb5dd..8ee82c8 100644 --- a/APP/main.c +++ b/APP/main.c @@ -1,6 +1,95 @@ #include #include "ADC_Temp.h" +// Функция для сохранения таблицы в файл +void save_table_to_file(const char* filename, const adc_temp_lookup* table, const char* table_name) { + FILE* file = fopen(filename, "w"); + if (file == NULL) { + printf("Ошибка: не удалось создать файл %s\n", filename); + return; + } + + fprintf(file, "=== Таблица быстрого поиска: %s ===\n", table_name); + fprintf(file, "Всего записей: %d\n", TABLE_SIZE_LOOKUP); + fprintf(file, "%-8s %-12s %-15s\n", "ADC", "Temp (°C)", "Resistance (Ω)"); + fprintf(file, "----------------------------------------\n"); + + for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) { + fprintf(file, "%-8u %-12.1f %-15.2f\n", + table[i].adc_value, + table[i].temp_c / 10.0f, + table[i].resistance_ohm); + } + + fclose(file); + printf("Таблица '%s' сохранена в файл: %s\n", table_name, filename); +} + +// Функция для сохранения таблицы в CSV формате +void save_table_to_csv(const char* filename, const adc_temp_lookup* table, const char* table_name) { + FILE* file = fopen(filename, "w"); + if (file == NULL) { + printf("Ошибка: не удалось создать файл %s\n", filename); + return; + } + + fprintf(file, "# Таблица быстрого поиска: %s\n", table_name); + fprintf(file, "ADC,Temperature_C,Resistance_Ohm\n"); + + for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) { + fprintf(file, "%u,%.1f,%.2f\n", + table[i].adc_value, + table[i].temp_c / 10.0f, + table[i].resistance_ohm); + } + + fclose(file); + printf("Таблица '%s' сохранена в CSV файл: %s\n", table_name, filename); +} + +// Функция для сохранения обеих таблиц +void save_both_tables(void) { + const fast_lookup_tables_t* tables = get_fast_tables(); + + // Сохраняем в текстовом формате + save_table_to_file("kst45_table.txt", tables->kst45, "KST45"); + save_table_to_file("incar_table.txt", tables->incar, "INCAR"); + + // Сохраняем в CSV формате (удобно для Excel) + save_table_to_csv("kst45_table.csv", tables->kst45, "KST45"); + save_table_to_csv("incar_table.csv", tables->incar, "INCAR"); +} + +// Функция для сохранения только рабочего диапазона (без зон насыщения) +void save_working_range_to_file(const char* filename, const adc_temp_lookup* table, + const char* table_name, uint16_t min_adc, uint16_t max_adc) { + FILE* file = fopen(filename, "w"); + if (file == NULL) { + printf("Ошибка: не удалось создать файл %s\n", filename); + return; + } + + fprintf(file, "=== Рабочий диапазон таблицы: %s ===\n", table_name); + fprintf(file, "Диапазон ADC: %u - %u\n", min_adc, max_adc); + fprintf(file, "%-8s %-12s %-15s\n", "ADC", "Temp (°C)", "Resistance (Ω)"); + fprintf(file, "----------------------------------------\n"); + + int count = 0; + for (int i = 0; i < TABLE_SIZE_LOOKUP; i++) { + if (table[i].adc_value >= min_adc && table[i].adc_value <= max_adc) { + fprintf(file, "%-8u %-12.1f %-15.2f\n", + table[i].adc_value, + table[i].temp_c / 10.0f, + table[i].resistance_ohm); + count++; + } + } + + fprintf(file, "\nВсего записей в рабочем диапазоне: %d\n", count); + fclose(file); + printf("Рабочий диапазон таблицы '%s' сохранен в файл: %s\n", table_name, filename); +} + int main() { // Инициализируем обе таблицы одновременно с разными значениями R1 init_both_tables(3300.0f, // R1 для KST45 @@ -34,39 +123,46 @@ int main() { const fast_lookup_tables_t* tables = get_fast_tables(); printf("\n=== Пример данных из таблиц быстрого поиска ===\n"); - printf("KST45 таблица (первые 3 записи):\n"); - for(int i = 0; i < 3; i++) { + printf("KST45 таблица (первые 15 записи):\n"); + for(int i = 0; i < 15; i++) { printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", tables->kst45[i].adc_value, tables->kst45[i].temp_c / 10.0f, tables->kst45[i].resistance_ohm); } - printf("\nINCAR таблица (первые 3 записи):\n"); - for(int i = 0; i < 3; i++) { + printf("\nINCAR таблица (первые 15 записи):\n"); + for(int i = 0; i < 15; i++) { printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", tables->incar[i].adc_value, tables->incar[i].temp_c / 10.0f, tables->incar[i].resistance_ohm); } - - printf("\nKST45 таблица (последние 3 записи):\n"); - for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 4; i--) { + printf("\nKST45 таблица (последние 15 записи):\n"); + for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 16; i--) { printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", tables->kst45[i].adc_value, tables->kst45[i].temp_c / 10.0f, tables->kst45[i].resistance_ohm); } - printf("\nINCAR таблица (последние 3 записи):\n"); - for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 4; i--) { + printf("\nINCAR таблица (последние 15 записи):\n"); + for(int i = TABLE_SIZE_LOOKUP - 1; i > TABLE_SIZE_LOOKUP - 16; i--) { printf(" ADC: %u, Temp: %.1f °C, R: %.2f Ω\n", tables->incar[i].adc_value, tables->incar[i].temp_c / 10.0f, tables->incar[i].resistance_ohm); } + // Сохраняем таблицы в файлы + printf("\n=== Сохранение таблиц в файлы ===\n"); + save_both_tables(); + + // Сохраняем только рабочие диапазоны (без зон насыщения) + // Для KST45 рабочий диапазон примерно от 58 до 3418 + save_working_range_to_file("kst45_working_range.txt", tables->kst45, "KST45", 58, 3418); + save_working_range_to_file("incar_working_range.txt", tables->incar, "INCAR", 58, 3418); // Пример обратного преобразования (температура -> сопротивление) printf("\n=== Обратное преобразование ===\n"); diff --git a/APP/src/ADC_Temp.c b/APP/src/ADC_Temp.c index e445b92..3961b53 100644 --- a/APP/src/ADC_Temp.c +++ b/APP/src/ADC_Temp.c @@ -319,48 +319,91 @@ void init_fast_lookup_table(eNtcTable table_type, float r1, eAlg use_alg) { uint16_t min_valid_adc = 0; uint16_t max_valid_adc = 0; - // Ищем минимальное АЦП, при котором температура >= start_temp + // Значения для граничных точек + 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 + // Ищем максимальное АЦП, при котором температура <= 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; } } - // Если не нашли корректные значения, используем весь диапазон - if (min_valid_adc == 0) min_valid_adc = 1; - if (max_valid_adc == 0) max_valid_adc = (uint16_t)(ADC_MAX - 1); + // Заполняем таблицу для всего диапазона 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; - // Заполняем таблицу 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)); + uint16_t adc; - float resistance = calculate_resistance(adc, r1); - float temp = get_temperature_from_adc_with_table(adc, use_alg, table_type, r1); + 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 (temp < start_temp) temp = (float)start_temp; - if (temp > end_temp) temp = (float)end_temp; + // Убеждаемся, что значения монотонно возрастают и нет дубликатов + 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; } // Устанавливаем флаг инициализации @@ -397,11 +440,6 @@ const fast_lookup_tables_t* get_fast_tables(void) { return &g_fast_tables; } -// Быстрые функции с использованием активной таблицы -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_log_fast_for_table(uint16_t adc_value, eNtcTable table_type) { if (!is_table_initialized(table_type)) { @@ -413,49 +451,34 @@ int16_t get_temperature_log_fast_for_table(uint16_t adc_value, eNtcTable table_t adc_temp_lookup* fast_table = get_fast_table_by_type(table_type); - // Защита от выхода за границы - if (adc_value >= fast_table[TABLE_SIZE_LOOKUP - 1].adc_value) { - return fast_table[TABLE_SIZE_LOOKUP - 1].temp_c; - } - if (adc_value <= fast_table[0].adc_value) { - return fast_table[0].temp_c; - } - - // Бинарный поиск интервала - int left = 0; - int right = TABLE_SIZE_LOOKUP - 1; - - while (left <= right) { - int mid = left + (right - left) / 2; - - if (fast_table[mid].adc_value <= adc_value && - (mid == TABLE_SIZE_LOOKUP - 1 || adc_value < fast_table[mid + 1].adc_value)) { - // Нашли интервал - if (mid == TABLE_SIZE_LOOKUP - 1) { - return fast_table[mid].temp_c; - } - + // Простой линейный поиск (так как таблица небольшая - 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[mid].adc_value; - uint16_t adc2 = fast_table[mid + 1].adc_value; - int16_t temp1 = fast_table[mid].temp_c; - int16_t temp2 = fast_table[mid + 1].temp_c; + 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[mid].adc_value) { - right = mid - 1; - } else { - left = mid + 1; + return temp1 + ((int32_t)(temp2 - temp1) * (adc_value - adc1)) / (adc2 - adc1); } } - return fast_table[0].temp_c; + // Если не нашли, возвращаем ближайшее значение + 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); } // Альтернативная простая версия @@ -463,11 +486,6 @@ 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(int16_t temperature_c10) { - return get_resistance_log_fast_for_table(temperature_c10, active_config.table_type); -} - // Функция для получения сопротивления из температуры для конкретной таблицы float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table_type) { if (!is_table_initialized(table_type)) { @@ -522,6 +540,11 @@ float get_resistance_log_fast_for_table(int16_t temperature_c10, eNtcTable table 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);